aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore11
-rw-r--r--ChangeLog1291
-rw-r--r--LICENSE33
-rw-r--r--Makefile.am37
-rw-r--r--Makefile.nmake10
-rw-r--r--ReleaseNotes1146
-rw-r--r--acinclude.m44
-rwxr-xr-xautogen.sh14
-rw-r--r--changes/10777_netunreach7
-rw-r--r--changes/6783_big_hammer6
-rw-r--r--changes/98543
-rw-r--r--changes/bug101243
-rw-r--r--changes/bug1040211
-rw-r--r--changes/bug104093
-rw-r--r--changes/bug104234
-rw-r--r--changes/bug104566
-rw-r--r--changes/bug104653
-rw-r--r--changes/bug104704
-rw-r--r--changes/bug104854
-rw-r--r--changes/bug10777_internal_0244
-rw-r--r--changes/bug107934
-rw-r--r--changes/bug108354
-rw-r--r--changes/bug109045
-rw-r--r--changes/bug199211
-rw-r--r--changes/bug22865
-rw-r--r--changes/bug55958
-rw-r--r--changes/bug60242
-rw-r--r--changes/bug60264
-rw-r--r--changes/bug60436
-rw-r--r--changes/bug60556
-rw-r--r--changes/bug61746
-rw-r--r--changes/bug62066
-rw-r--r--changes/bug62183
-rw-r--r--changes/bug6244_part_c6
-rw-r--r--changes/bug62516
-rw-r--r--changes/bug6252_again11
-rw-r--r--changes/bug62717
-rw-r--r--changes/bug62743
-rw-r--r--changes/bug6274_23
-rw-r--r--changes/bug62964
-rw-r--r--changes/bug63044
-rw-r--r--changes/bug63415
-rw-r--r--changes/bug63774
-rw-r--r--changes/bug63796
-rw-r--r--changes/bug63873
-rw-r--r--changes/bug63974
-rw-r--r--changes/bug640416
-rw-r--r--changes/bug64233
-rw-r--r--changes/bug64363
-rw-r--r--changes/bug64724
-rw-r--r--changes/bug64756
-rw-r--r--changes/bug64805
-rw-r--r--changes/bug64904
-rw-r--r--changes/bug65002
-rw-r--r--changes/bug650715
-rw-r--r--changes/bug65145
-rw-r--r--changes/bug65305
-rw-r--r--changes/bug65724
-rw-r--r--changes/bug66734
-rw-r--r--changes/bug66907
-rw-r--r--changes/bug67106
-rw-r--r--changes/bug67323
-rw-r--r--changes/bug67439
-rw-r--r--changes/bug67744
-rw-r--r--changes/bug68015
-rw-r--r--changes/bug68115
-rw-r--r--changes/bug68279
-rw-r--r--changes/bug68444
-rw-r--r--changes/bug68664
-rw-r--r--changes/bug70145
-rw-r--r--changes/bug70223
-rw-r--r--changes/bug70376
-rw-r--r--changes/bug70544
-rw-r--r--changes/bug70655
-rw-r--r--changes/bug71399
-rw-r--r--changes/bug71434
-rw-r--r--changes/bug7164_diagnostic4
-rw-r--r--changes/bug71906
-rw-r--r--changes/bug71915
-rw-r--r--changes/bug719210
-rw-r--r--changes/bug72804
-rw-r--r--changes/bug730211
-rw-r--r--changes/bug73504
-rw-r--r--changes/bug735212
-rw-r--r--changes/bug74644
-rw-r--r--changes/bug75829
-rw-r--r--changes/bug7707_diagnostic5
-rw-r--r--changes/bug77683
-rw-r--r--changes/bug77997
-rw-r--r--changes/bug780113
-rw-r--r--changes/bug7816.0248
-rw-r--r--changes/bug7816_0237
-rw-r--r--changes/bug7816_023_small3
-rw-r--r--changes/bug78898
-rw-r--r--changes/bug79027
-rw-r--r--changes/bug79474
-rw-r--r--changes/bug79504
-rw-r--r--changes/bug79823
-rw-r--r--changes/bug80025
-rw-r--r--changes/bug80145
-rw-r--r--changes/bug80317
-rw-r--r--changes/bug80378
-rw-r--r--changes/bug80596
-rw-r--r--changes/bug80625
-rw-r--r--changes/bug80656
-rw-r--r--changes/bug8093.part13
-rw-r--r--changes/bug811713
-rw-r--r--changes/bug81217
-rw-r--r--changes/bug81515
-rw-r--r--changes/bug81583
-rw-r--r--changes/bug81616
-rw-r--r--changes/bug81807
-rw-r--r--changes/bug8185_diagnostic3
-rw-r--r--changes/bug82005
-rw-r--r--changes/bug82034
-rw-r--r--changes/bug82077
-rw-r--r--changes/bug82096
-rw-r--r--changes/bug82106
-rw-r--r--changes/bug82186
-rw-r--r--changes/bug82315
-rw-r--r--changes/bug8235-diagnosing5
-rw-r--r--changes/bug8253-fix6
-rw-r--r--changes/bug82733
-rw-r--r--changes/bug82909
-rw-r--r--changes/bug84084
-rw-r--r--changes/bug84275
-rw-r--r--changes/bug84354
-rw-r--r--changes/bug84645
-rw-r--r--changes/bug84754
-rw-r--r--changes/bug8477-easypart3
-rw-r--r--changes/bug85875
-rw-r--r--changes/bug85963
-rw-r--r--changes/bug85986
-rw-r--r--changes/bug85994
-rw-r--r--changes/bug86383
-rw-r--r--changes/bug86395
-rw-r--r--changes/bug87116
-rw-r--r--changes/bug87163
-rw-r--r--changes/bug87196
-rw-r--r--changes/bug88225
-rw-r--r--changes/bug88333
-rw-r--r--changes/bug88453
-rw-r--r--changes/bug88464
-rw-r--r--changes/bug88795
-rw-r--r--changes/bug89653
-rw-r--r--changes/bug90476
-rw-r--r--changes/bug90632
-rw-r--r--changes/bug91224
-rw-r--r--changes/bug91474
-rw-r--r--changes/bug92005
-rw-r--r--changes/bug92544
-rw-r--r--changes/bug92884
-rw-r--r--changes/bug92954
-rw-r--r--changes/bug93096
-rw-r--r--changes/bug93374
-rw-r--r--changes/bug93545
-rw-r--r--changes/bug93664
-rw-r--r--changes/bug94007
-rw-r--r--changes/bug95434
-rw-r--r--changes/bug95964
-rw-r--r--changes/bug96025
-rw-r--r--changes/bug96444
-rw-r--r--changes/bug9645a5
-rw-r--r--changes/bug97164
-rw-r--r--changes/bug97313
-rw-r--r--changes/bug97765
-rw-r--r--changes/bug97808
-rw-r--r--changes/bug98808
-rw-r--r--changes/bug99044
-rw-r--r--changes/bug99274
-rw-r--r--changes/bug994611
-rw-r--r--changes/cov7090564
-rw-r--r--changes/cov9806504
-rw-r--r--changes/cve-2012-22495
-rw-r--r--changes/dirserv-BUGGY-a7
-rw-r--r--changes/disable_pathbias_messages3
-rw-r--r--changes/doc-heartbeat-loglevel3
-rw-r--r--changes/easy.ratelim3
-rw-r--r--changes/feature49947
-rw-r--r--changes/feature95747
-rw-r--r--changes/fix-geoipexclude-doc4
-rw-r--r--changes/geoip-dec20123
-rw-r--r--changes/geoip-jan20133
-rw-r--r--changes/geoip-nov20123
-rw-r--r--changes/integers_donna3
-rw-r--r--changes/less_charbuf_usage5
-rw-r--r--changes/link_negotiation_assert6
-rw-r--r--changes/log-noise11
-rw-r--r--changes/no_client_timestamps_02414
-rw-r--r--changes/pathsel-BUGGY-a14
-rw-r--r--changes/port_doc3
-rw-r--r--changes/revert-geoip-may20126
-rw-r--r--changes/signof_enum7
-rw-r--r--changes/smartlist_foreach8
-rw-r--r--changes/ticket22678
-rw-r--r--changes/ticket57493
-rw-r--r--changes/ticket82404
-rw-r--r--changes/ticket84434
-rw-r--r--changes/ticket96584
-rw-r--r--changes/ticket98663
-rw-r--r--changes/v3_intro_len8
-rw-r--r--changes/warn-unsigned-time_t5
-rw-r--r--configure.ac (renamed from configure.in)235
-rw-r--r--contrib/Makefile.am23
-rwxr-xr-xcontrib/findMergedChanges.pl2
-rw-r--r--contrib/include.am17
-rw-r--r--contrib/polipo/polipo-mingw.nsi2
-rwxr-xr-xcontrib/redox.py2
-rw-r--r--contrib/suse/Makefile.am3
-rw-r--r--contrib/suse/include.am1
-rw-r--r--contrib/tor-mingw.nsi.in4
-rw-r--r--contrib/tor-tsocks.conf13
-rw-r--r--contrib/tor.nsi.in2
-rwxr-xr-xcontrib/updateVersions.pl16
-rw-r--r--doc/HACKING32
-rw-r--r--doc/Makefile.am89
-rw-r--r--doc/TODO11
-rw-r--r--doc/TODO.021386
-rw-r--r--doc/TODO.02292
-rw-r--r--doc/TODO.external4
-rw-r--r--doc/TODO.future330
-rwxr-xr-xdoc/asciidoc-helper.sh4
-rw-r--r--doc/contrib/authority-policy.txt89
-rw-r--r--doc/contrib/incentives.txt479
-rw-r--r--doc/contrib/tor-rpm-creation.txt (renamed from doc/tor-rpm-creation.txt)0
-rw-r--r--doc/contrib/torel-design.txt181
-rw-r--r--doc/include.am89
-rw-r--r--doc/spec/README11
-rw-r--r--doc/tor-fw-helper.1.txt26
-rw-r--r--doc/tor-gencert.1.txt2
-rw-r--r--doc/tor-resolve.1.txt2
-rw-r--r--doc/tor-win32-mingw-creation.txt119
-rw-r--r--doc/tor.1.txt833
-rw-r--r--doc/torify.1.txt26
-rw-r--r--doc/translations.txt182
-rw-r--r--doc/v3-authority-howto.txt84
-rw-r--r--m4/ax_check_sign.m454
-rw-r--r--src/Makefile.am5
-rw-r--r--src/common/Makefile.am67
-rw-r--r--src/common/Makefile.nmake11
-rw-r--r--src/common/address.c259
-rw-r--r--src/common/address.h27
-rw-r--r--src/common/aes.c43
-rw-r--r--src/common/aes.h6
-rw-r--r--src/common/compat.c167
-rw-r--r--src/common/compat.h58
-rw-r--r--src/common/compat_libevent.c105
-rw-r--r--src/common/compat_libevent.h6
-rw-r--r--src/common/container.c165
-rw-r--r--src/common/container.h69
-rw-r--r--src/common/crypto.c515
-rw-r--r--src/common/crypto.h40
-rw-r--r--src/common/crypto_curve25519.c191
-rw-r--r--src/common/crypto_curve25519.h68
-rw-r--r--src/common/crypto_format.c46
-rw-r--r--src/common/di_ops.c93
-rw-r--r--src/common/di_ops.h18
-rw-r--r--src/common/include.am96
-rw-r--r--src/common/log.c147
-rw-r--r--src/common/memarea.c6
-rw-r--r--src/common/memarea.h6
-rw-r--r--src/common/mempool.c16
-rw-r--r--src/common/mempool.h6
-rw-r--r--src/common/procmon.c41
-rw-r--r--src/common/procmon.h2
-rw-r--r--src/common/sha256.c331
-rw-r--r--src/common/torgzip.c2
-rw-r--r--src/common/torgzip.h6
-rw-r--r--src/common/torint.h10
-rw-r--r--src/common/torlog.h82
-rw-r--r--src/common/tortls.c512
-rw-r--r--src/common/tortls.h22
-rw-r--r--src/common/util.c868
-rw-r--r--src/common/util.h118
-rw-r--r--src/config/Makefile.am16
-rw-r--r--src/config/README.geoip90
-rwxr-xr-xsrc/config/deanonymind.py194
-rw-r--r--src/config/geoip-manual116
-rw-r--r--src/config/geoip611638
-rw-r--r--src/config/include.am16
-rw-r--r--src/config/torrc.sample.in4
-rw-r--r--src/ext/OpenBSD_malloc_Linux.c (renamed from src/common/OpenBSD_malloc_Linux.c)0
-rw-r--r--src/ext/README44
-rw-r--r--src/ext/curve25519_donna/README44
-rw-r--r--src/ext/curve25519_donna/curve25519-donna-c64.c451
-rw-r--r--src/ext/curve25519_donna/curve25519-donna.c732
-rw-r--r--src/ext/eventdns.c (renamed from src/or/eventdns.c)131
-rw-r--r--src/ext/eventdns.h (renamed from src/or/eventdns.h)4
-rw-r--r--src/ext/ht.h (renamed from src/common/ht.h)22
-rw-r--r--src/ext/include.am17
-rw-r--r--src/ext/strlcat.c (renamed from src/common/strlcat.c)0
-rw-r--r--src/ext/strlcpy.c (renamed from src/common/strlcpy.c)0
-rw-r--r--src/ext/tinytest.c (renamed from src/test/tinytest.c)0
-rw-r--r--src/ext/tinytest.h (renamed from src/test/tinytest.h)0
-rw-r--r--src/ext/tinytest_demo.c (renamed from src/test/tinytest_demo.c)0
-rw-r--r--src/ext/tinytest_macros.h (renamed from src/test/tinytest_macros.h)0
-rw-r--r--src/ext/tor_queue.h568
-rw-r--r--src/ext/tor_queue.txt883
-rw-r--r--src/include.am7
-rw-r--r--src/or/Makefile.am158
-rw-r--r--src/or/Makefile.nmake81
-rw-r--r--src/or/addressmap.c1078
-rw-r--r--src/or/addressmap.h60
-rw-r--r--src/or/buffers.c87
-rw-r--r--src/or/buffers.h6
-rw-r--r--src/or/channel.c4132
-rw-r--r--src/or/channel.h484
-rw-r--r--src/or/channeltls.c2037
-rw-r--r--src/or/channeltls.h57
-rw-r--r--src/or/circuitbuild.c5846
-rw-r--r--src/or/circuitbuild.h160
-rw-r--r--src/or/circuitlist.c647
-rw-r--r--src/or/circuitlist.h42
-rw-r--r--src/or/circuitmux.c1745
-rw-r--r--src/or/circuitmux.h136
-rw-r--r--src/or/circuitmux_ewma.c684
-rw-r--r--src/or/circuitmux_ewma.h29
-rw-r--r--src/or/circuitstats.c1556
-rw-r--r--src/or/circuitstats.h65
-rw-r--r--src/or/circuituse.c519
-rw-r--r--src/or/circuituse.h7
-rw-r--r--src/or/command.c1183
-rw-r--r--src/or/command.h14
-rw-r--r--src/or/config.c3104
-rw-r--r--src/or/config.h24
-rw-r--r--src/or/confparse.c1231
-rw-r--r--src/or/confparse.h132
-rw-r--r--src/or/connection.c533
-rw-r--r--src/or/connection.h64
-rw-r--r--src/or/connection_edge.c1699
-rw-r--r--src/or/connection_edge.h80
-rw-r--r--src/or/connection_or.c906
-rw-r--r--src/or/connection_or.h34
-rw-r--r--src/or/control.c214
-rw-r--r--src/or/control.h11
-rw-r--r--src/or/cpuworker.c435
-rw-r--r--src/or/cpuworker.h14
-rw-r--r--src/or/directory.c636
-rw-r--r--src/or/directory.h29
-rw-r--r--src/or/dirserv.c856
-rw-r--r--src/or/dirserv.h53
-rw-r--r--src/or/dirvote.c606
-rw-r--r--src/or/dirvote.h61
-rw-r--r--src/or/dns.c1032
-rw-r--r--src/or/dns.h7
-rw-r--r--src/or/dnsserv.c42
-rw-r--r--src/or/dnsserv.h9
-rw-r--r--src/or/entrynodes.c2255
-rw-r--r--src/or/entrynodes.h127
-rw-r--r--src/or/eventdns_tor.h7
-rw-r--r--src/or/fp_pair.c308
-rw-r--r--src/or/fp_pair.h45
-rw-r--r--src/or/geoip.c705
-rw-r--r--src/or/geoip.h27
-rw-r--r--src/or/hibernate.c21
-rw-r--r--src/or/hibernate.h6
-rw-r--r--src/or/include.am195
-rw-r--r--src/or/main.c167
-rw-r--r--src/or/main.h6
-rw-r--r--src/or/microdesc.c181
-rw-r--r--src/or/microdesc.h10
-rw-r--r--src/or/networkstatus.c172
-rw-r--r--src/or/networkstatus.h12
-rw-r--r--src/or/nodelist.c794
-rw-r--r--src/or/nodelist.h41
-rw-r--r--src/or/ntmain.c2
-rw-r--r--src/or/ntmain.h6
-rw-r--r--src/or/onion.c1343
-rw-r--r--src/or/onion.h128
-rw-r--r--src/or/onion_fast.c123
-rw-r--r--src/or/onion_fast.h38
-rw-r--r--src/or/onion_ntor.c295
-rw-r--r--src/or/onion_ntor.h63
-rw-r--r--src/or/onion_tap.c218
-rw-r--r--src/or/onion_tap.h37
-rw-r--r--src/or/or.h1040
-rw-r--r--src/or/policies.c222
-rw-r--r--src/or/policies.h21
-rw-r--r--src/or/reasons.c38
-rw-r--r--src/or/reasons.h6
-rw-r--r--src/or/relay.c1194
-rw-r--r--src/or/relay.h46
-rw-r--r--src/or/rendclient.c179
-rw-r--r--src/or/rendclient.h6
-rw-r--r--src/or/rendcommon.c21
-rw-r--r--src/or/rendcommon.h7
-rw-r--r--src/or/rendmid.c72
-rw-r--r--src/or/rendmid.h6
-rw-r--r--src/or/rendservice.c1897
-rw-r--r--src/or/rendservice.h79
-rw-r--r--src/or/rephist.c96
-rw-r--r--src/or/rephist.h16
-rw-r--r--src/or/replaycache.c215
-rw-r--r--src/or/replaycache.h66
-rw-r--r--src/or/router.c747
-rw-r--r--src/or/router.h30
-rw-r--r--src/or/routerlist.c2497
-rw-r--r--src/or/routerlist.h123
-rw-r--r--src/or/routerparse.c621
-rw-r--r--src/or/routerparse.h18
-rw-r--r--src/or/routerset.c466
-rw-r--r--src/or/routerset.h49
-rw-r--r--src/or/statefile.c616
-rw-r--r--src/or/statefile.h22
-rw-r--r--src/or/status.c29
-rw-r--r--src/or/status.h6
-rw-r--r--src/or/tor_main.c8
-rw-r--r--src/or/transports.c541
-rw-r--r--src/or/transports.h53
-rw-r--r--src/test/Makefile.am49
-rw-r--r--src/test/Makefile.nmake24
-rw-r--r--src/test/bench.c264
-rw-r--r--src/test/include.am68
-rw-r--r--src/test/ntor_ref.py387
-rw-r--r--src/test/test-child.c2
-rw-r--r--src/test/test.c342
-rw-r--r--src/test/test.h10
-rw-r--r--src/test/test_addr.c260
-rw-r--r--src/test/test_cell_formats.c888
-rw-r--r--src/test/test_config.c11
-rw-r--r--src/test/test_containers.c241
-rw-r--r--src/test/test_crypto.c332
-rw-r--r--src/test/test_data.c2
-rw-r--r--src/test/test_dir.c1452
-rw-r--r--src/test/test_introduce.c528
-rw-r--r--src/test/test_microdesc.c63
-rw-r--r--src/test/test_ntor_cl.c170
-rw-r--r--src/test/test_pt.c2
-rw-r--r--src/test/test_replay.c178
-rw-r--r--src/test/test_util.c452
-rw-r--r--src/tools/Makefile.am22
-rw-r--r--src/tools/Makefile.nmake4
-rw-r--r--src/tools/include.am24
-rw-r--r--src/tools/tor-checkkey.c4
-rw-r--r--src/tools/tor-fw-helper/Makefile.am38
-rw-r--r--src/tools/tor-fw-helper/include.am36
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-natpmp.c74
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-natpmp.h10
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-upnp.c46
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-upnp.h9
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper.c371
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper.h26
-rw-r--r--src/tools/tor-gencert.c15
-rw-r--r--src/tools/tor-resolve.c83
-rw-r--r--src/win32/Makefile.am3
-rw-r--r--src/win32/include.am3
-rw-r--r--src/win32/orconfig.h17
-rw-r--r--tor.spec.in360
448 files changed, 62163 insertions, 21958 deletions
diff --git a/.gitignore b/.gitignore
index 3a28ecfd4..e48918d32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,8 +21,11 @@
*.log
# Autotools stuff
.deps
+.dirstamp
# Stuff made by our makefiles
*.bak
+# Python droppings
+*.pyc
# /
/Makefile
@@ -41,10 +44,12 @@
/config.guess
/config.sub
/conftest*
+/micro-revision.*
/patch-stamp
/stamp-h
/stamp-h.in
/stamp-h1
+/test-driver
/tor.sh
/tor.spec
/depcomp
@@ -128,6 +133,8 @@
/src/common/libor-crypto.lib
/src/common/libor-event.a
/src/common/libor-event.lib
+/src/common/libcurve25519_donna.a
+/src/common/libcurve25519_donna.lib
# /src/config/
/src/config/Makefile
@@ -140,7 +147,6 @@
/src/or/Makefile
/src/or/Makefile.in
/src/or/or_sha1.i
-/src/or/micro-revision.*
/src/or/tor
/src/or/tor.exe
/src/or/libtor.a
@@ -153,9 +159,10 @@
/src/test/bench.exe
/src/test/test
/src/test/test-child
+/src/test/test-ntor-cl
/src/test/test.exe
/src/test/test-child.exe
-
+/src/test/test-ntor-cl.exe
# /src/tools/
/src/tools/tor-checkkey
diff --git a/ChangeLog b/ChangeLog
index 3d666a654..e08f3c1c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1266 @@
+Changes in version 0.2.4.10-alpha - 2013-02-04
+ Tor 0.2.4.10-alpha adds defenses at the directory authority level from
+ certain attacks that flood the network with relays; changes the queue
+ for circuit create requests from a sized-based limit to a time-based
+ limit; resumes building with MSVC on Windows; and fixes a wide variety
+ of other issues.
+
+ o Major bugfixes (directory authority):
+ - When computing directory thresholds, ignore any rejected-as-sybil
+ nodes during the computation so that they can't influence Fast,
+ Guard, etc. (We should have done this for proposal 109.) Fixes
+ bug 8146.
+ - When marking a node as a likely sybil, reset its uptime metrics
+ to zero, so that it cannot time towards getting marked as Guard,
+ Stable, or HSDir. (We should have done this for proposal 109.) Fixes
+ bug 8147.
+
+ o Major bugfixes:
+ - When a TLS write is partially successful but incomplete, remember
+ that the flushed part has been flushed, and notice that bytes were
+ actually written. Reported and fixed pseudonymously. Fixes bug
+ 7708; bugfix on Tor 0.1.0.5-rc.
+ - Reject bogus create and relay cells with 0 circuit ID or 0 stream
+ ID: these could be used to create unexpected streams and circuits
+ which would count as "present" to some parts of Tor but "absent"
+ to others, leading to zombie circuits and streams or to a bandwidth
+ denial-of-service. Fixes bug 7889; bugfix on every released version
+ of Tor. Reported by "oftc_must_be_destroyed".
+ - Rename all macros in our local copy of queue.h to begin with "TOR_".
+ This change seems the only good way to permanently prevent conflicts
+ with queue.h on various operating systems. Fixes bug 8107; bugfix
+ on 0.2.4.6-alpha.
+
+ o Major features (relay):
+ - Instead of limiting the number of queued onionskins (aka circuit
+ create requests) to a fixed, hard-to-configure number, we limit
+ the size of the queue based on how many we expect to be able to
+ process in a given amount of time. We estimate the time it will
+ take to process an onionskin based on average processing time
+ of previous onionskins. Closes ticket 7291. You'll never have to
+ configure MaxOnionsPending again.
+
+ o Major features (portability):
+ - Resume building correctly with MSVC and Makefile.nmake. This patch
+ resolves numerous bugs and fixes reported by ultramage, including
+ 7305, 7308, 7309, 7310, 7312, 7313, 7315, 7316, and 7669.
+ - Make the ntor and curve25519 code build correctly with MSVC.
+ Fix on 0.2.4.8-alpha.
+
+ o Minor features:
+ - When directory authorities are computing thresholds for flags,
+ never let the threshold for the Fast flag fall below 4096
+ bytes. Also, do not consider nodes with extremely low bandwidths
+ when deciding thresholds for various directory flags. This change
+ should raise our threshold for Fast relays, possibly in turn
+ improving overall network performance; see ticket 1854. Resolves
+ ticket 8145.
+ - The Tor client now ignores sub-domain components of a .onion
+ address. This change makes HTTP "virtual" hosting
+ possible: http://foo.aaaaaaaaaaaaaaaa.onion/ and
+ http://bar.aaaaaaaaaaaaaaaa.onion/ can be two different websites
+ hosted on the same hidden service. Implements proposal 204.
+ - We compute the overhead from passing onionskins back and forth to
+ cpuworkers, and report it when dumping statistics in response to
+ SIGUSR1. Supports ticket 7291.
+
+ o Minor features (path selection):
+ - When deciding whether we have enough descriptors to build circuits,
+ instead of looking at raw relay counts, look at which fraction
+ of (bandwidth-weighted) paths we're able to build. This approach
+ keeps clients from building circuits if their paths are likely to
+ stand out statistically. The default fraction of paths needed is
+ taken from the consensus directory; you can override it with the
+ new PathsNeededToBuildCircuits option. Fixes ticket 5956.
+ - When any country code is listed in ExcludeNodes or ExcludeExitNodes,
+ and we have GeoIP information, also exclude all nodes with unknown
+ countries "??" and "A1". This behavior is controlled by the
+ new GeoIPExcludeUnknown option: you can make such nodes always
+ excluded with "GeoIPExcludeUnknown 1", and disable the feature
+ with "GeoIPExcludeUnknown 0". Setting "GeoIPExcludeUnknown auto"
+ gets you the default behavior. Implements feature 7706.
+ - Path Use Bias: Perform separate accounting for successful circuit
+ use. Keep separate statistics on stream attempt rates versus stream
+ success rates for each guard. Provide configurable thresholds to
+ determine when to emit log messages or disable use of guards that
+ fail too many stream attempts. Resolves ticket 7802.
+
+ o Minor features (log messages):
+ - When learning a fingerprint for a bridge, log its corresponding
+ transport type. Implements ticket 7896.
+ - Improve the log message when "Bug/attack: unexpected sendme cell
+ from client" occurs, to help us track bug 8093.
+
+ o Minor bugfixes:
+ - Remove a couple of extraneous semicolons that were upsetting the
+ cparser library. Patch by Christian Grothoff. Fixes bug 7115;
+ bugfix on 0.2.2.1-alpha.
+ - Remove a source of rounding error during path bias count scaling;
+ don't count cannibalized circuits as used for path bias until we
+ actually try to use them; and fix a circuit_package_relay_cell()
+ warning message about n_chan==NULL. Fixes bug 7802.
+ - Detect nacl when its headers are in a nacl/ subdirectory. Also,
+ actually link against nacl when we're configured to use it. Fixes
+ bug 7972; bugfix on 0.2.4.8-alpha.
+ - Compile correctly with the --disable-curve25519 option. Fixes
+ bug 8153; bugfix on 0.2.4.8-alpha.
+
+ o Build improvements:
+ - Do not report status verbosely from autogen.sh unless the -v flag
+ is specified. Fixes issue 4664. Patch from Onizuka.
+ - Replace all calls to snprintf() outside of src/ext with
+ tor_snprintf(). Also remove the #define to replace snprintf with
+ _snprintf on Windows; they have different semantics, and all of
+ our callers should be using tor_snprintf() anyway. Fixes bug 7304.
+ - Try to detect if we are ever building on a platform where
+ memset(...,0,...) does not set the value of a double to 0.0. Such
+ platforms are permitted by the C standard, though in practice
+ they're pretty rare (since IEEE 754 is nigh-ubiquitous). We don't
+ currently support them, but it's better to detect them and fail
+ than to perform erroneously.
+
+ o Removed features:
+ - Stop exporting estimates of v2 and v3 directory traffic shares
+ in extrainfo documents. They were unneeded and sometimes inaccurate.
+ Also stop exporting any v2 directory request statistics. Resolves
+ ticket 5823.
+ - Drop support for detecting and warning about versions of Libevent
+ before 1.3e. Nothing reasonable ships with them any longer;
+ warning the user about them shouldn't be needed. Resolves ticket
+ 6826.
+
+ o Code simplifications and refactoring:
+ - Rename "isin" functions to "contains", for grammar. Resolves
+ ticket 5285.
+ - Rename Tor's logging function log() to tor_log(), to avoid conflicts
+ with the natural logarithm function from the system libm. Resolves
+ ticket 7599.
+
+
+Changes in version 0.2.4.9-alpha - 2013-01-15
+ Tor 0.2.4.9-alpha provides a quick fix to make the new ntor handshake
+ work more robustly.
+
+ o Major bugfixes:
+ - Fix backward compatibility logic when receiving an embedded ntor
+ handshake tunneled in a CREATE cell. This clears up the "Bug:
+ couldn't format CREATED cell" warning. Fixes bug 7959; bugfix
+ on 0.2.4.8-alpha.
+
+
+Changes in version 0.2.4.8-alpha - 2013-01-14
+ Tor 0.2.4.8-alpha introduces directory guards to reduce user enumeration
+ risks, adds a new stronger and faster circuit handshake, and offers
+ stronger and faster link encryption when both sides support it.
+
+ o Major features:
+ - Preliminary support for directory guards (proposal 207): when
+ possible, clients now use their entry guards for non-anonymous
+ directory requests. This can help prevent client enumeration. Note
+ that this behavior only works when we have a usable consensus
+ directory, and when options about what to download are more or less
+ standard. In the future we should re-bootstrap from our guards,
+ rather than re-bootstrapping from the preconfigured list of
+ directory sources that ships with Tor. Resolves ticket 6526.
+ - Tor relays and clients now support a better CREATE/EXTEND cell
+ format, allowing the sender to specify multiple address, identity,
+ and handshake types. Implements Robert Ransom's proposal 200;
+ closes ticket 7199.
+
+ o Major features (new circuit handshake):
+ - Tor now supports a new circuit extension handshake designed by Ian
+ Goldberg, Douglas Stebila, and Berkant Ustaoglu. Our original
+ circuit extension handshake, later called "TAP", was a bit slow
+ (especially on the relay side), had a fragile security proof, and
+ used weaker keys than we'd now prefer. The new circuit handshake
+ uses Dan Bernstein's "curve25519" elliptic-curve Diffie-Hellman
+ function, making it significantly more secure than the older
+ handshake, and significantly faster. Tor can use one of two built-in
+ pure-C curve25519-donna implementations by Adam Langley, or it
+ can link against the "nacl" library for a tuned version if present.
+
+ The built-in version is very fast for 64-bit systems when building
+ with GCC. The built-in 32-bit version is still faster than the
+ old TAP protocol, but using libnacl is better on most such hosts.
+
+ Clients don't currently use this protocol by default, since
+ comparatively few clients support it so far. To try it, set
+ UseNTorHandshake to 1.
+
+ Implements proposal 216; closes ticket 7202.
+
+ o Major features (better link encryption):
+ - Relays can now enable the ECDHE TLS ciphersuites when available
+ and appropriate. These ciphersuites let us negotiate forward-secure
+ TLS secret keys more safely and more efficiently than with our
+ previous use of Diffie-Hellman modulo a 1024-bit prime. By default,
+ public relays prefer the (faster) P224 group, and bridges prefer
+ the (more common) P256 group; you can override this with the
+ TLSECGroup option.
+
+ Enabling these ciphers was a little tricky, since for a long time,
+ clients had been claiming to support them without actually doing
+ so, in order to foil fingerprinting. But with the client-side
+ implementation of proposal 198 in 0.2.3.17-beta, clients can now
+ match the ciphers from recent Firefox versions *and* list the
+ ciphers they actually mean, so relays can believe such clients
+ when they advertise ECDHE support in their TLS ClientHello messages.
+
+ This feature requires clients running 0.2.3.17-beta or later,
+ and requires both sides to be running OpenSSL 1.0.0 or later
+ with ECC support. OpenSSL 1.0.1, with the compile-time option
+ "enable-ec_nistp_64_gcc_128", is highly recommended.
+
+ Implements the relay side of proposal 198; closes ticket 7200.
+
+ o Major bugfixes:
+ - Avoid crashing when, as a relay without IPv6-exit support, a
+ client insists on getting an IPv6 address or nothing. Fixes bug
+ 7814; bugfix on 0.2.4.7-alpha.
+
+ o Minor features:
+ - Improve circuit build timeout handling for hidden services.
+ In particular: adjust build timeouts more accurately depending
+ upon the number of hop-RTTs that a particular circuit type
+ undergoes. Additionally, launch intro circuits in parallel
+ if they timeout, and take the first one to reply as valid.
+ - Work correctly on Unix systems where EAGAIN and EWOULDBLOCK are
+ separate error codes; or at least, don't break for that reason.
+ Fixes bug 7935. Reported by "oftc_must_be_destroyed".
+ - Update to the January 2 2013 Maxmind GeoLite Country database.
+
+ o Minor features (testing):
+ - Add benchmarks for DH (1024-bit multiplicative group) and ECDH
+ (P-256) Diffie-Hellman handshakes to src/or/bench.
+ - Add benchmark functions to test onion handshake performance.
+
+ o Minor features (path bias detection):
+ - Alter the Path Bias log messages to be more descriptive in terms
+ of reporting timeouts and other statistics.
+ - Create three levels of Path Bias log messages, as opposed to just
+ two. These are configurable via consensus as well as via the torrc
+ options PathBiasNoticeRate, PathBiasWarnRate, PathBiasExtremeRate.
+ The default values are 0.70, 0.50, and 0.30 respectively.
+ - Separate the log message levels from the decision to drop guards,
+ which also is available via torrc option PathBiasDropGuards.
+ PathBiasDropGuards still defaults to 0 (off).
+ - Deprecate PathBiasDisableRate in favor of PathBiasDropGuards
+ in combination with PathBiasExtremeRate.
+ - Increase the default values for PathBiasScaleThreshold and
+ PathBiasCircThreshold from (200, 20) to (300, 150).
+ - Add in circuit usage accounting to path bias. If we try to use a
+ built circuit but fail for any reason, it counts as path bias.
+ Certain classes of circuits where the adversary gets to pick your
+ destination node are exempt from this accounting. Usage accounting
+ can be specifically disabled via consensus parameter or torrc.
+ - Convert all internal path bias state to double-precision floating
+ point, to avoid roundoff error and other issues.
+ - Only record path bias information for circuits that have completed
+ *two* hops. Assuming end-to-end tagging is the attack vector, this
+ makes us more resilient to ambient circuit failure without any
+ detection capability loss.
+
+ o Minor bugfixes (log messages):
+ - Rate-limit the "No circuits are opened. Relaxed timeout for a
+ circuit with channel state open..." message to once per hour to
+ keep it from filling the notice logs. Mitigates bug 7799 but does
+ not fix the underlying cause. Bugfix on 0.2.4.7-alpha.
+ - Avoid spurious warnings when configuring multiple client ports of
+ which only some are nonlocal. Previously, we had claimed that some
+ were nonlocal when in fact they weren't. Fixes bug 7836; bugfix on
+ 0.2.3.3-alpha.
+
+ o Code simplifications and refactoring:
+ - Get rid of a couple of harmless clang warnings, where we compared
+ enums to ints. These warnings are newly introduced in clang 3.2.
+ - Split the onion.c file into separate modules for the onion queue
+ and the different handshakes it supports.
+ - Remove the marshalling/unmarshalling code for sending requests to
+ cpuworkers over a socket, and instead just send structs. The
+ recipient will always be the same Tor binary as the sender, so
+ any encoding is overkill.
+
+
+Changes in version 0.2.4.7-alpha - 2012-12-24
+ Tor 0.2.4.7-alpha introduces a new approach to providing fallback
+ directory mirrors for more robust bootstrapping; fixes more issues where
+ clients with changing network conditions refuse to make any circuits;
+ adds initial support for exiting to IPv6 addresses; resumes being able
+ to update our GeoIP database, and includes the geoip6 file this time;
+ turns off the client-side DNS cache by default due to privacy risks;
+ and fixes a variety of other issues.
+
+ o Major features (client resilience):
+ - Add a new "FallbackDir" torrc option to use when we can't use
+ a directory mirror from the consensus (either because we lack a
+ consensus, or because they're all down). Currently, all authorities
+ are fallbacks by default, and there are no other default fallbacks,
+ but that will change. This option will allow us to give clients a
+ longer list of servers to try to get a consensus from when first
+ connecting to the Tor network, and thereby reduce load on the
+ directory authorities. Implements proposal 206, "Preconfigured
+ directory sources for bootstrapping". We also removed the old
+ "FallbackNetworkstatus" option, since we never got it working well
+ enough to use it. Closes bug 572.
+ - If we have no circuits open, use a relaxed timeout (the
+ 95-percentile cutoff) until a circuit succeeds. This heuristic
+ should allow Tor to succeed at building circuits even when the
+ network connection drastically changes. Should help with bug 3443.
+
+ o Major features (IPv6):
+ - Relays can now exit to IPv6 addresses: make sure that you have IPv6
+ connectivity, then set the IPv6Exit flag to 1. Also make sure your
+ exit policy reads as you would like: the address * applies to all
+ address families, whereas *4 is IPv4 address only, and *6 is IPv6
+ addresses only. On the client side, you'll need to wait until the
+ authorities have upgraded, wait for enough exits to support IPv6,
+ apply the "IPv6Traffic" flag to a SocksPort, and use Socks5. Closes
+ ticket 5547, implements proposal 117 as revised in proposal 208.
+
+ We DO NOT recommend that clients with actual anonymity needs start
+ using IPv6 over Tor yet, since not enough exits support it yet.
+
+ o Major features (geoip database):
+ - Maxmind began labelling Tor relays as being in country "A1",
+ which breaks by-country node selection inside Tor. Now we use a
+ script to replace "A1" ("Anonymous Proxy") entries in our geoip
+ file with real country codes. This script fixes about 90% of "A1"
+ entries automatically and uses manual country code assignments to
+ fix the remaining 10%. See src/config/README.geoip for details.
+ Fixes bug 6266. Also update to the December 5 2012 Maxmind GeoLite
+ Country database, as modified above.
+
+ o Major bugfixes (client-side DNS):
+ - Turn off the client-side DNS cache by default. Updating and using
+ the DNS cache is now configurable on a per-client-port
+ level. SOCKSPort, DNSPort, etc lines may now contain
+ {No,}Cache{IPv4,IPv6,}DNS lines to indicate that we shouldn't
+ cache these types of DNS answers when we receive them from an
+ exit node in response to an application request on this port, and
+ {No,}UseCached{IPv4,IPv6,DNS} lines to indicate that if we have
+ cached DNS answers of these types, we shouldn't use them. It's
+ potentially risky to use cached DNS answers at the client, since
+ doing so can indicate to one exit what answers we've gotten
+ for DNS lookups in the past. With IPv6, this becomes especially
+ problematic. Using cached DNS answers for requests on the same
+ circuit would present less linkability risk, since all traffic
+ on a circuit is already linkable, but it would also provide
+ little performance benefit: the exit node caches DNS replies
+ too. Implements a simplified version of Proposal 205. Implements
+ ticket 7570.
+
+ o Major bugfixes (other):
+ - Alter circuit build timeout measurement to start at the point
+ where we begin the CREATE/CREATE_FAST step (as opposed to circuit
+ initialization). This should make our timeout measurements more
+ uniform. Previously, we were sometimes including ORconn setup time
+ in our circuit build time measurements. Should resolve bug 3443.
+ - Fix an assertion that could trigger in hibernate_go_dormant() when
+ closing an or_connection_t: call channel_mark_for_close() rather
+ than connection_mark_for_close(). Fixes bug 7267. Bugfix on
+ 0.2.4.4-alpha.
+ - Include the geoip6 IPv6 GeoIP database in the tarball. Fixes bug
+ 7655; bugfix on 0.2.4.6-alpha.
+
+ o Minor features:
+ - Add a new torrc option "ServerTransportListenAddr" to let bridge
+ operators select the address where their pluggable transports will
+ listen for connections. Resolves ticket 7013.
+ - Allow an optional $ before the node identity digest in the
+ controller command GETINFO ns/id/<identity>, for consistency with
+ md/id/<identity> and desc/id/<identity>. Resolves ticket 7059.
+ - Log packaged cell fullness as part of the heartbeat message.
+ Diagnosis to try to determine the extent of bug 7743.
+
+ o Minor features (IPv6):
+ - AutomapHostsOnResolve now supports IPv6 addresses. By default, we
+ prefer to hand out virtual IPv6 addresses, since there are more of
+ them and we can't run out. To override this behavior and make IPv4
+ addresses preferred, set NoPreferIPv6Automap on whatever SOCKSPort
+ or DNSPort you're using for resolving. Implements ticket 7571.
+ - AutomapHostsOnResolve responses are now randomized, to avoid
+ annoying situations where Tor is restarted and applications
+ connect to the wrong addresses.
+ - Never try more than 1000 times to pick a new virtual address when
+ AutomapHostsOnResolve is set. That's good enough so long as we
+ aren't close to handing out our entire virtual address space;
+ if you're getting there, it's best to switch to IPv6 virtual
+ addresses anyway.
+
+ o Minor bugfixes:
+ - The ADDRMAP command can no longer generate an ill-formed error
+ code on a failed MAPADDRESS. It now says "internal" rather than
+ an English sentence fragment with spaces in the middle. Bugfix on
+ Tor 0.2.0.19-alpha.
+ - Fix log messages and comments to avoid saying "GMT" when we mean
+ "UTC". Fixes bug 6113.
+ - Compile on win64 using mingw64. Fixes bug 7260; patches from
+ "yayooo".
+ - Fix a crash when debugging unit tests on Windows: deallocate a
+ shared library with FreeLibrary, not CloseHandle. Fixes bug 7306;
+ bugfix on 0.2.2.17-alpha. Reported by "ultramage".
+
+ o Renamed options:
+ - The DirServer option is now DirAuthority, for consistency with
+ current naming patterns. You can still use the old DirServer form.
+
+ o Code simplification and refactoring:
+ - Move the client-side address-map/virtual-address/DNS-cache code
+ out of connection_edge.c into a new addressmap.c module.
+ - Remove unused code for parsing v1 directories and "running routers"
+ documents. Fixes bug 6887.
+
+
+Changes in version 0.2.3.25 - 2012-11-19
+ The Tor 0.2.3 release series is dedicated to the memory of Len "rabbi"
+ Sassaman (1980-2011), a long-time cypherpunk, anonymity researcher,
+ Mixmaster maintainer, Pynchon Gate co-designer, CodeCon organizer,
+ programmer, and friend. Unstinting in his dedication to the cause of
+ freedom, he inspired and helped many of us as we began our work on
+ anonymity, and inspires us still. Please honor his memory by writing
+ software to protect people's freedoms, and by helping others to do so.
+
+ Tor 0.2.3.25, the first stable release in the 0.2.3 branch, features
+ significantly reduced directory overhead (via microdescriptors),
+ enormous crypto performance improvements for fast relays on new
+ enough hardware, a new v3 TLS handshake protocol that can better
+ resist fingerprinting, support for protocol obfuscation plugins (aka
+ pluggable transports), better scalability for hidden services, IPv6
+ support for bridges, performance improvements like allowing clients
+ to skip the first round-trip on the circuit ("optimistic data") and
+ refilling token buckets more often, a new "stream isolation" design
+ to isolate different applications on different circuits, and many
+ stability, security, and privacy fixes.
+
+ o Major bugfixes:
+ - Tor tries to wipe potentially sensitive data after using it, so
+ that if some subsequent security failure exposes Tor's memory,
+ the damage will be limited. But we had a bug where the compiler
+ was eliminating these wipe operations when it decided that the
+ memory was no longer visible to a (correctly running) program,
+ hence defeating our attempt at defense in depth. We fix that
+ by using OpenSSL's OPENSSL_cleanse() operation, which a compiler
+ is unlikely to optimize away. Future versions of Tor may use
+ a less ridiculously heavy approach for this. Fixes bug 7352.
+ Reported in an article by Andrey Karpov.
+
+ o Minor bugfixes:
+ - Fix a harmless bug when opting against publishing a relay descriptor
+ because DisableNetwork is set. Fixes bug 7464; bugfix on
+ 0.2.3.9-alpha.
+
+
+Changes in version 0.2.4.6-alpha - 2012-11-13
+ Tor 0.2.4.6-alpha fixes an assert bug that has been plaguing relays,
+ makes our defense-in-depth memory wiping more reliable, and begins to
+ count IPv6 addresses in bridge statistics,
+
+ o Major bugfixes:
+ - Fix an assertion failure that could occur when closing a connection
+ with a spliced rendezvous circuit. Fix for bug 7212; bugfix on
+ Tor 0.2.4.4-alpha.
+ - Tor tries to wipe potentially sensitive data after using it, so
+ that if some subsequent security failure exposes Tor's memory,
+ the damage will be limited. But we had a bug where the compiler
+ was eliminating these wipe operations when it decided that the
+ memory was no longer visible to a (correctly running) program,
+ hence defeating our attempt at defense in depth. We fix that
+ by using OpenSSL's OPENSSL_cleanse() operation, which a compiler
+ is unlikely to optimize away. Future versions of Tor may use
+ a less ridiculously heavy approach for this. Fixes bug 7352.
+ Reported in an article by Andrey Karpov.
+
+ o Minor features:
+ - Add GeoIP database for IPv6 addresses. The new config option
+ is GeoIPv6File.
+ - Bridge statistics now count bridge clients connecting over IPv6:
+ bridge statistics files now list "bridge-ip-versions" and
+ extra-info documents list "geoip6-db-digest". The control protocol
+ "CLIENTS_SEEN" and "ip-to-country" queries now support IPv6. Initial
+ implementation by "shkoo", addressing ticket 5055.
+
+ o Minor bugfixes:
+ - Warn when we are binding low ports when hibernation is enabled;
+ previously we had warned when we were _advertising_ low ports with
+ hibernation enabled. Fixes bug 7285; bugfix on 0.2.3.9-alpha.
+ - Fix a harmless bug when opting against publishing a relay descriptor
+ because DisableNetwork is set. Fixes bug 7464; bugfix on
+ 0.2.3.9-alpha.
+ - Add warning message when a managed proxy dies during configuration.
+ Fixes bug 7195; bugfix on 0.2.4.2-alpha.
+ - Fix a linking error when building tor-fw-helper without miniupnp.
+ Fixes bug 7235; bugfix on 0.2.4.2-alpha. Fix by Anthony G. Basile.
+ - Check for closing an or_connection_t without going through correct
+ channel functions; emit a warning and then call
+ connection_or_close_for_error() so we don't assert as in bugs 7212
+ and 7267.
+ - Compile correctly on compilers without C99 designated initializer
+ support. Fixes bug 7286; bugfix on 0.2.4.4-alpha.
+ - Avoid a possible assert that can occur when channel_send_destroy() is
+ called on a channel in CHANNEL_STATE_CLOSING, CHANNEL_STATE_CLOSED,
+ or CHANNEL_STATE_ERROR when the Tor process is resumed after being
+ blocked for a long interval. Fixes bug 7350; bugfix on 0.2.4.4-alpha.
+ - Fix a memory leak on failing cases of channel_tls_process_certs_cell.
+ Fixes bug 7422; bugfix on 0.2.4.4-alpha.
+
+ o Code simplification and refactoring:
+ - Start using OpenBSD's implementation of queue.h, so that we don't
+ need to hand-roll our own pointer and list structures whenever we
+ need them. (We can't rely on a sys/queue.h, since some operating
+ systems don't have them, and the ones that do have them don't all
+ present the same extensions.)
+
+
+Changes in version 0.2.4.5-alpha - 2012-10-25
+ Tor 0.2.4.5-alpha comes hard at the heels of 0.2.4.4-alpha, to fix
+ two important security vulnerabilities that could lead to remotely
+ triggerable relay crashes, fix a major bug that was preventing clients
+ from choosing suitable exit nodes, and refactor some of our code.
+
+ o Major bugfixes (security, also in 0.2.3.24-rc):
+ - Fix a group of remotely triggerable assertion failures related to
+ incorrect link protocol negotiation. Found, diagnosed, and fixed
+ by "some guy from France". Fix for CVE-2012-2250; bugfix on
+ 0.2.3.6-alpha.
+ - Fix a denial of service attack by which any directory authority
+ could crash all the others, or by which a single v2 directory
+ authority could crash everybody downloading v2 directory
+ information. Fixes bug 7191; bugfix on 0.2.0.10-alpha.
+
+ o Major bugfixes (also in 0.2.3.24-rc):
+ - When parsing exit policy summaries from microdescriptors, we had
+ previously been ignoring the last character in each one, so that
+ "accept 80,443,8080" would be treated by clients as indicating
+ a node that allows access to ports 80, 443, and 808. That would
+ lead to clients attempting connections that could never work,
+ and ignoring exit nodes that would support their connections. Now
+ clients parse these exit policy summaries correctly. Fixes bug 7192;
+ bugfix on 0.2.3.1-alpha.
+
+ o Minor bugfixes (also in 0.2.3.24-rc):
+ - Clients now consider the ClientRejectInternalAddresses config option
+ when using a microdescriptor consensus stanza to decide whether
+ an exit relay would allow exiting to an internal address. Fixes
+ bug 7190; bugfix on 0.2.3.1-alpha.
+
+ o Minor bugfixes:
+ - Only disable TLS session ticket support when running as a TLS
+ server. Now clients will blend better with regular Firefox
+ connections. Fixes bug 7189; bugfix on Tor 0.2.3.23-rc.
+
+ o Code simplification and refactoring:
+ - Start using OpenBSD's implementation of queue.h (originally by
+ Niels Provos).
+ - Move the entry node code from circuitbuild.c to its own file.
+ - Move the circuit build timeout tracking code from circuitbuild.c
+ to its own file.
+
+
+Changes in version 0.2.3.24-rc - 2012-10-25
+ Tor 0.2.3.24-rc fixes two important security vulnerabilities that
+ could lead to remotely triggerable relay crashes, and fixes
+ a major bug that was preventing clients from choosing suitable exit
+ nodes.
+
+ o Major bugfixes (security):
+ - Fix a group of remotely triggerable assertion failures related to
+ incorrect link protocol negotiation. Found, diagnosed, and fixed
+ by "some guy from France". Fix for CVE-2012-2250; bugfix on
+ 0.2.3.6-alpha.
+ - Fix a denial of service attack by which any directory authority
+ could crash all the others, or by which a single v2 directory
+ authority could crash everybody downloading v2 directory
+ information. Fixes bug 7191; bugfix on 0.2.0.10-alpha.
+
+ o Major bugfixes:
+ - When parsing exit policy summaries from microdescriptors, we had
+ previously been ignoring the last character in each one, so that
+ "accept 80,443,8080" would be treated by clients as indicating
+ a node that allows access to ports 80, 443, and 808. That would
+ lead to clients attempting connections that could never work,
+ and ignoring exit nodes that would support their connections. Now
+ clients parse these exit policy summaries correctly. Fixes bug 7192;
+ bugfix on 0.2.3.1-alpha.
+
+ o Minor bugfixes:
+ - Clients now consider the ClientRejectInternalAddresses config option
+ when using a microdescriptor consensus stanza to decide whether
+ an exit relay would allow exiting to an internal address. Fixes
+ bug 7190; bugfix on 0.2.3.1-alpha.
+
+
+Changes in version 0.2.4.4-alpha - 2012-10-20
+ Tor 0.2.4.4-alpha adds a new v3 directory authority, fixes a privacy
+ vulnerability introduced by a change in OpenSSL, fixes a remotely
+ triggerable assert, and adds new channel_t and circuitmux_t abstractions
+ that will make it easier to test new connection transport and cell
+ scheduling algorithms.
+
+ o New directory authorities (also in 0.2.3.23-rc):
+ - Add Faravahar (run by Sina Rabbani) as the ninth v3 directory
+ authority. Closes ticket 5749.
+
+ o Major bugfixes (security/privacy, also in 0.2.3.23-rc):
+ - Disable TLS session tickets. OpenSSL's implementation was giving
+ our TLS session keys the lifetime of our TLS context objects, when
+ perfect forward secrecy would want us to discard anything that
+ could decrypt a link connection as soon as the link connection
+ was closed. Fixes bug 7139; bugfix on all versions of Tor linked
+ against OpenSSL 1.0.0 or later. Found by Florent Daignière.
+ - Discard extraneous renegotiation attempts once the V3 link
+ protocol has been initiated. Failure to do so left us open to
+ a remotely triggerable assertion failure. Fixes CVE-2012-2249;
+ bugfix on 0.2.3.6-alpha. Reported by "some guy from France".
+
+ o Internal abstraction features:
+ - Introduce new channel_t abstraction between circuits and
+ or_connection_t to allow for implementing alternate OR-to-OR
+ transports. A channel_t is an abstract object which can either be a
+ cell-bearing channel, which is responsible for authenticating and
+ handshaking with the remote OR and transmitting cells to and from
+ it, or a listening channel, which spawns new cell-bearing channels
+ at the request of remote ORs. Implements part of ticket 6465.
+ - Also new is the channel_tls_t subclass of channel_t, adapting it
+ to the existing or_connection_t code. The V2/V3 protocol handshaking
+ code which formerly resided in command.c has been moved below the
+ channel_t abstraction layer and may be found in channeltls.c now.
+ Implements the rest of ticket 6465.
+ - Introduce new circuitmux_t storing the queue of circuits for
+ a channel; this encapsulates and abstracts the queue logic and
+ circuit selection policy, and allows the latter to be overridden
+ easily by switching out a policy object. The existing EWMA behavior
+ is now implemented as a circuitmux_policy_t. Resolves ticket 6816.
+
+ o Required libraries:
+ - Tor now requires OpenSSL 0.9.8 or later. OpenSSL 1.0.0 or later is
+ strongly recommended.
+
+ o Minor features:
+ - Warn users who run hidden services on a Tor client with
+ UseEntryGuards disabled that their hidden services will be
+ vulnerable to http://freehaven.net/anonbib/#hs-attack06 (the
+ attack which motivated Tor to support entry guards in the first
+ place). Resolves ticket 6889.
+ - Tor now builds correctly on Bitrig, an OpenBSD fork. Patch from
+ dhill. Resolves ticket 6982.
+ - Option OutboundBindAddress can be specified multiple times and
+ accepts IPv6 addresses. Resolves ticket 6876.
+
+ o Minor bugfixes (also in 0.2.3.23-rc):
+ - Don't serve or accept v2 hidden service descriptors over a
+ relay's DirPort. It's never correct to do so, and disabling it
+ might make it more annoying to exploit any bugs that turn up in the
+ descriptor-parsing code. Fixes bug 7149.
+ - Fix two cases in src/or/transports.c where we were calling
+ fmt_addr() twice in a parameter list. Bug found by David
+ Fifield. Fixes bug 7014; bugfix on 0.2.3.9-alpha.
+ - Fix memory leaks whenever we logged any message about the "path
+ bias" detection. Fixes bug 7022; bugfix on 0.2.3.21-rc.
+ - When relays refuse a "create" cell because their queue of pending
+ create cells is too big (typically because their cpu can't keep up
+ with the arrival rate), send back reason "resource limit" rather
+ than reason "internal", so network measurement scripts can get a
+ more accurate picture. Fixes bug 7037; bugfix on 0.1.1.11-alpha.
+
+ o Minor bugfixes:
+ - Command-line option "--version" implies "--quiet". Fixes bug 6997.
+ - Free some more still-in-use memory at exit, to make hunting for
+ memory leaks easier. Resolves bug 7029.
+ - When a Tor client gets a "truncated" relay cell, the first byte of
+ its payload specifies why the circuit was truncated. We were
+ ignoring this 'reason' byte when tearing down the circuit, resulting
+ in the controller not being told why the circuit closed. Now we
+ pass the reason from the truncated cell to the controller. Bugfix
+ on 0.1.2.3-alpha; fixes bug 7039.
+ - Downgrade "Failed to hand off onionskin" messages to "debug"
+ severity, since they're typically redundant with the "Your computer
+ is too slow" messages. Fixes bug 7038; bugfix on 0.2.2.16-alpha.
+ - Make clients running with IPv6 bridges connect over IPv6 again,
+ even without setting new config options ClientUseIPv6 and
+ ClientPreferIPv6ORPort. Fixes bug 6757; bugfix on 0.2.4.1-alpha.
+ - Use square brackets around IPv6 addresses in numerous places
+ that needed them, including log messages, HTTPS CONNECT proxy
+ requests, TransportProxy statefile entries, and pluggable transport
+ extra-info lines. Fixes bug 7011; patch by David Fifield.
+
+ o Code refactoring and cleanup:
+ - Source files taken from other packages now reside in src/ext;
+ previously they were scattered around the rest of Tor.
+ - Avoid use of reserved identifiers in our C code. The C standard
+ doesn't like us declaring anything that starts with an
+ underscore, so let's knock it off before we get in trouble. Fix
+ for bug 1031; bugfix on the first Tor commit.
+
+
+Changes in version 0.2.3.23-rc - 2012-10-20
+ Tor 0.2.3.23-rc adds a new v3 directory authority, fixes a privacy
+ vulnerability introduced by a change in OpenSSL, and fixes a variety
+ of smaller bugs in preparation for the release.
+
+ o New directory authorities:
+ - Add Faravahar (run by Sina Rabbani) as the ninth v3 directory
+ authority. Closes ticket 5749.
+
+ o Major bugfixes (security/privacy):
+ - Disable TLS session tickets. OpenSSL's implementation was giving
+ our TLS session keys the lifetime of our TLS context objects, when
+ perfect forward secrecy would want us to discard anything that
+ could decrypt a link connection as soon as the link connection
+ was closed. Fixes bug 7139; bugfix on all versions of Tor linked
+ against OpenSSL 1.0.0 or later. Found by Florent Daignière.
+ - Discard extraneous renegotiation attempts once the V3 link
+ protocol has been initiated. Failure to do so left us open to
+ a remotely triggerable assertion failure. Fixes CVE-2012-2249;
+ bugfix on 0.2.3.6-alpha. Reported by "some guy from France".
+
+ o Major bugfixes:
+ - Fix a possible crash bug when checking for deactivated circuits
+ in connection_or_flush_from_first_active_circuit(). Fixes bug 6341;
+ bugfix on 0.2.2.7-alpha. Bug report and fix received pseudonymously.
+
+ o Minor bugfixes (on 0.2.3.x):
+ - Fix two cases in src/or/transports.c where we were calling
+ fmt_addr() twice in a parameter list. Bug found by David
+ Fifield. Fixes bug 7014; bugfix on 0.2.3.9-alpha.
+ - Convert an assert in the pathbias code to a log message. The assert
+ appears to only be triggerable by Tor2Web mode. Fixes bug 6866;
+ bugfix on 0.2.3.17-beta.
+ - Fix memory leaks whenever we logged any message about the "path
+ bias" detection. Fixes bug 7022; bugfix on 0.2.3.21-rc.
+
+ o Minor bugfixes (on 0.2.2.x and earlier):
+ - Don't serve or accept v2 hidden service descriptors over a relay's
+ DirPort. It's never correct to do so, and disabling it might
+ make it more annoying to exploit any bugs that turn up in the
+ descriptor-parsing code. Fixes bug 7149.
+ - When relays refuse a "create" cell because their queue of pending
+ create cells is too big (typically because their cpu can't keep up
+ with the arrival rate), send back reason "resource limit" rather
+ than reason "internal", so network measurement scripts can get a
+ more accurate picture. Bugfix on 0.1.1.11-alpha; fixes bug 7037.
+ - Correct file sizes when reading binary files on Cygwin, to avoid
+ a bug where Tor would fail to read its state file. Fixes bug 6844;
+ bugfix on 0.1.2.7-alpha.
+ - Avoid undefined behaviour when parsing the list of supported
+ rendezvous/introduction protocols in a hidden service descriptor.
+ Previously, Tor would have confused (as-yet-unused) protocol version
+ numbers greater than 32 with lower ones on many platforms. Fixes
+ bug 6827; bugfix on 0.2.0.10-alpha. Found by George Kadianakis.
+
+ o Documentation fixes:
+ - Clarify that hidden services are TCP only. Fixes bug 6024.
+
+
+Changes in version 0.2.4.3-alpha - 2012-09-22
+ Tor 0.2.4.3-alpha fixes another opportunity for a remotely triggerable
+ assertion, resumes letting relays test reachability of their DirPort,
+ and cleans up a bunch of smaller bugs.
+
+ o Security fixes:
+ - Fix an assertion failure in tor_timegm() that could be triggered
+ by a badly formatted directory object. Bug found by fuzzing with
+ Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc.
+
+ o Major bugfixes:
+ - Fix a possible crash bug when checking for deactivated circuits
+ in connection_or_flush_from_first_active_circuit(). Fixes bug 6341;
+ bugfix on 0.2.2.7-alpha. Bug report and fix received pseudonymously.
+ - Allow routers to detect that their own DirPorts are running. When
+ we removed support for versions_supports_begindir, we also
+ accidentally removed the mechanism we used to self-test our
+ DirPort. Diagnosed with help from kargig. Fixes bugs 6814 and 6815;
+ bugfix on 0.2.4.2-alpha.
+
+ o Security features:
+ - Switch to a completely time-invariant approach for picking nodes
+ weighted by bandwidth. Our old approach would run through the
+ part of the loop after it had made its choice slightly slower
+ than it ran through the part of the loop before it had made its
+ choice. Addresses ticket 6538.
+ - Disable the use of Guard nodes when in Tor2WebMode. Guard usage
+ by tor2web clients allows hidden services to identify tor2web
+ clients through their repeated selection of the same rendezvous
+ and introduction point circuit endpoints (their guards). Resolves
+ ticket 6888.
+
+ o Minor features:
+ - Enable Tor to read configuration, state, and key information from
+ a FIFO. Previously Tor would only read from files with a positive
+ stat.st_size. Code from meejah; fixes bug 6044.
+
+ o Minor bugfixes:
+ - Correct file sizes when reading binary files on Cygwin, to avoid
+ a bug where Tor would fail to read its state file. Fixes bug 6844;
+ bugfix on 0.1.2.7-alpha.
+ - Correctly handle votes with more than 31 flags. Fixes bug 6853;
+ bugfix on 0.2.0.3-alpha.
+ - When complaining about a client port on a public address, log
+ which address we're complaining about. Fixes bug 4020; bugfix on
+ 0.2.3.3-alpha. Patch by Tom Fitzhenry.
+ - Convert an assert in the pathbias code to a log message. The assert
+ appears to only be triggerable by Tor2Web mode. Fixes bug 6866;
+ bugfix on 0.2.3.17-beta.
+ - Our new buildsystem was overzealous about rebuilding manpages: it
+ would rebuild them all whenever any one of them changed. Now our
+ dependency checking should be correct. Fixes bug 6843; bugfix on
+ 0.2.4.1-alpha.
+ - Don't do reachability testing over IPv6 unless AuthDirPublishIPv6
+ is set. Fixes bug 6880. Bugfix on 0.2.4.1-alpha.
+ - Correct log printout about which address family is preferred
+ when connecting to a bridge with both an IPv4 and IPv6 OR port.
+ Fixes bug 6884; bugfix on 0.2.4.1-alpha.
+
+ o Minor bugfixes (code cleanliness):
+ - Fix round_to_power_of_2() so it doesn't invoke undefined behavior
+ with large values. This situation was untriggered, but nevertheless
+ incorrect. Fixes bug 6831; bugfix on 0.2.0.1-alpha.
+ - Reject consensus votes with more than 64 known-flags. We aren't even
+ close to that limit yet, and our code doesn't handle it correctly.
+ Fixes bug 6833; bugfix on 0.2.0.1-alpha.
+ - Avoid undefined behaviour when parsing the list of supported
+ rendezvous/introduction protocols in a hidden service descriptor.
+ Previously, Tor would have confused (as-yet-unused) protocol version
+ numbers greater than 32 with lower ones on many platforms. Fixes
+ bug 6827; bugfix on 0.2.0.10-alpha. Found by George Kadianakis.
+ - Fix handling of rendezvous client authorization types over 8.
+ Fixes bug 6861; bugfix on 0.2.1.5-alpha.
+ - Fix building with older versions of GCC (2.95, for one) that don't
+ like preprocessor directives inside macro arguments. Found by
+ grarpamp. Fixes bug 6842; bugfix on 0.2.4.2-alpha.
+ - Switch weighted node selection rule from using a list of doubles
+ to using a list of int64_t. This change should make the process
+ slightly easier to debug and maintain. Needed to finish ticket 6538.
+
+ o Code simplification and refactoring:
+ - Move the generic "config" code into a new file, and have "config.c"
+ hold only torrc- and state-related code. Resolves ticket 6823.
+ - Move the core of our "choose a weighted element at random" logic
+ into its own function, and give it unit tests. Now the logic is
+ testable, and a little less fragile too.
+ - Removed the testing_since field of node_t, which hasn't been used
+ for anything since 0.2.0.9-alpha.
+
+ o Documentation fixes:
+ - Clarify that hidden services are TCP only. Fixes bug 6024.
+ - Resolve a typo in torrc.sample.in. Fixes bug 6819; bugfix on
+ 0.2.3.14-alpha.
+
+
+Changes in version 0.2.3.22-rc - 2012-09-11
+ Tor 0.2.3.22-rc fixes another opportunity for a remotely triggerable
+ assertion.
+
+ o Security fixes:
+ - Fix an assertion failure in tor_timegm() that could be triggered
+ by a badly formatted directory object. Bug found by fuzzing with
+ Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc.
+
+ o Minor bugfixes:
+ - Avoid segfault when starting up having run with an extremely old
+ version of Tor and parsing its state file. Fixes bug 6801; bugfix
+ on 0.2.2.23-alpha.
+
+
+Changes in version 0.2.2.39 - 2012-09-11
+ Tor 0.2.2.39 fixes two more opportunities for remotely triggerable
+ assertions.
+
+ o Security fixes:
+ - Fix an assertion failure in tor_timegm() that could be triggered
+ by a badly formatted directory object. Bug found by fuzzing with
+ Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc.
+ - Do not crash when comparing an address with port value 0 to an
+ address policy. This bug could have been used to cause a remote
+ assertion failure by or against directory authorities, or to
+ allow some applications to crash clients. Fixes bug 6690; bugfix
+ on 0.2.1.10-alpha.
+
+
+Changes in version 0.2.4.2-alpha - 2012-09-10
+ Tor 0.2.4.2-alpha enables port forwarding for pluggable transports,
+ raises the default rate limiting even more, and makes the bootstrapping
+ log messages less noisy.
+
+ o Major features:
+ - Automatically forward the TCP ports of pluggable transport
+ proxies using tor-fw-helper if PortForwarding is enabled. Implements
+ ticket 4567.
+
+ o Major bugfixes:
+ - Raise the default BandwidthRate/BandwidthBurst values from 5MB/10MB
+ to 1GB/1GB. The previous defaults were intended to be "basically
+ infinite", but it turns out they're now limiting our 100mbit+
+ relays and bridges. Fixes bug 6605; bugfix on 0.2.0.10-alpha (the
+ last time we raised it).
+
+ o Minor features:
+ - Detect when we're running with a version of OpenSSL other than the
+ one we compiled with. This has occasionally given people hard-to-
+ track-down errors.
+ - Log fewer lines at level "notice" about our OpenSSL and Libevent
+ versions and capabilities when everything is going right. Resolves
+ part of ticket 6736.
+ - Directory authorities no long accept descriptors for any version of
+ Tor before 0.2.2.35, or for any 0.2.3 release before 0.2.3.10-alpha.
+ These versions are insecure, unsupported, or both. Implements
+ ticket 6789.
+
+ o Minor bugfixes:
+ - Rename the (internal-use-only) UsingTestingNetworkDefaults option
+ to start with a triple-underscore so the controller won't touch it.
+ Patch by Meejah. Fixes bug 3155. Bugfix on 0.2.2.23-alpha.
+ - Avoid segfault when starting up having run with an extremely old
+ version of Tor and parsing its state file. Fixes bug 6801; bugfix
+ on 0.2.2.23-alpha.
+ - Rename the (testing-use-only) _UseFilteringSSLBufferevents option
+ so it doesn't start with _. Fixes bug 3155. Bugfix on 0.2.3.1-alpha.
+ - Don't follow the NULL pointer if microdescriptor generation fails.
+ (This does not appear to be triggerable, but it's best to be safe.)
+ Found by "f. tp.". Fixes bug 6797; bugfix on 0.2.4.1-alpha.
+ - Fix mis-declared dependencies on src/common/crypto.c and
+ src/or/tor_main.c that could break out-of-tree builds under some
+ circumstances. Fixes bug 6778; bugfix on 0.2.4.1-alpha.
+ - Avoid a warning when building common_sha1.i out of tree. Fixes bug
+ 6778; bugfix on 0.2.4.1-alpha.
+ - Fix a harmless (in this case) build warning for implicitly
+ converting a strlen() to an int. Bugfix on 0.2.4.1-alpha.
+
+ o Removed features:
+ - Now that all versions before 0.2.2.x are disallowed, we no longer
+ need to work around their missing features. Thus we can remove a
+ bunch of compatibility code.
+
+ o Code refactoring:
+ - Tweak tor-fw-helper to accept an arbitrary amount of arbitrary
+ TCP ports to forward. In the past it only accepted two ports:
+ the ORPort and the DirPort.
+
+
+Changes in version 0.2.4.1-alpha - 2012-09-05
+ Tor 0.2.4.1-alpha lets bridges publish their pluggable transports to
+ bridgedb; lets relays use IPv6 addresses and directory authorities
+ advertise them; and switches to a cleaner build interface.
+
+ This is the first alpha release in a new series, so expect there to
+ be bugs. Users who would rather test out a more stable branch should
+ stay with 0.2.3.x for now.
+
+ o Major features (bridges):
+ - Bridges now report the pluggable transports they support to the
+ bridge authority, so it can pass the supported transports on to
+ bridgedb and/or eventually do reachability testing. Implements
+ ticket 3589.
+
+ o Major features (IPv6):
+ - Bridge authorities now accept IPv6 bridge addresses and include
+ them in network status documents. Implements ticket 5534.
+ - Clients who set "ClientUseIPv6 1" may connect to entry nodes over
+ IPv6. Set "ClientPreferIPv6ORPort 1" to make this even more likely
+ to happen. Implements ticket 5535.
+ - All kind of relays, not just bridges, can now advertise an IPv6
+ OR port. Implements ticket 6362.
+ - Directory authorities vote on IPv6 OR ports using the new consensus
+ method 14. Implements ticket 6363.
+
+ o Major features (build):
+ - Switch to a nonrecursive Makefile structure. Now instead of each
+ Makefile.am invoking other Makefile.am's, there is a master
+ Makefile.am that includes the others. This change makes our build
+ process slightly more maintainable, and improves parallelism for
+ building with make -j. Original patch by Stewart Smith; various
+ fixes by Jim Meyering.
+ - Where available, we now use automake's "silent" make rules by
+ default, so that warnings are easier to spot. You can get the old
+ behavior with "make V=1". Patch by Stewart Smith for ticket 6522.
+
+ o Minor features (code security and spec conformance):
+ - Clear keys and key-derived material left on the stack in
+ rendservice.c and rendclient.c. Check return value of
+ crypto_pk_write_private_key_to_string() in end_service_load_keys().
+ These fixes should make us more forward-secure against cold-boot
+ attacks and the like. Fixes bug 2385.
+ - Reject EXTEND cells sent to nonexistent streams. According to the
+ spec, an EXTEND cell sent to _any_ nonzero stream ID is invalid, but
+ we were only checking for stream IDs that were currently in use.
+ Found while hunting for more instances of bug 6271. Bugfix on
+ 0.0.2pre8, which introduced incremental circuit construction.
+
+ o Minor features (streamlining);
+ - No longer include the "opt" prefix when generating routerinfos
+ or v2 directories: it has been needless since Tor 0.1.2. Closes
+ ticket 5124.
+ - Remove some now-needless code that tried to aggressively flush
+ OR connections as data was added to them. Since 0.2.0.1-alpha, our
+ cell queue logic has saved us from the failure mode that this code
+ was supposed to prevent. Removing this code will limit the number
+ of baroque control flow paths through Tor's network logic. Reported
+ pseudonymously on IRC. Fixes bug 6468; bugfix on 0.2.0.1-alpha.
+
+ o Minor features (controller):
+ - Add a "GETINFO signal/names" control port command. Implements
+ ticket 3842.
+ - Provide default values for all options via "GETINFO config/defaults".
+ Implements ticket 4971.
+
+ o Minor features (IPv6):
+ - New config option "AuthDirHasIPv6Connectivity 1" that directory
+ authorities should set if they have IPv6 connectivity and want to
+ do reachability tests for IPv6 relays. Implements feature 5974.
+ - A relay with an IPv6 OR port now sends that address in NETINFO
+ cells (in addition to its other address). Implements ticket 6364.
+
+ o Minor features (log messages):
+ - Omit the first heartbeat log message, because it never has anything
+ useful to say, and it clutters up the bootstrapping messages.
+ Resolves ticket 6758.
+ - Don't log about reloading the microdescriptor cache at startup. Our
+ bootstrap warnings are supposed to tell the user when there's a
+ problem, and our bootstrap notices say when there isn't. Resolves
+ ticket 6759; bugfix on 0.2.2.6-alpha.
+ - Don't log "I learned some more directory information" when we're
+ reading cached directory information. Reserve it for when new
+ directory information arrives in response to a fetch. Resolves
+ ticket 6760.
+ - Prevent rounding error in path bias counts when scaling
+ them down, and use the correct scale factor default. Also demote
+ some path bias related log messages down a level and make others
+ less scary sounding. Fixes bug 6647. Bugfix against 0.2.3.17-beta.
+ - We no longer warn so much when generating manpages from their
+ asciidoc source.
+
+ o Code simplifications and refactoring:
+ - Enhance our internal sscanf replacement so that we can eliminate
+ the last remaining uses of the system sscanf. (Though those uses
+ of sscanf were safe, sscanf itself is generally error prone, so
+ we want to eliminate when we can.) Fixes ticket 4195 and Coverity
+ CID 448.
+ - Move ipv6_preferred from routerinfo_t to node_t. Addresses bug 4620.
+ - Move last_reachable and testing_since from routerinfo_t to node_t.
+ Implements ticket 5529.
+ - Add replaycache_t structure, functions and unit tests, then refactor
+ rend_service_introduce() to be more clear to read, improve, debug,
+ and test. Resolves bug 6177.
+ - Finally remove support for malloc_good_size and malloc_usable_size.
+ We had hoped that these functions would let us eke a little more
+ memory out of our malloc implementation. Unfortunately, the only
+ implementations that provided these functions are also ones that
+ are already efficient about not overallocation: they never got us
+ more than 7 or so bytes per allocation. Removing them saves us a
+ little code complexity and a nontrivial amount of build complexity.
+
+ o New requirements:
+ - Tor maintainers now require Automake version 1.9 or later to build
+ Tor from the Git repository. (Automake is not required when building
+ from a source distribution.)
+
+
+Changes in version 0.2.3.21-rc - 2012-09-05
+ Tor 0.2.3.21-rc is the fourth release candidate for the Tor 0.2.3.x
+ series. It fixes a trio of potential security bugs, fixes a bug where
+ we were leaving some of the fast relays out of the microdescriptor
+ consensus, resumes interpreting "ORPort 0" and "DirPort 0" correctly,
+ and cleans up other smaller issues.
+
+ o Major bugfixes (security):
+ - Tear down the circuit if we get an unexpected SENDME cell. Clients
+ could use this trick to make their circuits receive cells faster
+ than our flow control would have allowed, or to gum up the network,
+ or possibly to do targeted memory denial-of-service attacks on
+ entry nodes. Fixes bug 6252. Bugfix on the 54th commit on Tor --
+ from July 2002, before the release of Tor 0.0.0. We had committed
+ this patch previously, but we had to revert it because of bug 6271.
+ Now that 6271 is fixed, this patch appears to work.
+ - Reject any attempt to extend to an internal address. Without
+ this fix, a router could be used to probe addresses on an internal
+ network to see whether they were accepting connections. Fixes bug
+ 6710; bugfix on 0.0.8pre1.
+ - Do not crash when comparing an address with port value 0 to an
+ address policy. This bug could have been used to cause a remote
+ assertion failure by or against directory authorities, or to
+ allow some applications to crash clients. Fixes bug 6690; bugfix
+ on 0.2.1.10-alpha.
+
+ o Major bugfixes:
+ - Remove the upper bound on microdescriptor length. We were hitting
+ the limit for routers with complex exit policies or family
+ declarations, causing clients to not use them. Fixes the first
+ piece of bug 6404; fix on 0.2.2.6-alpha.
+ - Detect "ORPort 0" as meaning, uniformly, that we're not running
+ as a relay. Previously, some of our code would treat the presence
+ of any ORPort line as meaning that we should act like a relay,
+ even though our new listener code would correctly not open any
+ ORPorts for ORPort 0. Similar bugs in other Port options are also
+ fixed. Fixes the first half of bug 6507; bugfix on 0.2.3.3-alpha.
+
+ o Minor bugfixes:
+ - Avoid a pair of double-free and use-after-mark bugs that can
+ occur with certain timings in canceled and re-received DNS
+ requests. Fixes bug 6472; bugfix on 0.0.7rc1.
+ - Fix build and 64-bit compile warnings from --enable-openbsd-malloc.
+ Fixes bug 6379. Bugfix on 0.2.0.20-rc.
+ - Allow one-hop directory fetching circuits the full "circuit build
+ timeout" period, rather than just half of it, before failing them
+ and marking the relay down. This fix should help reduce cases where
+ clients declare relays (or worse, bridges) unreachable because
+ the TLS handshake takes a few seconds to complete. Fixes bug 6743;
+ bugfix on 0.2.2.2-alpha, where we changed the timeout from a static
+ 30 seconds.
+ - Authorities no longer include any router in their microdescriptor
+ consensuses for which they couldn't generate or agree on a
+ microdescriptor. Fixes the second piece of bug 6404; fix on
+ 0.2.2.6-alpha.
+ - Detect and reject attempts to specify both "FooPort" and
+ "FooPort 0" in the same configuration domain. (It's still okay
+ to have a FooPort in your configuration file, and use "FooPort 0"
+ on the command line to disable it.) Fixes the second half of bug
+ 6507; bugfix on 0.2.3.3-alpha.
+ - Make wildcarded addresses (that is, ones beginning with "*.") work
+ when provided via the controller's MapAddress command. Previously,
+ they were accepted, but we never actually noticed that they were
+ wildcards. Fixes bug 6244; bugfix on 0.2.3.9-alpha.
+ - Avoid crashing on a malformed state file where EntryGuardPathBias
+ precedes EntryGuard. Fix for bug 6774; bugfix on 0.2.3.17-beta.
+ - Add a (probably redundant) memory clear between iterations of
+ the router status voting loop, to prevent future coding errors
+ where data might leak between iterations of the loop. Resolves
+ ticket 6514.
+
+ o Minor bugfixes (log messages):
+ - Downgrade "set buildtimeout to low value" messages to "info"
+ severity; they were never an actual problem, there was never
+ anything reasonable to do about them, and they tended to spam logs
+ from time to time. Fixes bug 6251; bugfix on 0.2.2.2-alpha.
+ - Downgrade path-bias warning messages to "info". We'll try to get
+ them working better in 0.2.4. Add internal circuit construction
+ state to protect against the noisy warn message "Unexpectedly high
+ circuit_successes". Also add some additional rate-limited notice
+ messages to help determine the root cause of the warn. Fixes bug
+ 6475. Bugfix against 0.2.3.17-beta.
+ - Move log message when unable to find a microdesc in a routerstatus
+ entry to parse time. Previously we'd spam this warning every time
+ we tried to figure out which microdescriptors to download. Fixes
+ the third piece of bug 6404; fix on 0.2.3.18-rc.
+
+ o Minor features:
+ - Consider new, removed or changed IPv6 OR ports a non-cosmetic
+ change when the authority is deciding whether to accept a newly
+ uploaded descriptor. Implements ticket 6423.
+ - Add missing documentation for consensus and microdesc files.
+ Resolves ticket 6732.
+
+
+Changes in version 0.2.2.38 - 2012-08-12
+ Tor 0.2.2.38 fixes a remotely triggerable crash bug, and fixes a timing
+ attack that could in theory leak path information.
+
+ o Security fixes:
+ - Avoid an uninitialized memory read when reading a vote or consensus
+ document that has an unrecognized flavor name. This read could
+ lead to a remote crash bug. Fixes bug 6530; bugfix on 0.2.2.6-alpha.
+ - Try to leak less information about what relays a client is
+ choosing to a side-channel attacker. Previously, a Tor client would
+ stop iterating through the list of available relays as soon as it
+ had chosen one, thus finishing a little earlier when it picked
+ a router earlier in the list. If an attacker can recover this
+ timing information (nontrivial but not proven to be impossible),
+ they could learn some coarse-grained information about which relays
+ a client was picking (middle nodes in particular are likelier to
+ be affected than exits). The timing attack might be mitigated by
+ other factors (see bug 6537 for some discussion), but it's best
+ not to take chances. Fixes bug 6537; bugfix on 0.0.8rc1.
+
+
+Changes in version 0.2.3.20-rc - 2012-08-05
+ Tor 0.2.3.20-rc is the third release candidate for the Tor 0.2.3.x
+ series. It fixes a pair of code security bugs and a potential anonymity
+ issue, updates our RPM spec files, and cleans up other smaller issues.
+
+ o Security fixes:
+ - Avoid read-from-freed-memory and double-free bugs that could occur
+ when a DNS request fails while launching it. Fixes bug 6480;
+ bugfix on 0.2.0.1-alpha.
+ - Avoid an uninitialized memory read when reading a vote or consensus
+ document that has an unrecognized flavor name. This read could
+ lead to a remote crash bug. Fixes bug 6530; bugfix on 0.2.2.6-alpha.
+ - Try to leak less information about what relays a client is
+ choosing to a side-channel attacker. Previously, a Tor client would
+ stop iterating through the list of available relays as soon as it
+ had chosen one, thus finishing a little earlier when it picked
+ a router earlier in the list. If an attacker can recover this
+ timing information (nontrivial but not proven to be impossible),
+ they could learn some coarse-grained information about which relays
+ a client was picking (middle nodes in particular are likelier to
+ be affected than exits). The timing attack might be mitigated by
+ other factors (see bug 6537 for some discussion), but it's best
+ not to take chances. Fixes bug 6537; bugfix on 0.0.8rc1.
+
+ o Minor features:
+ - Try to make the warning when giving an obsolete SOCKSListenAddress
+ a little more useful.
+ - Terminate active server managed proxies if Tor stops being a
+ relay. Addresses parts of bug 6274; bugfix on 0.2.3.6-alpha.
+ - Provide a better error message about possible OSX Asciidoc failure
+ reasons. Fixes bug 6436.
+ - Warn when Tor is configured to use accounting in a way that can
+ link a hidden service to some other hidden service or public
+ address. Resolves ticket 6490.
+
+ o Minor bugfixes:
+ - Check return value of fputs() when writing authority certificate
+ file. Fixes Coverity issue 709056; bugfix on 0.2.0.1-alpha.
+ - Ignore ServerTransportPlugin lines when Tor is not configured as
+ a relay. Fixes bug 6274; bugfix on 0.2.3.6-alpha.
+ - When disabling guards for having too high a proportion of failed
+ circuits, make sure to look at each guard. Fixes bug 6397; bugfix
+ on 0.2.3.17-beta.
+
+ o Packaging (RPM):
+ - Update our default RPM spec files to work with mock and rpmbuild
+ on RHEL/Fedora. They have an updated set of dependencies and
+ conflicts, a fix for an ancient typo when creating the "_tor"
+ user, and better instructions. Thanks to Ondrej Mikle for the
+ patch series. Fixes bug 6043.
+
+ o Testing:
+ - Make it possible to set the TestingTorNetwork configuration
+ option using AlternateDirAuthority and AlternateBridgeAuthority
+ as an alternative to setting DirServer. Addresses ticket 6377.
+
+ o Documentation:
+ - Clarify the documentation for the Alternate*Authority options.
+ Fixes bug 6387.
+ - Fix some typos in the manpages. Patch from A. Costa. Fixes bug 6500.
+
+ o Code simplification and refactoring:
+ - Do not use SMARTLIST_FOREACH for any loop whose body exceeds
+ 10 lines. Also, don't nest them. Doing so in the past has
+ led to hard-to-debug code. The new style is to use the
+ SMARTLIST_FOREACH_{BEGIN,END} pair. Addresses issue 6400.
+
+
+Changes in version 0.2.3.19-rc - 2012-07-06
+ Tor 0.2.3.19-rc is the second release candidate for the Tor 0.2.3.x
+ series. It fixes the compile on Windows, reverts to a GeoIP database
+ that isn't as broken, and fixes a flow control bug that has been around
+ since the beginning of Tor.
+
+ o Major bugfixes:
+ - Fix a bug handling SENDME cells on nonexistent streams that could
+ result in bizarre window values. Report and patch contributed
+ pseudonymously. Fixes part of bug 6271. This bug was introduced
+ before the first Tor release, in svn commit r152.
+ - Revert to the May 1 2012 Maxmind GeoLite Country database. In the
+ June 2012 database, Maxmind marked many Tor relays as country "A1",
+ which will cause risky behavior for clients that set EntryNodes
+ or ExitNodes. Addresses bug 6334; bugfix on 0.2.3.17-beta.
+ - Instead of ENOBUFS on Windows, say WSAENOBUFS. Fixes compilation
+ on Windows. Fixes bug 6296; bugfix on 0.2.3.18-rc.
+
+ o Minor bugfixes:
+ - Fix wrong TCP port range in parse_port_range(). Fixes bug 6218;
+ bugfix on 0.2.1.10-alpha.
+
+
Changes in version 0.2.3.18-rc - 2012-06-28
Tor 0.2.3.18-rc is the first release candidate for the Tor 0.2.3.x
series. It fixes a few smaller bugs, but generally appears stable.
@@ -225,7 +1488,7 @@ Changes in version 0.2.3.16-alpha - 2012-06-05
indefinitely. Fixes bug 5380; bugfix on 0.2.1.14-rc.
- When fetching a bridge descriptor from a bridge authority,
always do so anonymously, whether we have been able to open
- circuits or not. Partial fix for bug 1938; bugfix on 2.0.7-alpha.
+ circuits or not. Partial fix for bug 1938; bugfix on 0.2.0.7-alpha.
This behavior makes it *safer* to use UpdateBridgesFromAuthority,
but we'll need to wait for bug 6010 before it's actually usable.
@@ -955,7 +2218,8 @@ Changes in version 0.2.3.11-alpha - 2012-01-22
FastFlagMaxThreshold) to control the range of allowable bandwidths
for the Fast directory flag. These allow authorities to run
experiments on appropriate requirements for being a "Fast" node.
- The AuthDirFastGuarantee config value still applies.
+ The AuthDirFastGuarantee config value still applies. Implements
+ ticket 3946.
- Document the GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays
directory authority option (introduced in Tor 0.2.2.34).
@@ -1270,6 +2534,29 @@ Changes in version 0.2.2.35 - 2011-12-16
by removing an absolute path from makensis.exe command.
+Changes in version 0.2.1.32 - 2011-12-16
+ Tor 0.2.1.32 backports important security and privacy fixes for
+ oldstable. This release is intended only for package maintainers and
+ others who cannot use the 0.2.2 stable series. All others should be
+ using Tor 0.2.2.x or newer.
+
+ The Tor 0.2.1.x series will reach formal end-of-life some time in
+ early 2012; we will stop releasing patches for it then.
+
+ o Major bugfixes (also included in 0.2.2.x):
+ - Correctly sanity-check that we don't underflow on a memory
+ allocation (and then assert) for hidden service introduction
+ point decryption. Bug discovered by Dan Rosenberg. Fixes bug 4410;
+ bugfix on 0.2.1.5-alpha.
+ - Fix a heap overflow bug that could occur when trying to pull
+ data into the first chunk of a buffer, when that chunk had
+ already had some data drained from it. Fixes CVE-2011-2778;
+ bugfix on 0.2.0.16-alpha. Reported by "Vektor".
+
+ o Minor features:
+ - Update to the December 6 2011 Maxmind GeoLite Country database.
+
+
Changes in version 0.2.3.9-alpha - 2011-12-08
Tor 0.2.3.9-alpha introduces initial IPv6 support for bridges, adds
a "DisableNetwork" security feature that bundles can use to avoid
diff --git a/LICENSE b/LICENSE
index bf90e614a..4ed3bd8da 100644
--- a/LICENSE
+++ b/LICENSE
@@ -13,7 +13,7 @@ Tor is distributed under this license:
Copyright (c) 2001-2004, Roger Dingledine
Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
-Copyright (c) 2007-2012, The Tor Project, Inc.
+Copyright (c) 2007-2013, The Tor Project, Inc.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -43,7 +43,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===============================================================================
-src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
+src/ext/strlcat.c and src/ext/strlcpy.c by Todd C. Miller are licensed
under the following license:
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -70,6 +70,35 @@ under the following license:
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+src/ext/tor_queue.h is licensed under the following license:
+
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
===============================================================================
src/config/geoip is licensed under the following license:
diff --git a/Makefile.am b/Makefile.am
index 29bba715b..4639c22c4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,22 +4,33 @@
# See LICENSE for licensing information
# "foreign" means we don't follow GNU package layout standards
-# 1.7 means we require automake vesion 1.7
-AUTOMAKE_OPTIONS = foreign 1.7
+# 1.9 means we require automake vesion 1.9
+AUTOMAKE_OPTIONS = foreign 1.9 subdir-objects
-SUBDIRS = src doc contrib
+ACLOCAL_AMFLAGS = -I m4
-DIST_SUBDIRS = src doc contrib
+noinst_LIBRARIES=
+EXTRA_DIST=
+noinst_HEADERS=
+bin_PROGRAMS=
+CLEANFILES=
+TESTS=
+noinst_PROGRAMS=
+DISTCLEANFILES=
+bin_SCRIPTS=
+AM_CPPFLAGS=
+include src/include.am
+include doc/include.am
+include contrib/include.am
-EXTRA_DIST = \
+
+EXTRA_DIST+= \
ChangeLog \
INSTALL \
LICENSE \
Makefile.nmake \
README \
- ReleaseNotes \
- tor.spec \
- tor.spec.in
+ ReleaseNotes
#install-data-local:
# $(INSTALL) -m 755 -d $(LOCALSTATEDIR)/lib/tor
@@ -53,13 +64,9 @@ test: all
# eventdns.[hc], tinytest*.[ch]
check-spaces:
./contrib/checkSpace.pl -C \
- src/common/*.h \
- src/common/[^asO]*.c \
- src/common/address.c \
- src/or/[^e]*.[ch] \
- src/or/eventdns_tor.h \
- src/test/test*.[ch] \
- src/test/[^t]*.[ch] \
+ src/common/*.[ch] \
+ src/or/*.[ch] \
+ src/test/*.[ch] \
src/tools/*.[ch] \
src/tools/tor-fw-helper/*.[ch]
diff --git a/Makefile.nmake b/Makefile.nmake
index 425f1ec26..a0a11ebdb 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -3,3 +3,13 @@ all:
$(MAKE) /F Makefile.nmake
cd ../../src/or
$(MAKE) /F Makefile.nmake
+ cd ../../src/test
+ $(MAKE) /F Makefile.nmake
+
+clean:
+ cd src/common
+ $(MAKE) /F Makefile.nmake clean
+ cd ../../src/or
+ $(MAKE) /F Makefile.nmake clean
+ cd ../../src/test
+ $(MAKE) /F Makefile.nmake clean
diff --git a/ReleaseNotes b/ReleaseNotes
index 93e38faf3..d68eca99e 100644
--- a/ReleaseNotes
+++ b/ReleaseNotes
@@ -3,6 +3,1129 @@ This document summarizes new features and bugfixes in each stable release
of Tor. If you want to see more detailed descriptions of the changes in
each development snapshot, see the ChangeLog file.
+Changes in version 0.2.3.25 - 2012-11-19
+ The Tor 0.2.3 release series is dedicated to the memory of Len "rabbi"
+ Sassaman (1980-2011), a long-time cypherpunk, anonymity researcher,
+ Mixmaster maintainer, Pynchon Gate co-designer, CodeCon organizer,
+ programmer, and friend. Unstinting in his dedication to the cause of
+ freedom, he inspired and helped many of us as we began our work on
+ anonymity, and inspires us still. Please honor his memory by writing
+ software to protect people's freedoms, and by helping others to do so.
+
+ Tor 0.2.3.25, the first stable release in the 0.2.3 branch, features
+ significantly reduced directory overhead (via microdescriptors),
+ enormous crypto performance improvements for fast relays on new
+ enough hardware, a new v3 TLS handshake protocol that can better
+ resist fingerprinting, support for protocol obfuscation plugins (aka
+ pluggable transports), better scalability for hidden services, IPv6
+ support for bridges, performance improvements like allowing clients
+ to skip the first round-trip on the circuit ("optimistic data") and
+ refilling token buckets more often, a new "stream isolation" design
+ to isolate different applications on different circuits, and many
+ stability, security, and privacy fixes.
+
+ Major features (v3 directory protocol):
+ - Clients now use microdescriptors instead of regular descriptors
+ to build circuits. Microdescriptors are authority-generated
+ summaries of regular descriptors' contents, designed to change very
+ rarely (see proposal 158 for details). This feature is designed
+ to save bandwidth, especially for clients on slow internet
+ connections. Use "UseMicrodescriptors 0" to disable it.
+ - Caches now download, cache, and serve microdescriptors, as well
+ as multiple "flavors" of the consensus, including a flavor that
+ describes microdescriptors.
+
+ o Major features (build hardening):
+ - Enable gcc and ld hardening by default. Resolves ticket 5210.
+
+ o Major features (relay scaling):
+ - When built to use OpenSSL 1.0.1, and built for an x86 or x86_64
+ instruction set, take advantage of OpenSSL's AESNI, bitsliced, or
+ vectorized AES implementations as appropriate. These can be much,
+ much faster than other AES implementations.
+ - When using OpenSSL 1.0.0 or later, use OpenSSL's counter mode
+ implementation. It makes AES_CTR about 7% faster than our old one
+ (which was about 10% faster than the one OpenSSL used to provide).
+ Resolves ticket 4526.
+ - Use OpenSSL's EVP interface for AES encryption, so that all AES
+ operations can use hardware acceleration (if present). Resolves
+ ticket 4442.
+ - Unconditionally use OpenSSL's AES implementation instead of our
+ old built-in one. OpenSSL's AES has been better for a while, and
+ relatively few servers should still be on any version of OpenSSL
+ that doesn't have good optimized assembly AES.
+
+ o Major features (blocking resistance):
+ - Update TLS cipher list to match Firefox 8 and later. Resolves
+ ticket 4744.
+ - Remove support for clients falsely claiming to support standard
+ ciphersuites that they can actually provide. As of modern OpenSSL
+ versions, it's not necessary to fake any standard ciphersuite,
+ and doing so prevents us from using better ciphersuites in the
+ future, since servers can't know whether an advertised ciphersuite
+ is really supported or not. Some hosts -- notably, ones with very
+ old versions of OpenSSL or where OpenSSL has been built with ECC
+ disabled -- will stand out because of this change; TBB users should
+ not be affected. Implements the client side of proposal 198.
+ - Implement a new handshake protocol (v3) for authenticating Tors to
+ each other over TLS. It should be more resistant to fingerprinting
+ than previous protocols, and should require less TLS hacking for
+ future Tor implementations. Implements proposal 176.
+ - Allow variable-length padding cells, to disguise the length of
+ Tor's TLS records. Implements part of proposal 184.
+ - While we're trying to bootstrap, record how many TLS connections
+ fail in each state, and report which states saw the most failures
+ in response to any bootstrap failures. This feature may speed up
+ diagnosis of censorship events. Implements ticket 3116.
+
+ o Major features (pluggable transports):
+ - Clients and bridges can now be configured to use a separate
+ "transport" proxy. This approach makes the censorship arms race
+ easier by allowing bridges to use protocol obfuscation plugins.
+ Implements proposal 180 (tickets 2841 and 3472).
+
+ o Major features (DoS resistance):
+ - Now that Tor 0.2.0.x is completely deprecated, enable the final
+ part of "Proposal 110: Avoiding infinite length circuits" by
+ refusing all circuit-extend requests that do not use a relay_early
+ cell. This change helps Tor resist a class of denial-of-service
+ attacks by limiting the maximum circuit length.
+ - Tear down the circuit if we get an unexpected SENDME cell. Clients
+ could use this trick to make their circuits receive cells faster
+ than our flow control would have allowed, or to gum up the network,
+ or possibly to do targeted memory denial-of-service attacks on
+ entry nodes. Fixes bug 6252. Bugfix on the 54th commit on Tor --
+ from July 2002, before the release of Tor 0.0.0.
+
+ o Major features (hidden services):
+ - Adjust the number of introduction points that a hidden service
+ will try to maintain based on how long its introduction points
+ remain in use and how many introductions they handle. Fixes
+ part of bug 3825.
+ - Add a "tor2web mode" for clients that want to connect to hidden
+ services non-anonymously (and possibly more quickly). As a safety
+ measure to try to keep users from turning this on without knowing
+ what they are doing, tor2web mode must be explicitly enabled at
+ compile time, and a copy of Tor compiled to run in tor2web mode
+ cannot be used as a normal Tor client. Implements feature 2553.
+
+ o Major features (IPv6):
+ - Clients can now connect to private bridges over IPv6. Bridges
+ still need at least one IPv4 address in order to connect to
+ other relays. Note that we don't yet handle the case where the
+ user has two bridge lines for the same bridge (one IPv4, one
+ IPv6). Implements parts of proposal 186.
+
+ o Major features (directory authorities):
+ - Use a more secure consensus parameter voting algorithm. Now at
+ least three directory authorities or a majority of them must
+ vote on a given parameter before it will be included in the
+ consensus. Implements proposal 178.
+ - Remove the artificially low cutoff of 20KB to guarantee the Fast
+ flag. In the past few years the average relay speed has picked
+ up, and while the "top 7/8 of the network get the Fast flag" and
+ "all relays with 20KB or more of capacity get the Fast flag" rules
+ used to have the same result, now the top 7/8 of the network has
+ a capacity more like 32KB. Bugfix on 0.2.1.14-rc. Fixes bug 4489.
+
+ o Major features (performance):
+ - Exit nodes now accept and queue data on not-yet-connected streams.
+ Previously, the client wasn't allowed to send data until the
+ stream was connected, which slowed down all connections. This
+ change will enable clients to perform a "fast-start" on streams
+ and send data without having to wait for a confirmation that the
+ stream has opened. Patch from Ian Goldberg; implements the server
+ side of Proposal 174.
+ - When using an exit relay running 0.2.3.x, clients can now
+ "optimistically" send data before the exit relay reports that
+ the stream has opened. This saves a round trip when starting
+ connections where the client speaks first (such as web browsing).
+ This behavior is controlled by a consensus parameter (currently
+ disabled). To turn it on or off manually, use the "OptimisticData"
+ torrc option. Implements proposal 181; code by Ian Goldberg.
+ - Add a new TokenBucketRefillInterval option to refill token buckets
+ more frequently than once per second. This should improve network
+ performance, alleviate queueing problems, and make traffic less
+ bursty. Implements proposal 183; closes ticket 3630. Design by
+ Florian Tschorsch and Björn Scheuermann; implementation by
+ Florian Tschorsch.
+ - Raise the threshold of server descriptors needed (75%) and exit
+ server descriptors needed (50%) before we will declare ourselves
+ bootstrapped. This will make clients start building circuits a
+ little later, but makes the initially constructed circuits less
+ skewed and less in conflict with further directory fetches. Fixes
+ ticket 3196.
+
+ o Major features (relays):
+ - Relays now try regenerating and uploading their descriptor more
+ frequently if they are not listed in the consensus, or if the
+ version of their descriptor listed in the consensus is too
+ old. This fix should prevent situations where a server declines
+ to re-publish itself because it has done so too recently, even
+ though the authorities decided not to list its recent-enough
+ descriptor. Fix for bug 3327.
+
+ o Major features (stream isolation):
+ - You can now configure Tor so that streams from different
+ applications are isolated on different circuits, to prevent an
+ attacker who sees your streams as they leave an exit node from
+ linking your sessions to one another. To do this, choose some way
+ to distinguish the applications: have them connect to different
+ SocksPorts, or have one of them use SOCKS4 while the other uses
+ SOCKS5, or have them pass different authentication strings to the
+ SOCKS proxy. Then, use the new SocksPort syntax to configure the
+ degree of isolation you need. This implements Proposal 171.
+ - There's a new syntax for specifying multiple client ports (such as
+ SOCKSPort, TransPort, DNSPort, NATDPort): you can now just declare
+ multiple *Port entries with full addr:port syntax on each.
+ The old *ListenAddress format is still supported, but you can't
+ mix it with the new *Port syntax.
+
+ o Major features (bufferevents):
+ - Tor can now optionally build with the "bufferevents" buffered IO
+ backend provided by Libevent 2. To use this feature, make sure you
+ have the latest possible version of Libevent, and pass the
+ --enable-bufferevents flag to configure when building Tor from
+ source. This feature will make our networking code more flexible,
+ let us stack layers on each other, and let us use more efficient
+ zero-copy transports where available.
+ - Add experimental support for running on Windows with IOCP and no
+ kernel-space socket buffers. This feature is controlled by a new
+ "UserspaceIOCPBuffers" config option (off by default), which has
+ no effect unless Tor has been built with bufferevents enabled,
+ you're running on Windows, and you've set "DisableIOCP 0". In the
+ long run, this may help solve or mitigate bug 98.
+
+ o Major features (path selection):
+ - The EntryNodes option can now include country codes like {de} or IP
+ addresses or network masks. Previously we had disallowed these
+ options because we didn't have an efficient way to keep the list up
+ to date. Addresses ticket 1982, but see bug 2798 for an unresolved
+ issue here.
+
+ o Major features (port forwarding):
+ - Add support for automatic port mapping on the many home routers
+ that support NAT-PMP or UPnP. To build the support code, you'll
+ need to have the libnatpnp library and/or the libminiupnpc library,
+ and you'll need to enable the feature specifically by passing
+ "--enable-upnp" and/or "--enable-natpnp" to ./configure. To turn
+ it on, use the new PortForwarding option.
+
+ o Major features (logging):
+ - Add a new 'Heartbeat' log message type to periodically log a message
+ describing Tor's status at level Notice. This feature is meant for
+ operators who log at notice, and want to make sure that their Tor
+ server is still working. Implementation by George Kadianakis.
+ - Make logging resolution configurable with a new LogTimeGranularity
+ option, and change the default from 1 millisecond to 1 second.
+ Implements enhancement 1668.
+
+ o Major features (other):
+ - New "DisableNetwork" config option to prevent Tor from launching any
+ connections or accepting any connections except on a control port.
+ Bundles and controllers can set this option before letting Tor talk
+ to the rest of the network, for example to prevent any connections
+ to a non-bridge address. Packages like Orbot can also use this
+ option to instruct Tor to save power when the network is off.
+ - Try to use system facilities for enumerating local interface
+ addresses, before falling back to our old approach (which was
+ binding a UDP socket, and calling getsockname() on it). That
+ approach was scaring OS X users whose draconian firewall
+ software warned about binding to UDP sockets regardless of
+ whether packets were sent. Now we try to use getifaddrs(),
+ SIOCGIFCONF, or GetAdaptersAddresses(), depending on what the
+ system supports. Resolves ticket 1827.
+ - Add experimental support for a "defaults" torrc file to be parsed
+ before the regular torrc. Torrc options override the defaults file's
+ options in the same way that the command line overrides the torrc.
+ The SAVECONF controller command saves only those options which
+ differ between the current configuration and the defaults file. HUP
+ reloads both files. Implements task 4552.
+
+ o New directory authorities:
+ - Add Faravahar (run by Sina Rabbani) as the ninth v3 directory
+ authority. Closes ticket 5749.
+
+ o Security/privacy fixes:
+ - Avoid read-from-freed-memory and double-free bugs that could occur
+ when a DNS request fails while launching it. Fixes bug 6480;
+ bugfix on 0.2.0.1-alpha.
+ - Reject any attempt to extend to an internal address. Without
+ this fix, a router could be used to probe addresses on an internal
+ network to see whether they were accepting connections. Fixes bug
+ 6710; bugfix on 0.0.8pre1.
+ - Close any connection that sends unrecognized junk before the TLS
+ handshake. Solves an issue noted in bug 4369.
+ - The advertised platform of a relay now includes only its operating
+ system's name (e.g., "Linux", "Darwin", "Windows 7"), and not
+ its service pack level (for Windows) or its CPU architecture
+ (for Unix). Also drop the "git-XYZ" tag in the version. Packagers
+ can insert an extra string in the platform line by setting the
+ preprocessor variable TOR_BUILD_TAG. Resolves bug 2988.
+ - Disable TLS session tickets. OpenSSL's implementation was giving
+ our TLS session keys the lifetime of our TLS context objects, when
+ perfect forward secrecy would want us to discard anything that
+ could decrypt a link connection as soon as the link connection
+ was closed. Fixes bug 7139; bugfix on all versions of Tor linked
+ against OpenSSL 1.0.0 or later. Found by Florent Daignière.
+ - Tor tries to wipe potentially sensitive data after using it, so
+ that if some subsequent security failure exposes Tor's memory,
+ the damage will be limited. But we had a bug where the compiler
+ was eliminating these wipe operations when it decided that the
+ memory was no longer visible to a (correctly running) program,
+ hence defeating our attempt at defense in depth. We fix that
+ by using OpenSSL's OPENSSL_cleanse() operation, which a compiler
+ is unlikely to optimize away. Future versions of Tor may use
+ a less ridiculously heavy approach for this. Fixes bug 7352.
+ Reported in an article by Andrey Karpov.
+
+ o Major bugfixes (crashes and asserts):
+ - Avoid a pair of double-free and use-after-mark bugs that can
+ occur with certain timings in canceled and re-received DNS
+ requests. Fixes bug 6472; bugfix on 0.0.7rc1.
+ - Fix a denial of service attack by which any directory authority
+ could crash all the others, or by which a single v2 directory
+ authority could crash everybody downloading v2 directory
+ information. Fixes bug 7191; bugfix on 0.2.0.10-alpha.
+ - Fix an assert that directory authorities could trigger on sighup
+ during some configuration state transitions. We now don't treat
+ it as a fatal error when the new descriptor we just generated in
+ init_keys() isn't accepted. Fixes bug 4438; bugfix on 0.2.1.9-alpha.
+ - Avoid segfault when starting up having run with an extremely old
+ version of Tor and parsing its state file. Fixes bug 6801; bugfix
+ on 0.2.2.23-alpha.
+
+ o Major bugfixes (clients):
+ - If we are unable to find any exit that supports our predicted ports,
+ stop calling them predicted, so that we don't loop and build
+ hopeless circuits indefinitely. Fixes bug 3296; bugfix on 0.0.9pre6,
+ which introduced predicted ports.
+ - Check at each new consensus whether our entry guards were picked
+ long enough ago that we should rotate them. Previously, we only
+ did this check at startup, which could lead to us holding a guard
+ indefinitely. Fixes bug 5380; bugfix on 0.2.1.14-rc.
+ - When fetching a bridge descriptor from a bridge authority,
+ always do so anonymously, whether we have been able to open
+ circuits or not. Partial fix for bug 1938; bugfix on 0.2.0.7-alpha.
+ This behavior makes it *safer* to use UpdateBridgesFromAuthority,
+ but we'll need to wait for bug 6010 before it's actually usable.
+
+ o Major bugfixes (directory voting):
+ - Check more thoroughly to prevent a rogue authority from
+ double-voting on any consensus directory parameter. Previously,
+ authorities would crash in this case if the total number of
+ votes for any parameter exceeded the number of active voters,
+ but would let it pass otherwise. Partially fixes bug 5786; bugfix
+ on 0.2.2.2-alpha.
+ - When computing weight parameters, behave more robustly in the
+ presence of a bad bwweightscale value. Previously, the authorities
+ would crash if they agreed on a sufficiently broken weight_scale
+ value; now, they use a reasonable default and carry on. Fixes the
+ rest of bug 5786; bugfix on 0.2.2.17-alpha.
+ - If authorities are unable to get a v2 consensus document from other
+ directory authorities, they no longer fall back to fetching
+ them from regular directory caches. Fixes bug 5635; bugfix on
+ 0.2.2.26-beta, where routers stopped downloading v2 consensus
+ documents entirely.
+
+ o Major bugfixes (relays):
+ - Fix a bug handling SENDME cells on nonexistent streams that could
+ result in bizarre window values. Report and patch contributed
+ pseudonymously. Fixes part of bug 6271. This bug was introduced
+ before the first Tor release, in svn commit r152.
+ - Don't update the AccountingSoftLimitHitAt state file entry whenever
+ tor gets started. This prevents a wrong average bandwidth
+ estimate, which would cause relays to always start a new accounting
+ interval at the earliest possible moment. Fixes bug 2003; bugfix
+ on 0.2.2.7-alpha. Reported by Bryon Eldridge, who also helped
+ immensely in tracking this bug down.
+ - Fix a possible crash bug when checking for deactivated circuits
+ in connection_or_flush_from_first_active_circuit(). Fixes bug 6341;
+ bugfix on 0.2.2.7-alpha. Bug report and fix received pseudonymously.
+ - Set the SO_REUSEADDR socket option before we call bind() on outgoing
+ connections. This change should allow busy exit relays to stop
+ running out of available sockets as quickly. Fixes bug 4950;
+ bugfix on 0.2.2.26-beta.
+
+ o Major bugfixes (blocking resistance):
+ - Bridges no longer include their address in NETINFO cells on outgoing
+ OR connections, to allow them to blend in better with clients.
+ Removes another avenue for enumerating bridges. Reported by
+ "troll_un". Fixes bug 4348; bugfix on 0.2.0.10-alpha, when NETINFO
+ cells were introduced.
+ - Warn the user when HTTPProxy, but no other proxy type, is
+ configured. This can cause surprising behavior: it doesn't send
+ all of Tor's traffic over the HTTPProxy -- it sends unencrypted
+ directory traffic only. Resolves ticket 4663.
+
+ o Major bugfixes (hidden services):
+ - Improve hidden service robustness: when an attempt to connect to
+ a hidden service ends, be willing to refetch its hidden service
+ descriptors from each of the HSDir relays responsible for them
+ immediately. Previously, we would not consider refetching the
+ service's descriptors from each HSDir for 15 minutes after the last
+ fetch, which was inconvenient if the hidden service was not running
+ during the first attempt. Bugfix on 0.2.0.18-alpha; fixes bug 3335.
+ - Hidden services now ignore the timestamps on INTRODUCE2 cells.
+ They used to check that the timestamp was within 30 minutes
+ of their system clock, so they could cap the size of their
+ replay-detection cache, but that approach unnecessarily refused
+ service to clients with wrong clocks. Bugfix on 0.2.1.6-alpha, when
+ the v3 intro-point protocol (the first one which sent a timestamp
+ field in the INTRODUCE2 cell) was introduced; fixes bug 3460.
+ - When one of a hidden service's introduction points appears to be
+ unreachable, stop trying it. Previously, we would keep trying
+ to build circuits to the introduction point until we lost the
+ descriptor, usually because the user gave up and restarted Tor.
+ Fixes part of bug 3825.
+
+ o Changes to default torrc file:
+ - Stop listing "socksport 9050" in torrc.sample. We open a socks
+ port on 9050 by default anyway, so this should not change anything
+ in practice.
+ - Stop mentioning the deprecated *ListenAddress options in
+ torrc.sample. Fixes bug 5438.
+ - Document unit of bandwidth-related options in sample torrc.
+ Fixes bug 5621.
+ - Fix broken URLs in the sample torrc file, and tell readers about
+ the OutboundBindAddress, ExitPolicyRejectPrivate, and
+ PublishServerDescriptor options. Addresses bug 4652.
+
+ o Minor features (directory authorities):
+ - Consider new, removed or changed IPv6 OR ports a non-cosmetic
+ change when the authority is deciding whether to accept a newly
+ uploaded descriptor. Implements ticket 6423.
+ - Directory authorities are now a little more lenient at accepting
+ older router descriptors, or newer router descriptors that don't
+ make big changes. This should help ameliorate past and future
+ issues where routers think they have uploaded valid descriptors,
+ but the authorities don't think so. Fix for ticket 2479.
+ - Authority operators can now vote for all relays in a given
+ set of countries to be BadDir/BadExit/Invalid/Rejected.
+ - Provide two consensus parameters (FastFlagMinThreshold and
+ FastFlagMaxThreshold) to control the range of allowable bandwidths
+ for the Fast directory flag. These allow authorities to run
+ experiments on appropriate requirements for being a "Fast" node.
+ The AuthDirFastGuarantee config value still applies. Implements
+ ticket 3946.
+
+ o Minor features (bridges / bridge authorities):
+ - Make bridge SSL certificates a bit more stealthy by using random
+ serial numbers, in the same fashion as OpenSSL when generating
+ self-signed certificates. Implements ticket 4584.
+ - Tag a bridge's descriptor as "never to be sent unencrypted".
+ This shouldn't matter, since bridges don't open non-anonymous
+ connections to the bridge authority and don't allow unencrypted
+ directory connections from clients, but we might as well make
+ sure. Closes bug 5139.
+ - The Bridge Authority now writes statistics on how many bridge
+ descriptors it gave out in total, and how many unique descriptors
+ it gave out. It also lists how often the most and least commonly
+ fetched descriptors were given out, as well as the median and
+ 25th/75th percentile. Implements tickets 4200 and 4294.
+
+ o Minor features (IPv6):
+ - Make the code that clients use to detect an address change be
+ IPv6-aware, so that it won't fill clients' logs with error
+ messages when trying to get the IPv4 address of an IPv6
+ connection. Implements ticket 5537.
+ - Relays now understand an IPv6 address when they get one from a
+ directory server. Resolves ticket 4875.
+
+ o Minor features (hidden services):
+ - Expire old or over-used hidden service introduction points.
+ Required by fix for bug 3460.
+ - Reduce the lifetime of elements of hidden services' Diffie-Hellman
+ public key replay-detection cache from 60 minutes to 5 minutes. This
+ replay-detection cache is now used only to detect multiple
+ INTRODUCE2 cells specifying the same rendezvous point, so we can
+ avoid launching multiple simultaneous attempts to connect to it.
+ - When a hidden service's introduction point times out, consider
+ trying it again during the next attempt to connect to the
+ HS. Previously, we would not try it again unless a newly fetched
+ descriptor contained it. Required by fixes for bugs 1297 and 3825.
+
+ o Minor features (relays):
+ - Relays now include a reason for regenerating their descriptors
+ in an HTTP header when uploading to the authorities. This will
+ make it easier to debug descriptor-upload issues in the future.
+ - Turn on directory request statistics by default and include them in
+ extra-info descriptors. Don't break if we have no GeoIP database.
+ - Replace files in stats/ rather than appending to them. Now that we
+ include statistics in extra-info descriptors, it makes no sense to
+ keep old statistics forever. Implements ticket 2930.
+ - Relays that set "ConnDirectionStatistics 1" write statistics on the
+ bidirectional use of connections to disk every 24 hours.
+ - Add a GeoIP file digest to the extra-info descriptor. Implements
+ ticket 1883.
+
+ o Minor features (new config options):
+ - New config option "DynamicDHGroups" (disabled by default) provides
+ each bridge with a unique prime DH modulus to be used during
+ SSL handshakes. This option attempts to help against censors
+ who might use the Apache DH modulus as a static identifier for
+ bridges. Addresses ticket 4548.
+ - New config option "DisableDebuggerAttachment" (on by default)
+ to prevent basic debugging attachment attempts by other processes.
+ Supports Mac OS X and Gnu/Linux. Resolves ticket 3313.
+ - Ordinarily, Tor does not count traffic from private addresses (like
+ 127.0.0.1 or 10.0.0.1) when calculating rate limits or accounting.
+ There is now a new option, CountPrivateBandwidth, to disable this
+ behavior. Patch from Daniel Cagara.
+
+ o Minor features (different behavior for old config options):
+ - Allow MapAddress directives to specify matches against super-domains,
+ as in "MapAddress *.torproject.org *.torproject.org.torserver.exit".
+ Implements issue 933.
+ - Don't disable the DirPort when we cannot exceed our AccountingMax
+ limit during this interval because the effective bandwidthrate is
+ low enough. This is useful in a situation where AccountMax is only
+ used as an additional safeguard or to provide statistics.
+ - Add port 6523 (Gobby) to LongLivedPorts. Patch by intrigeri;
+ implements ticket 3439.
+ - When configuring a large set of nodes in EntryNodes, and there are
+ enough of them listed as Guard so that we don't need to consider
+ the non-guard entries, prefer the ones listed with the Guard flag.
+ - If you set the NumCPUs option to 0, Tor will now try to detect how
+ many CPUs you have. This is the new default behavior.
+ - The NodeFamily option -- which let you declare that you want to
+ consider nodes to be part of a family whether they list themselves
+ that way or not -- now allows IP address ranges and country codes.
+
+ o Minor features (new command-line config behavior):
+ - Slightly change behavior of "list" options (that is, config
+ options that can appear more than once) when they appear both in
+ torrc and on the command line. Previously, the command-line options
+ would be appended to the ones from torrc. Now, the command-line
+ options override the torrc options entirely. This new behavior
+ allows the user to override list options (like exit policies and
+ ports to listen on) from the command line, rather than simply
+ appending to the list.
+ - You can get the old (appending) command-line behavior for "list"
+ options by prefixing the option name with a "+".
+ - You can remove all the values for a "list" option from the command
+ line without adding any new ones by prefixing the option name
+ with a "/".
+
+ o Minor features (controller, new events):
+ - Extend the control protocol to report flags that control a circuit's
+ path selection in CIRC events and in replies to 'GETINFO
+ circuit-status'. Implements part of ticket 2411.
+ - Extend the control protocol to report the hidden service address
+ and current state of a hidden-service-related circuit in CIRC
+ events and in replies to 'GETINFO circuit-status'. Implements part
+ of ticket 2411.
+ - Include the creation time of a circuit in CIRC and CIRC2
+ control-port events and the list produced by the 'GETINFO
+ circuit-status' control-port command.
+ - Add a new CONF_CHANGED event so that controllers can be notified
+ of any configuration changes made by other controllers, or by the
+ user. Implements ticket 1692.
+ - Add a new SIGNAL event to the controller interface so that
+ controllers can be notified when Tor handles a signal. Resolves
+ issue 1955. Patch by John Brooks.
+
+ o Minor features (controller, new getinfo options):
+ - Expose our view of whether we have gone dormant to the controller,
+ via a new "GETINFO dormant" value. Torbutton and other controllers
+ can use this to avoid doing periodic requests through Tor while
+ it's dormant (bug 4718). Resolves ticket 5954.
+ - Add a new GETINFO option to get total bytes read and written. Patch
+ from pipe, revised by atagar. Resolves ticket 2345.
+ - Implement new GETINFO controller fields to provide information about
+ the Tor process's pid, euid, username, and resource limits.
+
+ o Minor features (controller, other):
+ - Allow controllers to request an event notification whenever a
+ circuit is cannibalized or its purpose is changed. Implements
+ part of ticket 3457.
+ - Use absolute path names when reporting the torrc filename in the
+ control protocol, so a controller can more easily find the torrc
+ file. Resolves bug 1101.
+ - When reporting the path to the cookie file to the controller,
+ give an absolute path. Resolves ticket 4881.
+
+ o Minor features (log messages):
+ - Add more information to a log statement that might help track down
+ bug 4091. If you're seeing "Bug: tor_addr_is_internal() called with a
+ non-IP address" messages (or any Bug messages, for that matter!),
+ please let us know about it.
+ - If EntryNodes are given, but UseEntryGuards is set to 0, warn that
+ EntryNodes will have no effect. Resolves issue 2571.
+ - Try to make the introductory warning message that Tor prints on
+ startup more useful for actually finding help and information.
+ Resolves ticket 2474.
+ - When the system call to create a listener socket fails, log the
+ error message explaining why. This may help diagnose bug 4027.
+
+ o Minor features (other):
+ - When we fail to initialize Libevent, retry with IOCP disabled so we
+ don't need to turn on multi-threading support in Libevent, which in
+ turn requires a working socketpair(). This is a workaround for bug
+ 4457, which affects Libevent versions from 2.0.1-alpha through
+ 2.0.15-stable.
+ - When starting as root and then changing our UID via the User
+ control option, and we have a ControlSocket configured, make sure
+ that the ControlSocket is owned by the same account that Tor will
+ run under. Implements ticket 3421; fix by Jérémy Bobbio.
+ - Accept attempts to include a password authenticator in the
+ handshake, as supported by SOCKS5. This handles SOCKS clients that
+ don't know how to omit a password when authenticating. Resolves
+ bug 1666.
+ - Check for and recover from inconsistency in the microdescriptor
+ cache. This will make it harder for us to accidentally free a
+ microdescriptor without removing it from the appropriate data
+ structures. Fixes issue 3135; issue noted by "wanoskarnet".
+ - Shorten links in the tor-exit-notice file. Patch by Christian Kujau.
+
+ o Minor bugfixes (code security):
+ - Prevent a null-pointer dereference when receiving a data cell
+ for a nonexistent stream when the circuit in question has an
+ empty deliver window. We don't believe this is triggerable,
+ since we don't currently allow deliver windows to become empty,
+ but the logic is tricky enough that it's better to make the code
+ robust. Fixes bug 5541; bugfix on 0.0.2pre14.
+ - Fix a (harmless) integer overflow in cell statistics reported by
+ some fast relays. Fixes bug 5849; bugfix on 0.2.2.1-alpha.
+ - Fix our implementation of crypto_random_hostname() so it can't
+ overflow on ridiculously large inputs. (No Tor version has ever
+ provided this kind of bad inputs, but let's be correct in depth.)
+ Fixes bug 4413; bugfix on 0.2.2.9-alpha. Fix by Stephen Palmateer.
+ - Add a (probably redundant) memory clear between iterations of
+ the router status voting loop, to prevent future coding errors
+ where data might leak between iterations of the loop. Resolves
+ ticket 6514.
+
+ o Minor bugfixes (wrapper functions):
+ - Abort if tor_vasprintf() fails in connection_printf_to_buf() (a
+ utility function used in the control-port code). This shouldn't
+ ever happen unless Tor is completely out of memory, but if it did
+ happen and Tor somehow recovered from it, Tor could have sent a log
+ message to a control port in the middle of a reply to a controller
+ command. Fixes part of bug 3428; bugfix on 0.1.2.3-alpha.
+ - Fix some (not actually triggerable) buffer size checks in usage of
+ tor_inet_ntop(). Fixes bug 4434; bugfix on Tor 0.2.0.1-alpha. Patch
+ by Anders Sundman.
+ - Fix parsing of some corner-cases with tor_inet_pton(). Fixes
+ bug 4515; bugfix on 0.2.0.1-alpha; fix by Anders Sundman.
+ - Enforce correct return behavior of tor_vsscanf() when the '%%'
+ pattern is used. Fixes bug 5558. Bugfix on 0.2.1.13.
+ - Make our replacement implementation of strtok_r() compatible with
+ the standard behavior of strtok_r(). Patch by nils. Fixes bug 5091;
+ bugfix on 0.2.2.1-alpha.
+ - Find more places in the code that should have been testing for
+ invalid sockets using the SOCKET_OK macro. Required for a fix
+ for bug 4533. Bugfix on 0.2.2.28-beta.
+
+ o Minor bugfixes (code correctness):
+ - Check return value of fputs() when writing authority certificate
+ file. Fixes Coverity issue 709056; bugfix on 0.2.0.1-alpha.
+ - When building Tor on Windows with -DUNICODE (not default), ensure
+ that error messages, filenames, and DNS server names are always
+ NUL-terminated when we convert them to a single-byte encoding.
+ Fixes bug 5909; bugfix on 0.2.2.16-alpha.
+ - Fix a memory leak when trying to launch a DNS request when the
+ nameservers are unconfigurable. Fixes bug 5916; bugfix on Tor
+ 0.1.2.1-alpha.
+ - Correct file sizes when reading binary files on Cygwin, to avoid
+ a bug where Tor would fail to read its state file. Fixes bug 6844;
+ bugfix on 0.1.2.7-alpha.
+ - Make sure to set *socket_error in all error cases in
+ connection_connect(), so it can't produce a warning about
+ errno being zero from errno_to_orconn_end_reason(). Bugfix on
+ 0.2.1.1-alpha; resolves ticket 6028.
+ - Initialize conn->addr to a valid state in spawn_cpuworker(). Fixes
+ bug 4532; found by "troll_un".
+
+ o Minor bugfixes (clients):
+ - Allow one-hop directory-fetching circuits the full "circuit build
+ timeout" period, rather than just half of it, before failing them
+ and marking the relay down. This fix should help reduce cases where
+ clients declare relays (or worse, bridges) unreachable because
+ the TLS handshake takes a few seconds to complete. Fixes bug 6743;
+ bugfix on 0.2.2.2-alpha, where we changed the timeout from a static
+ 30 seconds.
+ - Ensure we don't cannibalize circuits that are longer than three hops
+ already, so we don't end up making circuits with 5 or more
+ hops. Patch contributed by wanoskarnet. Fixes bug 5231; bugfix on
+ 0.1.0.1-rc which introduced cannibalization.
+
+ o Minor bugfixes (relays):
+ - Don't publish a new relay descriptor when we reload our onion key,
+ unless the onion key has actually changed. Fixes bug 3263 and
+ resolves another cause of bug 1810. Bugfix on 0.1.1.11-alpha.
+ - When relays refuse a "create" cell because their queue of pending
+ create cells is too big (typically because their cpu can't keep up
+ with the arrival rate), send back reason "resource limit" rather
+ than reason "internal", so network measurement scripts can get a
+ more accurate picture. Bugfix on 0.1.1.11-alpha; fixes bug 7037.
+ - Exit nodes don't need to fetch certificates for authorities that
+ they don't recognize; only directory authorities, bridges,
+ and caches need to do that. Fixes part of bug 2297; bugfix on
+ 0.2.2.11-alpha.
+
+ o Minor bugfixes (directory authority / mirrors):
+ - Avoid O(n^2) performance characteristics when parsing a large
+ extrainfo cache. Fixes bug 5828; bugfix on 0.2.0.1-alpha.
+ - Authorities no longer include any router in their microdescriptor
+ consensuses for which they couldn't generate or agree on a
+ microdescriptor. Fixes the second piece of bug 6404; fix on
+ 0.2.2.6-alpha.
+ - When checking for requested signatures on the latest consensus
+ before serving it to a client, make sure to check the right
+ consensus flavor. Bugfix on 0.2.2.6-alpha.
+ - Fix an edge case where TestingTorNetwork is set but the authorities
+ and relays all have an uptime of zero, so the private Tor network
+ could briefly lack support for hidden services. Fixes bug 3886;
+ bugfix on 0.2.2.18-alpha.
+ - Directory caches no longer refuse to clean out descriptors because
+ of missing v2 networkstatus documents, unless they're configured
+ to retrieve v2 networkstatus documents. Fixes bug 4838; bugfix on
+ 0.2.2.26-beta. Patch by Daniel Bryg.
+ - Don't serve or accept v2 hidden service descriptors over a relay's
+ DirPort. It's never correct to do so, and disabling it might
+ make it more annoying to exploit any bugs that turn up in the
+ descriptor-parsing code. Fixes bug 7149.
+
+ o Minor bugfixes (hidden services, client-side):
+ - Assert that hidden-service-related operations are not performed
+ using single-hop circuits. Previously, Tor would assert that
+ client-side streams are not attached to single-hop circuits,
+ but not that other sensitive operations on the client and service
+ side are not performed using single-hop circuits. Fixes bug 3332;
+ bugfix on 0.0.6.
+ - Avoid undefined behaviour when parsing the list of supported
+ rendezvous/introduction protocols in a hidden service descriptor.
+ Previously, Tor would have confused (as-yet-unused) protocol version
+ numbers greater than 32 with lower ones on many platforms. Fixes
+ bug 6827; bugfix on 0.2.0.10-alpha. Found by George Kadianakis.
+ - Don't close hidden service client circuits which have almost
+ finished connecting to their destination when they reach
+ the normal circuit-build timeout. Previously, we would close
+ introduction circuits which are waiting for an acknowledgement
+ from the introduction point, and rendezvous circuits which have
+ been specified in an INTRODUCE1 cell sent to a hidden service,
+ after the normal CBT. Now, we mark them as 'timed out', and launch
+ another rendezvous attempt in parallel. This behavior change can
+ be disabled using the new CloseHSClientCircuitsImmediatelyOnTimeout
+ option. Fixes part of bug 1297; bugfix on 0.2.2.2-alpha.
+
+ o Minor bugfixes (hidden services, service-side):
+ - Don't close hidden-service-side rendezvous circuits when they
+ reach the normal circuit-build timeout. This behaviour change can
+ be disabled using the new
+ CloseHSServiceRendCircuitsImmediatelyOnTimeout option. Fixes the
+ remaining part of bug 1297; bugfix on 0.2.2.2-alpha.
+ - Don't launch more than 10 service-side introduction-point circuits
+ for a hidden service in five minutes. Previously, we would consider
+ launching more introduction-point circuits if at least one second
+ had passed without any introduction-point circuits failing. Fixes
+ bug 4607; bugfix on 0.0.7pre1.
+
+ o Minor bugfixes (config option behavior):
+ - If the user tries to set MyFamily on a bridge, refuse to
+ do so, and warn about the security implications. Fixes bug 4657;
+ bugfix on 0.2.0.3-alpha.
+ - The "--quiet" and "--hush" options now apply not only to Tor's
+ behavior before logs are configured, but also to Tor's behavior in
+ the absense of configured logs. Fixes bug 3550; bugfix on
+ 0.2.0.10-alpha.
+ - Change the AllowDotExit rules so they should actually work.
+ We now enforce AllowDotExit only immediately after receiving an
+ address via SOCKS or DNSPort: other sources are free to provide
+ .exit addresses after the resolution occurs. Fixes bug 3940;
+ bugfix on 0.2.2.1-alpha.
+ - Make "LearnCircuitBuildTimeout 0" work more reliably. Specifically,
+ don't depend on the consensus parameters or compute adaptive
+ timeouts when it is disabled. Fixes bug 5049; bugfix on
+ 0.2.2.14-alpha.
+ - After we pick a directory mirror, we would refuse to use it if
+ it's in our ExcludeExitNodes list, resulting in mysterious failures
+ to bootstrap for people who just wanted to avoid exiting from
+ certain locations. Fixes bug 5623; bugfix on 0.2.2.25-alpha.
+ - When told to add a bridge with the same digest as a preexisting
+ bridge but a different addr:port, change the addr:port as
+ requested. Previously we would not notice the change. Fixes half
+ of bug 5603; fix on 0.2.2.26-beta.
+
+ o Minor bugfixes (controller):
+ - Allow manual 'authenticate' commands to the controller interface
+ from netcat (nc) as well as telnet. We were rejecting them because
+ they didn't come with the expected whitespace at the end of the
+ command. Bugfix on 0.1.1.1-alpha; fixes bug 2893.
+ - Report a real bootstrap problem to the controller on router
+ identity mismatch. Previously we just said "foo", which probably
+ made a lot of sense at the time. Fixes bug 4169; bugfix on
+ 0.2.1.1-alpha.
+ - When we receive a SIGHUP and the controller __ReloadTorrcOnSIGHUP
+ option is set to 0 (which Vidalia version 0.2.16 now does when
+ a SAVECONF attempt fails), perform other actions that SIGHUP
+ usually causes (like reopening the logs). Fixes bug 5095; bugfix
+ on 0.2.1.9-alpha.
+ - Correctly handle checking the permissions on the parent
+ directory of a control socket in the root directory. Bug found
+ by Esteban Manchado Velázquez. Fixes bug 5089; bugfix on Tor
+ 0.2.2.26-beta.
+ - End AUTHCHALLENGE error messages (in the control protocol) with
+ a CRLF. Fixes bug 5760; bugfix on 0.2.2.36.
+
+ o Minor bugfixes (network reading/writing):
+ - Disable writing on marked-for-close connections when they are
+ blocked on bandwidth, to prevent busy-looping in Libevent. Fixes
+ bug 5263; bugfix on 0.0.2pre13, where we first added a special
+ case for flushing marked connections.
+ - Make sure that there are no unhandled pending TLS errors before
+ reading from a TLS stream. We had checks in 0.1.0.3-rc, but
+ lost them in 0.1.0.5-rc when we refactored read_to_buf_tls().
+ Bugfix on 0.1.0.5-rc; fixes bug 4528.
+ - Detect SSL handshake even when the initial attempt to write the
+ server hello fails. Fixes bug 4592; bugfix on 0.2.0.13-alpha.
+ - If the client fails to set a reasonable set of ciphersuites
+ during its v2 handshake renegotiation, allow the renegotiation to
+ continue nevertheless (i.e. send all the required certificates).
+ Fixes bug 4591; bugfix on 0.2.0.20-rc.
+
+ o Minor bugfixes (other):
+ - Exit nodes now correctly report EADDRINUSE and EADDRNOTAVAIL as
+ resource exhaustion, so that clients can adjust their load to
+ try other exits. Fixes bug 4710; bugfix on 0.1.0.1-rc, which
+ started using END_STREAM_REASON_RESOURCELIMIT.
+ - Don't check for whether the address we're using for outbound
+ connections has changed until after the outbound connection has
+ completed. On Windows, getsockname() doesn't succeed until the
+ connection is finished. Fixes bug 5374; bugfix on 0.1.1.14-alpha.
+ - Don't hold a Windows file handle open for every file mapping;
+ the file mapping handle is sufficient. Fixes bug 5951; bugfix on
+ 0.1.2.1-alpha.
+ - Fix wrong TCP port range in parse_port_range(). Fixes bug 6218;
+ bugfix on 0.2.1.10-alpha.
+ - If we fail to write a microdescriptor to the disk cache, do not
+ continue replacing the old microdescriptor file. Fixes bug 2954;
+ bugfix on 0.2.2.6-alpha.
+
+ o Minor bugfixes (log messages, path selection):
+ - Downgrade "set buildtimeout to low value" messages to "info"
+ severity; they were never an actual problem, there was never
+ anything reasonable to do about them, and they tended to spam logs
+ from time to time. Fixes bug 6251; bugfix on 0.2.2.2-alpha.
+ - Rate-limit the "Weighted bandwidth is 0.000000" message, and add
+ more information to it, so that we can track it down in case it
+ returns again. Mitigates bug 5235.
+ - Check CircuitBuildTimeout and LearnCircuitBuildTimeout in
+ options_validate(); warn if LearnCircuitBuildTimeout is disabled and
+ CircuitBuildTimeout is set unreasonably low. Resolves ticket 5452.
+ - Issue a log message if a guard completes less than 40% of your
+ circuits. Threshold is configurable by torrc option
+ PathBiasNoticeRate and consensus parameter pb_noticepct. There is
+ additional, off-by-default code to disable guards which fail too
+ many circuits. Addresses ticket 5458.
+
+ o Minor bugfixes (log messages, client):
+ - Downgrade "Got a certificate, but we already have it" log messages
+ from warning to info, except when we're a dirauth. Fixes bug 5238;
+ bugfix on 0.2.1.7-alpha.
+ - Fix the log message describing how we work around discovering
+ that our version is the ill-fated OpenSSL 0.9.8l. Fixes bug
+ 4837; bugfix on 0.2.2.9-alpha.
+ - When logging about a disallowed .exit name, do not also call it
+ an "invalid onion address". Fixes bug 3325; bugfix on 0.2.2.9-alpha.
+ - Fix a log message suggesting that people contact a non-existent
+ email address. Fixes bug 3448.
+ - Rephrase the log message emitted if the TestSocks check is
+ successful. Patch from Fabian Keil; fixes bug 4094.
+ - Log (at debug level) whenever a circuit's purpose is changed.
+ - Log SSL state transitions at log level DEBUG, log domain
+ HANDSHAKE. This can be useful for debugging censorship events.
+ Implements ticket 3264.
+ - We now log which torrc file we're using on startup. Implements
+ ticket 2444.
+ - Rate-limit log messages when asked to connect anonymously to
+ a private address. When these hit, they tended to hit fast and
+ often. Also, don't bother trying to connect to addresses that we
+ are sure will resolve to 127.0.0.1: getting 127.0.0.1 in a directory
+ reply makes us think we have been lied to, even when the address the
+ client tried to connect to was "localhost." Resolves ticket 2822.
+
+ o Minor bugfixes (log messages, non-client):
+ - Downgrade "eventdns rejected address" message to LOG_PROTOCOL_WARN.
+ Fixes bug 5932; bugfix on 0.2.2.7-alpha.
+ - Don't log that we have "decided to publish new relay descriptor"
+ unless we are actually publishing a descriptor. Fixes bug 3942;
+ bugfix on 0.2.2.28-beta.
+ - Log which authority we're missing votes from when we go to fetch
+ them from the other auths.
+ - Replace "Sending publish request" log messages with "Launching
+ upload", so that they no longer confusingly imply that we're
+ sending something to a directory we might not even be connected
+ to yet. Fixes bug 3311; bugfix on 0.2.0.10-alpha.
+ - Warn when Tor is configured to use accounting in a way that can
+ link a hidden service to some other hidden service or public
+ address. Resolves ticket 6490.
+ - Fix a minor formatting issue in one of tor-gencert's error messages.
+ Fixes bug 4574.
+
+ o Testing:
+ - Update to the latest version of the tinytest unit testing framework.
+ This includes a couple of bugfixes that can be relevant for
+ running forked unit tests on Windows, and removes all reserved
+ identifiers.
+ - Avoid a false positive in the util/threads unit test by increasing
+ the maximum timeout time. Fixes bug 6227; bugfix on 0.2.0.4-alpha.
+ - Make it possible to set the TestingTorNetwork configuration
+ option using AlternateDirAuthority and AlternateBridgeAuthority
+ as an alternative to setting DirServer. Addresses ticket 6377.
+ - Add a unit test for the environment_variable_names_equal() function.
+ - A wide variety of new unit tests by Esteban Manchado Velázquez.
+ - Numerous new unit tests for functions in util.c and address.c by
+ Anders Sundman.
+ - The long-disabled benchmark tests are now split into their own
+ ./src/test/bench binary.
+ - The benchmark tests can now use more accurate timers than
+ gettimeofday() when such timers are available.
+ - Use tt_assert(), not tor_assert(), for checking for test failures.
+ This makes the unit tests more able to go on in the event that
+ one of them fails.
+
+ o Build improvements:
+ - Use the dead_strip option when building Tor on OS X. This reduces
+ binary size by almost 19% when linking openssl and libevent
+ statically, which we do for Tor Browser Bundle.
+ - Provide a better error message about possible OSX Asciidoc failure
+ reasons. Fixes bug 6436.
+ - Detect attempts to build Tor on (as yet hypothetical) versions
+ of Windows where sizeof(intptr_t) != sizeof(SOCKET). Partial
+ fix for bug 4533. Bugfix on 0.2.2.28-beta.
+ - On Windows, we now define the _WIN32_WINNT macros only if they
+ are not already defined. This lets the person building Tor decide,
+ if they want, to require a later version of Windows.
+ - Our autogen.sh script now uses autoreconf to launch autoconf,
+ automake, and so on. This is more robust against some of the failure
+ modes associated with running the autotools pieces on their own.
+ - Running "make version" now displays the version of Tor that
+ we're about to build. Idea from katmagic; resolves issue 4400.
+ - Make 'tor --digests' list hashes of all Tor source files. Bugfix
+ on 0.2.2.4-alpha; fixes bug 3427.
+ - New --enable-static-tor configure option for building Tor as
+ statically as possible. Idea, general hackery and thoughts from
+ Alexei Czeskis, John Gilmore, Jacob Appelbaum. Implements ticket
+ 2702.
+ - Limited, experimental support for building with nmake and MSVC.
+
+ o Build requirements:
+ - Building Tor with bufferevent support now requires Libevent
+ 2.0.13-stable or later. Previous versions of Libevent had bugs in
+ SSL-related bufferevents and related issues that would make Tor
+ work badly with bufferevents. Requiring 2.0.13-stable also allows
+ Tor with bufferevents to take advantage of Libevent APIs
+ introduced after 2.0.8-rc.
+ - Our build system requires automake 1.6 or later to create the
+ Makefile.in files. Previously, you could have used 1.4.
+ This only affects developers and people building Tor from git;
+ people who build Tor from the source distribution without changing
+ the Makefile.am files should be fine.
+ - Detect when we try to build on a platform that doesn't define
+ AF_UNSPEC to 0. We don't work there, so refuse to compile.
+
+ o Build fixes (compile/link):
+ - Format more doubles with %f, not %lf. Patch from grarpamp to make
+ Tor build correctly on older BSDs again. Fixes bug 3894; bugfix on
+ Tor 0.2.0.8-alpha.
+ - When building with --enable-static-tor on OpenBSD, do not
+ erroneously attempt to link -lrt. Fixes bug 5103.
+ - Set _WIN32_WINNT to 0x0501 consistently throughout the code, so
+ that IPv6 stuff will compile on MSVC, and compilation issues
+ will be easier to track down. Fixes bug 5861.
+ - Fix build and 64-bit compile warnings from --enable-openbsd-malloc.
+ Fixes bug 6379. Bugfix on 0.2.0.20-rc.
+ - Make Tor build correctly again with -DUNICODE -D_UNICODE defined.
+ Fixes bug 6097; bugfix on 0.2.2.16-alpha.
+
+ o Build fixes (other):
+ - Use the _WIN32 macro throughout our code to detect Windows.
+ (Previously we had used the obsolete 'WIN32' and the idiosyncratic
+ 'MS_WINDOWS'.)
+ - Properly handle the case where the build-tree is not the same
+ as the source tree when generating src/common/common_sha1.i,
+ src/or/micro-revision.i, and src/or/or_sha1.i. Fixes bug 3953;
+ bugfix on 0.2.0.1-alpha.
+ - During configure, search for library containing cos function as
+ libm lives in libcore on some platforms (BeOS/Haiku). Linking
+ against libm was hard-coded before. Fixes the first part of bug
+ 4727; bugfix on 0.2.2.2-alpha. Patch and analysis by Martin Hebnes
+ Pedersen.
+ - Prevent a false positive from the check-spaces script, by disabling
+ the "whitespace between function name and (" check for functions
+ named 'op()'.
+
+ o Packaging (RPM) changes:
+ - Update our default RPM spec files to work with mock and rpmbuild
+ on RHEL/Fedora. They have an updated set of dependencies and
+ conflicts, a fix for an ancient typo when creating the "_tor"
+ user, and better instructions. Thanks to Ondrej Mikle for the
+ patch series. Fixes bug 6043.
+ - On OpenSUSE, create the /var/run/tor directory on startup if it
+ is not already created. Patch from Andreas Stieger. Fixes bug 2573.
+
+ o Code refactoring (safety):
+ - Do not use SMARTLIST_FOREACH for any loop whose body exceeds
+ 10 lines. Also, don't nest them. Doing so in the past has
+ led to hard-to-debug code. The new style is to use the
+ SMARTLIST_FOREACH_{BEGIN,END} pair. Addresses issue 6400.
+ - Use macros to indicate OpenSSL versions, so we don't need to worry
+ about accidental hexadecimal bit shifts.
+ - Use tor_sscanf() in place of scanf() in more places through the
+ code. This makes us a little more locale-independent, and
+ should help shut up code-analysis tools that can't tell
+ a safe sscanf string from a dangerous one.
+ - Convert more instances of tor_snprintf+tor_strdup into tor_asprintf.
+ - Use the smartlist_add_asprintf() alias more consistently.
+
+ o Code refactoring (consolidate):
+ - A major revision to our internal node-selecting and listing logic.
+ Tor already had at least two major ways to look at the question of
+ "which Tor servers do we know about": a list of router descriptors,
+ and a list of entries in the current consensus. With
+ microdescriptors, we're adding a third. Having so many systems
+ without an abstraction layer over them was hurting the codebase.
+ Now, we have a new "node_t" abstraction that presents a consistent
+ interface to a client's view of a Tor node, and holds (nearly) all
+ of the mutable state formerly in routerinfo_t and routerstatus_t.
+ - Move tor_gettimeofday_cached() into compat_libevent.c, and use
+ Libevent's notion of cached time when possible.
+ - Remove duplicate code for invoking getrlimit() from control.c.
+ - Use OpenSSL's built-in SSL_state_string_long() instead of our
+ own homebrewed ssl_state_to_string() replacement. Patch from
+ Emile Snyder. Fixes bug 4653.
+ - Change the symmetric cipher interface so that creating and
+ initializing a stream cipher are no longer separate functions.
+
+ o Code refactoring (separate):
+ - Make a new "entry connection" struct as an internal subtype of "edge
+ connection", to simplify the code and make exit connections smaller.
+ - Split connection_about_to_close() into separate functions for each
+ connection type.
+ - Rewrite the listener-selection logic so that parsing which ports
+ we want to listen on is now separate from binding to the ports
+ we want.
+
+ o Code refactoring (name changes):
+ - Rename a handful of old identifiers, mostly related to crypto
+ structures and crypto functions. By convention, our "create an
+ object" functions are called "type_new()", our "free an object"
+ functions are called "type_free()", and our types indicate that
+ they are types only with a final "_t". But a handful of older
+ types and functions broke these rules, with function names like
+ "type_create" or "subsystem_op_type", or with type names like
+ type_env_t.
+ - Rename Tor functions that turn strings into addresses, so that
+ "parse" indicates that no hostname resolution occurs, and
+ "lookup" indicates that hostname resolution may occur. This
+ should help prevent mistakes in the future. Fixes bug 3512.
+ - Use the name "CERTS" consistently to refer to the new cell type;
+ we were calling it CERT in some places and CERTS in others.
+ - Use a TOR_INVALID_SOCKET macro when initializing a socket to an
+ invalid value, rather than just -1.
+ - Rename the bench_{aes,dmap} functions to test_*, so that tinytest
+ can pick them up when the tests aren't disabled. Bugfix on
+ 0.2.2.4-alpha which introduced tinytest.
+
+ o Code refactoring (other):
+ - Defensively refactor rend_mid_rendezvous() so that protocol
+ violations and length checks happen in the beginning. Fixes
+ bug 5645.
+ - Remove the pure attribute from all functions that used it
+ previously. In many cases we assigned it incorrectly, because the
+ functions might assert or call impure functions, and we don't have
+ evidence that keeping the pure attribute is worthwhile. Implements
+ changes suggested in ticket 4421.
+ - Move the replay-detection cache for the RSA-encrypted parts of
+ INTRODUCE2 cells to the introduction point data structures.
+ Previously, we would use one replay-detection cache per hidden
+ service. Required by fix for bug 3460.
+ - The helper programs tor-gencert, tor-resolve, and tor-checkkey
+ no longer link against Libevent: they never used it, but
+ our library structure used to force them to link it.
+
+ o Removed features and files:
+ - Remove all internal support for unpadded RSA. We never used it, and
+ it would be a bad idea to start.
+ - Remove some workaround code for OpenSSL 0.9.6 (which is no longer
+ supported).
+ - Remove some redundant #include directives throughout the code.
+ Patch from Andrea Gelmini.
+ - Remove some old code to remember statistics about which descriptors
+ we've served as a directory mirror. The feature wasn't used and
+ is outdated now that microdescriptors are around.
+ - Remove some old code to work around even older versions of Tor that
+ used forked processes to handle DNS requests. Such versions of Tor
+ are no longer in use as relays.
+ - The "torify" script no longer supports the "tsocks" socksifier
+ tool, since tsocks doesn't support DNS and UDP right for Tor.
+ Everyone should be using torsocks instead. Fixes bugs 3530 and
+ 5180. Based on a patch by "ugh".
+ - Remove the torrc.bridge file: we don't use it for anything, and
+ it had become badly desynchronized from torrc.sample. Resolves
+ bug 5622.
+
+ o Documentation:
+ - Begin a doc/state-contents.txt file to explain the contents of
+ the Tor state file. Fixes bug 2987.
+ - Clarify the documentation for the Alternate*Authority options.
+ Fixes bug 6387.
+ - Document the --defaults-torrc option, and the new semantics for
+ overriding, extending, and clearing lists of options. Closes
+ bug 4748.
+ - Add missing man page documentation for consensus and microdesc
+ files. Resolves ticket 6732.
+ - Fix some typos in the manpages. Patch from A. Costa. Fixes bug 6500.
+
+ o Documentation fixes:
+ - Improve the manual's documentation for the NT Service command-line
+ options. Addresses ticket 3964.
+ - Clarify SessionGroup documentation slightly; resolves ticket 5437.
+ - Document the changes to the ORPort and DirPort options, and the
+ fact that {OR/Dir}ListenAddress is now unnecessary (and
+ therefore deprecated). Resolves ticket 5597.
+ - Correct a broken faq link in the INSTALL file. Fixes bug 2307.
+ - Clarify that hidden services are TCP only. Fixes bug 6024.
+
+
+Changes in version 0.2.2.39 - 2012-09-11
+ Tor 0.2.2.39 fixes two more opportunities for remotely triggerable
+ assertions.
+
+ o Security fixes:
+ - Fix an assertion failure in tor_timegm() that could be triggered
+ by a badly formatted directory object. Bug found by fuzzing with
+ Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc.
+ - Do not crash when comparing an address with port value 0 to an
+ address policy. This bug could have been used to cause a remote
+ assertion failure by or against directory authorities, or to
+ allow some applications to crash clients. Fixes bug 6690; bugfix
+ on 0.2.1.10-alpha.
+
+
+Changes in version 0.2.2.38 - 2012-08-12
+ Tor 0.2.2.38 fixes a remotely triggerable crash bug, and fixes a timing
+ attack that could in theory leak path information.
+
+ o Security fixes:
+ - Avoid an uninitialized memory read when reading a vote or consensus
+ document that has an unrecognized flavor name. This read could
+ lead to a remote crash bug. Fixes bug 6530; bugfix on 0.2.2.6-alpha.
+ - Try to leak less information about what relays a client is
+ choosing to a side-channel attacker. Previously, a Tor client would
+ stop iterating through the list of available relays as soon as it
+ had chosen one, thus finishing a little earlier when it picked
+ a router earlier in the list. If an attacker can recover this
+ timing information (nontrivial but not proven to be impossible),
+ they could learn some coarse-grained information about which relays
+ a client was picking (middle nodes in particular are likelier to
+ be affected than exits). The timing attack might be mitigated by
+ other factors (see bug 6537 for some discussion), but it's best
+ not to take chances. Fixes bug 6537; bugfix on 0.0.8rc1.
+
+
Changes in version 0.2.2.37 - 2012-06-06
Tor 0.2.2.37 introduces a workaround for a critical renegotiation
bug in OpenSSL 1.0.1 (where 20% of the Tor network can't talk to itself
@@ -294,6 +1417,29 @@ Changes in version 0.2.2.35 - 2011-12-16
by removing an absolute path from makensis.exe command.
+Changes in version 0.2.1.32 - 2011-12-16
+ Tor 0.2.1.32 backports important security and privacy fixes for
+ oldstable. This release is intended only for package maintainers and
+ others who cannot use the 0.2.2 stable series. All others should be
+ using Tor 0.2.2.x or newer.
+
+ The Tor 0.2.1.x series will reach formal end-of-life some time in
+ early 2012; we will stop releasing patches for it then.
+
+ o Major bugfixes (also included in 0.2.2.x):
+ - Correctly sanity-check that we don't underflow on a memory
+ allocation (and then assert) for hidden service introduction
+ point decryption. Bug discovered by Dan Rosenberg. Fixes bug 4410;
+ bugfix on 0.2.1.5-alpha.
+ - Fix a heap overflow bug that could occur when trying to pull
+ data into the first chunk of a buffer, when that chunk had
+ already had some data drained from it. Fixes CVE-2011-2778;
+ bugfix on 0.2.0.16-alpha. Reported by "Vektor".
+
+ o Minor features:
+ - Update to the December 6 2011 Maxmind GeoLite Country database.
+
+
Changes in version 0.2.2.34 - 2011-10-26
Tor 0.2.2.34 fixes a critical anonymity vulnerability where an attacker
can deanonymize Tor users. Everybody should upgrade.
diff --git a/acinclude.m4 b/acinclude.m4
index 9ab684877..af1505156 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -1,8 +1,8 @@
-dnl Helper macros for Tor configure.in
+dnl Helper macros for Tor configure.ac
dnl Copyright (c) 2001-2004, Roger Dingledine
dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
dnl Copyright (c) 2007-2008, Roger Dingledine, Nick Mathewson
-dnl Copyright (c) 2007-2012, The Tor Project, Inc.
+dnl Copyright (c) 2007-2013, The Tor Project, Inc.
dnl See LICENSE for licensing information
AC_DEFUN([TOR_EXTEND_CODEPATH],
diff --git a/autogen.sh b/autogen.sh
index 0592f16c2..8c43a9798 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,13 +1,23 @@
#!/bin/sh
if [ -x "`which autoreconf 2>/dev/null`" ] ; then
- exec autoreconf -ivf
+ opt="-if"
+
+ for i in $@; do
+ case "$i" in
+ -v)
+ opt=$opt"v"
+ ;;
+ esac
+ done
+
+ exec autoreconf $opt
fi
set -e
# Run this to generate all the initial makefiles, etc.
-aclocal && \
+aclocal -I m4 && \
autoheader && \
autoconf && \
automake --add-missing --copy
diff --git a/changes/10777_netunreach b/changes/10777_netunreach
new file mode 100644
index 000000000..899181423
--- /dev/null
+++ b/changes/10777_netunreach
@@ -0,0 +1,7 @@
+ - Minor bugfixes:
+
+ - Treat ENETUNREACH, EACCES, and EPERM at an exit node as a
+ NOROUTE error, not an INTERNAL error, since they can apparently
+ happen when trying to connect to the wrong sort of
+ netblocks. Fixes a part of bug 10777; bugfix on 0.1.0.1-rc.
+
diff --git a/changes/6783_big_hammer b/changes/6783_big_hammer
new file mode 100644
index 000000000..2ff3249b3
--- /dev/null
+++ b/changes/6783_big_hammer
@@ -0,0 +1,6 @@
+ o Major features (deprecation):
+ - There's now a "DisableV2DirectoryInfo_" option that prevents us
+ from serving any directory requests for v2 directory information.
+ This is for us to test disabling the old deprecated V2 directory
+ format, so that we can see whether doing so has any effect on
+ network load. Part of a fix for bug 6783.
diff --git a/changes/9854 b/changes/9854
new file mode 100644
index 000000000..30105cb73
--- /dev/null
+++ b/changes/9854
@@ -0,0 +1,3 @@
+ o Documentation fixes:
+ - Clarify the usage and risks of ContactInfo. Resolves ticket 9854.
+
diff --git a/changes/bug10124 b/changes/bug10124
new file mode 100644
index 000000000..95b083883
--- /dev/null
+++ b/changes/bug10124
@@ -0,0 +1,3 @@
+ o Documentation:
+ - Replace remaining references to DirServer in man page and
+ log entries. Resolves ticket 10124.
diff --git a/changes/bug10402 b/changes/bug10402
new file mode 100644
index 000000000..eac00bdc6
--- /dev/null
+++ b/changes/bug10402
@@ -0,0 +1,11 @@
+ o Major bugfixes:
+ - Do not allow OpenSSL engines to replace the PRNG, even when
+ HardwareAccel is set. The only default builtin PRNG engine uses
+ the Intel RDRAND instruction to replace the entire PRNG, and
+ ignores all attempts to seed it with more entropy. That's
+ cryptographically stupid: the right response to a new alleged
+ entropy source is never to discard all previously used entropy
+ sources. Fixes bug 10402; works around behavior introduced in
+ OpenSSL 1.0.0. Diagnosis and investigation thanks to "coderman"
+ and "rl1987".
+
diff --git a/changes/bug10409 b/changes/bug10409
new file mode 100644
index 000000000..5ef5ae29d
--- /dev/null
+++ b/changes/bug10409
@@ -0,0 +1,3 @@
+ o Minor bugfixes:
+ - Avoid a crash bug when starting with a corrupted microdescriptor
+ cache file. Fix for bug 10406; bugfix on 0.2.2.6-alpha.
diff --git a/changes/bug10423 b/changes/bug10423
new file mode 100644
index 000000000..493b7b15e
--- /dev/null
+++ b/changes/bug10423
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - If we fail to dump a previously cached microdescriptor to disk, avoid
+ freeing duplicate data later on. Fix for bug 10423; bugfix on
+ 0.2.4.13-alpha. Spotted by "bobnomnom".
diff --git a/changes/bug10456 b/changes/bug10456
new file mode 100644
index 000000000..fb3b92fcd
--- /dev/null
+++ b/changes/bug10456
@@ -0,0 +1,6 @@
+ o Major bugfixes:
+ - Avoid launching spurious extra circuits when a stream is pending.
+ This fixes a bug where any circuit that _wasn't_ unusable for new
+ streams would be treated as if it were, causing extra circuits to
+ be launched. Fixes bug 10456; bugfix on 0.2.4.12-alpha.
+
diff --git a/changes/bug10465 b/changes/bug10465
new file mode 100644
index 000000000..330f96941
--- /dev/null
+++ b/changes/bug10465
@@ -0,0 +1,3 @@
+ o Major bugfixes:
+ - Fix assertion failure when AutomapHostsOnResolve yields an IPv6
+ address. Fixes bug 10465; bugfix on 0.2.4.7-alpha.
diff --git a/changes/bug10470 b/changes/bug10470
new file mode 100644
index 000000000..2b753436d
--- /dev/null
+++ b/changes/bug10470
@@ -0,0 +1,4 @@
+ o Documentation fixes:
+ - Note that all but one DirPort entry must have the NoAdvertise flag
+ set. Fix for #10470.
+
diff --git a/changes/bug10485 b/changes/bug10485
new file mode 100644
index 000000000..7e5fa530e
--- /dev/null
+++ b/changes/bug10485
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Move message about circuit handshake counts into the heartbeat
+ message where it belongs, instead of logging it once per hour
+ unconditionally. Fixes bug 10485; bugfix on 0.2.4.17-rc.
diff --git a/changes/bug10777_internal_024 b/changes/bug10777_internal_024
new file mode 100644
index 000000000..4544147f6
--- /dev/null
+++ b/changes/bug10777_internal_024
@@ -0,0 +1,4 @@
+ o Major bugfixes:
+ - Do not treat END_STREAM_REASON_INTERNAL as indicating a definite
+ circuit failure, since it could also indicate an ENETUNREACH
+ error. Fixes part of bug 10777; bugfix on 0.2.4.8-alpha.
diff --git a/changes/bug10793 b/changes/bug10793
new file mode 100644
index 000000000..24c4025dd
--- /dev/null
+++ b/changes/bug10793
@@ -0,0 +1,4 @@
+ o Minor features (security):
+ - Always clear OpenSSL bignums before freeing them--even bignums
+ that don't contain secrets. Resolves ticket 10793. Patch by
+ Florent Daigniere.
diff --git a/changes/bug10835 b/changes/bug10835
new file mode 100644
index 000000000..9df7bdd27
--- /dev/null
+++ b/changes/bug10835
@@ -0,0 +1,4 @@
+ o Minor bugfixes (testing):
+ - Fix a segmentation fault in our benchmark code when running with
+ Fedora's OpenSSL package, or any other OpenSSL that provides
+ ECDH but not P224. Fixes bug 10835; bugfix on 0.2.4.8-alpha.
diff --git a/changes/bug10904 b/changes/bug10904
new file mode 100644
index 000000000..6f551ea41
--- /dev/null
+++ b/changes/bug10904
@@ -0,0 +1,5 @@
+ o Minor bugfixes (compilation):
+ - Build without warnings under clang 3.4. (We have some macros that
+ define static functions only some of which will get used later in
+ the module. Starting with clang 3.4, these give a warning unless the
+ unused attribute is set on them.)
diff --git a/changes/bug1992 b/changes/bug1992
new file mode 100644
index 000000000..6a751dc7e
--- /dev/null
+++ b/changes/bug1992
@@ -0,0 +1,11 @@
+ o Minor bugfixes:
+ - Stop trying to resolve our hostname so often (e.g. every time we
+ think about doing a directory fetch). Now we reuse the cached
+ answer in some cases. Fixes bugs 1992 (bugfix on 0.2.0.20-rc)
+ and 2410 (bugfix on 0.1.2.2-alpha).
+
+ o Minor features:
+ - Make bridge relays check once a minute for whether their IP
+ address has changed, rather than only every 15 minutes. Resolves
+ bugs 1913 and 1992.
+
diff --git a/changes/bug2286 b/changes/bug2286
new file mode 100644
index 000000000..4f8dfbbf6
--- /dev/null
+++ b/changes/bug2286
@@ -0,0 +1,5 @@
+ o Major features (directory authority):
+ - Directory authorities now support a new consensus method (17)
+ where they cap the published bandwidth of servers for which
+ insufficient bandwidth measurements exist. Fixes part of bug
+ 2286.
diff --git a/changes/bug5595 b/changes/bug5595
new file mode 100644
index 000000000..31f4b84b0
--- /dev/null
+++ b/changes/bug5595
@@ -0,0 +1,8 @@
+ o Critical bugfixes:
+ - Distinguish downloading an authority certificate by identity digest from
+ downloading one by identity digest/signing key digest pair; formerly we
+ always request them only by identity digest and get the newest one even
+ when we wanted one with a different signing key. Then we would complain
+ about being given a certificate we already had, and never get the one we
+ really wanted. Now we use the "fp-sk/" resource as well as the "fp/"
+ resource to request the one we want. Fixes bug 5595.
diff --git a/changes/bug6024 b/changes/bug6024
deleted file mode 100644
index 743e6ef1f..000000000
--- a/changes/bug6024
+++ /dev/null
@@ -1,2 +0,0 @@
- o Documentation fixes:
- - Clarify that hidden services are TCP only. Fixes bug 6024.
diff --git a/changes/bug6026 b/changes/bug6026
new file mode 100644
index 000000000..de5d6ead0
--- /dev/null
+++ b/changes/bug6026
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Relays now treat a changed IPv6 ORPort as sufficient reason to
+ publish an updated descriptor. Fix for bug 6026; bugfix for
+ 0.2.4.1-alpha.
diff --git a/changes/bug6043 b/changes/bug6043
deleted file mode 100644
index b88bafb78..000000000
--- a/changes/bug6043
+++ /dev/null
@@ -1,6 +0,0 @@
- o Packaging (RPM):
- - Our default RPM spec files have been updated to work with mock
- and rpmbuild on RHEL/Fedora. They have an updated set of
- dependencies and conflicts, a fix for an ancient typo when creating
- the "_tor" user, and better instructions. Thanks to Ondrej
- Mikle for the patch series; fix for bug 6043.
diff --git a/changes/bug6055 b/changes/bug6055
new file mode 100644
index 000000000..00730073a
--- /dev/null
+++ b/changes/bug6055
@@ -0,0 +1,6 @@
+ o Major enhancements:
+ - Re-enable TLS 1.1 and 1.2 when built with OpenSSL 1.0.1e or later.
+ (OpenSSL before 1.0.1 didn't have TLS 1.1 or 1.2. OpenSSL from 1.0.1
+ through 1.0.1d had bugs that prevented renegotiation from working
+ with TLS 1.1 or 1.2, so we disabled them to solve bug 6033.) Fix for
+ issue #6055.
diff --git a/changes/bug6174 b/changes/bug6174
new file mode 100644
index 000000000..79d2930ec
--- /dev/null
+++ b/changes/bug6174
@@ -0,0 +1,6 @@
+ o Major bugfixes:
+ - When we mark a circuit as unusable for new circuits, have it
+ continue to be unusable for new circuits even if MaxCircuitDirtiness
+ is increased too much at the wrong time, or the system clock jumped
+ backwards. Fix for bug 6174; bugfix on 0.0.2pre26.
+
diff --git a/changes/bug6206 b/changes/bug6206
new file mode 100644
index 000000000..61a16d291
--- /dev/null
+++ b/changes/bug6206
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - Always check the return values of functions fcntl() and
+ setsockopt(). We don't believe these are ever actually failing in
+ practice, but better safe than sorry. Also, checking these return
+ values should please some analysis tools (like Coverity). Patch
+ from 'flupzor'. Fix for bug 8206; bugfix on all versions of Tor.
diff --git a/changes/bug6218 b/changes/bug6218
deleted file mode 100644
index 5d5d108b0..000000000
--- a/changes/bug6218
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes:
- - Fix wrong TCP port range in parse_port_range(). Fixes bug 6218;
- bugfix on 0.2.1.10-alpha.
diff --git a/changes/bug6244_part_c b/changes/bug6244_part_c
deleted file mode 100644
index dea6e7b69..000000000
--- a/changes/bug6244_part_c
+++ /dev/null
@@ -1,6 +0,0 @@
- o Major bugfixes (controller):
- - Make wildcarded addresses (that is, ones beginning with *.) work when
- provided via the controller's MapAddress command. Previously, they
- were accepted, but we never actually noticed that they were wildcards.
- Fix for bug 6244; bugfix on 0.2.3.9-alpha.
-
diff --git a/changes/bug6251 b/changes/bug6251
deleted file mode 100644
index c782a93e4..000000000
--- a/changes/bug6251
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes:
- - Downgrade "set buildtimeout to low value" messages to INFO
- severity; they were never an actual problem, there was never
- anything reasonable to do about them, and they tended to spam
- logs from time to time. Fix for bug 6251; bugfix on
- 0.2.2.2-alpha. \ No newline at end of file
diff --git a/changes/bug6252_again b/changes/bug6252_again
deleted file mode 100644
index f7fd00cb3..000000000
--- a/changes/bug6252_again
+++ /dev/null
@@ -1,11 +0,0 @@
- o Security fixes:
- - Tear down the circuit if we get an unexpected SENDME cell. Clients
- could use this trick to make their circuits receive cells faster
- than our flow control would have allowed, or to gum up the network,
- or possibly to do targeted memory denial-of-service attacks on
- entry nodes. Fixes bug 6252. Bugfix on the 54th commit on Tor --
- from July 2002, before the release of Tor 0.0.0. We had committed
- this patch previously, but we had to revert it because of bug 6271.
- Now that 6271 is fixed, this appears to work.
-
-
diff --git a/changes/bug6271 b/changes/bug6271
deleted file mode 100644
index 06b129f73..000000000
--- a/changes/bug6271
+++ /dev/null
@@ -1,7 +0,0 @@
- o Major bugfixes
-
- - Fix a bug handling SENDME cells on nonexistent streams that
- could result in bizarre window values. Report and patch
- contributed pseudymously. Fixes part of bug 6271. This bug
- was introduced before the first Tor release, in svn commit
- r152.
diff --git a/changes/bug6274 b/changes/bug6274
deleted file mode 100644
index ad1abcde5..000000000
--- a/changes/bug6274
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes:
- - Ignore ServerTransportPlugin lines when Tor is not configured as
- a relay. Fixes bug 6274; bugfix on 0.2.3.6-alpha.
diff --git a/changes/bug6274_2 b/changes/bug6274_2
deleted file mode 100644
index 89576f932..000000000
--- a/changes/bug6274_2
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Terminate active server managed proxies if Tor stops being a
- relay. Addresses parts of bug 6274; bugfix on 0.2.3.6-alpha.
diff --git a/changes/bug6296 b/changes/bug6296
deleted file mode 100644
index b452b1745..000000000
--- a/changes/bug6296
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes:
-
- - Instead of ENOBUFS on Windows, say WSAENOBUFS. Fixes
- compilation on Windows. Fixes bug 6296; bugfix on 0.2.3.18-rc.
diff --git a/changes/bug6304 b/changes/bug6304
new file mode 100644
index 000000000..445560a8e
--- /dev/null
+++ b/changes/bug6304
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Behave correctly when the user disables LearnCircuitBuildTimeout
+ but doesn't tell us what they would like the timeout to be. Fixes
+ bug 6304; bugfix on 0.2.2.14-alpha.
diff --git a/changes/bug6341 b/changes/bug6341
deleted file mode 100644
index 04e52c7cd..000000000
--- a/changes/bug6341
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major bugfixes:
- - Fix a possible crash bug when checking for deactivated circuits
- in connection_or_flush_from_first_active_circuit(). Fixes bug
- 6341; bugfix on 0.2.2.7-alpha. Bug report and fix received
- pseudonymously.
diff --git a/changes/bug6377 b/changes/bug6377
deleted file mode 100644
index a3a367278..000000000
--- a/changes/bug6377
+++ /dev/null
@@ -1,4 +0,0 @@
- o Testing:
- - Make it possible to set the TestingTorNetwork configuration
- option using AlternateDirAuthority and AlternateBridgeAuthority
- as an alternative to setting DirServer.
diff --git a/changes/bug6379 b/changes/bug6379
deleted file mode 100644
index 1f2b6941c..000000000
--- a/changes/bug6379
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes:
- - Fix build warnings from --enable-openbsd-malloc with gcc warnings
- enabled. Fixes bug 6379.
- - Fix 64-bit warnings from --enable-openbsd-malloc. Fixes bug 6379.
- Bugfix on 0.2.0.20-rc.
-
diff --git a/changes/bug6387 b/changes/bug6387
deleted file mode 100644
index 73fc4f7cf..000000000
--- a/changes/bug6387
+++ /dev/null
@@ -1,3 +0,0 @@
- o Documentation:
- - Clarify the documentation for the Alternate*Authority options.
- Fixes bug 6387.
diff --git a/changes/bug6397 b/changes/bug6397
deleted file mode 100644
index 23d8359bd..000000000
--- a/changes/bug6397
+++ /dev/null
@@ -1,4 +0,0 @@
- o Major bugfixes:
- - When disabling guards for having too high a proportion of failed
- circuits, make sure to look at each guard. Fix for bug 6397; bugfix
- on 0.2.3.17-beta.
diff --git a/changes/bug6404 b/changes/bug6404
deleted file mode 100644
index 948f00b92..000000000
--- a/changes/bug6404
+++ /dev/null
@@ -1,16 +0,0 @@
- o Minor bugfixes:
-
- - Remove the maximum length of microdescriptor we are willing to
- generate. Occasionally this is needed for routers
- with complex policies or family declarations. Partial fix for
- bug 6404; fix on 0.2.2.6-alpha.
-
- - Authorities no longer include any router in their
- microdescriptor consensuses for which they couldn't generate or
- agree on a microdescriptor. Partial fix for bug 6404; fix on
- 0.2.2.6-alpha.
-
- - Move log message when unable to find a microdesc in a
- routerstatus entry to parse time. Previously we'd spam this
- warning every time we tried to figure out which microdescriptors
- to download. Partial fix for bug 6404; fix on 0.2.3.18-rc.
diff --git a/changes/bug6423 b/changes/bug6423
deleted file mode 100644
index 2ea4f1410..000000000
--- a/changes/bug6423
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Consider new, removed or changed IPv6 OR ports a non cosmetic
- change.
diff --git a/changes/bug6436 b/changes/bug6436
deleted file mode 100644
index 2c163df10..000000000
--- a/changes/bug6436
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Provide a better error message about possible OSX Asciidoc failure
- reasons. Fix for bug 6436.
diff --git a/changes/bug6472 b/changes/bug6472
deleted file mode 100644
index dcd42ebe6..000000000
--- a/changes/bug6472
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes:
- - Avoid a pair of double-free and use-after-mark bugs that can
- occur with certain timings in canceled and re-received DNS
- requests. Fix for bug 6472; bugfix on 0.0.7rc1.
diff --git a/changes/bug6475 b/changes/bug6475
deleted file mode 100644
index 67bab9962..000000000
--- a/changes/bug6475
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes:
- - Add internal circuit construction state to protect against
- the noisy warn message "Unexpectedly high circuit_successes".
- Also add some additional rate-limited notice messages to help
- determine the root cause of the warn. Fixes bug 6475.
- Bugfix against 0.2.3.17-beta.
diff --git a/changes/bug6480 b/changes/bug6480
deleted file mode 100644
index 83ae00b25..000000000
--- a/changes/bug6480
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major bugfixes:
- - Avoid read-from-freed-RAM bug and related double-free bug that
- could occur when a DNS request fails while launching it. Fixes
- bug 6480; bugfix on 0.2.0.1-alpha.
-
diff --git a/changes/bug6490 b/changes/bug6490
deleted file mode 100644
index c92daad8f..000000000
--- a/changes/bug6490
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features:
- - Warn when Tor is configured to use accounting in a way that will
- link a hidden service to some other hidden service or public
- address. Fix for bug 6490.
diff --git a/changes/bug6500 b/changes/bug6500
deleted file mode 100644
index cac2054a3..000000000
--- a/changes/bug6500
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor bugfixes:
- - Fix some typos in the manpages. Patch from A. Costa. Fixes bug 6500.
diff --git a/changes/bug6507 b/changes/bug6507
deleted file mode 100644
index 89940cbf7..000000000
--- a/changes/bug6507
+++ /dev/null
@@ -1,15 +0,0 @@
- o Major bugfixes:
- - Detect 'ORPort 0' as meaning, uniformly, that we're not running
- as a server. Previously, some of our code would treat the
- presence of any ORPort line as meaning that we should act like a
- server, even though our new listener code would correctly not
- open any ORPorts for ORPort 0. Similar bugs in other Port
- options are also fixed. Fixes bug 6507; bugfix on 0.2.3.3-alpha.
-
- o Minor features:
-
- - Detect and reject attempts to specify both 'FooPort' and
- 'FooPort 0' in the same configuration domain. (It's still okay
- to have a FooPort in your configuration file,and use 'FooPort 0'
- on the command line to disable it.) Fixes another case of
- bug6507; bugfix on 0.2.3.3-alpha.
diff --git a/changes/bug6514 b/changes/bug6514
deleted file mode 100644
index 84633bd27..000000000
--- a/changes/bug6514
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes:
- - Add a (probably redundant) memory clear between iterations of
- the router status voting loop, to prevent future coding errors
- where data might leak between iterations of the loop. Resolves
- ticket 6514.
diff --git a/changes/bug6530 b/changes/bug6530
deleted file mode 100644
index 825bbb752..000000000
--- a/changes/bug6530
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major security fixes:
- - Avoid a read of uninitializd RAM when reading a vote or consensus
- document with an unrecognized flavor name. This could lead to a
- remote crash bug. Fixes bug 6530; bugfix on 0.2.2.6-alpha.
-
diff --git a/changes/bug6572 b/changes/bug6572
new file mode 100644
index 000000000..6508d1bcb
--- /dev/null
+++ b/changes/bug6572
@@ -0,0 +1,4 @@
+ o Minor bugfixes (log messages)
+ - Use circuit creation time for network liveness evaluation. This
+ should eliminate warning log messages about liveness caused by
+ changes in timeout evaluation. Fixes bug 6572; bugfix on 0.2.4.8-alpha.
diff --git a/changes/bug6673 b/changes/bug6673
new file mode 100644
index 000000000..506b44989
--- /dev/null
+++ b/changes/bug6673
@@ -0,0 +1,4 @@
+ o Minor features (build):
+ - Detect and reject attempts to build Tor with threading support
+ when OpenSSL have been compiled with threading support disabled.
+ Fixes bug 6673.
diff --git a/changes/bug6690 b/changes/bug6690
deleted file mode 100644
index 99d42976e..000000000
--- a/changes/bug6690
+++ /dev/null
@@ -1,7 +0,0 @@
- o Major bugfixes (security):
- - Do not crash when comparing an address with port value 0 to an
- address policy. This bug could have been used to cause a remote
- assertion failure by or against directory authorities, or to
- allow some applications to crash clients. Fixes bug 6690; bugfix
- on 0.2.1.10-alpha.
-
diff --git a/changes/bug6710 b/changes/bug6710
deleted file mode 100644
index 2c8934611..000000000
--- a/changes/bug6710
+++ /dev/null
@@ -1,6 +0,0 @@
- o Major bugfixes (security):
- - Reject any attempt to extend to an internal address. Without
- this fix, a router could be used to probe addresses on an
- internal network to see whether they were accepting
- connections. Fix for bug 6710; bugfix on 0.0.8pre1.
-
diff --git a/changes/bug6732 b/changes/bug6732
deleted file mode 100644
index 7a744e014..000000000
--- a/changes/bug6732
+++ /dev/null
@@ -1,3 +0,0 @@
- o Documentation:
- - Add missing documentation for consensus and microdesc files. Fix for
- bug 6732.
diff --git a/changes/bug6743 b/changes/bug6743
deleted file mode 100644
index 6ec78f853..000000000
--- a/changes/bug6743
+++ /dev/null
@@ -1,9 +0,0 @@
- o Minor bugfixes:
- - Allow one-hop directory fetching circuits the full "circuit build
- timeout" period, rather than just half of it, before failing them
- and marking the relay down. This fix should help reduce cases where
- clients declare relays (or worse, bridges) unreachable because
- the TLS handshake takes a few seconds to complete. Fixes bug 6743;
- bugfix on 0.2.2.2-alpha, where we changed the timeout from a static
- 30 seconds.
-
diff --git a/changes/bug6774 b/changes/bug6774
deleted file mode 100644
index 0c137fd67..000000000
--- a/changes/bug6774
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes:
- - Avoid crashing on a malformed state file where EntryGuardPathBias
- precedes EntryGuard. Fix for bug 6774; bugfix on 0.2.3.17-beta.
-
diff --git a/changes/bug6801 b/changes/bug6801
deleted file mode 100644
index ef21acc98..000000000
--- a/changes/bug6801
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes:
- - Avoid segfault when starting up having run with an extremely old
- version of Tor and parsing its state file. Fixes bug 6801; bugfix on
- 0.2.2.23-alpha.
-
diff --git a/changes/bug6811 b/changes/bug6811
deleted file mode 100644
index 841ec1c54..000000000
--- a/changes/bug6811
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major security fixes:
- - Fix an assertion failure in tor_timegm that could be triggered
- by a badly formatted directory object. Bug found by fuzzing with
- Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc.
-
diff --git a/changes/bug6827 b/changes/bug6827
deleted file mode 100644
index bf71d2b97..000000000
--- a/changes/bug6827
+++ /dev/null
@@ -1,9 +0,0 @@
- o Minor bugfixes:
-
- - Avoid undefined behaviour when parsing the list of supported
- rendezvous/introduction protocols in a hidden service
- descriptor. Previously, Tor would have confused (as-yet-unused)
- protocol version numbers greater than 32 with lower ones on many
- platforms. Fixes bug 6827; bugfix on 0.2.0.10-alpha; found by
- George Kadianakis.
-
diff --git a/changes/bug6844 b/changes/bug6844
deleted file mode 100644
index 338e19d9a..000000000
--- a/changes/bug6844
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes:
- - Correct file sizes when reading binary files on
- Cygwin, to avoid a bug where Tor would fail to read its state file.
- Fixes bug 6844; bugfix on 0.1.2.7-alpha.
diff --git a/changes/bug6866 b/changes/bug6866
deleted file mode 100644
index 561676b76..000000000
--- a/changes/bug6866
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes:
- - Convert an assert in the pathbias code to a log message. Assert
- appears to only be triggerable by Tor2Web mode. Fixes bug 6866;
- bugfix on 0.2.3.17-beta.
diff --git a/changes/bug7014 b/changes/bug7014
deleted file mode 100644
index 1d39103a5..000000000
--- a/changes/bug7014
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes:
- - Fix two cases in src/or/transports.c where we were calling
- fmt_addr() twice in a parameter list. Bug found by David
- Fifield. Fixes bug 7014; bugfix on 0.2.3.9-alpha.
-
diff --git a/changes/bug7022 b/changes/bug7022
deleted file mode 100644
index 10ac35472..000000000
--- a/changes/bug7022
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes:
- - Fix memory leaks whenever we logged any message about the "path
- bias" detection. Fixes bug 7022; bugfix on 0.2.3.21-rc.
diff --git a/changes/bug7037 b/changes/bug7037
deleted file mode 100644
index fc3a1ad1c..000000000
--- a/changes/bug7037
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes:
- - When relays refuse a "create" cell because their queue of pending
- create cells is too big (typically because their cpu can't keep up
- with the arrival rate), send back reason "resource limit" rather
- than reason "internal", so network measurement scripts can get a
- more accurate picture. Bugfix on 0.1.1.11-alpha; fixes bug 7037.
diff --git a/changes/bug7054 b/changes/bug7054
new file mode 100644
index 000000000..15680d72c
--- /dev/null
+++ b/changes/bug7054
@@ -0,0 +1,4 @@
+ o Minor bugfixes (man page):
+ - Say "KBytes" rather than "KB" in the man page (for various values
+ of K), to further reduce confusion about whether Tor counts in
+ units of memory or fractions of units of memory. Fixes bug 7054.
diff --git a/changes/bug7065 b/changes/bug7065
new file mode 100644
index 000000000..1ca684102
--- /dev/null
+++ b/changes/bug7065
@@ -0,0 +1,5 @@
+ o Minor bugfix (log cleanups):
+ - Eliminate several instances where we use Nickname=ID to refer to
+ nodes in logs. Use Nickname (ID) instead. (Elsewhere, we still use
+ $ID=Nickname, which is also acceptable.) Fixes bug #7065. Bugfix
+ on 0.2.3.21-rc, 0.2.4.5-alpha, 0.2.4.8-alpha, and 0.2.4.10-alpha.
diff --git a/changes/bug7139 b/changes/bug7139
deleted file mode 100644
index dfb7d3283..000000000
--- a/changes/bug7139
+++ /dev/null
@@ -1,9 +0,0 @@
- o Major bugfixes (security):
-
- - Disable TLS session tickets. OpenSSL's implementation were giving
- our TLS session keys the lifetime of our TLS context objects, when
- perfect forward secrecy would want us to discard anything that
- could decrypt a link connection as soon as the link connection was
- closed. Fixes bug 7139; bugfix on all versions of Tor linked
- against OpenSSL 1.0.0 or later. Found by "nextgens".
-
diff --git a/changes/bug7143 b/changes/bug7143
new file mode 100644
index 000000000..d26135ae6
--- /dev/null
+++ b/changes/bug7143
@@ -0,0 +1,4 @@
+ o Minor bugfixes (build):
+ - Add the old src/or/micro-revision.i filename to CLEANFILES.
+ On the off chance that somebody has one, it will go away as soon
+ as they run "make clean". Fix for bug 7143; bugfix on 0.2.4.1-alpha.
diff --git a/changes/bug7164_diagnostic b/changes/bug7164_diagnostic
new file mode 100644
index 000000000..8bedfc4bd
--- /dev/null
+++ b/changes/bug7164_diagnostic
@@ -0,0 +1,4 @@
+ o Minor features (bug diagnostic):
+ - If we fail to free a microdescriptor because of bug #7164, log
+ the filename and line number from which we tried to free it.
+ This should help us finally fix #7164.
diff --git a/changes/bug7190 b/changes/bug7190
deleted file mode 100644
index 1607f7944..000000000
--- a/changes/bug7190
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes:
- - Clients now consider the ClientRejectInternalAddresses config option
- when using a microdescriptor consensus stanza to decide whether
- an exit relay would allow exiting to an internal address. Fixes
- bug 7190; bugfix on 0.2.3.1-alpha.
-
diff --git a/changes/bug7191 b/changes/bug7191
deleted file mode 100644
index a3bee6e5f..000000000
--- a/changes/bug7191
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major bugfixes:
- - Fix a denial of service attack by which any directory authority
- could crash all the others, or by which a single v2 directory
- authority could crash everybody downloading v2 directory
- information. Fixes bug 7191; bugfix on 0.2.0.10-alpha.
diff --git a/changes/bug7192 b/changes/bug7192
deleted file mode 100644
index 10cbc2469..000000000
--- a/changes/bug7192
+++ /dev/null
@@ -1,10 +0,0 @@
- o Major bugfixes:
- - When parsing exit policy summaries from microdescriptors, we had
- previously been ignoring the last character in each one, so that
- "accept 80,443,8080" would be treated by clients as indicating a
- node that allows access to ports 80, 443, and 808. That would lead
- to clients attempting connections that could never work, and
- ignoring exit nodes that would support their connections. Now clients
- parse these exit policy summaries correctly. Fixes bug 7192;
- bugfix on 0.2.3.1-alpha.
-
diff --git a/changes/bug7280 b/changes/bug7280
new file mode 100644
index 000000000..ef5d36a80
--- /dev/null
+++ b/changes/bug7280
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Fix some bugs in tor-fw-helper-natpmp when trying to build and
+ run it on Windows. More bugs likely remain. Patch from Gisle Vanem.
+ Fixes bug 7280; bugfix on 0.2.3.1-alpha.
diff --git a/changes/bug7302 b/changes/bug7302
new file mode 100644
index 000000000..fec615ff9
--- /dev/null
+++ b/changes/bug7302
@@ -0,0 +1,11 @@
+ o Minor bugfixes:
+ - Don't log inappropriate heartbeat messages when hibernating: a
+ hibernating node is _expected_ to drop out of the consensus,
+ decide it isn't bootstrapped, and so forth. Fixes part of bug
+ 7302; bugfix on 0.2.3.1-alpha.
+
+ - Don't complain about bootstrapping problems while hibernating.
+ These complaints reflect a general code problems, but not one
+ with any problematic effects. (No connections are actually
+ opened.) Fixes part of bug 7302; bugfix on 0.2.3.2-alpha.
+
diff --git a/changes/bug7350 b/changes/bug7350
new file mode 100644
index 000000000..b0ee9d091
--- /dev/null
+++ b/changes/bug7350
@@ -0,0 +1,4 @@
+ o Major bugfixes:
+ - Avoid an assertion when we discover that we'd like to write a cell
+ onto a closing connection: just discard the cell. Fixes another
+ case of bug 7350; bugfix on 0.2.4.4-alpha.
diff --git a/changes/bug7352 b/changes/bug7352
deleted file mode 100644
index 74a878dbe..000000000
--- a/changes/bug7352
+++ /dev/null
@@ -1,12 +0,0 @@
- o Major bugfixes:
- - Tor tries to wipe potentially sensitive data after using it, so
- that if some subsequent security failure exposes Tor's memory,
- the damage will be limited. But we had a bug where the compiler
- was eliminating these wipe operations when it decided that the
- memory was no longer visible to a (correctly running) program,
- hence defeating our attempt at defense in depth. We fix that
- by using OpenSSL's OPENSSL_cleanse() operation, which a compiler
- is unlikely to optimize away. Future versions of Tor may use
- a less ridiculously heavy approach for this. Fixes bug 7352.
- Reported in an article by Andrey Karpov.
-
diff --git a/changes/bug7464 b/changes/bug7464
deleted file mode 100644
index 9259cc74a..000000000
--- a/changes/bug7464
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes:
- - Fix a harmless bug when opting against publishing a relay descriptor
- because DisableNetwork is set. Fixes bug 7464; bugfix on
- 0.2.3.9-alpha.
diff --git a/changes/bug7582 b/changes/bug7582
new file mode 100644
index 000000000..f3b063576
--- /dev/null
+++ b/changes/bug7582
@@ -0,0 +1,9 @@
+ o Major bugfixes:
+
+ - When an exit node tells us that it is rejecting because of its
+ exit policy a stream we expected it to accept (because of its exit
+ policy), do not mark the node as useless for exiting if our
+ expectation was only based on an exit policy summary. Instead,
+ mark the circuit as unsuitable for that particular address. Fixes
+ part of bug 7582; bugfix on 0.2.3.2-alpha.
+
diff --git a/changes/bug7707_diagnostic b/changes/bug7707_diagnostic
new file mode 100644
index 000000000..0c3138e78
--- /dev/null
+++ b/changes/bug7707_diagnostic
@@ -0,0 +1,5 @@
+ o Minor features:
+ - Add another diagnostic to the heartbeat message: track and log
+ overhead that TLS is adding to the data we write. If this is
+ high, we are sending too little data to SSL_write at a time.
+ Diagnostic for bug 7707.
diff --git a/changes/bug7768 b/changes/bug7768
new file mode 100644
index 000000000..e3f9600af
--- /dev/null
+++ b/changes/bug7768
@@ -0,0 +1,3 @@
+ o Documentation fixes:
+ - Update tor-fw-helper.1.txt and tor-fw-helper.c to make option
+ names match. Fixes bug 7768.
diff --git a/changes/bug7799 b/changes/bug7799
new file mode 100644
index 000000000..ed4570129
--- /dev/null
+++ b/changes/bug7799
@@ -0,0 +1,7 @@
+ o Minor changes (log clarification)
+ - Add more detail to a log message about relaxed timeouts. Hopefully
+ this additional detail will allow us to diagnose the cause of bug 7799.
+ o Minor bugfixes
+ - Don't attempt to relax the timeout of already opened 1-hop circuits.
+ They might never timeout. This should eliminate some/all cases of
+ the relaxed timeout log message.
diff --git a/changes/bug7801 b/changes/bug7801
new file mode 100644
index 000000000..1d6d021f3
--- /dev/null
+++ b/changes/bug7801
@@ -0,0 +1,13 @@
+ o Minor bugfixes:
+ - When choosing which stream on a formerly stalled circuit to wake
+ first, make better use of the platform's weak RNG. Previously, we
+ had been using the % ("modulo") operator to try to generate a 1/N
+ chance of picking each stream, but this behaves badly with many
+ platforms' choice of weak RNG. Fix for bug 7801; bugfix on
+ 0.2.2.20-alpha.
+ - Use our own weak RNG when we need a weak RNG. Windows's rand()
+ and Irix's random() only return 15 bits; Solaris's random()
+ returns more bits but its RAND_MAX says it only returns 15, and
+ so on. Fixes another aspect of bug 7801; bugfix on
+ 0.2.2.20-alpha.
+
diff --git a/changes/bug7816.024 b/changes/bug7816.024
new file mode 100644
index 000000000..b5d55f5d6
--- /dev/null
+++ b/changes/bug7816.024
@@ -0,0 +1,8 @@
+ o Minor bugfixes:
+ - Avoid leaking IPv6 policy content if we fail to format it into
+ a router descriptor. Spotted by Coverity. Fixes part of 7816;
+ bugfix on 0.2.4.7-alpha.
+
+ - Avoid leaking memory if we fail to compute a consensus signature
+ or we generated a consensus we couldn't parse. Spotted by Coverity.
+ Fixes part of 7816; bugfix on 0.2.0.5-alpha.
diff --git a/changes/bug7816_023 b/changes/bug7816_023
new file mode 100644
index 000000000..a4530292c
--- /dev/null
+++ b/changes/bug7816_023
@@ -0,0 +1,7 @@
+ o Minor bugfixes (memory leak, controller):
+ - Fix a memory leak during safe-cookie controller authentication.
+ Spotted by Coverity. Fixes part of bug 7816; bugfix on 0.2.3.13-alpha.
+
+ o Minor bugfixes (memory leak, HTTPS proxy support):
+ - Fix a memory leak when receiving headers from an HTTPS proxy.
+ Spotted by Coverity. Fixes part of bug 7816; bugfix on 0.2.1.1-alpha.
diff --git a/changes/bug7816_023_small b/changes/bug7816_023_small
new file mode 100644
index 000000000..cd90f035f
--- /dev/null
+++ b/changes/bug7816_023_small
@@ -0,0 +1,3 @@
+ o Minor bugfixes:
+ - Fix various places where we leak file descriptors or memory on
+ error cases. Spotted by coverity. Fixes parts of bug 7816.
diff --git a/changes/bug7889 b/changes/bug7889
deleted file mode 100644
index ce99a59ce..000000000
--- a/changes/bug7889
+++ /dev/null
@@ -1,8 +0,0 @@
- o Major bugfixes:
- - Reject bogus create and relay cells with 0 circuit ID or 0 stream
- ID: these could be used to create unexpected streams and circuits
- which would count as "present" to some parts of Tor but "absent"
- to others, leading to zombie circuits and streams or to a
- bandwidth DOS. Fixes bug 7889; bugfix on every released version of
- Tor. Reported by "oftc_must_be_destroyed".
-
diff --git a/changes/bug7902 b/changes/bug7902
new file mode 100644
index 000000000..051759dc0
--- /dev/null
+++ b/changes/bug7902
@@ -0,0 +1,7 @@
+ o Minor bugfixes:
+ - When we receive a RELAY_END cell with the reason DONE, or with no
+ reason, before receiving a RELAY_CONNECTED cell, report the SOCKS
+ status as "connection refused." Previously we reporting these
+ cases as success but then immediately closing the connection.
+ Fixes bug 7902; bugfix on 0.1.0.1-rc. Reported by "oftc_must_
+ be_destroyed."
diff --git a/changes/bug7947 b/changes/bug7947
new file mode 100644
index 000000000..6200ba2d8
--- /dev/null
+++ b/changes/bug7947
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Fix the handling of a TRUNCATE cell when it arrives while the circuit
+ extension is in progress. Fixes bug 7947; bugfix on 0.0.7.1.
+
diff --git a/changes/bug7950 b/changes/bug7950
new file mode 100644
index 000000000..e62cca07a
--- /dev/null
+++ b/changes/bug7950
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - When rejecting a configuration because we were unable to parse a
+ quoted string, log an actual error message. Fix for bug 7950;
+ bugfix on 0.2.0.16-alpha.
diff --git a/changes/bug7982 b/changes/bug7982
new file mode 100644
index 000000000..46aa53249
--- /dev/null
+++ b/changes/bug7982
@@ -0,0 +1,3 @@
+ o Minor bugfixes:
+ - Copy-paste description for PathBias params from man page into or.h
+ comment. Fixes bug 7982.
diff --git a/changes/bug8002 b/changes/bug8002
new file mode 100644
index 000000000..d6e2ff249
--- /dev/null
+++ b/changes/bug8002
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - When autodetecting the number of CPUs, use the number of available
+ CPUs in preferernce to the number of configured CPUs. Inform the
+ user if this reduces the number of avialable CPUs. Fix for bug 8002.
+ Bugfix on 0.2.3.1-alpha.
diff --git a/changes/bug8014 b/changes/bug8014
new file mode 100644
index 000000000..c09a86098
--- /dev/null
+++ b/changes/bug8014
@@ -0,0 +1,5 @@
+ o Minor usability improvements (build):
+ - Clarify that when autconf is checking for nacl, it is checking
+ specifically for nacl with a fast curve25519 implementation.
+ Fixes bug 8014.
+
diff --git a/changes/bug8031 b/changes/bug8031
new file mode 100644
index 000000000..17329ec5b
--- /dev/null
+++ b/changes/bug8031
@@ -0,0 +1,7 @@
+ o Minor bugfixes:
+ - Use direct writes rather than stdio when building microdescriptor
+ caches, in an attempt to mitigate bug 8031, or at least make it
+ less common.
+ - Warn more aggressively when flushing microdescriptors to a
+ microdescriptor cache fails, in an attempt to mitegate bug 8031,
+ or at least make it more diagnosable.
diff --git a/changes/bug8037 b/changes/bug8037
new file mode 100644
index 000000000..989745fc3
--- /dev/null
+++ b/changes/bug8037
@@ -0,0 +1,8 @@
+ o Minor bugfixes:
+ - Correctly store microdescriptors and extrainfo descriptors with
+ an internal NUL byte. Fixes bug 8037; bugfix on 0.2.0.1-alpha.
+ Bug reported by "cypherpunks".
+
+ o Minor features:
+ - Reject as invalid most directory objects containing a
+ NUL. Belt-and-suspender fix for bug 8037.
diff --git a/changes/bug8059 b/changes/bug8059
new file mode 100644
index 000000000..47273ed0a
--- /dev/null
+++ b/changes/bug8059
@@ -0,0 +1,6 @@
+ o Minor bugfixes (protocol conformance):
+ - Fix a misframing issue when reading the version numbers in a
+ VERSIONS cell. Previously we would recognize [00 01 00 02] as
+ 'version 1, version 2, and version 0x100', when it should have
+ only included versions 1 and 2. Fixes bug 8059; bugfix on
+ 0.2.0.10-alpha. Reported pseudonymously.
diff --git a/changes/bug8062 b/changes/bug8062
new file mode 100644
index 000000000..805e51ed4
--- /dev/null
+++ b/changes/bug8062
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Increase the width of the field used to remember a connection's
+ link protocol version to two bytes. Harmless for now, since the
+ only currently recognized versions are one byte long. Reported
+ pseudynmously. Fixes bug 8062, bugfix on 0.2.0.10-alpha.
diff --git a/changes/bug8065 b/changes/bug8065
new file mode 100644
index 000000000..06dbae8cd
--- /dev/null
+++ b/changes/bug8065
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - Downgrade an assertion in connection_ap_expire_beginning to
+ an LD_BUG message. The fix for bug 8024 should prevent this
+ message from displaying, but just in case a warn that we can
+ diagnose is better than more assert crashes. Fix for bug 8065;
+ bugfix on 0.2.4.8-alpha.
diff --git a/changes/bug8093.part1 b/changes/bug8093.part1
new file mode 100644
index 000000000..2450794dd
--- /dev/null
+++ b/changes/bug8093.part1
@@ -0,0 +1,3 @@
+ o Minor features:
+ - Downgrade "unexpected SENDME" warnings to protocol-warn for 0.2.4,
+ for bug 8093.
diff --git a/changes/bug8117 b/changes/bug8117
new file mode 100644
index 000000000..910e8056f
--- /dev/null
+++ b/changes/bug8117
@@ -0,0 +1,13 @@
+ o Major bugfixes:
+
+ - Many SOCKS5 clients, when configured to offer a username/password,
+ offer both username/password authentication and "no authentication".
+ Tor had previously preferred no authentication, but this was
+ problematic when trying to make applications get proper stream
+ isolation with IsolateSOCKSAuth. Now, on any SOCKS port with
+ IsolateSOCKSAuth turned on (which is the default), Tor selects
+ username/password authentication if it's offered. If this confuses your
+ application, you can disable it on a per-SOCKSPort basis via
+ PreferSOCKSNoAuth. Fixes bug 8117; bugfix on 0.2.3.3-alpha.
+
+
diff --git a/changes/bug8121 b/changes/bug8121
new file mode 100644
index 000000000..60cba7284
--- /dev/null
+++ b/changes/bug8121
@@ -0,0 +1,7 @@
+ o Minor features:
+ - Clear the high bit on curve25519 public keys before passing them to
+ our backend, in case we ever wind up using a backend that doesn't do
+ so itself. If we used such a backend, and *didn't* clear the high bit,
+ we could wind up in a situation where users with such backends would
+ be distinguishable from users without. Fix for bug 8121; bugfix on
+ 0.2.4.8-alpha.
diff --git a/changes/bug8151 b/changes/bug8151
new file mode 100644
index 000000000..e20fa3c31
--- /dev/null
+++ b/changes/bug8151
@@ -0,0 +1,5 @@
+ o Minor features (directory authority):
+ - Include inside each vote a statement of the performance
+ thresholds that made the authority vote for its flags. Implements
+ ticket 8151.
+ \ No newline at end of file
diff --git a/changes/bug8158 b/changes/bug8158
new file mode 100644
index 000000000..65b21c2a2
--- /dev/null
+++ b/changes/bug8158
@@ -0,0 +1,3 @@
+ o Minor bugfixes:
+ - Use less space when formatting identical microdescriptor lines in
+ directory votes. Fixes bug 8158; bugfix on 0.2.4.1-alpha.
diff --git a/changes/bug8161 b/changes/bug8161
new file mode 100644
index 000000000..ab7b9c0ca
--- /dev/null
+++ b/changes/bug8161
@@ -0,0 +1,6 @@
+ o Minor changes:
+ - Lower path use bias thresholds to .80 for notice and .60 for warn.
+ Fixes bug #8161; bugfix on 0.2.4.10-alpa.
+ - Make the rate limiting flags for the path use bias log messages
+ independent from the original path bias flags. Fixes bug #8161;
+ bugfix on 0.2.4.10-alpha.
diff --git a/changes/bug8180 b/changes/bug8180
new file mode 100644
index 000000000..39e6ce7f9
--- /dev/null
+++ b/changes/bug8180
@@ -0,0 +1,7 @@
+ o Minor bugfixes (security usability):
+ - Elevate the severity of the warning message when setting
+ EntryNodes but disabling UseGuardNodes to an error. The outcome
+ of letting Tor procede with those options enabled (which causes
+ EntryNodes to get ignored) is sufficiently different from what
+ was expected that it's best to just refuse to proceed. Fixes bug
+ 8180; bugfix on 0.2.3.11-alpha.
diff --git a/changes/bug8185_diagnostic b/changes/bug8185_diagnostic
new file mode 100644
index 000000000..b0f888475
--- /dev/null
+++ b/changes/bug8185_diagnostic
@@ -0,0 +1,3 @@
+ o Minor features:
+ - Improve debugging output to attempt to diagnose the underlying
+ cause of bug 8185.
diff --git a/changes/bug8200 b/changes/bug8200
new file mode 100644
index 000000000..65fc9dd03
--- /dev/null
+++ b/changes/bug8200
@@ -0,0 +1,5 @@
+ o Minor bugfix:
+ - Stop sending a stray "(null)" in some cases for the server status
+ "EXTERNAL_ADDRESS" controller event. Resolves bug 8200; bugfix
+ on 0.1.2.6-alpha.
+
diff --git a/changes/bug8203 b/changes/bug8203
new file mode 100644
index 000000000..d26dc0fcc
--- /dev/null
+++ b/changes/bug8203
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Make the format and order of STREAM events for DNS lookups consistent
+ among the various ways to launch DNS lookups. Fix for bug 8203;
+ bugfix on 0.2.0.24-rc. Patch by "Desoxy."
diff --git a/changes/bug8207 b/changes/bug8207
new file mode 100644
index 000000000..0028d3380
--- /dev/null
+++ b/changes/bug8207
@@ -0,0 +1,7 @@
+ o Major bugfixes (hidden services):
+ - Allow hidden service authentication to succeed again. When we
+ refactored the hidden service introduction code back in 0.2.4.1-alpha,
+ we didn't update the code that checks whether authentication
+ information is present, causing all authentication checks to
+ return "false". Fix for bug 8207; bugfix on 0.2.4.1-alpha. Found by
+ Coverity; this is CID 718615.
diff --git a/changes/bug8209 b/changes/bug8209
new file mode 100644
index 000000000..c58923540
--- /dev/null
+++ b/changes/bug8209
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - When detecting the largest possible file descriptor (in order to close
+ all file descriptors when launching a new program), actually use
+ _SC_OPEN_MAX. The old code for doing this was very, very broken.
+ Fix for bug 8209; bugfix on 0.2.3.1-alpha. Found by Coverity; this
+ is CID 743383.
diff --git a/changes/bug8210 b/changes/bug8210
new file mode 100644
index 000000000..85d41b844
--- /dev/null
+++ b/changes/bug8210
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - Fix an impossible-to-trigger integer overflow when
+ estimating how long out onionskin queue would take. (This overflow
+ would require us to accept 4 million onionskins before processing
+ 100 of them.) Fixes bug 8210; bugfix on 0.2.4.10-alpha.
+
diff --git a/changes/bug8218 b/changes/bug8218
new file mode 100644
index 000000000..ce8d53ba6
--- /dev/null
+++ b/changes/bug8218
@@ -0,0 +1,6 @@
+ o Major bugfixes:
+ - Stop marking every relay as having been down for one hour every
+ time we restart a directory authority. These artificial downtimes
+ were messing with our Stable and Guard flag calculations. Fixes
+ bug 8218 (introduced by the fix for 1035). Bugfix on 0.2.2.23-alpha.
+
diff --git a/changes/bug8231 b/changes/bug8231
new file mode 100644
index 000000000..fd87a1dae
--- /dev/null
+++ b/changes/bug8231
@@ -0,0 +1,5 @@
+ o Major bugfixes:
+ - When unable to find any working directory nodes to use as a
+ directory guard, give up rather than adding the same non-working
+ nodes to the list over and over. Fixes bug 8231; bugfix on
+ 0.2.4.8-alpha.
diff --git a/changes/bug8235-diagnosing b/changes/bug8235-diagnosing
new file mode 100644
index 000000000..b760035cf
--- /dev/null
+++ b/changes/bug8235-diagnosing
@@ -0,0 +1,5 @@
+ o Minor features (diagnostic)
+ - If the state file's path bias counts are invalid (presumably from a
+ buggy tor prior to 0.2.4.10-alpha), make them correct.
+ - Add additional checks and log messages to the scaling of Path Bias
+ counts, in case there still are remaining issues with scaling.
diff --git a/changes/bug8253-fix b/changes/bug8253-fix
new file mode 100644
index 000000000..3d36d06c8
--- /dev/null
+++ b/changes/bug8253-fix
@@ -0,0 +1,6 @@
+ o Minor bugfixes (log messages)
+ - Fix a scaling issue in the path bias accounting code that resulted in
+ "Bug:" log messages from either pathbias_scale_close_rates() or
+ pathbias_count_build_success(). This represents a bugfix on a previous
+ bugfix: The original fix attempted in 0.2.4.10-alpha was incomplete.
+ Fixes bug 8235; bugfix on 0.2.4.1-alpha.
diff --git a/changes/bug8273 b/changes/bug8273
new file mode 100644
index 000000000..257f57e7a
--- /dev/null
+++ b/changes/bug8273
@@ -0,0 +1,3 @@
+ o Critical bugfixes:
+ - When dirserv.c computes flags and thresholds, use measured bandwidths
+ in preference to advertised ones.
diff --git a/changes/bug8290 b/changes/bug8290
new file mode 100644
index 000000000..d1fce7d8b
--- /dev/null
+++ b/changes/bug8290
@@ -0,0 +1,9 @@
+ o Removed files:
+ - The tor-tsocks.conf is no longer distributed or installed. We
+ recommend that tsocks users use torsocks instead. Resolves
+ ticket 8290.
+
+ o Documentation fixes:
+ - The torify manpage no longer refers to tsocks; torify hasn't
+ supported tsocks since 0.2.3.14-alpha.
+ - The manpages no longer reference tsocks.
diff --git a/changes/bug8408 b/changes/bug8408
new file mode 100644
index 000000000..ae9cf172e
--- /dev/null
+++ b/changes/bug8408
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Allow TestingTorNetworks to override the 4096-byte minimum for the Fast
+ threshold. Otherwise they can't bootstrap until they've observed more
+ traffic. Fixes bug 8508; bugfix on 0.2.4.10-alpha.
diff --git a/changes/bug8427 b/changes/bug8427
new file mode 100644
index 000000000..22b003fc3
--- /dev/null
+++ b/changes/bug8427
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - If we encounter a write failure on a SOCKS connection before we
+ finish our SOCKS handshake, don't warn that we closed the
+ connection before we could send a SOCKS reply. Fixes bug 8427;
+ bugfix on 0.1.0.1-rc.
diff --git a/changes/bug8435 b/changes/bug8435
new file mode 100644
index 000000000..da7ca7c1f
--- /dev/null
+++ b/changes/bug8435
@@ -0,0 +1,4 @@
+ o Major bugfixes:
+ - When dirserv.c computes flags and thresholds, ignore advertised
+ bandwidths if we have more than a threshold number of routers with
+ measured bandwidths.
diff --git a/changes/bug8464 b/changes/bug8464
new file mode 100644
index 000000000..74ff2e39f
--- /dev/null
+++ b/changes/bug8464
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Correct our check for which versions of Tor support the EXTEND2
+ cell. We had been willing to send it to Tor 0.2.4.7-alpha and
+ later, when support was really added in version 0.2.4.8-alpha.
+ Fixes bug 8464; bugfix on 0.2.4.8-alpha.
diff --git a/changes/bug8475 b/changes/bug8475
new file mode 100644
index 000000000..eb8debedb
--- /dev/null
+++ b/changes/bug8475
@@ -0,0 +1,4 @@
+ o Major bugfixes:
+ - If configured via ClientDNSRejectInternalAddresses not to report
+ DNS queries which have resolved to internal addresses, apply that
+ rule to IPv6 as well. Fixes bug 8475; bugfix on 0.2.0.7-alpha.
diff --git a/changes/bug8477-easypart b/changes/bug8477-easypart
new file mode 100644
index 000000000..0f8f1031c
--- /dev/null
+++ b/changes/bug8477-easypart
@@ -0,0 +1,3 @@
+ o Minor bugfixes:
+ - Log the purpose of a path-bias testing circuit correctly.
+ Improves a log message from bug 8477; bugfix on 0.2.4.8-alpha.
diff --git a/changes/bug8587 b/changes/bug8587
new file mode 100644
index 000000000..84d2f1ec0
--- /dev/null
+++ b/changes/bug8587
@@ -0,0 +1,5 @@
+ o Minor bugfixes (build):
+ - Build Tor correctly on 32-bit platforms where the compiler can build
+ but not run code using the "uint128_t" construction. Fixes bug 8587;
+ bugfix on 0.2.4.8-alpha.
+
diff --git a/changes/bug8596 b/changes/bug8596
new file mode 100644
index 000000000..dd36bad85
--- /dev/null
+++ b/changes/bug8596
@@ -0,0 +1,3 @@
+ o Minor features:
+ - Add CACHED keyword to ADDRMAP events in the control protocol to indicate
+ whether a DNS result will be cached or not.
diff --git a/changes/bug8598 b/changes/bug8598
new file mode 100644
index 000000000..e31c8f3c7
--- /dev/null
+++ b/changes/bug8598
@@ -0,0 +1,6 @@
+ o Bugfixes:
+ - Fix compilation warning with some versions of clang that would prefer
+ the -Wswitch-enum compiler flag to warn about switch statements with
+ missing enum values, even if those switch statements have a default:
+ statement. Fixes bug 8598; bugfix on 0.2.4.10-alpha.
+
diff --git a/changes/bug8599 b/changes/bug8599
new file mode 100644
index 000000000..204ef58c3
--- /dev/null
+++ b/changes/bug8599
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Fix some logic errors when the user manually overrides the
+ PathsNeededToBuildCircuits option in torrc. Fixes bug 8599; bugfix
+ on 0.2.4.10-alpha.
diff --git a/changes/bug8638 b/changes/bug8638
new file mode 100644
index 000000000..3a790e567
--- /dev/null
+++ b/changes/bug8638
@@ -0,0 +1,3 @@
+ o Minor features
+ In our testsuite, create temporary directories with a bit more entropy
+ in their name to make name collissions less likely. Fixes bug 8638.
diff --git a/changes/bug8639 b/changes/bug8639
new file mode 100644
index 000000000..0db5c9142
--- /dev/null
+++ b/changes/bug8639
@@ -0,0 +1,5 @@
+ o Normal bugfixes:
+ - When launching a resolve request on behalf of an AF_UNIX control
+ socket, omit the address field of the new entry connection, used in
+ subsequent controller events, rather than letting tor_dup_addr() set
+ it to "<unknown address type>". Fixes bug 8639.
diff --git a/changes/bug8711 b/changes/bug8711
new file mode 100644
index 000000000..28a1daa45
--- /dev/null
+++ b/changes/bug8711
@@ -0,0 +1,6 @@
+ o Minor features (authority):
+ - Add a "ignoring-advertised-bws" boolean to our flag-thresholds
+ lines to describe whether we have enough measured bandwidths to
+ ignore advertised bandwidth claims. Closes ticket 8711.
+
+
diff --git a/changes/bug8716 b/changes/bug8716
new file mode 100644
index 000000000..74c74f82a
--- /dev/null
+++ b/changes/bug8716
@@ -0,0 +1,3 @@
+ o Minor bugfixes (memory leak):
+ - Fix a memory leak that would occur whenever a configuration
+ option changed. Fixes bug #8718; bugfix on 0.2.3.3-alpha.
diff --git a/changes/bug8719 b/changes/bug8719
new file mode 100644
index 000000000..c05b79dde
--- /dev/null
+++ b/changes/bug8719
@@ -0,0 +1,6 @@
+ o Major bugfixes (memory leak):
+ - Avoid a memory leak where we would leak a consensus body when we find
+ that a consensus which we couldn't previously verify due to missing
+ certificates is now verifiable. Fixes bug 8719; bugfix on
+ 0.2.0.10-alpha.
+
diff --git a/changes/bug8822 b/changes/bug8822
new file mode 100644
index 000000000..c6787afe0
--- /dev/null
+++ b/changes/bug8822
@@ -0,0 +1,5 @@
+ o Major bugfixes (windows):
+ - Prevent failures on Windows Vista and later when rebuilding the
+ microdescriptor cache. Diagnosed by Robert Ransom. Fixes bug 8822;
+ bugfix on 0.2.4.12-alpha.
+
diff --git a/changes/bug8833 b/changes/bug8833
new file mode 100644
index 000000000..681a86191
--- /dev/null
+++ b/changes/bug8833
@@ -0,0 +1,3 @@
+ o Major bugfixes (directory authority):
+ - Fix a crash bug when building a consensus using an older consensus as
+ its basis. Fixes bug 8833. Bugfix on 0.2.4.12-alpha.
diff --git a/changes/bug8845 b/changes/bug8845
new file mode 100644
index 000000000..ace043ab9
--- /dev/null
+++ b/changes/bug8845
@@ -0,0 +1,3 @@
+ o Minor bugfixes (test):
+ - Fix an impossible buffer overrun in the AES unit tests. Fixes bug 8845;
+ bugfix on 0.2.0.7-alpha. Found by eugenis.
diff --git a/changes/bug8846 b/changes/bug8846
new file mode 100644
index 000000000..377cc3708
--- /dev/null
+++ b/changes/bug8846
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Give a less useless error message when the user asks for an IPv4
+ address on an IPv6-only port, or vice versa. Fixes bug 8846; bugfix
+ on 0.2.4.7-alpha.
diff --git a/changes/bug8879 b/changes/bug8879
new file mode 100644
index 000000000..0d2a70086
--- /dev/null
+++ b/changes/bug8879
@@ -0,0 +1,5 @@
+ o Major bugfixes:
+ - Follow the socks5 protocol when offering username/password
+ authentication. The fix for bug 8117 exposed this bug, and it
+ turns out real-world applications like Pidgin do care. Bugfix on
+ 0.2.3.2-alpha; fixes bug 8879.
diff --git a/changes/bug8965 b/changes/bug8965
new file mode 100644
index 000000000..b5af27963
--- /dev/null
+++ b/changes/bug8965
@@ -0,0 +1,3 @@
+ o Removed documentation:
+ - Remove some of the older contents of doc/ as obsolete; move others
+ to torspec.git. Fixes bug 8965.
diff --git a/changes/bug9047 b/changes/bug9047
new file mode 100644
index 000000000..497f0d337
--- /dev/null
+++ b/changes/bug9047
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - If for some reason we fail to write a microdescriptor while
+ rebuilding the cache, do not let the annotations from that
+ microdescriptor linger in the cache file, and do not let the
+ microdescriptor stay recorded as present in its old location.
+ Fixes bug 9047; bugfix on 0.2.2.6-alpha.
diff --git a/changes/bug9063 b/changes/bug9063
index af3b1a87f..dcbecf617 100644
--- a/changes/bug9063
+++ b/changes/bug9063
@@ -1,3 +1,3 @@
o Normal bugfixes:
- Close any circuit that has more cells queued than the spec permits.
- Fixes bug #9063; bugfix on 0.2.3.25.
+ Fixes bug #9063; bugfix on 0.2.4.12.
diff --git a/changes/bug9122 b/changes/bug9122
new file mode 100644
index 000000000..5009da612
--- /dev/null
+++ b/changes/bug9122
@@ -0,0 +1,4 @@
+ o Major bugfixes:
+ - When receiving a new configuration file via the control port's
+ LOADCONF command, do not treat the defaults file as absent.
+ Fixes bug 9122; bugfix on 0.2.3.9-alpha.
diff --git a/changes/bug9147 b/changes/bug9147
new file mode 100644
index 000000000..e6064ea0e
--- /dev/null
+++ b/changes/bug9147
@@ -0,0 +1,4 @@
+ o Minor features:
+ - Issue a warning when running with the bufferevents backend enabled.
+ It's still not stable, and people should know that they're likely
+ to hit unexpected problems. Closes ticket 9147.
diff --git a/changes/bug9200 b/changes/bug9200
new file mode 100644
index 000000000..7b64dd174
--- /dev/null
+++ b/changes/bug9200
@@ -0,0 +1,5 @@
+ o Major bugfixes:
+ - Fix a bug in the voting algorithm that could yield incorrect results
+ when a non-naming authority declared too many flags. Fixes bug 9200;
+ bugfix on 0.2.0.3-alpha.
+
diff --git a/changes/bug9254 b/changes/bug9254
new file mode 100644
index 000000000..5179bdc52
--- /dev/null
+++ b/changes/bug9254
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Fix a spurious compilation warning with some older versions of
+ GCC on FreeBSD. Fixes bug 9254; bugfix on 0.2.4.14-alpha.
+
diff --git a/changes/bug9288 b/changes/bug9288
new file mode 100644
index 000000000..59bf414ea
--- /dev/null
+++ b/changes/bug9288
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Fix an invalid memory read that occured when a pluggable
+ transport proxy failed its configuration protocol.
+ Fixes bug 9288.
diff --git a/changes/bug9295 b/changes/bug9295
new file mode 100644
index 000000000..2c113616c
--- /dev/null
+++ b/changes/bug9295
@@ -0,0 +1,4 @@
+ o Major bugfixes:
+ - Avoid a crash when using --hash-password. Fixes bug 9295; bugfix on
+ 0.2.4.15-rc. Found by stem integration tests.
+
diff --git a/changes/bug9309 b/changes/bug9309
new file mode 100644
index 000000000..38c462bc0
--- /dev/null
+++ b/changes/bug9309
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - When evaluating whether to use a connection that we haven't
+ decided is canonical using a recent link protocol version,
+ decide that it's canonical only if it used address _does_
+ match the desired address. Fixes bug 9309; bugfix on
+ 0.2.4.4-alpha. Reported by skruffy.
diff --git a/changes/bug9337 b/changes/bug9337
new file mode 100644
index 000000000..ce99bc818
--- /dev/null
+++ b/changes/bug9337
@@ -0,0 +1,4 @@
+ o Major bugfixes (DNS):
+ - Avoid an assertion failure when processing DNS replies without the
+ answer types we expected. Fixes bug 9337; bugfix on 0.2.4.7-alpha.
+
diff --git a/changes/bug9354 b/changes/bug9354
new file mode 100644
index 000000000..68fc81a59
--- /dev/null
+++ b/changes/bug9354
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Make the default behavior of NumDirectoryGuards be to track
+ NumEntryGuards. Now a user who changes only NumEntryGuards will get
+ the behavior she expects. Fixes bug 9354; bugfix on 0.2.4.8-alpha.
+
diff --git a/changes/bug9366 b/changes/bug9366
new file mode 100644
index 000000000..acc919e77
--- /dev/null
+++ b/changes/bug9366
@@ -0,0 +1,4 @@
+ o Minor features (usability):
+ - Warn and fail if a server is configured not to advertise any
+ ORPorts at all. (We need *something* to put in our descriptor, or
+ we just won't work.)
diff --git a/changes/bug9400 b/changes/bug9400
new file mode 100644
index 000000000..974224068
--- /dev/null
+++ b/changes/bug9400
@@ -0,0 +1,7 @@
+ o Minor bugfixes:
+
+ - Avoid double-closing the listener socket in our socketpair replacement
+ (used on Windows) in the case where the addresses on our opened
+ sockets don't match what we expected. Fixes bug 9400; bugfix on
+ every released Tor version. Found by Coverity.
+
diff --git a/changes/bug9543 b/changes/bug9543
new file mode 100644
index 000000000..753947f6f
--- /dev/null
+++ b/changes/bug9543
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Avoid overflows when the user sets MaxCircuitDirtiness to a
+ ridiculously high value, by imposing a (ridiculously high) 30-day
+ maximum on MaxCircuitDirtiness.
diff --git a/changes/bug9596 b/changes/bug9596
new file mode 100644
index 000000000..b3d138ecd
--- /dev/null
+++ b/changes/bug9596
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Correctly log long IPv6 exit policy, instead of truncating them
+ or reporting an error. Fixes bug 9596; bugfix on 0.2.4.7-alpha.
+
diff --git a/changes/bug9602 b/changes/bug9602
new file mode 100644
index 000000000..2dc13c4c0
--- /dev/null
+++ b/changes/bug9602
@@ -0,0 +1,5 @@
+ o Bugfixes
+ - Null out orconn->chan->conn when closing orconn in case orconn is freed
+ before channel_run_cleanup() gets to orconn->chan, and handle the null
+ conn edge case correctly in channel_tls_t methods. Fixes bug #9602;
+ bugfix on 0.2.4.4-alpha.
diff --git a/changes/bug9644 b/changes/bug9644
new file mode 100644
index 000000000..51c58a5ff
--- /dev/null
+++ b/changes/bug9644
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Fix a small memory leak on exit. (We weren't freeing directory
+ authority certificate download statuses.) Fixes bug 9644; bugfix
+ on 0.2.4.13-alpha.
diff --git a/changes/bug9645a b/changes/bug9645a
new file mode 100644
index 000000000..2daba65a0
--- /dev/null
+++ b/changes/bug9645a
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - If we are unable to save a microdescriptor to the journal, do not
+ drop it from memory and then reattempt downloading it. Fixes bug
+ 9645; bugfix on 0.2.2.6-alpha.
+
diff --git a/changes/bug9716 b/changes/bug9716
new file mode 100644
index 000000000..5e3907717
--- /dev/null
+++ b/changes/bug9716
@@ -0,0 +1,4 @@
+ o Bugfixes (performance):
+ - Set the listen() backlog limit to the largest actually supported
+ on the system, not to the value in a header file. Fixes bug 9716;
+ bugfix on every released Tor.
diff --git a/changes/bug9731 b/changes/bug9731
new file mode 100644
index 000000000..828496af3
--- /dev/null
+++ b/changes/bug9731
@@ -0,0 +1,3 @@
+ o Major bugfixes:
+ - Do not apply connection_consider_empty_read/write_buckets to
+ cpuworker connections.
diff --git a/changes/bug9776 b/changes/bug9776
new file mode 100644
index 000000000..ea3a96abb
--- /dev/null
+++ b/changes/bug9776
@@ -0,0 +1,5 @@
+ o Normal bugfixes:
+ - Always call circuit_n_chan_done(chan, 0) from channel_closed(), so we
+ can't leak pending circuits in some cases where
+ run_connection_housekeeping() calls connection_or_close_normally().
+ Fixes bug #9776; bugfix on 0.2.4.17.
diff --git a/changes/bug9780 b/changes/bug9780
new file mode 100644
index 000000000..3cb51bd52
--- /dev/null
+++ b/changes/bug9780
@@ -0,0 +1,8 @@
+ o Minor bugfixes (performance, fingerprinting):
+ - Our default TLS ecdhe groups were backwards: we meant to be using
+ P224 for relays (for performance win) and P256 for bridges (since
+ it is more common in the wild). Instead we had it backwards. After
+ reconsideration, we decided that the default should be P256 on all
+ hosts, since its security is probably better, and since P224 is
+ reportedly used quite little in the wild. Found by "skruffy" on
+ IRC. Fix for bug 9780; bugfix on 0.2.4.8-alpha.
diff --git a/changes/bug9880 b/changes/bug9880
new file mode 100644
index 000000000..a7dda8f82
--- /dev/null
+++ b/changes/bug9880
@@ -0,0 +1,8 @@
+ o Minor bugfixes:
+
+ - When closing a channel that has already been open, do not close
+ pending circuits that were waiting to connect to the same relay.
+ Fixes bug 9880; bugfix on 0.2.5.1-alpha. Thanks to skruffy for
+ finding this bug. (Bug was merged to 0.2.4 branch but not released
+ in any 0.2.4 version)
+
diff --git a/changes/bug9904 b/changes/bug9904
new file mode 100644
index 000000000..eec4144cc
--- /dev/null
+++ b/changes/bug9904
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - When examining list of network interfaces to find our address, do
+ not consider non-running or disabled network interfaces. Fixes bug
+ 9904; bugfix on 0.2.3.11-alpha. Patch from "hantwister".
diff --git a/changes/bug9927 b/changes/bug9927
new file mode 100644
index 000000000..e66280c3c
--- /dev/null
+++ b/changes/bug9927
@@ -0,0 +1,4 @@
+ o Minor features:
+ - Generate bootstrapping status update events correctly for fetching
+ microdescriptors. Fixes bug 9927.
+
diff --git a/changes/bug9946 b/changes/bug9946
new file mode 100644
index 000000000..5d1c88874
--- /dev/null
+++ b/changes/bug9946
@@ -0,0 +1,11 @@
+ o Minor bugfixes:
+ - If the guard we choose first doesn't answer, we would try the
+ second guard, but once we connected to the second guard we would
+ abandon it and retry the first one, slowing down bootstrapping.
+ The fix is to treat all our initially chosen guards as acceptable
+ to use. Fixes bug 9946; bugfix on 0.1.1.11-alpha.
+
+ o Major bugfixes:
+ - Stop trying to fetch all our directory information from our first
+ guard. Discovered while fixing bug 9946; bugfix on 0.2.4.8-alpha.
+
diff --git a/changes/cov709056 b/changes/cov709056
deleted file mode 100644
index 64a75ad8a..000000000
--- a/changes/cov709056
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes:
- - Check return value of fputs() when writing authority certificate
- file. Fixes Coverity issue 709056; bugfix on 0.2.0.1-alpha.
-
diff --git a/changes/cov980650 b/changes/cov980650
new file mode 100644
index 000000000..cbbada2e6
--- /dev/null
+++ b/changes/cov980650
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Fix a copy-and-paste error when adding a missing A1 to a routerset
+ because of GeoIPExcludeUnknown. Fix for coverity CID 980650.
+ Bugfix on 0.2.4.10-alpha.
diff --git a/changes/cve-2012-2249 b/changes/cve-2012-2249
deleted file mode 100644
index 625bfa2f5..000000000
--- a/changes/cve-2012-2249
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major bugfixes (security):
- - Discard extraneous renegotiation attempts once the V3 link
- protocol has been initiated. Failure to do so left us open to
- a remotely triggerable assertion failure. Fixes CVE-2012-2249;
- bugfix on 0.2.3.6-alpha. Reported by "some guy from France".
diff --git a/changes/dirserv-BUGGY-a b/changes/dirserv-BUGGY-a
deleted file mode 100644
index 35b492a2d..000000000
--- a/changes/dirserv-BUGGY-a
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor bugfixes:
-
- - Don't serve or accept v2 hidden service descriptors over a
- relay's DirPort. It's never correct to do so, and disabling it
- might make it more annoying to exploit any bugs that turn up in the
- descriptor-parsing code. Fixes bug 7149.
-
diff --git a/changes/disable_pathbias_messages b/changes/disable_pathbias_messages
deleted file mode 100644
index 3bc996347..000000000
--- a/changes/disable_pathbias_messages
+++ /dev/null
@@ -1,3 +0,0 @@
- o Disabeled features
- - Downgrade path-bias warning messages to INFO. We'll try to get them
- working better in 0.2.4. Fixes bug 6475; bugfix on 0.2.3.17-beta.
diff --git a/changes/doc-heartbeat-loglevel b/changes/doc-heartbeat-loglevel
new file mode 100644
index 000000000..91f40ad26
--- /dev/null
+++ b/changes/doc-heartbeat-loglevel
@@ -0,0 +1,3 @@
+ o Minor documentation fixes:
+ - Fix the documentation of HeartbeatPeriod to say that the heartbeat
+ message is logged at notice, not at info.
diff --git a/changes/easy.ratelim b/changes/easy.ratelim
new file mode 100644
index 000000000..cadd1e4f5
--- /dev/null
+++ b/changes/easy.ratelim
@@ -0,0 +1,3 @@
+ o Code simplification and refactoring:
+ - Add a wrapper function for the common "log a message with a rate-limit"
+ case.
diff --git a/changes/feature4994 b/changes/feature4994
new file mode 100644
index 000000000..4fa0e037b
--- /dev/null
+++ b/changes/feature4994
@@ -0,0 +1,7 @@
+ o Minor features:
+ - Teach bridge-using clients to avoid 0.2.2 bridges when making
+ microdescriptor-related dir requests, and only fall back to normal
+ descriptors if none of their bridges can handle microdescriptors
+ (as opposed to the fix in ticket 4013, which caused them to fall
+ back to normal descriptors if *any* of their bridges preferred
+ them). Resolves ticket 4994.
diff --git a/changes/feature9574 b/changes/feature9574
new file mode 100644
index 000000000..723606e39
--- /dev/null
+++ b/changes/feature9574
@@ -0,0 +1,7 @@
+ o Major features:
+ - Relays now process the new "NTor" circuit-level handshake requests
+ with higher priority than the old "TAP" circuit-level handshake
+ requests. We still process some TAP requests to not totally starve
+ 0.2.3 clients when NTor becomes popular. A new consensus parameter
+ "NumNTorsPerTAP" lets us tune the balance later if we need to.
+ Implements ticket 9574.
diff --git a/changes/fix-geoipexclude-doc b/changes/fix-geoipexclude-doc
new file mode 100644
index 000000000..63b544ef2
--- /dev/null
+++ b/changes/fix-geoipexclude-doc
@@ -0,0 +1,4 @@
+ o Documentation fixes:
+ - Fix the GeoIPExcludeUnknown documentation to refer to ExcludeExitNodes
+ rather than the currently nonexistent ExcludeEntryNodes. Spotted by
+ "hamahangi" on tor-talk.
diff --git a/changes/geoip-dec2012 b/changes/geoip-dec2012
deleted file mode 100644
index 26431c2e8..000000000
--- a/changes/geoip-dec2012
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Update to the December 5 2012 Maxmind GeoLite Country database.
-
diff --git a/changes/geoip-jan2013 b/changes/geoip-jan2013
deleted file mode 100644
index 45e5a150c..000000000
--- a/changes/geoip-jan2013
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Update to the January 2 2013 Maxmind GeoLite Country database.
-
diff --git a/changes/geoip-nov2012 b/changes/geoip-nov2012
deleted file mode 100644
index 22e7bace5..000000000
--- a/changes/geoip-nov2012
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Update to the November 7 2012 Maxmind GeoLite Country database.
-
diff --git a/changes/integers_donna b/changes/integers_donna
new file mode 100644
index 000000000..e9c69e8e1
--- /dev/null
+++ b/changes/integers_donna
@@ -0,0 +1,3 @@
+ o Minor bugfixes (portability)
+ - Tweak the curve25519-donna*.c implementations to tolerate systems
+ that lack stdint.h. Fixes bug 3894; bugfix on 0.2.4.8-alpha.
diff --git a/changes/less_charbuf_usage b/changes/less_charbuf_usage
new file mode 100644
index 000000000..2ec42b544
--- /dev/null
+++ b/changes/less_charbuf_usage
@@ -0,0 +1,5 @@
+ o Code simplification and refactoring:
+ - Avoid using character buffers when constructing most directory
+ objects: this approach was unweildy and error-prone. Instead,
+ build smartlists of strings, and concatenate them when done.
+
diff --git a/changes/link_negotiation_assert b/changes/link_negotiation_assert
deleted file mode 100644
index 398a54557..000000000
--- a/changes/link_negotiation_assert
+++ /dev/null
@@ -1,6 +0,0 @@
- o Major bugfixs (security):
- - Fix a group of remotely triggerable assertion failures related to
- incorrect link protocol negotiation. Found, diagnosed, and fixed
- by "some guy from France." Fix for CVE-2012-2250; bugfix on
- 0.2.3.6-alpha.
-
diff --git a/changes/log-noise b/changes/log-noise
new file mode 100644
index 000000000..bbbf0d2c0
--- /dev/null
+++ b/changes/log-noise
@@ -0,0 +1,11 @@
+ o Minor bugfixes (log message reduction)
+ - Fix a path state issue that triggered a notice during relay startup.
+ Fixes bug #8320; bugfix on 0.2.4.10-alpha.
+ - Reduce occurrences of warns about circuit purpose in
+ connection_ap_expire_building(). Fixes bug #8477; bugfix on
+ 0.2.4.11-alpha.
+ - Fix a directory authority warn caused when we have a large amount
+ of badexit bandwidth. Fixes bug #8419; bugfix on 0.2.2.10-alpha.
+ - Reduce a path bias length check notice log to info. The notice
+ is triggered when creating controller circuits. Fixes bug #8196;
+ bugfix on 0.2.4.8-alpha.
diff --git a/changes/no_client_timestamps_024 b/changes/no_client_timestamps_024
new file mode 100644
index 000000000..41dea2f1a
--- /dev/null
+++ b/changes/no_client_timestamps_024
@@ -0,0 +1,14 @@
+ o Minor features (security, timestamp avoidance, proposal 222):
+ - Clients no longer send timestamps in their NETINFO cells. These were
+ not used for anything, and they provided one small way for clients
+ to be distinguished from each other as they moved from network to
+ network or behind NAT. Implements part of proposal 222.
+ - Clients now round timestamps in INTRODUCE cells down to the nearest
+ 10 minutes. If a new Support022HiddenServices option is set to 0,
+ or if it's set to "auto" and the feature is disabled in the consensus,
+ the timestamp is sent as 0 instead. Implements part of proposal 222.
+ - Stop sending timestamps in AUTHENTICATE cells. This is not such
+ a big deal from a security point of view, but it achieves no actual
+ good purpose, and isn't needed. Implements part of proposal 222.
+ - Reduce down accuracy of timestamps in hidden service descriptors.
+ Implements part of proposal 222.
diff --git a/changes/pathsel-BUGGY-a b/changes/pathsel-BUGGY-a
deleted file mode 100644
index 2e642c795..000000000
--- a/changes/pathsel-BUGGY-a
+++ /dev/null
@@ -1,14 +0,0 @@
- o Security fixes:
-
- - Try to leak less information about what relays a client is
- choosing to a side-channel attacker. Previously, a Tor client
- would stop iterating through the list of available relays as
- soon as it had chosen one, thus finishing a little earlier
- when it picked a router earlier in the list. If an attacker
- can recover this timing information (nontrivial but not
- proven to be impossible), they could learn some coarse-
- grained information about which relays a client was picking
- (middle nodes in particular are likelier to be affected than
- exits). The timing attack might be mitigated by other factors
- (see bug #6537 for some discussion), but it's best not to
- take chances. Fixes bug 6537; bugfix on 0.0.8rc1.
diff --git a/changes/port_doc b/changes/port_doc
deleted file mode 100644
index 0e8662f0a..000000000
--- a/changes/port_doc
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (usability):
- - Try to make the warning when giving an obsolete SOCKSListenAddress
- a littel more useful.
diff --git a/changes/revert-geoip-may2012 b/changes/revert-geoip-may2012
deleted file mode 100644
index e420947a3..000000000
--- a/changes/revert-geoip-may2012
+++ /dev/null
@@ -1,6 +0,0 @@
- o Major bugfixes:
- - Revert to the May 1 2012 Maxmind GeoLite Country database. In the
- June 2012 database, Maxmind marked many Tor relays as country "A1",
- which will cause risky behavior for clients that set EntryNodes
- or ExitNodes. Addresses bug 6334; bugfix on 0.2.3.17-beta.
-
diff --git a/changes/signof_enum b/changes/signof_enum
new file mode 100644
index 000000000..ba4fb597d
--- /dev/null
+++ b/changes/signof_enum
@@ -0,0 +1,7 @@
+ o Code simplifications and refactoring:
+ - Use Ville Laurikari's implementation of AX_CHECK_SIGN() to determine
+ the signs of types during autoconf. This is better than our old
+ approach, which didn't work when cross-compiling.
+ - Detect the sign of enum values, rather than assuming that MSC is the
+ only compiler where enum types are all signed. Fix for bug 7727;
+ bugfix on 0.2.4.10-alpha.
diff --git a/changes/smartlist_foreach b/changes/smartlist_foreach
deleted file mode 100644
index 2fd3a1a85..000000000
--- a/changes/smartlist_foreach
+++ /dev/null
@@ -1,8 +0,0 @@
- o Code simplification and refactoring:
- - Do not use SMARTLIST_FOREACH for any loop whose body exceeds
- 10 lines. Doing so in the past has led to hard-to-debug code.
- The new style is to use the SMARTLIST_FOREACH_{BEGIN,END} pair.
- Issue 6400.
- - Do not nest SMARTLIST_FOREACH blocks within one another. Any
- nested block ought to be using SMARTLIST_FOREACH_{BEGIN,END}.
- Issue 6400.
diff --git a/changes/ticket2267 b/changes/ticket2267
new file mode 100644
index 000000000..b589b5721
--- /dev/null
+++ b/changes/ticket2267
@@ -0,0 +1,8 @@
+ o Minor features:
+ - Refactor resolve_my_address() so it returns the method by which we
+ decided our public IP address (explicitly configured, resolved from
+ explicit hostname, guessed from interfaces, learned by gethostname).
+ Now we can provide more helpful log messages when a relay guesses
+ its IP address incorrectly (e.g. due to unexpected lines in
+ /etc/hosts). Resolves ticket 2267.
+
diff --git a/changes/ticket5749 b/changes/ticket5749
deleted file mode 100644
index 023724198..000000000
--- a/changes/ticket5749
+++ /dev/null
@@ -1,3 +0,0 @@
- o New directory authorities:
- - Add Faravahar (run by Sina Rabbani) as the ninth v3 directory
- authority. Closes ticket 5749.
diff --git a/changes/ticket8240 b/changes/ticket8240
new file mode 100644
index 000000000..91e6f8c14
--- /dev/null
+++ b/changes/ticket8240
@@ -0,0 +1,4 @@
+ o Major security fixes:
+ - Make the default guard lifetime controllable via a new
+ GuardLifetime torrc option and a GuardLifetime consensus
+ parameter. Start of a fix for bug 8240; bugfix on 0.1.1.11-alpha.
diff --git a/changes/ticket8443 b/changes/ticket8443
new file mode 100644
index 000000000..ca6fb2f47
--- /dev/null
+++ b/changes/ticket8443
@@ -0,0 +1,4 @@
+ o Minor features:
+ - Randomize the lifetime of our SSL link certificate, so censors can't
+ use the static value for filtering Tor flows. Resolves ticket 8443;
+ related to ticket 4014 which was included in 0.2.2.33.
diff --git a/changes/ticket9658 b/changes/ticket9658
new file mode 100644
index 000000000..a8db2efba
--- /dev/null
+++ b/changes/ticket9658
@@ -0,0 +1,4 @@
+ o Minor features:
+ - Track how many "TAP" and "NTor" circuit handshake requests we get,
+ and how many we complete, and log it every hour to help relay
+ operators follow trends in network load. Addresses ticket 9658.
diff --git a/changes/ticket9866 b/changes/ticket9866
new file mode 100644
index 000000000..6cbb1110d
--- /dev/null
+++ b/changes/ticket9866
@@ -0,0 +1,3 @@
+ o Documentation:
+ - Add anchors to the manpage so we can link to the documentation for
+ specific options. Resolves ticket 9866.
diff --git a/changes/v3_intro_len b/changes/v3_intro_len
new file mode 100644
index 000000000..fbe39bce3
--- /dev/null
+++ b/changes/v3_intro_len
@@ -0,0 +1,8 @@
+ o Major bugfixes:
+
+ - Fix an uninitialized read that could (in some cases) lead to a remote
+ crash while parsing INTRODUCE 1 cells. (This is, so far as we know,
+ unrelated to the recent news.) Fixes bug XXX; bugfix on
+ 0.2.4.1-alpha. Anybody running a hidden service on the experimental
+ 0.2.4.x branch should upgrade.
+
diff --git a/changes/warn-unsigned-time_t b/changes/warn-unsigned-time_t
new file mode 100644
index 000000000..5f0c36d09
--- /dev/null
+++ b/changes/warn-unsigned-time_t
@@ -0,0 +1,5 @@
+ o Build improvements:
+ - Warn if building on a platform with an unsigned time_t: there
+ are too many places where Tor currently assumes that time_t can
+ hold negative values. We'd like to fix them all, but probably
+ some will remain.
diff --git a/configure.in b/configure.ac
index 8aa90f641..6f40ac4ad 100644
--- a/configure.in
+++ b/configure.ac
@@ -1,11 +1,14 @@
dnl Copyright (c) 2001-2004, Roger Dingledine
dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
-dnl Copyright (c) 2007-2012, The Tor Project, Inc.
+dnl Copyright (c) 2007-2013, The Tor Project, Inc.
dnl See LICENSE for licensing information
-AC_INIT
-AM_INIT_AUTOMAKE(tor, 0.2.3.18-rc-dev)
-AM_CONFIG_HEADER(orconfig.h)
+AC_INIT([tor],[0.2.4.10-alpha-dev])
+AC_CONFIG_SRCDIR([src/or/main.c])
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AC_CONFIG_HEADERS([orconfig.h])
AC_CANONICAL_HOST
@@ -34,6 +37,8 @@ AC_ARG_ENABLE(static-zlib,
AS_HELP_STRING(--enable-static-zlib, Link against a static zlib library. Requires --with-zlib-dir))
AC_ARG_ENABLE(static-tor,
AS_HELP_STRING(--enable-static-tor, Create an entirely static Tor binary. Requires --with-openssl-dir and --with-libevent-dir and --with-zlib-dir))
+AC_ARG_ENABLE(curve25519,
+ AS_HELP_STRING(--disable-curve25519, Build Tor with no curve25519 elliptic-curve crypto support))
if test "$enable_static_tor" = "yes"; then
enable_static_libevent="yes";
@@ -301,6 +306,7 @@ AC_CHECK_FUNCS(
inet_aton \
ioctl \
issetugid \
+ llround \
localtime_r \
lround \
memmem \
@@ -315,20 +321,9 @@ AC_CHECK_FUNCS(
sysconf \
uname \
vasprintf \
+ _vscprintf
)
-using_custom_malloc=no
-if test x$enable_openbsd_malloc = xyes ; then
- AC_DEFINE(HAVE_MALLOC_GOOD_SIZE, 1, [Defined if we have the malloc_good_size function])
- using_custom_malloc=yes
-fi
-if test x$tcmalloc = xyes ; then
- using_custom_malloc=yes
-fi
-if test $using_custom_malloc = no ; then
- AC_CHECK_FUNCS(mallinfo malloc_good_size malloc_usable_size)
-fi
-
if test "$enable_threads" = "yes"; then
AC_CHECK_HEADERS(pthread.h)
AC_CHECK_FUNCS(pthread_create)
@@ -647,6 +642,118 @@ if test "$upnp" = "true"; then
fi
fi
+dnl ============================================================
+dnl We need an implementation of curve25519.
+
+dnl set these defaults.
+have_a_curve25519=no
+build_curve25519_donna=no
+build_curve25519_donna_c64=no
+use_curve25519_donna=no
+use_curve25519_nacl=no
+CURVE25519_LIBS=
+
+if test x$enable_curve25519 != xno; then
+
+ dnl The best choice is using curve25519-donna-c64, but that requires
+ dnl that we
+ AC_CACHE_CHECK([whether we can use curve25519-donna-c64],
+ tor_cv_can_use_curve25519_donna_c64,
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([dnl
+ #include <stdint.h>
+ typedef unsigned uint128_t __attribute__((mode(TI)));
+ int func(uint64_t a, uint64_t b) {
+ uint128_t c = ((uint128_t)a) * b;
+ int ok = ((uint64_t)(c>>96)) == 522859 &&
+ (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L &&
+ (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L &&
+ (((uint64_t)(c))&0xffffffffL) == 0;
+ return ok;
+ }
+ ], [dnl
+ int ok = func( ((uint64_t)2000000000) * 1000000000,
+ ((uint64_t)1234567890) << 24);
+ return !ok;
+ ])],
+ [tor_cv_can_use_curve25519_donna_c64=yes],
+ [tor_cv_can_use_curve25519_donna_c64=no],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([dnl
+ #include <stdint.h>
+ typedef unsigned uint128_t __attribute__((mode(TI)));
+ int func(uint64_t a, uint64_t b) {
+ uint128_t c = ((uint128_t)a) * b;
+ int ok = ((uint64_t)(c>>96)) == 522859 &&
+ (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L &&
+ (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L &&
+ (((uint64_t)(c))&0xffffffffL) == 0;
+ return ok;
+ }
+ ], [dnl
+ int ok = func( ((uint64_t)2000000000) * 1000000000,
+ ((uint64_t)1234567890) << 24);
+ return !ok;
+ ])],
+ [tor_cv_can_use_curve25519_donna_c64=cross],
+ [tor_cv_can_use_curve25519_donna_c64=no])])])
+
+ AC_CHECK_HEADERS([crypto_scalarmult_curve25519.h \
+ nacl/crypto_scalarmult_curve25519.h])
+
+ AC_CACHE_CHECK([for nacl compiled with a fast curve25519 implementation],
+ tor_cv_can_use_curve25519_nacl,
+ [tor_saved_LIBS="$LIBS"
+ LIBS="$LIBS -lnacl"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([dnl
+ #ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H
+ #include <crypto_scalarmult_curve25519.h>
+ #elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H)
+ #include <nacl/crypto_scalarmult_curve25519.h>
+ #endif
+ #ifdef crypto_scalarmult_curve25519_ref_BYTES
+ #error Hey, this is the reference implementation! That's not fast.
+ #endif
+ ], [
+ unsigned char *a, *b, *c; crypto_scalarmult_curve25519(a,b,c);
+ ])], [tor_cv_can_use_curve25519_nacl=yes],
+ [tor_cv_can_use_curve25519_nacl=no])
+ LIBS="$tor_saved_LIBS" ])
+
+ dnl Okay, now we need to figure out which one to actually use. Fall back
+ dnl to curve25519-donna.c
+
+ if test x$tor_cv_can_use_curve25519_donna_c64 != xno; then
+ build_curve25519_donna_c64=yes
+ use_curve25519_donna=yes
+ elif test x$tor_cv_can_use_curve25519_nacl = xyes; then
+ use_curve25519_nacl=yes
+ CURVE25519_LIBS=-lnacl
+ else
+ build_curve25519_donna=yes
+ use_curve25519_donna=yes
+ fi
+ have_a_curve25519=yes
+fi
+
+if test x$have_a_curve25519 = xyes; then
+ AC_DEFINE(CURVE25519_ENABLED, 1,
+ [Defined if we have a curve25519 implementation])
+fi
+if test x$use_curve25519_donna = xyes; then
+ AC_DEFINE(USE_CURVE25519_DONNA, 1,
+ [Defined if we should use an internal curve25519_donna{,_c64} implementation])
+fi
+if test x$use_curve25519_nacl = xyes; then
+ AC_DEFINE(USE_CURVE25519_NACL, 1,
+ [Defined if we should use a curve25519 from nacl])
+fi
+AM_CONDITIONAL(BUILD_CURVE25519_DONNA, test x$build_curve25519_donna = xyes)
+AM_CONDITIONAL(BUILD_CURVE25519_DONNA_C64, test x$build_curve25519_donna_c64 = xyes)
+AM_CONDITIONAL(CURVE25519_ENABLED, test x$have_a_curve25519 = xyes)
+AC_SUBST(CURVE25519_LIBS)
+
dnl Make sure to enable support for large off_t if available.
AC_SYS_LARGEFILE
@@ -703,14 +810,6 @@ AC_CHECK_HEADERS(
AC_CHECK_HEADERS(sys/param.h)
-TOR_CHECK_PROTOTYPE(malloc_good_size, HAVE_MALLOC_GOOD_SIZE_PROTOTYPE,
-[#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#endif
-#ifdef HAVE_MALLOC_MALLOC_H
-#include <malloc/malloc.h>
-#endif])
-
AC_CHECK_HEADERS(net/if.h, net_if_found=1, net_if_found=0,
[#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@@ -760,7 +859,7 @@ if test x$transparent = xtrue ; then
if test x$transparent_ok = x1 ; then
AC_DEFINE(USE_TRANSPARENT, 1, "Define to enable transparent proxy support")
case $host in
- *-*-openbsd*)
+ *-*-openbsd* | *-*-bitrig*)
AC_DEFINE(OPENBSD, 1, "Define to handle pf on OpenBSD properly") ;;
esac
else
@@ -801,6 +900,7 @@ AC_CHECK_SIZEOF(__int64)
AC_CHECK_SIZEOF(void *)
AC_CHECK_SIZEOF(time_t)
AC_CHECK_SIZEOF(size_t)
+AC_CHECK_SIZEOF(pid_t)
AC_CHECK_TYPES([uint, u_char, ssize_t])
@@ -866,8 +966,9 @@ AC_CHECK_TYPES([rlim_t], , ,
#endif
])
-AC_CACHE_CHECK([whether time_t is signed], tor_cv_time_t_signed, [
-AC_RUN_IFELSE([AC_LANG_SOURCE([
+AX_CHECK_SIGN([time_t],
+ [ AC_DEFINE(TIME_T_IS_SIGNED, 1, [Define if time_t is signed]) ],
+ [ : ], [
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
@@ -877,36 +978,30 @@ AC_RUN_IFELSE([AC_LANG_SOURCE([
#ifdef HAVE_TIME_H
#include <time.h>
#endif
-int main(int c, char**v) { if (((time_t)-1)<0) return 1; else return 0; }])],
- tor_cv_time_t_signed=no, tor_cv_time_t_signed=yes, tor_cv_time_t_signed=cross)
])
-if test "$tor_cv_time_t_signed" = cross; then
- AC_MSG_NOTICE([Cross compiling: assuming that time_t is signed.])
-fi
-
-if test "$tor_cv_time_t_signed" != no; then
- AC_DEFINE([TIME_T_IS_SIGNED], 1,
- [Define to 1 iff time_t is signed])
+if test "$ax_cv_decl_time_t_signed" = no; then
+ AC_MSG_WARN([You have an unsigned time_t; some things will probably break. Please tell the Tor developers about your interesting platform.])
fi
-AC_CACHE_CHECK([whether size_t is signed], tor_cv_size_t_signed, [
-AC_RUN_IFELSE([AC_LANG_SOURCE([
+AX_CHECK_SIGN([size_t],
+ [ tor_cv_size_t_signed=yes ],
+ [ tor_cv_size_t_signed=no ], [
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
-int main(int c, char**v) { if (((size_t)-1)<0) return 1; else return 0; }])],
- tor_cv_size_t_signed=no, tor_cv_size_t_signed=yes, tor_cv_size_t_signed=cross)
])
-if test "$tor_cv_size_t_signed" = cross; then
- AC_MSG_NOTICE([Cross compiling: assuming that size_t is not signed.])
-fi
-
-if test "$tor_cv_size_t_signed" = yes; then
+if test "$ax_cv_decl_size_t_signed" = yes; then
AC_MSG_ERROR([You have a signed size_t; that's grossly nonconformant.])
fi
+AX_CHECK_SIGN([enum always],
+ [ AC_DEFINE(ENUM_VALS_ARE_SIGNED, 1, [Define if enum is always signed]) ],
+ [ : ], [
+ enum always { AAA, BBB, CCC };
+])
+
AC_CHECK_SIZEOF(socklen_t, , [AC_INCLUDES_DEFAULT()
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
@@ -942,6 +1037,30 @@ if test "$tor_cv_null_is_zero" != no; then
[Define to 1 iff memset(0) sets pointers to NULL])
fi
+AC_CACHE_CHECK([whether memset(0) sets doubles to 0.0], tor_cv_dbl0_is_zero,
+[AC_RUN_IFELSE([AC_LANG_SOURCE(
+[[#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+int main () { double d1,d2; d1=0; memset(&d2,0,sizeof(d2));
+return memcmp(&d1,&d2,sizeof(d1))?1:0; }]])],
+ [tor_cv_dbl0_is_zero=yes],
+ [tor_cv_dbl0_is_zero=no],
+ [tor_cv_dbl0_is_zero=cross])])
+
+if test "$tor_cv_dbl0_is_zero" = cross ; then
+ # Cross-compiling; let's hope that the target isn't raving mad.
+ AC_MSG_NOTICE([Cross-compiling: we'll assume that 0.0 can be represented as a sequence of 0-valued bytes.])
+fi
+
+if test "$tor_cv_dbl0_is_zero" != no; then
+ AC_DEFINE([DOUBLE_0_REP_IS_ZERO_BYTES], 1,
+ [Define to 1 iff memset(0) sets doubles to 0.0])
+fi
+
# And what happens when we malloc zero?
AC_CACHE_CHECK([whether we can malloc(0) safely.], tor_cv_malloc_zero_works,
[AC_RUN_IFELSE([AC_LANG_SOURCE(
@@ -1032,6 +1151,17 @@ if test x$tcmalloc = xyes ; then
LDFLAGS="-ltcmalloc $LDFLAGS"
fi
+using_custom_malloc=no
+if test x$enable_openbsd_malloc = xyes ; then
+ using_custom_malloc=yes
+fi
+if test x$tcmalloc = xyes ; then
+ using_custom_malloc=yes
+fi
+if test $using_custom_malloc = no ; then
+ AC_CHECK_FUNCS(mallinfo)
+fi
+
# By default, we're going to assume we don't have mlockall()
# bionic and other platforms have various broken mlockall subsystems.
# Some systems don't have a working mlockall, some aren't linkable,
@@ -1258,7 +1388,7 @@ if test x$enable_gcc_warnings = xyes || test x$enable_gcc_warnings_advisory = xy
CFLAGS="$save_CFLAGS"
case $host in
- *-*-openbsd*)
+ *-*-openbsd* | *-*-bitrig*)
# Some OpenBSD versions (like 4.8) have -Wsystem-headers by default.
# That's fine, except that the headers don't pass -Wredundant-decls.
# Therefore, let's disable -Wsystem-headers when we're building
@@ -1317,24 +1447,12 @@ CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_z
AC_CONFIG_FILES([
Doxyfile
Makefile
- contrib/Makefile
- contrib/suse/Makefile
contrib/suse/tor.sh
contrib/tor.logrotate
contrib/tor.sh
contrib/torctl
contrib/torify
- doc/Makefile
- src/Makefile
- src/common/Makefile
- src/config/Makefile
src/config/torrc.sample
- src/or/Makefile
- src/test/Makefile
- src/tools/Makefile
- src/tools/tor-fw-helper/Makefile
- src/win32/Makefile
- tor.spec
])
AC_OUTPUT
@@ -1342,4 +1460,3 @@ AC_OUTPUT
if test -x /usr/bin/perl && test -x ./contrib/updateVersions.pl ; then
./contrib/updateVersions.pl
fi
-
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
deleted file mode 100644
index 795c351f3..000000000
--- a/contrib/Makefile.am
+++ /dev/null
@@ -1,23 +0,0 @@
-SUBDIRS = suse
-DIST_SUBDIRS = suse
-
-confdir = $(sysconfdir)/tor
-
-EXTRA_DIST = \
- cross.sh \
- exitlist \
- linux-tor-prio.sh \
- package_nsis-mingw.sh \
- rc.subr \
- tor-ctrl.sh \
- tor-exit-notice.html \
- tor-mingw.nsi.in \
- tor-tsocks.conf \
- tor.ico \
- tor.nsi.in \
- tor.sh \
- torctl
-
-conf_DATA = tor-tsocks.conf
-
-bin_SCRIPTS = torify
diff --git a/contrib/findMergedChanges.pl b/contrib/findMergedChanges.pl
index 46e070f94..e4ff6163e 100755
--- a/contrib/findMergedChanges.pl
+++ b/contrib/findMergedChanges.pl
@@ -19,7 +19,7 @@ my $look_for_type = "merged";
if (! @ARGV) {
print <<EOF
Usage:
- findMergedChanges.pl [--merged/--unmerged/--weird/--list] changes/*
+ findMergedChanges.pl [--merged/--unmerged/--weird/--list] [--branch=<branchname] changes/*
A change is "merged" if it has ever been merged to release-0.2.2 and it has had
no subsequent changes in master.
diff --git a/contrib/include.am b/contrib/include.am
new file mode 100644
index 000000000..6d7fb16f9
--- /dev/null
+++ b/contrib/include.am
@@ -0,0 +1,17 @@
+include contrib/suse/include.am
+
+EXTRA_DIST+= \
+ contrib/cross.sh \
+ contrib/exitlist \
+ contrib/linux-tor-prio.sh \
+ contrib/package_nsis-mingw.sh \
+ contrib/rc.subr \
+ contrib/tor-ctrl.sh \
+ contrib/tor-exit-notice.html \
+ contrib/tor-mingw.nsi.in \
+ contrib/tor.ico \
+ contrib/tor.nsi.in \
+ contrib/tor.sh \
+ contrib/torctl
+
+bin_SCRIPTS+= contrib/torify
diff --git a/contrib/polipo/polipo-mingw.nsi b/contrib/polipo/polipo-mingw.nsi
index 624e825eb..f119675eb 100644
--- a/contrib/polipo/polipo-mingw.nsi
+++ b/contrib/polipo/polipo-mingw.nsi
@@ -165,7 +165,7 @@ SectionEnd
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${Polipo} "The core executable and config files needed for Polipo to run."
!insertmacro MUI_DESCRIPTION_TEXT ${ShortCuts} "Shortcuts to easily start Polipo"
- !insertmacro MUI_DESCRIPTION_TEXT ${StartMenu} "Shortcuts to access Polipo and it's documentation from the Start Menu"
+ !insertmacro MUI_DESCRIPTION_TEXT ${StartMenu} "Shortcuts to access Polipo and its documentation from the Start Menu"
!insertmacro MUI_DESCRIPTION_TEXT ${Desktop} "A shortcut to start Polipo from the desktop"
!insertmacro MUI_DESCRIPTION_TEXT ${Startup} "Launches Polipo automatically at startup in a minimized window"
!insertmacro MUI_FUNCTION_DESCRIPTION_END
diff --git a/contrib/redox.py b/contrib/redox.py
index 43200dd07..e9914dab1 100755
--- a/contrib/redox.py
+++ b/contrib/redox.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Copyright (c) 2008-2012 The Tor Project, Inc.
+# Copyright (c) 2008-2013, The Tor Project, Inc.
# See LICENSE for licensing information.
#
# Hi!
diff --git a/contrib/suse/Makefile.am b/contrib/suse/Makefile.am
deleted file mode 100644
index 06511c042..000000000
--- a/contrib/suse/Makefile.am
+++ /dev/null
@@ -1,3 +0,0 @@
-confdir = $(sysconfdir)/tor
-
-EXTRA_DIST = tor.sh
diff --git a/contrib/suse/include.am b/contrib/suse/include.am
new file mode 100644
index 000000000..4aed0e123
--- /dev/null
+++ b/contrib/suse/include.am
@@ -0,0 +1 @@
+EXTRA_DIST+= contrib/suse/tor.sh
diff --git a/contrib/tor-mingw.nsi.in b/contrib/tor-mingw.nsi.in
index 2133a471b..d5379bd57 100644
--- a/contrib/tor-mingw.nsi.in
+++ b/contrib/tor-mingw.nsi.in
@@ -8,7 +8,7 @@
!include "LogicLib.nsh"
!include "FileFunc.nsh"
!insertmacro GetParameters
-!define VERSION "0.2.3.18-rc-dev"
+!define VERSION "0.2.4.10-alpha-dev"
!define INSTALLER "tor-${VERSION}-win32.exe"
!define WEBSITE "https://www.torproject.org/"
!define LICENSE "LICENSE"
@@ -147,7 +147,7 @@ SectionEnd
!insertmacro MUI_DESCRIPTION_TEXT ${Tor} "The core executable and config files needed for Tor to run."
!insertmacro MUI_DESCRIPTION_TEXT ${Docs} "Documentation about Tor."
!insertmacro MUI_DESCRIPTION_TEXT ${ShortCuts} "Shortcuts to easily start Tor"
-!insertmacro MUI_DESCRIPTION_TEXT ${StartMenu} "Shortcuts to access Tor and it's documentation from the Start Menu"
+!insertmacro MUI_DESCRIPTION_TEXT ${StartMenu} "Shortcuts to access Tor and its documentation from the Start Menu"
!insertmacro MUI_DESCRIPTION_TEXT ${Desktop} "A shortcut to start Tor from the desktop"
!insertmacro MUI_DESCRIPTION_TEXT ${Startup} "Launches Tor automatically at startup in a minimized window"
!insertmacro MUI_FUNCTION_DESCRIPTION_END
diff --git a/contrib/tor-tsocks.conf b/contrib/tor-tsocks.conf
deleted file mode 100644
index 3dddaddbc..000000000
--- a/contrib/tor-tsocks.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-# This is the configuration for libtsocks (transparent socks) for use
-# with tor, which is providing a socks server on port 9050 by default.
-#
-# See tsocks.conf(5) and torify(1) manpages.
-
-server = 127.0.0.1
-server_port = 9050
-
-# We specify local as 127.0.0.0 - 127.191.255.255 because the
-# Tor MAPADDRESS virtual IP range is the rest of net 127.
-local = 127.0.0.0/255.128.0.0
-local = 127.128.0.0/255.192.0.0
-
diff --git a/contrib/tor.nsi.in b/contrib/tor.nsi.in
index a7ed914b8..dd24df454 100644
--- a/contrib/tor.nsi.in
+++ b/contrib/tor.nsi.in
@@ -207,7 +207,7 @@ SectionEnd
!insertmacro MUI_DESCRIPTION_TEXT ${OpenSSL} "OpenSSL libraries required by Tor."
!insertmacro MUI_DESCRIPTION_TEXT ${Docs} "Documentation about Tor."
!insertmacro MUI_DESCRIPTION_TEXT ${ShortCuts} "Shortcuts to easily start Tor"
- !insertmacro MUI_DESCRIPTION_TEXT ${StartMenu} "Shortcuts to access Tor and it's documentation from the Start Menu"
+ !insertmacro MUI_DESCRIPTION_TEXT ${StartMenu} "Shortcuts to access Tor and its documentation from the Start Menu"
!insertmacro MUI_DESCRIPTION_TEXT ${Desktop} "A shortcut to start Tor from the desktop"
!insertmacro MUI_DESCRIPTION_TEXT ${Startup} "Launches Tor automatically at startup in a minimized window"
!insertmacro MUI_FUNCTION_DESCRIPTION_END
diff --git a/contrib/updateVersions.pl b/contrib/updateVersions.pl
index 76b6fe567..9dae1ff95 100755
--- a/contrib/updateVersions.pl
+++ b/contrib/updateVersions.pl
@@ -1,9 +1,11 @@
#!/usr/bin/perl -w
-$CONFIGURE_IN = './configure.in';
+$CONFIGURE_IN = './configure.ac';
$ORCONFIG_H = './src/win32/orconfig.h';
$TOR_NSI = './contrib/tor-mingw.nsi.in';
+$quiet = 1;
+
sub demand {
my $fn = shift;
die "Missing file $fn" unless (-f $fn);
@@ -13,18 +15,18 @@ demand($CONFIGURE_IN);
demand($ORCONFIG_H);
demand($TOR_NSI);
-# extract version from configure.in
+# extract version from configure.ac
open(F, $CONFIGURE_IN) or die "$!";
$version = undef;
while (<F>) {
- if (/AM_INIT_AUTOMAKE\(tor,\s*([^\)]*)\)/) {
+ if (/AC_INIT\(\[tor\],\s*\[([^\]]*)\]\)/) {
$version = $1;
last;
}
}
die "No version found" unless $version;
-print "Tor version is $version\n";
+print "Tor version is $version\n" unless $quiet;
close F;
sub correctversion {
@@ -36,7 +38,7 @@ sub correctversion {
if ($s =~ /^$defchar(?:)define\s+VERSION\s+\"([^\"]+)\"/m) {
$oldver = $1;
if ($oldver ne $version) {
- print "Version mismatch in $fn: It thinks that the version is $oldver. Fixing.\n";
+ print "Version mismatch in $fn: It thinks that the version is $oldver. I think it's $version. Fixing.\n";
$line = $defchar . "define VERSION \"$version\"";
open(F, ">$fn.bak");
print F $s;
@@ -44,9 +46,9 @@ sub correctversion {
$s =~ s/^$defchar(?:)define\s+VERSION.*?$/$line/m;
open(F, ">$fn");
print F $s;
- close F;
+ close F;
} else {
- print "$fn has the correct version. Good.\n";
+ print "$fn has the correct version. Good.\n" unless $quiet;
}
} else {
print "Didn't find a version line in $fn -- uh oh.\n";
diff --git a/doc/HACKING b/doc/HACKING
index bc409dc0d..b7cd8952d 100644
--- a/doc/HACKING
+++ b/doc/HACKING
@@ -12,7 +12,7 @@ https://gitweb.torproject.org/torspec.git/blob_plain/HEAD:/proposals/001-process
For the latest version of the code, get a copy of git, and
- git clone git://git.torproject.org/git/tor .
+ git clone https://git.torproject.org/git/tor
We talk about Tor on the tor-talk mailing list. Design proposals and
discussion belong on the tor-dev mailing list. We hang around on
@@ -38,9 +38,9 @@ release. Occasionally, we'll merge an urgent bugfix into the release branch
before it gets merged into maint, but that's rare.
If you're working on a bugfix for a bug that occurs in a particular version,
-base your bugfix branch on the "maint" branch for the first _actively
-developed_ series that has that bug. (Right now, that's 0.2.1.) If you're
-working on a new feature, base it on the master branch.
+base your bugfix branch on the "maint" branch for the first supported series
+that has that bug. (As of June 2013, we're supporting 0.2.3 and later.) If
+you're working on a new feature, base it on the master branch.
How we log changes
@@ -51,7 +51,7 @@ the "changes" toplevel subdirectory. It should have the format of a
one-entry changelog section from the current ChangeLog file, as in
o Major bugfixes:
- - Fix a potential buffer overflow. Fixes bug 9999; bugfix on
+ - Fix a potential buffer overflow. Fixes bug 99999; bugfix on
0.3.1.4-beta.
To write a changes file, first categorize the change. Some common categories
@@ -90,10 +90,10 @@ Useful tools
These aren't strictly necessary for hacking on Tor, but they can help track
down bugs.
-The buildbot
-~~~~~~~~~~~~
+Jenkins
+~~~~~~~
-https://buildbot.vidalia-project.net/one_line_per_build
+http://jenkins.torproject.org
Dmalloc
~~~~~~~
@@ -121,7 +121,8 @@ Running gcov for unit test coverage
make clean
make CFLAGS='-g -fprofile-arcs -ftest-coverage'
./src/test/test
- cd src/common; gcov *.[ch]
+ gcov -o src/common src/common/*.[ch]
+ gcov -o src/or src/or/*.[ch]
cd ../or; gcov *.[ch]
-----
@@ -130,6 +131,13 @@ compiler generated no code for that line. '######' means that the
line was never reached. Lines with numbers were called that number
of times.
+If that doesn't work:
+ * Try configuring Tor with --disable-gcc-hardening
+ * On recent OSX versions, you might need to add CC=clang to your
+ build line, as in:
+ make CFLAGS='-g -fprofile-arcs -ftest-coverage' CC=clang
+ Their llvm-gcc doesn't work so great for me.
+
Profiling Tor with oprofile
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -174,6 +182,8 @@ Did you remember...
- To build your code while configured with --enable-gcc-warnings?
- To run "make check-spaces" on your code?
+ - To run "make check-docs" to see whether all new options are on
+ the manpage?
- To write unit tests, as possible?
- To base your code on the appropriate branch?
- To include a file in the "changes" directory as appropriate?
@@ -304,7 +314,7 @@ do your own profiling to determine otherwise.
Log conventions
~~~~~~~~~~~~~~~
-https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ#LogLevels
+https://trac.torproject.org/projects/tor/wiki/doc/TorFAQ#loglevel
No error or warning messages should be expected during normal OR or OP
operation.
@@ -467,7 +477,7 @@ a stable release, add it to the ReleaseNotes file too. If we're adding
to a release-0.2.x branch, manually commit the changelogs to the later
git branches too.
-4) Bump the version number in configure.in and rebuild.
+4) Bump the version number in configure.ac and rebuild.
5) Make dist, put the tarball up somewhere, and tell #tor about it. Wait
a while to see if anybody has problems building it. Try to get Sebastian
diff --git a/doc/Makefile.am b/doc/Makefile.am
deleted file mode 100644
index 6cdd66d51..000000000
--- a/doc/Makefile.am
+++ /dev/null
@@ -1,89 +0,0 @@
-# We use a two-step process to generate documentation from asciidoc files.
-#
-# First, we use asciidoc/a2x to process the asciidoc files into .1.in and
-# .html.in files (see the asciidoc-helper.sh script). These are the same as
-# the regular .1 and .html files, except that they still have some autoconf
-# variables set in them.
-#
-# Second, we use config.status to turn .1.in files into .1 files and
-# .html.in files into .html files.
-#
-# We do the steps in this order so that we can ship the .*.in files as
-# part of the source distribution, so that people without asciidoc can
-# just use the .1 and .html files.
-
-regular_mans = tor tor-gencert tor-resolve torify
-all_mans = $(regular_mans) tor-fw-helper
-
-if USE_ASCIIDOC
-if USE_FW_HELPER
-nodist_man_MANS = $(all_mans:=.1)
-doc_DATA = $(all_mans:=.html)
-else
-nodist_man_MANS = $(regular_mans:=.1)
-doc_DATA = $(regular_mans:=.html)
-endif
-html_in = $(all_mans:=.html.in)
-man_in = $(all_mans:=.1.in)
-txt_in = $(all_mans:=.1.txt)
-else
-html_in =
-man_in =
-txt_in =
-nodist_man_MANS =
-doc_DATA =
-endif
-
-EXTRA_DIST = HACKING asciidoc-helper.sh \
- $(html_in) $(man_in) $(txt_in) \
- tor-rpm-creation.txt \
- tor-win32-mingw-creation.txt spec/README \
- state-contents.txt
-
-docdir = @docdir@
-
-asciidoc_product = $(nodist_man_MANS) $(doc_DATA)
-
-# Generate the html documentation from asciidoc, but don't do
-# machine-specific replacements yet
-$(html_in) :
- $(top_srcdir)/doc/asciidoc-helper.sh html @ASCIIDOC@ $(top_srcdir)/doc/$@
-
-tor.html.in : tor.1.txt
-torify.html.in : torify.1.txt
-tor-gencert.html.in : tor-gencert.1.txt
-tor-resolve.html.in : tor-resolve.1.txt
-tor-fw-helper.html.in : tor-fw-helper.1.txt
-
-# Generate the manpage from asciidoc, but don't do
-# machine-specific replacements yet
-$(man_in) :
- $(top_srcdir)/doc/asciidoc-helper.sh man @A2X@ $(top_srcdir)/doc/$@
-
-tor.1.in : tor.1.txt
-torify.1.in : torify.1.txt
-tor-gencert.1.in : tor-gencert.1.txt
-tor-resolve.1.in : tor-resolve.1.txt
-tor-fw-helper.1.in : tor-fw-helper.1.txt
-
-# use ../config.status to swap all machine-specific magic strings
-# in the asciidoc with their replacements.
-$(asciidoc_product) :
- if test -e $(top_srcdir)/doc/$@.in && ! test -e ./$@.in ; then \
- cp $(top_srcdir)/doc/$@.in .; \
- fi
- ../config.status --file=$@;
-
-tor.1 : tor.1.in
-torify.1 : torify.1.in
-tor-gencert.1 : tor-gencert.1.in
-tor-resolve.1 : tor-resolve.1.in
-tor-fw-helper.1 : tor-fw-helper.1.in
-tor.html : tor.html.in
-torify.html : torify.html.in
-tor-gencert.html : tor-gencert.html.in
-tor-resolve.html : tor-resolve.html.in
-tor-fw-helper.html : tor-fw-helper.html.in
-
-CLEANFILES = $(asciidoc_product) config.log
-DISTCLEANFILES = $(html_in) $(man_in)
diff --git a/doc/TODO b/doc/TODO
deleted file mode 100644
index 194d6507b..000000000
--- a/doc/TODO
+++ /dev/null
@@ -1,11 +0,0 @@
-
-We've split out our TODO into three files:
-
-TODO.02x is the list of items we're planning to get done in the next
-stable release.
-
-TODO.external lives in svn under /projects/todo/. It's the list of
-external constraints and deliverables that we all need to keep in mind.
-
-TODO.future is the list of other items we plan to get to in later releases.
-
diff --git a/doc/TODO.021 b/doc/TODO.021
deleted file mode 100644
index 37c5b9845..000000000
--- a/doc/TODO.021
+++ /dev/null
@@ -1,386 +0,0 @@
-Legend:
-SPEC!! - Not specified
-SPEC - Spec not finalized
-N - nick claims
-R - arma claims
-P - phobos claims
-S - Steven claims
-E - Matt claims
-M - Mike claims
-J - Jeff claims
-I - ioerror claims
-W - weasel claims
-K - Karsten claims
- - Not done
- * Top priority
- . Partially done
- o Done
- d Deferrable
- D Deferred
- X Abandoned
-
-=======================================================================
-
-Things Roger would be excited to see:
-
-Nick
- * Look at Roger's proposal 141 discussions on or-dev, and help us
- decide how to proceed.
- . Tors start believing the contents of NETINFO cells.
- - respond to Steven's red-team TLS testing (a.k.a, look at a packet
- dump and compare)
-
-Matt
- - Fit Vidalia in 640x480 again.
- - Vidalia should avoid stomping on your custom exit policy lines
- just because you click on 'save' for a totally different config thing.
- - How much space do we save in TBB by stripping symbols from Vidalia
- first? Good idea or crazy idea?
- (phobos adds you save about 12MB total across all exes by stripping
- them) In fact, tbb-1.19 is stripped exes.
-
-ioerror
- * weather.torproject.org should go live.
- - Keep advocating new Tor servers and working with orgs like Mozilla
- to let them like Tor.
- - Find out what happened to the buildbot and get it back up:
- http://tor-buildbot.freehaven.net:8010/
- - Learn about locking memory pages that have sensitive content. Get
- that started in Tor.
- - Translation portal
- - Vidalia html help files
- - should we i18nize polipo's error messages too?
- - how to get our diagrams translated, and how to get our screenshots
- from the right language?
- - Some of our translated wml files are very old -- so old that they
- are harmful to leave in place. We need some sort of way to notice
- this and disable them.
-
-Steven
- - Move proposal 131 or equivalent forward.
- - Keep bugging us about exploits on the .exit notation.
- - Mike's question #3 on https://www.torproject.org/volunteer#Research
- - Worthwhile shipping TBB with some local html help files that come
- as bookmarks?
-
-Andrew
-
-Weasel
- - Figure out how to make Vidalia and Tor play nicely on Debian, make
- the necessary modifications, and make some Vidalia debs that pass
- muster.
- - Fix bug 393.
- - Get oftc to switch to Tor dns bulk exitlist. Or tell us why it's
- not suitable yet.
- - Move proposal 134 forward.
- - putting port predictions in state file
- - if tor hasn't been used in a while it stops fetching consensus
- documents. Retain that state over restarts.
-
-Roger
- - Finish tor-doc-bridge.wml
- . Fix FAQ entry on setting up private Tor network
- - Did we actually apply Steven's dkimproxy patch?
- - Brainstorm about safe but effective ways for vidalia to
- auto-update its user's bridges via Tor in the background.
- - it doesn't count as successfully opening a circuit if it's not
- an exit circuit.
-
-Mike:
- - Roger wants to get an email every time there's a blog change,
- e.g. a comment. That way spam doesn't go undetected for weeks.
- - Or, maybe just disable linking from blog comments entirely?
- (phobos mitigates this by checking it a few times a week)
-
-=======================================================================
-
-Bugs/issues for Tor 0.2.0.x:
- . we should have an off-by-default way for relays to dump geoip data to
- a file in their data directory, for measurement purposes.
- o Basic implementation
-N - Include probability-of-selection
-R d let bridges set relaybandwidthrate as low as 5kb
-
-Documentation for Tor 0.2.0.x:
- o Proposals:
- o 111: Prioritize local traffic over relayed.
- o 113: mark as closed close.
- o document the "3/4 and 7/8" business in the clients fetching consensus
- documents timeline.
-R - then document the bridge user download timeline.
- - HOWTO for DNSPort. See tup's wiki page.
- . Document transport and natdport in a good HOWTO.
- - Quietly document NT Service options: revise (or create) FAQ entry
-
-=======================================================================
-
-For 0.2.1.x-alpha:
-R d bug: if we launch using bridges, and then stop using bridges, we
- still have our bridges in our entryguards section, and may use them.
- o add an event to report geoip summaries to vidalia for bridge relays,
- so vidalia can say "recent activity (1-8 users) from sa".
-R - investigate: it looks like if the bridge authority is unreachable,
- we're not falling back on querying bridges directly?
- o if "no running bridges known", an application request should make
- us retry all our bridges.
-
-For 0.2.1.x:
- - Proposals to do:
- o 110: avoid infinite-length circuits
- * Figure out the right value for max RELAY_EARLY cells (Bug 878)
- - 117: IPv6 Exits
- - Internal code support for ipv6:
- o Clone ipv6 functions (inet_ntop, inet_pton) where they don't exist.
- o Many address variables need to become tor_addr_t
- o addr in connection_t
- o n_addr in extend_info_t
- - Teach resolving code how to handle ipv6.
- . Teach exit policies about ipv6 (consider ipv4/ipv6 interaction!)
- o Use IPv6 in connect/connected/failed-exitpolicy cells
- o accept ipv6 from socks
- o Generate END_REASON_EXITPOLICY cells right
- . ... and parse them right
- . Generate new BEGIN cell types and parse them right
- - Detect availability of ipv6
- - Advertise availability of ipv6.
- - Geoip support, if only to add a zone called "ipv6"
-
-K . 121: Hidden service authentication:
- - missing: delayed descriptor publication for 'stealth' mode.
- o 128: families of private bridges
- o 135: simplify configuration of private tor networks.
-K - 143: Improvements of Distributed Hidden Service Descriptor Storage:
- only easy parts for 0.2.1.x, defer complex ones to 0.2.2.x.
- o 148: Stream end reasons from the client side should be uniform.
-K o 155: Four Improvements of Hidden Service Performance
- - 145: Separate "suitable from a guard" from "suitable as a new guard"
- - 146: Adding new flag to reflect long-term stability
- - 149: Using data from NETINFO cells
- o Don't extend a circuit over a noncanonical connection with
- mismatched address.
- o Apply rovv's bugfixes wrt preferring canonical connections.
- o Make sure that having a non-canonical connection doesn't count
- as _having_ a connection for the purpose of connecting to others,
- and that when no canonical connection exists, we make one.
- - Learn our outgoing IP address from netinfo cells?
- - Learn skew from netinfo cells?
- o 157: Make certificate downloads specific.
-
- - Proposals to write:
- - Fix voting to handle bug 608 case when multiple servers get
- Named.
-N . Draft proposal for GeoIP aggregation (see external constraints *)
- . Figure out how to make good use of the fallback consensus file. Right
- now many of the addresses in the fallback consensus will be stale,
- so it will take dozens of minutes to bootstrap from it. This is a
- bad first Tor experience. But if we check the fallback consensus
- file *after* we fail to connect to any authorities, then it may
- still be valuable as a blocking-resistance step.
- o Write the proposal.
- - Patch our tor.spec rpm package so it knows where to put the fallback
- consensus file.
- . Put bandwidth weights in the networkstatus? So clients get weight
- their choices even before they have the descriptors; and so
- authorities can put in more accurate numbers in the future.
-
- - Spec compliance:
- * Make sure that clients could do the new handshake without sending any
- certs, if they wanted.
-
- - Tiny designs to write:
- - If a relay publishes a new descriptor with a significantly lower
- uptime or with a new IP address, then we should consider its current
- "running" interval to have ended even if it hadn't yet failed its
- third reachability test. the interval ended when the new descriptor
- appeared, and a new interval began then too.
-
- - Authority improvements:
-R - authorities should initiate a reachability test upon first
- glimpsing a new descriptor.
-
- - Use less bandwidth
- - Use if-modified-since to download consensuses
-
- - Testing
- - Better unit test coverage
- - Verify that write limits to linked connections work.
-
- - Security improvements
- - make is-consensus-fresh-enough check tighter.
- - If we haven't tried downloading a consensus for ages since we're tired,
- try getting a new one before we use old descriptors for a circuit.
- Related to bug 401. [What does "since we're tired" mean? -RD]
- [I don't know. -NM]
-
- - Feature removals and deprecations:
- - Get rid of the v1 directory stuff (making, serving, and caching)
- . First verify that the caches won't flip out?
- o If they will, just stop the caches from caching for now
- . perhaps replace it with a "this is a tor server" stock webpage.
- - Get the debs to set DirPortFrontPage in the default.
- - Decide how to handle DirPortFrontPage files with image links.
- - Can we deprecate controllers that don't use both features?
- - Both TorK and Vidalia use VERBOSE_NAMES.
- - TorK uses EXTENDED_EVENTS. Vidalia does not. (As of 9 Dec.)
- - Matt is checking whether Vidalia would break if we started to use
- EXTENDED_EVENTS by default. He says no.
-
-External tool improvements:
- - Get IOCP patches into libevent
-
-Nice to have for 0.2.1.x:
- - Proposals, time permitting
- - 134: handle authority fragmentation.
- - 140: Provide diffs betweeen consensuses
-
- - Handle multi-core cpus better
- - Split circuit AES across cores
- - Split cell_queue_t into a new structure with a processed subqueue,
- an unprocessed subqueue, and a symmetric key.
- - Write a function to pull cells from the unprocessed subqueue,
- en/decrypt them, and place them on the processed subqueue.
- - When a cell is added to a queue that previously had no
- unprocessed cells, put that queue into a set of queues that
- need to be processed. When the last cell is processed in a
- queue, remove it from the set of queues that need to be
- processed.
- - Worker code to process queues in round-robin fashion.
- - Think about how to be fair to differet circuits _and_ about to get
- CPU-affinity, if that matters.
- - When a cell is processed and placed onto a processed subqueue
- that was previously empty, _and_ the or_conn output buffer
- that the queue is targetting is empty, stick the buffer onto a
- list of buffers that need attention and notify the main
- thread if it was not already on the list.
- - When the main thread gets notified, it pumps those buffers.
- (i.e., it puts cells onto them from some of their circuits).
- - To free a queue that is not currently processing, grab its lock
- and free it.
- - To free a queue that _is_ processing, .... ?
-
- - Documentation
-P - Make documentation realize that location of system configuration file
- will depend on location of system defaults, and isn't always /etc/torrc.
-
- - Small controller features
- - A status event for when tor decides to stop fetching directory info
- if the client hasn't clicked recently: then make the onion change too.
- o Add a status event when new consensus arrives
-
- - Windows build
-P - create a "make win32-bundle" for vidalia-privoxy-tor-torbutton bundle
- - Is this obsolete with msi bundle coming soon asks phobos
-
- - Refactor bad code:
- - connection_or_get_by_identity_digest() and connection_good_enough_for
- _extend() could be merged into a smarter variant, perhaps.
- - Refactor the HTTP logic so the functions aren't so large.
- - Refactor buf_read and buf_write to have sensible ways to return
- error codes after partial writes
- - deprecate router_digest_is_trusted_dir() in favor of
- router_get_trusteddirserver_by_digest()
-
- - Should be trivial
- - Tor logs the libevent version on startup, for debugging purposes.
- This is great. But it does this before configuring the logs, so
- it only goes to stdout and is then lost.
- (phobos asks, is this still the case? because it shows up in my
- logs)
-
- - Deprecations
- - Even clients run rep_hist_load_mtbf_data(). This doesn't waste memory
- unless they had previously been non-clients collecting MTBF data.
- Dump it anyway?
- - Unless we start using ftime functions, dump them.
- - can we deprecate the FastFirstHopPK config option?
- - The v2dir flag isn't used for anything anymore, right? If so, dump it.
- - can we deprecate 'getinfo network-status'?
- - Dump most uint32_t addr functions.
-
- - do the part of the "abandon .exit" proposal that involves isolating
- circuits which have used a .exit stream from those that haven't
-
-Defer:
- - Proposals
- - 118: Listen on and advertise multiple ports:
- - Tor should be able to have a pool of outgoing IP addresses that it is
- able to rotate through. (maybe. Possible overlap with proposal 118.)
- - config option to publish what ports you listen on, beyond
- ORPort/DirPort. It should support ranges and bit prefixes (?) too.
- - Need to figure out the right format for routerinfo_t on this.
- - 147: Eliminate the need for v2 directories in generating v3 directories
-
- - Proposals to write.
- d Something for bug 469, to limit connections per IP.
- d Do we want to maintain our own set of entryguards that we use as
- next hop after the bridge?
- d Possibly: revise link protocol to allow big circuit IDs,
- variable-length cells, proposal-110 stuff, and versioned CREATES?
- d Fetch an updated geoip file from the directory authorities.
-R - bridge communities (revive proposal 128)
- . spec
- . deploy
- - man page entries for Alternate*Authority config options
-
- - Tiny designs to write
- - Better estimate of clock skew; has anonymity implications. Clients
- should estimate their skew as median of skew from servers over last
- N seconds, but for servers this is not so easy, since a server does
- not choose who it connects to.
- - Do TLS connection rotation more often than "once a week" in the
- extra-stable case.
- (One reason not to do it more often is because the old TLS conn
- probably has a circuit on it, and we don't really want to build up
- dozens of TCP connections to all the other extra-stable relays.)
-
-
- - Use less RAM
- - Optimize cell pool allocation.
- - Support (or just always use) jemalloc (if it helps)
- - mmap more files.
- - Pull serverdescs off buffers as they arrive.
- - Allocate routerstatus_t objects on a per-networkstatus memchunk.
-
- - Split TLS across multiple cores
-
- - "In the future, we should migrate to LOCAL_APPDATA entirely."
-
- - Use more mid-level and high-level libevent APIs
- - For dns?
- - For http?
- - For buffers?
-
- - Proposals to write
- - steven's plan for replacing check.torproject.org with a built-in
- answer by tor itself.
-
- - Refactor bad code:
- - Streamline how we pick entry nodes: Make choose_random_entry() have
- less magic and less control logic.
- - Move all status info out of routerinfo into local_routerstatus. Make
- "who can change what" in local_routerstatus explicit. Make
- local_routerstatus (or equivalent) subsume all places to go for "what
- router is this?"
- o Don't call time(NULL) so much; instead have a static time_t field
- that gets updated only a handful of times per second.
- - Refactor unit tests into multiple files
-
- - Make Tor able to chroot itself
- o allow it to load an entire config file from control interface
- - document LOADCONF
- - log rotation (and FD passing) via control interface
- - chroot yourself, including inhibit trying to read config file
- and reopen logs, unless they are under datadir.
-
- - Should be trivial:
- - Base relative control socket paths (and other stuff in torrc) on datadir.
- o enforce a lower limit on MaxCircuitDirtiness and CircuitBuildTimeout.
- - Make 'safelogging' extend to info-level logs too.
- - don't do dns hijacking tests if we're reject *:* exit policy?
- (deferred until 0.1.1.x is less common)
- - More consistent error checking in router_parse_entry_from_string().
- I can say "banana" as my bandwidthcapacity, and it won't even squeak.
-
- d Interface for letting SOAT modify flags that authorities assign.
- (How to keep the authority from clobbering them afterwards?
-
diff --git a/doc/TODO.022 b/doc/TODO.022
deleted file mode 100644
index d83ed6e67..000000000
--- a/doc/TODO.022
+++ /dev/null
@@ -1,92 +0,0 @@
-Nick's initial priorities for Tor 0.2.2:
-
-NOTE 1: I'm not looking at fiddly little stuff from TODO.021 yet. We
- can do a step where we triage the nice-to-have issues.
-
-NOTE 2: It's easy to list stuff like this with no time estimates and
- no target dates. I think we should pick a target date for
- 0.2.2, figure out how long the stuff we want will take, and
- triage accordingly, or vice versa.
-
-- Performance, mostly protocol-neutral.
-
- o Revise how we do bandwidth limiting and round-robining between
- circuits on a connection.
-
- . Revise how we do bandwidth limiting and round-robining between
- connections.
-
- - Better flow-control to avoid filling buffers on routers.
-
- - Figure out good ways to instrument Tor internals so we can tell
- how well our bandwidth and flow-control stuff is actually working.
- - What ports eat the bandwidth?
- - How full do queues get?
- - How much latency do queues get?
-
- - Rate limit at clients:
- - Give clients an upper bound on how much they're willing to use
- the network if they're not relaying?
- - ... or group client circuits by IP at the server and rate-limit
- like that.
-
- - Use if-modified-since to download consensuses
-
-
-- Other features
- - Proposals to implement:
- - 146: reflect long-term stability in consensuses
- - 147: Stop using v2 directories to generate v3 votes.
- - Start pinging as soon as we learn about a relay, not on a
- 22-minute cycle. Prioritize new and volatile relays for
- testing.
-
- - Proposals to improve and implement
- - 158: microdescriptors
- o Revise proposal
- - Implement
-
- - Proposals to improve and implement if not broken
- D IPv6 support. (Parts of 117, but figure out how to handle DNS
- requests.)
- - 140: Directory diffs
- - Need a decent simple C diff implementation.
- - Need a decent simple C ed patch implementation.
- - 149: learn info from netinfo cells.
- o Start discussion
- - Revise proposal based on discussion.
- X 134: handle authority fragmentation (Needs more analysis)
- - 165: Easy migration for voting authority sets
- - 163: Detect client-status better
- o Write proposal
- - Possibly implement, depending on discussion.
- - 164: Have authorities report relay and voting status better: make it
- easy to answer, "Why is my server not listed/not Guard/not
- Running/etc"
- o Write proposal
- - Possibly implement, depending on discussion
- - 162: Have consensuses come in multiple "flavours".
- o Write proposal
- - Possibly implement, depending on discussion.
-
- - Needs a proposal, or at least some design
- - Weaken the requirements for being a Guard, based on K's
- measurements.
-K - Finish measurements
-K? - Write proposal
- - Adaptive timeouts for giving up on circuits and streams.
-M - Revise proposal 151
- - Downweight guards more sensibly: be more forgiving about using
- Guard nodes as non-first-hop.
- - Write proposal.
- - Lagged weight updates in consensuses: don't just move abruptly.
-M? - Write proposal
- d Don't kill a circuit on the first failed extend.
-
-- Installers
- - Switch to MSI on win32
- - Use Thandy, perhaps?
-
-o Deprecations
- o Make .exit safe, or make it off-by-default.
-
diff --git a/doc/TODO.external b/doc/TODO.external
deleted file mode 100644
index 2e7e536ef..000000000
--- a/doc/TODO.external
+++ /dev/null
@@ -1,4 +0,0 @@
-
-[This file moved to svn in /projects/todo/. More people can edit
-it more easily there. -RD]
-
diff --git a/doc/TODO.future b/doc/TODO.future
deleted file mode 100644
index 85e07aa92..000000000
--- a/doc/TODO.future
+++ /dev/null
@@ -1,330 +0,0 @@
-Legend:
-SPEC!! - Not specified
-SPEC - Spec not finalized
-N - nick claims
-R - arma claims
-P - phobos claims
-S - Steven claims
-E - Matt claims
-M - Mike claims
-J - Jeff claims
-I - ioerror claims
-W - weasel claims
-K - Karsten claims
- - Not done
- * Top priority
- . Partially done
- o Done
- d Deferrable
- D Deferred
- X Abandoned
-
-=======================================================================
-
-Later, unless people want to implement them now:
- - Actually use SSL_shutdown to close our TLS connections.
- - Include "v" line in networkstatus getinfo values.
- [Nick: bridge authorities output a networkstatus that is missing
- version numbers. This is inconvenient if we want to make sure
- bridgedb gives out bridges with certain characteristics. -RD]
- [Okay. Is this a separate item, or is it the same issue as the lack of
- a "v" line in response to the controller GETINFO command? -NM]
- - MAYBE kill stalled circuits rather than stalled connections. This is
- possible thanks to cell queues, but we need to consider the anonymity
- implications.
- - Make resolves no longer use edge_connection_t unless they are actually
- _on_ a socks connection: have edge_connection_t and (say)
- dns_request_t both extend an edge_stream_t, and have p_streams and
- n_streams both be linked lists of edge_stream_t.
- - Generate torrc.{complete|sample}.in, tor.1.in, the HTML manual, and the
- online config documentation from a single source.
- - It would be potentially helpful to respond to https requests on
- the OR port by acting like an HTTPS server.
-
- - We should get smarter about handling address resolve failures, or
- addresses that resolve to local IPs. It would be neat to retry
- them, since right now we just close the stream. But we need to
- make sure we don't retry them on the same exit as before. But if
- we mark the circuit, then any user who types "localhost" will
- cycle through circuits till they run out of retries. See bug 872.
-
-Can anybody remember why we wanted to do this and/or what it means?
- - config option __ControllerLimit that hangs up if there are a limit
- of controller connections already.
- [This was mwenge's idea. The idea is that a Tor controller can
- "fill" Tor's controller slot quota, so jerks can't do cross-protocol
- attacks like the http form attack. -RD]
- - Bridge issues
- . Ask all directory questions to bridge via BEGIN_DIR.
- - use the bridges for dir fetches even when our dirport is open.
- - drop 'authority' queries if they're to our own identity key; accept
- them otherwise.
- - give extend_info_t a router_purpose again
-
-
-
-If somebody wants to do this in some version, they should:
- - Create packages for Maemo/Nokia 800/810, requested by Chris Soghoian
- - debian already makes ARM-arch debs, can maemo use these asks
- phobos?
- - More work on AvoidDiskWrites
- - Make DNSPort support TCP DNS.
-
-
-* * * * Roger, please sort these: * * * *
-
- - bridge communities with local bridge authorities:
- - clients who have a password configured decide to ask their bridge
- authority for a networkstatus
- - be able to have bridges that aren't in your torrc. save them in
- state file, etc.
- - Consider if we can solve: the Tor client doesn't know what flags
- its bridge has (since it only gets the descriptor), so it can't
- make decisions based on Fast or Stable.
- - Some mechanism for specifying that we want to stop using a cached
- bridge.
-
-=======================================================================
-
-Future versions:
-
- - Protocol
- - Our current approach to block attempts to use Tor as a single-hop proxy
- is pretty lame; we should get a better one.
- - Allow small cells and large cells on the same network?
- - Cell buffering and resending. This will allow us to handle broken
- circuits as long as the endpoints don't break, plus will allow
- connection (tls session key) rotation.
- - Implement Morphmix, so we can compare its behavior, complexity,
- etc. But see paper breaking morphmix.
- - Other transport. HTTP, udp, rdp, airhook, etc. May have to do our own
- link crypto, unless we can bully DTLS into it.
- - Need a relay teardown cell, separate from one-way ends.
- (Pending a user who needs this)
- - Handle half-open connections: right now we don't support all TCP
- streams, at least according to the protocol. But we handle all that
- we've seen in the wild.
- (Pending a user who needs this)
-
- - Directory system
- - BEGIN_DIR items
- - handle connect-dir streams that don't have a chosen_exit_name set.
- - Have a "Faster" status flag that means it. Fast2, Fast4, Fast8?
- - Add an option (related to AvoidDiskWrites) to disable directory
- caching. (Is this actually a good idea??)
- X Add d64 and fp64 along-side d and fp so people can paste status
- entries into a url. since + is a valid base64 char, only allow one
- at a time. Consider adding to controller as well.
- [abandoned for lack of demand]
- - Some back-out mechanism for auto-approval on authorities
- - a way of rolling back approvals to before a timestamp
- - Consider minion-like fingerprint file/log combination.
- X Have new people be in limbo and need to demonstrate usefulness
- before we approve them.
-
- - Hidden services:
- d Standby/hotswap/redundant hidden services: needs a proposal.
- - you can insert a hidserv descriptor via the controller.
- - auth mechanisms to let hidden service midpoint and responder filter
- connection requests: proposal 121.
- - Let each hidden service (or other thing) specify its own
- OutboundBindAddress?
-
- - Server operation
- - If the server is spewing complaints about raising your ulimit -n,
- we should add a note about this to the server descriptor so other
- people can notice too.
- - When we hit a funny error from a dir request (eg 403 forbidden),
- but tor is working and happy otherwise, and we haven't seen many
- such errors recently, then don't warn about it.
-
- - Controller
- - Implement missing status events and accompanying getinfos
- - DIR_REACHABLE
- - BAD_DIR_RESPONSE (Unexpected directory response; maybe we're behind
- a firewall.)
- - BAD_PROXY (Bad http or https proxy)
- - UNRECOGNIZED_ROUTER (a nickname we asked for is unavailable)
- - Status events related to hibernation
- - something about failing to parse our address?
- from resolve_my_address() in config.c
- - sketchy OS, sketchy threading
- - too many onions queued: threading problems or slow CPU?
- - Implement missing status event fields:
- - TIMEOUT on CHECKING_REACHABILITY
- - GETINFO status/client, status/server, status/general: There should be
- some way to learn which status events are currently "in effect."
- We should specify which these are, what format they appear in, and so
- on.
- - More information in events:
- - Include bandwidth breakdown by conn->type in BW events.
- - Change circuit status events to give more details, like purpose,
- whether they're internal, when they become dirty, when they become
- too dirty for further circuits, etc.
- - Change stream status events analogously.
- - Expose more information via getinfo:
- - import and export rendezvous descriptors
- - Review all static fields for additional candidates
- - Allow EXTENDCIRCUIT to unknown server.
- - We need some way to adjust server status, and to tell tor not to
- download directories/network-status, and a way to force a download.
- - Make everything work with hidden services
-
- - Performance/resources
- - per-conn write buckets
- - separate config options for read vs write limiting
- (It's hard to support read > write, since we need better
- congestion control to avoid overfull buffers there. So,
- defer the whole thing.)
- - Rate limit exit connections to a given destination -- this helps
- us play nice with websites when Tor users want to crawl them; it
- also introduces DoS opportunities.
- - Consider truncating rather than destroying failed circuits,
- in order to save the effort of restarting. There are security
- issues here that need thinking, though.
- - Handle full buffers without totally borking
- - Rate-limit OR and directory connections overall and per-IP and
- maybe per subnet.
-
- - Misc
- - Hold-open-until-flushed now works by accident; it should work by
- design.
- - Display the reasons in 'destroy' and 'truncated' cells under
- some circumstances?
- - Make router_is_general_exit() a bit smarter once we're sure what
- it's for.
- - Automatically determine what ports are reachable and start using
- those, if circuits aren't working and it's a pattern we
- recognize ("port 443 worked once and port 9001 keeps not
- working").
-
- - Security
- - some better fix for bug #516?
- - Directory guards
- - Mini-SoaT:
- - Servers might check certs for known-good ssl websites, and if
- they come back self-signed, declare themselves to be
- non-exits. Similar to how we test for broken/evil dns now.
- - Authorities should try using exits for http to connect to some
- URLS (specified in a configuration file, so as not to make the
- List Of Things Not To Censor completely obvious) and ask them
- for results. Exits that don't give good answers should have
- the BadExit flag set.
- - Alternatively, authorities should be able to import opinions
- from Snakes on a Tor.
- - Bind to random port when making outgoing connections to Tor servers,
- to reduce remote sniping attacks.
- - Audit everything to make sure rend and intro points are just as
- likely to be us as not.
- - Do something to prevent spurious EXTEND cells from making
- middleman nodes connect all over. Rate-limit failed
- connections, perhaps?
- - DoS protection: TLS puzzles, public key ops, bandwidth exhaustion.
-
- - Needs thinking
- - Now that we're avoiding exits when picking non-exit positions,
- we need to consider how to pick nodes for internal circuits. If
- we avoid exits for all positions, we skew the load balancing. If
- we accept exits for all positions, we leak whether it's an
- internal circuit at every step. If we accept exits only at the
- last hop, we reintroduce Lasse's attacks from the Oakland paper.
-
- - Windows server usability
- - Solve the ENOBUFS problem.
- - make tor's use of openssl operate on buffers rather than sockets,
- so we can make use of libevent's buffer paradigm once it has one.
- - make tor's use of libevent tolerate either the socket or the
- buffer paradigm; includes unifying the functions in connect.c.
- - We need a getrlimit equivalent on Windows so we can reserve some
- file descriptors for saving files, etc. Otherwise we'll trigger
- asserts when we're out of file descriptors and crash.
-
- - Documentation
- - a way to generate the website diagrams from source, so we can
- translate them as utf-8 text rather than with gimp. (svg? or
- imagemagick?)
- . Flesh out options_description array in src/or/config.c
- . multiple sample torrc files
- - Refactor tor man page to divide generally useful options from
- less useful ones?
- - Add a doxygen style checker to make check-spaces so nick doesn't drift
- too far from arma's undocumented styleguide. Also, document that
- styleguide in HACKING. (See r9634 for example.)
- - exactly one space at beginning and at end of comments, except i
- guess when there's line-length pressure.
- - if we refer to a function name, put a () after it.
- - only write <b>foo</b> when foo is an argument to this function.
- - doxygen comments must always end in some form of punctuation.
- - capitalize the first sentence in the doxygen comment, except
- when you shouldn't.
- - avoid spelling errors and incorrect comments. ;)
-
- - Packaging
- - The Debian package now uses --verify-config when (re)starting,
- to distinguish configuration errors from other errors. Perhaps
- the RPM and other startup scripts should too?
- - add a "default.action" file to the tor/vidalia bundle so we can
- fix the https thing in the default configuration:
- https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ#PrivoxyWeirdSSLPort
-
-
-=======================================================================
-
-Documentation, non-version-specific.
- - Specs
- - Mark up spec; note unclear points about servers
-NR - write a spec appendix for 'being nice with tor'
- - Specify the keys and key rotation schedules and stuff
- . Finish path-spec.txt
- - Mention controller libs someplace.
- - Remove need for HACKING file.
- - document http://wiki.noreply.org/noreply/TheOnionRouter/TransparentProxy on freebsd and osx
-P - figure out rpm spec files for bundles of vidalia-tor-polipo
-P - figure out polipo install scripts for bundles of vidalia-tor-polipo on osx, win32
- - figure out selinux policy for tor
-P - change packaging system to more automated and specific for each
- platform, suggested by Paul Wouter
-P - Setup repos for redhat and suse rpms & start signing the rpms the
- way package management apps prefer
-
-Website:
-J . tor-in-the-media page
-P - Figure out licenses for website material.
- (Phobos reccomends the Open Publication License with Option A at
- http://opencontent.org/openpub/)
-P - put the logo on the website, in source form, so people can put it on
- stickers directly, etc.
-P - put the source image for the stickers on the website, so people can
- print their own
-P - figure out a license for the logos and docs we publish (trademark
-figures into this)
- (Phobos reccomends the Open Publication License with Option A at
- http://opencontent.org/openpub/)
-I - add a page for localizing all tor's components.
- - It would be neat if we had a single place that described _all_ the
- tor-related tools you can use, and what they give you, and how well they
- work. Right now, we don't give a lot of guidance wrt
- torbutton/foxproxy/privoxy/polipo in any consistent place.
-P - create a 'blog badge' for tor fans to link to and feature on their
- blogs. A sample is at http://interloper.org/tmp/tor/tor-button.png
- - More prominently, we should have a recommended apps list.
- - recommend pidgin (gaim is renamed)
- - unrecommend IE because of ftp:// bug.
- - Addenda to tor-design
- - we should add a preamble to tor-design saying it's out of date.
- - we should add an appendix or errata on what's changed.
-
- - Tor mirrors
- - make a mailing list with the mirror operators
- o make an automated tool to check /project/trace/ at mirrors to
- learn which ones are lagging behind.
- - auto (or manually) cull the mirrors that are broken; and
- contact their operator?
- - a set of instructions for mirror operators to make their apaches
- serve our charsets correctly, and bonus points for language
- negotiation.
- - figure out how to load-balance the downloads across mirrors?
- - ponder how to get users to learn that they should google for
- "tor mirrors" if the main site is blocked.
- - find a mirror volunteer to coordinate all of this
-
diff --git a/doc/asciidoc-helper.sh b/doc/asciidoc-helper.sh
index dd420f7c4..c06b57026 100755
--- a/doc/asciidoc-helper.sh
+++ b/doc/asciidoc-helper.sh
@@ -52,8 +52,8 @@ elif [ "$1" = "man" ]; then
You need a working asciidoc installed to be able to build the manpage.
a2x is installed, but for some reason it isn't working. Sometimes
-This happens because required docbook support files are missing.
-Please install docbook-xsl, docbook-xml, and libxml2-utils (Debian) or
+this happens because required docbook support files are missing.
+Please install docbook-xsl, docbook-xml, and xmlto (Debian) or
similar. If you use homebrew on Mac OS X, install the docbook formula
and add "export XML_CATALOG_FILES=/usr/local/etc/xml/catalog" to your
.bashrc
diff --git a/doc/contrib/authority-policy.txt b/doc/contrib/authority-policy.txt
deleted file mode 100644
index dd3dc1178..000000000
--- a/doc/contrib/authority-policy.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-
-0. Overview.
-
- This document contains various informal policies for how to operate
- a directory authority, how to choose new ones, etc.
-
-1. How to pick a new directory authority.
-
- Here's our current guidelines for how to pick new directory
- authorities.
-
- (These won't ever be formal criteria -- we need to keep this flexible
- so we can adapt to new situations.)
-
- o Stability:
- - Must be a low-downtime Tor server (computer as well as network).
- - Must have a static IP.
- - The operator must have been running a stable Tor server for at least
- 3 months.
- - Must intend for this server to stick around for the next 12 months
- or more.
- - Must not hibernate.
- - Should not be an exit node (as this increases the risk both of
- downtime and of key compromise).
-
- o Performance:
- - Must have sufficient bandwidth: at least 300 kB/s symmetric,
- though in practice the inbound traffic can be considerably less.
-
- o Availability:
- - Must be available to upgrade within a few days in most cases.
- (While we're still developing Tor, we periodically find bugs that
- impact the whole network and require authority upgrades.)
- - Should have a well-known way to contact the administrator
- via PGP-encrypted message.
-
- o Integrity:
- - Must promise not to censor or attack the network and users.
- - Should be run by somebody that Tor (i.e. Roger) knows.
- - Should be widely regarded as fair/trustworthy, or at least
- known, by many people.
- - If somebody asks you to backdoor or change your server, legally or
- otherwise, you will fight it to the extent of your abilities. If
- you fail to fight it, you must shut down the Tor server and notify
- us that you have.
-
- o Diversity
- - We should avoid situations that make it likelier for multiple
- authority failures to happen at the same time. Therefore...
- - It's good when authorities are not all in the same country.
- - It's good when authorities are not all in the same jurisdictions.
- - It's good when authorities are not all running the same OS.
- - It's good when authorities are not all using the same ISP.
- - It's good when authorities are not all running the same
- version of Tor.
- - No two authorities should have the same operator.
- - Maximal diversity, however, is not always practical. Sometimes,
- for example, there is only one version of Tor that provides a
- given consensus generation algorithm.
- - A small group of authorities with the same country/jurisdiction/OS is
- not a problem, until that group's size approaches quorum (half the
- authorities).
-
-2. How to choose the recommended versions
-
- The policy, in a nutshell, is to not remove versions without a good
- reason. So this means we should recommend all versions except:
-
- - Versions that no longer conform to the spec. That is, if they wouldn't
- actually interact correctly with the current Tor network.
- - Versions that have known security problems.
- - Versions that have frequent crash or assert problems.
- - Versions that harm the performance or stability of the current Tor
- network or the anonymity of other users. For example, a version
- that load balances wrong, or a version that hammers the authorities
- too much.
-
-
-> some use the slight variant of requiring a *good* reason.
-> excellent reasons include "there's a security flaw"
-> good reasons include "that crashes every time you start it. you would think
-+tor is dumb if you tried to use that version and think of it as tor."
-> good reasons include "those old clients do their load balancing wrong, and
-+they're screwing up the whole network"
-> reasons include "the old one is really slow, clients should prefer the new
-+one"
-> i try to draw the line at 'good reasons and above'
-
-
diff --git a/doc/contrib/incentives.txt b/doc/contrib/incentives.txt
deleted file mode 100644
index 850a0d01e..000000000
--- a/doc/contrib/incentives.txt
+++ /dev/null
@@ -1,479 +0,0 @@
-
- Tor Incentives Design Brainstorms
-
-1. Goals: what do we want to achieve with an incentive scheme?
-
-1.1. Encourage users to provide good relay service (throughput, latency).
-1.2. Encourage users to allow traffic to exit the Tor network from
- their node.
-
-2. Approaches to learning who should get priority.
-
-2.1. "Hard" or quantitative reputation tracking.
-
- In this design, we track the number of bytes and throughput in and
- out of nodes we interact with. When a node asks to send or receive
- bytes, we provide service proportional to our current record of the
- node's value. One approach is to let each circuit be either a normal
- circuit or a premium circuit, and nodes can "spend" their value by
- sending and receiving bytes on premium circuits: see section 4.1 for
- details of this design. Another approach (section 4.2) would treat
- all traffic from the node with the same priority class, and so nodes
- that provide resources will get and provide better service on average.
-
- This approach could be complemented with an anonymous e-cash
- implementation to let people spend reputations gained from one context
- in another context.
-
-2.2. "Soft" or qualitative reputation tracking.
-
- Rather than accounting for every byte (if I owe you a byte, I don't
- owe it anymore once you've spent it), instead I keep a general opinion
- about each server: my opinion increases when they do good work for me,
- and it decays with time, but it does not decrease as they send traffic.
- Therefore we reward servers who provide value to the system without
- nickle and diming them at each step. We also let them benefit from
- relaying traffic for others without having to "reserve" some of the
- payment for their own use. See section 4.3 for a possible design.
-
-2.3. Centralized opinions from the reputation servers.
-
- The above approaches are complex and we don't have all the answers
- for them yet. A simpler approach is just to let some central set
- of trusted servers (say, the Tor directory servers) measure whether
- people are contributing to the network, and provide a signal about
- which servers should be rewarded. They can even do the measurements
- via Tor so servers can't easily perform only when they're being
- tested. See section 4.4.
-
-2.4. Reputation servers that aggregate opinions.
-
- The option above has the directory servers doing all of the
- measurements. This doesn't scale. We can set it up so we have "deputy
- testers" -- trusted other nodes that do performance testing and report
- their results.
-
- If we want to be really adventurous, we could even
- accept claims from every Tor user and build a complex weighting /
- reputation system to decide which claims are "probably" right.
- One possible way to implement the latter is something similar to
- EigenTrust [http://www.stanford.edu/~sdkamvar/papers/eigentrust.pdf],
- where the opinion of nodes with high reputation more is weighted
- higher.
-
-3. Related issues we need to keep in mind.
-
-3.1. Relay and exit configuration needs to be easy and usable.
-
- Implicit in all of the above designs is the need to make it easy to
- run a Tor server out of the box. We need to make it stable on all
- common platforms (including XP), it needs to detect its available
- bandwidth and not overreach that, and it needs to help the operator
- through opening up ports on his firewall. Then we need a slick GUI
- that lets people click a button or two rather than editing text files.
-
- Once we've done all this, we'll hit our first big question: is
- most of the barrier to growth caused by the unusability of the current
- software? If so, are the rest of these incentive schemes superfluous?
-
-3.2. The network effect: how many nodes will you interact with?
-
- One of the concerns with pairwise reputation systems is that as the
- network gets thousands of servers, the chance that you're going to
- interact with a given server decreases. So if 90% of interactions
- don't have any prior information, the "local" incentive schemes above
- are going to degrade. This doesn't mean they're pointless -- it just
- means we need to be aware that this is a limitation, and plan in the
- background for what step to take next. (It seems that e-cash solutions
- would scale better, though they have issues of their own.)
-
-3.3. Guard nodes
-
- As of Tor 0.1.1.11, Tor users pick from a small set of semi-permanent
- "guard nodes" for their first hop of each circuit. This seems like it
- would have a big impact on pairwise reputation systems since you
- will only be cashing in on your reputation to a few people, and it is
- unlikely that a given pair of nodes will use each other as guard nodes.
-
- What does this imply? For one, it means that we don't care at all
- about the opinions of most of the servers out there -- we should
- focus on keeping our guard nodes happy with us.
-
- One conclusion from that is that our design needs to judge performance
- not just through direct interaction (beginning of the circuit) but
- also through indirect interaction (middle of the circuit). That way
- you can never be sure when your guards are measuring you.
-
- Both 3.2 and 3.3 may be solved by having a global notion of reputation,
- as in 2.3 and 2.4. However, computing the global reputation from local
- views could be expensive (O(n^2)) when the network is really large.
-
-3.4. Restricted topology: benefits and roadmap.
-
- As the Tor network continues to grow, we will need to make design
- changes to the network topology so that each node does not need
- to maintain connections to an unbounded number of other nodes. For
- anonymity's sake, we may partition the network such that all
- the nodes have the same belief about the divisions and each node is
- in only one partition. (The alternative is that every user fetches
- his own random subset of the overall node list -- this is bad because
- of intersection attacks.)
-
- Therefore the "network horizon" for each user will stay bounded,
- which helps against the above issues in 3.2 and 3.3.
-
- It could be that the core of long-lived servers will all get to know
- each other, and so the critical point that decides whether you get
- good service is whether the core likes you. Or perhaps it will turn
- out to work some other way.
-
- A special case here is the social network, where the network isn't
- partitioned randomly but instead based on some external properties.
- Social network topologies can provide incentives in other ways, because
- people may be more inclined to help out their friends, and more willing
- to relay traffic if most of the traffic they are relaying comes
- from their friends. It also opens the door for out-of-band incentive
- schemes because of the out-of-band links in the graph.
-
-3.5. Profit-maximizing vs. Altruism.
-
- There are some interesting game theory questions here.
-
- First, in a volunteer culture, success is measured in public utility
- or in public esteem. If we add a reward mechanism, there's a risk that
- reward-maximizing behavior will surpass utility- or esteem-maximizing
- behavior.
-
- Specifically, if most of our servers right now are relaying traffic
- for the good of the community, we may actually *lose* those volunteers
- if we turn the act of relaying traffic into a selfish act.
-
- I am not too worried about this issue for now, since we're aiming
- for an incentive scheme so effective that it produces tens of
- thousands of new servers.
-
-3.6. What part of the node's performance do you measure?
-
- We keep referring to having a node measure how well the other nodes
- receive bytes. But don't leeching clients receive bytes just as well
- as servers?
-
- Further, many transactions in Tor involve fetching lots of
- bytes and not sending very many. So it seems that we want to turn
- things around: we need to measure how quickly a node is _sending_
- us bytes, and then only send it bytes in proportion to that.
-
- However, a sneaky user could simply connect to a node and send some
- traffic through it, and voila, he has performed for the network. This
- is no good. The first fix is that we only count if you're receiving
- bytes "backwards" in the circuit. Now the sneaky user needs to
- construct a circuit such that his node appears later in the circuit,
- and then send some bytes back quickly.
-
- Maybe that complexity is sufficient to deter most lazy users. Or
- maybe it's an argument in favor of a more penny-counting reputation
- approach.
-
- Addendum: I was more thinking of measuring based on who is the service
- provider and service receiver for the circuit. Say Alice builds a
- circuit to Bob. Then Bob is providing service to Alice, since he
- otherwise wouldn't need to spend his bandwidth. So traffic in either
- direction should be charged to Alice. Of course, the same attack would
- work, namely, Bob could cheat by sending bytes back quickly. So someone
- close to the origin needs to detect this and close the circuit, if
- necessary. -JN
-
-3.7. What is the appropriate resource balance for servers vs. clients?
-
- If we build a good incentive system, we'll still need to tune it
- to provide the right bandwidth allocation -- if we reserve too much
- bandwidth for fast servers, then we're wasting some potential, but
- if we reserve too little, then fewer people will opt to become servers.
- In fact, finding an optimum balance is especially hard because it's
- a moving target: the better our incentive mechanism (and the lower
- the barrier to setup), the more servers there will be. How do we find
- the right balance?
-
- One answer is that it doesn't have to be perfect: we can err on the
- side of providing extra resources to servers. Then we will achieve our
- desired goal -- when people complain about speed, we can tell them to
- run a server, and they will in fact get better performance.
-
-3.8. Anonymity attack: fast connections probably come from good servers.
-
- If only fast servers can consistently get good performance in the
- network, they will stand out. "Oh, that connection probably came from
- one of the top ten servers in the network." Intersection attacks over
- time can improve the certainty of the attack.
-
- I'm not too worried about this. First, in periods of low activity,
- many different people might be getting good performance. This dirties
- the intersection attack. Second, with many of these schemes, we will
- still be uncertain whether the fast node originated the traffic, or
- was the entry node for some other lucky user -- and we already accept
- this level of attack in other cases such as the Murdoch-Danezis attack
- [http://freehaven.net/anonbib/#torta05].
-
-3.9. How do we allocate bandwidth over the course of a second?
-
- This may be a simple matter of engineering, but it still needs to be
- addressed. Our current token bucket design refills each bucket once a
- second. If we have N tokens in our bucket, and we don't know ahead of
- time how many connections are going to want to send out how many bytes,
- how do we balance providing quick service to the traffic that is
- already here compared to providing service to potential high-importance
- future traffic?
-
- If we have only two classes of service, here is a simple design:
- At each point, when we are 1/t through the second, the total number
- of non-priority bytes we are willing to send out is N/t. Thus if N
- priority bytes are waiting at the beginning of the second, we drain
- our whole bucket then, and otherwise we provide some delayed service
- to the non-priority bytes.
-
- Does this design expand to cover the case of three priority classes?
- Ideally we'd give each remote server its own priority number. Or
- hopefully there's an easy design in the literature to point to --
- this is clearly not my field.
-
- Is our current flow control mechanism (each circuit and each stream
- start out with a certain window, and once they've exhausted it they
- need to receive an ack before they can send more) going to have
- problems with this new design now that we'll be queueing more bytes
- for less preferred nodes? If it turns out we do, the first fix is
- to have the windows start out at zero rather than start out full --
- it will slow down the startup phase but protect us better.
-
- While we have outgoing cells queued for a given server, we have the
- option of reordering them based on the priority of the previous hop.
- Is this going to turn out to be useful? If we're the exit node (that
- is, there is no previous hop) what priority do those cells get?
-
- Should we do this prioritizing just for sending out bytes (as I've
- described here) or would it help to do it also for receiving bytes?
- See next section.
-
-3.10. Different-priority cells arriving on the same TCP connection.
-
- In some of the proposed designs, servers want to give specific circuits
- priority rather than having all circuits from them get the same class
- of service.
-
- Since Tor uses TCP's flow control for rate limiting, this constraints
- our design choices -- it is easy to give different TCP connections
- different priorities, but it is hard to give different cells on the
- same connection priority, because you have to read them to know what
- priority they're supposed to get.
-
- There are several possible solutions though. First is that we rely on
- the sender to reorder them so the highest priority cells (circuits) are
- more often first. Second is that if we open two TCP connections -- one
- for the high-priority cells, and one for the low-priority cells. (But
- this prevents us from changing the priority of a circuit because
- we would need to migrate it from one connection to the other.) A
- third approach is to remember which connections have recently sent
- us high-priority cells, and preferentially read from those connections.
-
- Hopefully we can get away with not solving this section at all. But if
- necessary, we can consult Ed Knightly, a Professor at Rice
- [http://www.ece.rice.edu/~knightly/], for his extensive experience on
- networking QoS.
-
-3.11. Global reputation system: Congestion on high reputation servers?
-
- If the notion of reputation is global (as in 2.3 or 2.4), circuits that
- go through successive high reputation servers would be the fastest and
- most reliable. This would incentivize everyone, regardless of their own
- reputation, to choose only the highest reputation servers in its
- circuits, causing an over-congestion on those servers.
-
- One could argue, though, that once those servers are over-congested,
- their bandwidth per circuit drops, which would in turn lower their
- reputation in the future. A question is whether this would overall
- stabilize.
-
- Another possible way is to keep a cap on reputation. In this way, a
- fraction of servers would have the same high reputation, thus balancing
- such load.
-
-3.12. Another anonymity attack: learning from service levels.
-
- If reputation is local, it may be possible for an evil node to learn
- the identity of the origin through provision of differential service.
- For instance, the evil node provides crappy bandwidth to everyone,
- until it finds a circuit that it wants to trace the origin, then it
- provides good bandwidth. Now, as only those directly or indirectly
- observing this circuit would like the evil node, it can test each node
- by building a circuit via each node to another evil node. If the
- bandwidth is high, it is (somewhat) likely that the node was a part of
- the circuit.
-
- This problem does not exist if the reputation is global and nodes only
- follow the global reputation, i.e., completely ignore their own view.
-
-3.13. DoS through high priority traffic.
-
- Assume there is an evil node with high reputation (or high value on
- Alice) and this evil node wants to deny the service to Alice. What it
- needs to do is to send a lot of traffic to Alice. To Alice, all traffic
- from this evil node is of high priority. If the choice of circuits are
- too based toward high priority circuits, Alice would spend most of her
- available bandwidth on this circuit, thus providing poor bandwidth to
- everyone else. Everyone else would start to dislike Alice, making it
- even harder for her to forward other nodes' traffic. This could cause
- Alice to have a low reputation, and the only high bandwidth circuit
- Alice could use would be via the evil node.
-
-3.14. If you run a fast server, can you run your client elsewhere?
-
- A lot of people want to run a fast server at a colocation facility,
- and then reap the rewards using their cablemodem or DSL Tor client.
-
- If we use anonymous micropayments, where reputation can literally
- be transferred, this is trivial.
-
- If we pick a design where servers accrue reputation and can only
- use it themselves, though, the clients can configure the servers as
- their entry nodes and "inherit" their reputation. In this approach
- we would let servers configure a set of IP addresses or keys that get
- "like local" service.
-
-4. Sample designs.
-
-4.1. Two classes of service for circuits.
-
- Whenever a circuit is built, it is specified by the origin which class,
- either "premium" or "normal", this circuit belongs. A premium circuit
- gets preferred treatment at each node. A node "spends" its value, which
- it earned a priori by providing service, to the next node by sending
- and receiving bytes. Once a node has overspent its values, the circuit
- cannot stay as premium. It either breaks or converts into a normal
- circuit. Each node also reserves a small portion of bandwidth for
- normal circuits to prevent starvation.
-
- Pro: Even if a node has no value to spend, it can still use normal
- circuits. This allow casual user to use Tor without forcing them to run
- a server.
-
- Pro: Nodes have incentive to forward traffic as quick and as much as
- possible to accumulate value.
-
- Con: There is no proactive method for a node to rebalance its debt. It
- has to wait until there happens to be a circuit in the opposite
- direction.
-
- Con: A node needs to build circuits in such a way that each node in the
- circuit has to have good values to the next node. This requires
- non-local knowledge and makes circuits less reliable as the values are
- used up in the circuit.
-
- Con: May discourage nodes to forward traffic in some circuits, as they
- worry about spending more useful values to get less useful values in
- return.
-
-4.2. Treat all the traffic from the node with the same service;
- hard reputation system.
-
- This design is similar to 4.1, except that instead of having two
- classes of circuits, there is only one. All the circuits are
- prioritized based on the value of the interacting node.
-
- Pro: It is simpler to design and give priority based on connections,
- not circuits.
-
- Con: A node only needs to keep a few guard nodes happy to forward their
- traffic.
-
- Con: Same as in 4.1, may discourage nodes to forward traffic in some
- circuits, as they worry about spending more useful values to get less
- useful values in return.
-
-4.3. Treat all the traffic from the node with the same service;
- soft reputation system.
-
- Rather than a guaranteed system with accounting (as 4.1 and 4.2),
- we instead try for a best-effort system. All bytes are in the same
- class of service. You keep track of other Tors by key, and give them
- service proportional to the service they have given you. That is, in
- the past when you have tried to push bytes through them, you track the
- number of bytes and the average bandwidth, and use that to weight the
- priority of their connections if they try to push bytes through you.
-
- Now you're going to get minimum service if you don't ever push bytes
- for other people, and you get increasingly improved service the more
- active you are. We should have memories fade over time (we'll have
- to tune that, which could be quite hard).
-
- Pro: Sybil attacks are pointless because new identities get lowest
- priority.
-
- Pro: Smoothly handles periods of both low and high network load. Rather
- than keeping track of the ratio/difference between what he's done for
- you and what you've done for him, simply keep track of what he's done
- for you, and give him priority based on that.
-
- Based on 3.3 above, it seems we should reward all the nodes in our
- path, not just the first one -- otherwise the node can provide good
- service only to its guards. On the other hand, there might be a
- second-order effect where you want nodes to like you so that *when*
- your guards choose you for a circuit, they'll be able to get good
- performance. This tradeoff needs more simulation/analysis.
-
- This approach focuses on incenting people to relay traffic, but it
- doesn't do much for incenting them to allow exits. It may help in
- one way through: if there are few exits, then they will attract a
- lot of use, so lots of people will like them, so when they try to
- use the network they will find their first hop to be particularly
- pleasant. After that they're like the rest of the world though. (An
- alternative would be to reward exit nodes with higher values. At the
- extreme, we could even ask the directory servers to suggest the extra
- values, based on the current availability of exit nodes.)
-
- Pro: this is a pretty easy design to add; and it can be phased in
- incrementally simply by having new nodes behave differently.
-
-4.4. Centralized opinions from the reputation servers.
-
- Have a set of official measurers who spot-check servers from the
- directory to see if they really do offer roughly the bandwidth
- they advertise. Include these observations in the directory. (For
- simplicity, the directory servers could be the measurers.) Then Tor
- servers give priority to other servers. We'd like to weight the
- priority by advertised bandwidth to encourage people to donate more,
- but it seems hard to distinguish between a slow server and a busy
- server.
-
- The spot-checking can be done anonymously to prevent selectively
- performing only for the measurers, because hey, we have an anonymity
- network.
-
- We could also reward exit nodes by giving them better priority, but
- like above this only will affect their first hop. Another problem
- is that it's darn hard to spot-check whether a server allows exits
- to all the pieces of the Internet that it claims to. If necessary,
- perhaps this can be solved by a distributed reporting mechanism,
- where clients that can reach a site from one exit but not another
- anonymously submit that site to the measurers, who verify.
-
- A last problem is that since directory servers will be doing their
- tests directly (easy to detect) or indirectly (through other Tor
- servers), then we know that we can get away with poor performance for
- people that aren't listed in the directory. Maybe we can turn this
- around and call it a feature though -- another reason to get listed
- in the directory.
-
-5. Recommendations and next steps.
-
-5.1. Simulation.
-
- For simulation trace, we can use two: one is what we obtained from Tor
- and one from existing web traces.
-
- We want to simulate all the four cases in 4.1-4. For 4.4, we may want
- to look at two variations: (1) the directory servers check the
- bandwidth themselves through Tor; (2) each node reports their perceived
- values on other nodes, while the directory servers use EigenTrust to
- compute global reputation and broadcast those.
-
-5.2. Deploying into existing Tor network.
-
diff --git a/doc/tor-rpm-creation.txt b/doc/contrib/tor-rpm-creation.txt
index a03891e2b..a03891e2b 100644
--- a/doc/tor-rpm-creation.txt
+++ b/doc/contrib/tor-rpm-creation.txt
diff --git a/doc/contrib/torel-design.txt b/doc/contrib/torel-design.txt
deleted file mode 100644
index 610cbe21f..000000000
--- a/doc/contrib/torel-design.txt
+++ /dev/null
@@ -1,181 +0,0 @@
-Design For A Tor DNS-based Exit List
-
-Status:
-
- This is a suggested design for a DNS Exit List (DNSEL) for Tor exit nodes.
- See http://exitlist.torproject.org/ for an implementation.
-
-Why?
-
- It's useful for third parties to be able to tell when a given connection
- is coming from a Tor exit node. Potential applications range from
- "anonymous user" cloaks on IRC networks like oftc, to networks like
- Freenode that apply special authentication rules to users from these
- IPs, to systems like Wikipedia that may want to make a priority of
- _unblocking_ shared IPs more liberally than non-shared IPs, since shared
- IPs presumably have non-abusive users as well as abusive ones.
-
- Since Tor provides exit policies, not every Tor server will connect to
- every address:port combination on the Internet. Unless you're trying to
- penalize hosts for supporting anonymity, it makes more sense to answer
- the fine-grained question "which Tor servers will connect to _me_?" than
- the coarse-grained question "which Tor servers exist?" The fine-grained
- approach also helps Tor server ops who share an IP with their Tor
- server: if they want to access a site that blocks Tor users, they
- can exclude that site from their exit policy, and the site can learn
- that they won't send it anonymous connections.
-
- Tor already ships with a tool (the "contrib/exitlist" script) to
- identify which Tor nodes might open anonymous connections to any given
- exit address. But this is a bit tricky to set up, so only sites like
- Freenode and OFTC that are dedicated to privacy use it.
- Conversely, providers of some DNSEL implementations are providing
- coarse-grained lists of Tor hosts -- sometimes even listing servers that
- permit no exit connections at all. This is rather a problem, since
- support for DNSEL is pretty ubiquitous.
-
-
-How?
-
- Keep a running Tor instance, and parse the cached-routers and
- cached-routers.new files as new routers arrive. To tell whether a given
- server allows connections to a certain address:port combo, look at the
- definitions in dir-spec.txt or follow the logic of the current exitlist
- script. If bug 405 is still open when you work on this
- (https://bugs.torproject.org/flyspray/index.php?do=details&id=405), you'll
- probably want to extend it to look at only the newest descriptor for
- each server, so you don't use obsolete exit policy data.
-
- FetchUselessDescriptors would probably be a good torrc option to enable.
-
- If you're also running a directory cache, you get extra-fresh
- information.
-
-
-The DNS interface
-
- Standard DNSEL, if I understand right, looks like this: There's some
- authoritative name server for foo.example.com. You want to know if
- 1.2.3.4 is in the list, so you query for an A record for
- 4.3.2.1.foo.example.com. If the record exists and has the value
- 127.0.0.2[DNSBL-EMAIL], 1.2.3.4 is in the list. If you get an NXDOMAIN
- error, 1.2.3.4 is not in the list. If you ask for a domain name outside
- of the foo.example.com zone, you get a Server Failure error[RFC 1035].
-
- Assume that the DNSEL answers queries authoritatively for some zone,
- torhosts.example.com. Below are some queries that could be supported,
- though some of them are possibly a bad idea.
-
-
- Query type 1: "General IP:Port"
-
- Format:
- {IP1}.{port}.{IP2}.ip-port.torhosts.example.com
-
- Rule:
- Iff {IP1} is a Tor server that permits connections to {port} on
- {IP2}, then there should be an A record with the value 127.0.0.2.
-
- Example:
- "1.0.0.10.80.4.3.2.1.ip-port.torhosts.example.com" should have the
- value 127.0.0.2 if and only if there is a Tor server at 10.0.0.1
- that allows connections to port 80 on 1.2.3.4.
-
- Example use:
- I'm running an IRC server at w.x.y.z:9999, and I want to tell
- whether an incoming connection is from a Tor server. I set
- up my IRC server to give a special mask to any user coming from
- an IP listed in 9999.z.y.x.w.ip-port.torhosts.example.com.
-
- Later, when I get a connection from a.b.c.d, my ircd looks up
- "d.c.b.a.9999.z.y.x.w.ip-port.torhosts.example.com" to see
- if it's a Tor server that allows connections to my ircd.
-
-
- Query type 2: "IP-port group"
-
- Format:
- {IP}.{listname}.list.torhosts.example.com
-
- Rule:
- Iff this Tor server is configured with an IP:Port list named
- {listname}, and {IP} is a Tor server that permits connections to
- any member of {listname}, then there exists an A record.
-
- Example:
- Suppose torhosts.example.com has a list of IP:Port called "foo".
- There is an A record for 4.3.2.1.foo.list.torhosts.example.com
- if and only if 1.2.3.4 is a Tor server that permits connections
- to one of the addresses in list "foo".
-
- Example use:
- Suppose torhosts.example.com has a list of hosts in "examplenet",
- a popular IRC network. Rather than having them each set up to
- query the appropriate "ip-port" list, they could instead all be
- set to query a central examplenet.list.torhosts.example.com.
-
- Problems:
- We'd be better off if each individual server queried about hosts
- that allowed connections to itself. That way, if I wanted to
- allow anonymous connections to foonet, but I wanted to be able to
- connect to foonet from my own IP without being marked, I could add
- just a few foonet addresses to my exit policy.
-
-
- Query type 3: "My IP, with port"
-
- Format:
- {IP}.{port}.me.torhosts.example.com
-
- Rule:
- An A record exists iff there is a tor server at {IP} that permits
- connections to {port} on the host that requested the lookup.
-
- Example:
- "4.3.2.1.80.me.torhosts.example.com" should have an A record if
- and only if there is a Tor server at 1.2.3.4 that allows
- connections to port 80 of the querying host.
-
- Example use:
- Somebody wants to set up a quick-and-dirty Tor detector for a
- single webserver: just point them at 80.me.torhosts.example.com.
-
- Problem:
- This would be easiest to use, but DNS gets in the way. If you
- create DNS records that give different results depending on who is
- asking, you mess up caching. There could be a fix here, but might
- not.
-
-
- RECOMMENDATION: Just build ip-port for now, and see what demand is
- like. There's no point in building mechanisms nobody wants.
-
-Web interface:
-
- Should provide the same data as the dns interface.
-
-Other issues:
-
- After a Tor server op turns off their server, it stops publishing server
- descriptors. We should consider that server's IP address to still
- represent a Tor node until 48 hours after its last descriptor was
- published.
-
- 30-60 minutes is not an unreasonable TTL.
-
- There could be some demand for address masks and port lists. Address
- masks wider than /8 make me nervous here, as do port ranges.
-
- We need an answer for what to do about hosts which exit from different
- IPs than their advertised IP. One approach would be for the DNSEL
- to launch periodic requests to itself through all exit servers whose
- policies allow it -- and then see where the requests actually come from.
-
-References:
-
- [DNSBL-EMAIL] Levine, J., "DNS Based Blacklists and Whitelists for
- E-Mail", http://tools.ietf.org/html/draft-irtf-asrg-dnsbl-02, November
- 2005.
-
- [RFC 1035] Mockapetris, P., "Domain Names - Implementation and
- Specification", RFC 1035, November 1987.
diff --git a/doc/include.am b/doc/include.am
new file mode 100644
index 000000000..9695292bd
--- /dev/null
+++ b/doc/include.am
@@ -0,0 +1,89 @@
+# We use a two-step process to generate documentation from asciidoc files.
+#
+# First, we use asciidoc/a2x to process the asciidoc files into .1.in and
+# .html.in files (see the asciidoc-helper.sh script). These are the same as
+# the regular .1 and .html files, except that they still have some autoconf
+# variables set in them.
+#
+# Second, we use config.status to turn .1.in files into .1 files and
+# .html.in files into .html files.
+#
+# We do the steps in this order so that we can ship the .*.in files as
+# part of the source distribution, so that people without asciidoc can
+# just use the .1 and .html files.
+
+regular_mans = doc/tor doc/tor-gencert doc/tor-resolve doc/torify
+all_mans = $(regular_mans) doc/tor-fw-helper
+
+if USE_ASCIIDOC
+if USE_FW_HELPER
+nodist_man1_MANS = $(all_mans:=.1)
+doc_DATA = $(all_mans:=.html)
+else
+nodist_man1_MANS = $(regular_mans:=.1)
+doc_DATA = $(regular_mans:=.html)
+endif
+html_in = $(all_mans:=.html.in)
+man_in = $(all_mans:=.1.in)
+txt_in = $(all_mans:=.1.txt)
+else
+html_in =
+man_in =
+txt_in =
+nodist_man1_MANS =
+doc_DATA =
+endif
+
+EXTRA_DIST+= doc/HACKING doc/asciidoc-helper.sh \
+ $(html_in) $(man_in) $(txt_in) \
+ doc/state-contents.txt
+
+docdir = @docdir@
+
+asciidoc_product = $(nodist_man1_MANS) $(doc_DATA)
+
+# Generate the html documentation from asciidoc, but don't do
+# machine-specific replacements yet
+$(html_in) :
+ $(AM_V_GEN)$(top_srcdir)/doc/asciidoc-helper.sh html @ASCIIDOC@ $(top_srcdir)/$@
+
+# Generate the manpage from asciidoc, but don't do
+# machine-specific replacements yet
+$(man_in) :
+ $(AM_V_GEN)$(top_srcdir)/doc/asciidoc-helper.sh man @A2X@ $(top_srcdir)/$@
+
+doc/tor.1.in: doc/tor.1.txt
+doc/tor-gencert.1.in: doc/tor-gencert.1.txt
+doc/tor-resolve.1.in: doc/tor-resolve.1.txt
+doc/torify.1.in: doc/torify.1.txt
+doc/tor-fw-helper.1.in: doc/tor-fw-helper.1.txt
+
+doc/tor.html.in: doc/tor.1.txt
+doc/tor-gencert.html.in: doc/tor-gencert.1.txt
+doc/tor-resolve.html.in: doc/tor-resolve.1.txt
+doc/torify.html.in: doc/torify.1.txt
+doc/tor-fw-helper.html.in: doc/tor-fw-helper.1.txt
+
+# use ../config.status to swap all machine-specific magic strings
+# in the asciidoc with their replacements.
+$(asciidoc_product) :
+ $(AM_V_GEN)$(MKDIR_P) $(@D)
+ $(AM_V_at)if test -e $(top_srcdir)/$@.in && ! test -e $@.in ; then \
+ cp $(top_srcdir)/$@.in $@; \
+ fi
+ $(AM_V_at)./config.status -q --file=$@;
+
+doc/tor.html: doc/tor.html.in
+doc/tor-gencert.html: doc/tor-gencert.html.in
+doc/tor-resolve.html: doc/tor-resolve.html.in
+doc/torify.html: doc/torify.html.in
+doc/tor-fw-helper.html: doc/tor-fw-helper.html.in
+
+doc/tor.1: doc/tor.1.in
+doc/tor-gencert.1: doc/tor-gencert.1.in
+doc/tor-resolve.1: doc/tor-resolve.1.in
+doc/torify.1: doc/torify.1.in
+doc/tor-fw-helper.1: doc/tor-fw-helper.1.in
+
+CLEANFILES+= $(asciidoc_product) config.log
+DISTCLEANFILES+= $(html_in) $(man_in)
diff --git a/doc/spec/README b/doc/spec/README
deleted file mode 100644
index ccd33a421..000000000
--- a/doc/spec/README
+++ /dev/null
@@ -1,11 +0,0 @@
-The Tor specifications and proposals have moved to a new repository.
-
-To browse the specifications, go to
- https://gitweb.torproject.org/torspec.git/tree
-
-To check out the specification repository, run
- git clone git://git.torproject.org/torspec.git
-
-For other information on the repository, see
- https://gitweb.torproject.org/torspec.git
-
diff --git a/doc/tor-fw-helper.1.txt b/doc/tor-fw-helper.1.txt
index 49b091038..1c103d925 100644
--- a/doc/tor-fw-helper.1.txt
+++ b/doc/tor-fw-helper.1.txt
@@ -2,6 +2,8 @@
// See LICENSE for licensing information
// This is an asciidoc file used to generate the manpage/html reference.
// Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html
+:man source: Tor
+:man manual: Tor Manual
tor-fw-helper(1)
================
Jacob Appelbaum
@@ -12,9 +14,8 @@ tor-fw-helper - Manage upstream firewall/NAT devices
SYNOPSIS
--------
-**tor-fw-helper** [-h|--help] [-T|--test] [-v|--verbose] [-g|--fetch-public-ip]
- -i|--internal-or-port __TCP port__ [-e|--external-or-port _TCP port_]
- [-d|--internal-dir-port _TCP port_] [-p|--external-dir-port _TCP port_]
+**tor-fw-helper** [-h|--help] [-T|--test-commandline] [-v|--verbose] [-g|--fetch-public-ip]
+ [-p __external port__:__internal_port__]
DESCRIPTION
-----------
@@ -29,28 +30,19 @@ OPTIONS
**-h** or **--help**::
Display help text and exit.
-**-v**::
+**-v** or **--verbose**::
Display verbose output.
-**-T** or **--test**::
+**-T** or **--test-commandline**::
Display test information and print the test information in
tor-fw-helper.log
**-g** or **--fetch-public-ip**::
Fetch the the public ip address for each supported NAT helper method.
-**-i** or **--internal-or-port** __port__::
- Inform **tor-fw-helper** of your internal OR port. This is the only
- required argument.
-
-**-e** or **--external-or-port** __port__::
- Inform **tor-fw-helper** of your external OR port.
-
-**-d** or **--internal-dir-port** __port__::
- Inform **tor-fw-helper** of your internal Dir port.
-
-**-p** or **--external-dir-port** __port__::
- Inform **tor-fw-helper** of your external Dir port.
+**-p** or **--port** __external_port__:__internal_port__::
+ Forward external_port to internal_port. This option can appear
+ more than once.
BUGS
----
diff --git a/doc/tor-gencert.1.txt b/doc/tor-gencert.1.txt
index 2a2d1179c..aa61ec3ec 100644
--- a/doc/tor-gencert.1.txt
+++ b/doc/tor-gencert.1.txt
@@ -2,6 +2,8 @@
// See LICENSE for licensing information
// This is an asciidoc file used to generate the manpage/html reference.
// Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html
+:man source: Tor
+:man manual: Tor Manual
tor-gencert(1)
==============
Nick Mathewson
diff --git a/doc/tor-resolve.1.txt b/doc/tor-resolve.1.txt
index bdc636b08..341d30224 100644
--- a/doc/tor-resolve.1.txt
+++ b/doc/tor-resolve.1.txt
@@ -2,6 +2,8 @@
// See LICENSE for licensing information
// This is an asciidoc file used to generate the manpage/html reference.
// Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html
+:man source: Tor
+:man manual: Tor Manual
tor-resolve(1)
==============
Peter Palfrader
diff --git a/doc/tor-win32-mingw-creation.txt b/doc/tor-win32-mingw-creation.txt
deleted file mode 100644
index 4a25e47a8..000000000
--- a/doc/tor-win32-mingw-creation.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-##
-## Instructions for building Tor with MinGW (http://www.mingw.org/)
-##
-
-Stage One: Download and Install MinGW.
----------------------------------------
-
-Download mingw:
-http://prdownloads.sf.net/mingw/MinGW-5.1.6.exe?download
-
-Download msys:
-http://prdownloads.sf.net/ming/MSYS-1.0.11.exe?download
-
-Download msysDTK:
-http://sourceforge.net/projects/mingw/files/MSYS%20Supplementary%20Tools/msysDTK-1.0.1/msysDTK-1.0.1.exe/download
-
-Install MinGW, msysDTK, and MSYS in that order.
-
-Make sure your PATH includes C:\MinGW\bin. You can verify this by right
-clicking on "My Computer", choose "Properties", choose "Advanced",
-choose "Environment Variables", select PATH.
-
-Start MSYS(rxvt).
-
-Create a directory called "tor-mingw".
-
-Stage Two: Download, extract, compile openssl
-----------------------------------------------
-
-Download openssl:
-http://www.openssl.org/source/openssl-0.9.8l.tar.gz
-
-Extract openssl:
-Copy the openssl tarball into the "tor-mingw" directory.
-Type "cd tor-mingw/"
-Type "tar zxf openssl-0.9.8l.tar.gz"
-(Note: There are many symlink errors because Windows doesn't support
-symlinks. You can ignore these errors.)
-
-Make openssl libraries:
-Type "cd tor-mingw/openssl-0.9.8l/"
-Type "./Configure -no-idea -no-rc5 -no-mdc2 mingw"
-Edit Makefile and remove the "test:" and "tests:" sections.
-Type "rm -rf ./test"
-Type "cd crypto/"
-Type "find ./ -name "*.h" -exec cp {} ../include/openssl/ \;"
-Type "cd ../ssl/"
-Type "find ./ -name "*.h" -exec cp {} ../include/openssl/ \;"
-Type "cd .."
-Type "cp *.h include/openssl/"
-Type "find ./fips -type f -name "*.h" -exec cp {} include/openssl/ \;"
-# The next steps can take up to 30 minutes to complete.
-Type "make"
-Type "make install"
-
-
-Stage Three: Download, extract, compile zlib
----------------------------------------------
-
-Download zlib source:
-http://www.zlib.net/zlib-1.2.3.tar.gz
-
-Extract zlib:
-Copy the zlib tarball into the "tor-mingw" directory
-Type "cd tor-mingw/"
-Type "tar zxf zlib-1.2.3.tar.gz"
-
-CHOICE:
-
-Make zlib.a:
-Type "cd tor-mingw/zlib-1.2.3/"
-Type "./configure"
-Type "make"
-Type "make install"
-
-Done.
-
-
-Stage Four: Download, extract, and compile libevent
-------------------------------------------------------
-
-Download the latest libevent release:
-http://www.monkey.org/~provos/libevent/
-
-Copy the libevent tarball into the "tor-mingw" directory.
-Type "cd tor-mingw"
-
-Extract libevent.
-
-Type "./configure --enable-static --disable-shared"
-Type "make"
-Type "make install"
-
-Stage Five: Build Tor
-----------------------
-
-Download the current Tor alpha release source code from https://torproject.org/download.html.
-Copy the Tor tarball into the "tor-mingw" directory.
-Extract Tor:
-Type "tar zxf latest-tor-alpha.tar.gz"
-
-cd tor-<version>
-Type "./configure"
-Type "make"
-
-You now have a tor.exe in src/or/. This is Tor.
-You now have a tor-resolve.exe in src/tools/.
-
-Stage Six: Build the installer
--------------------------------
-
-Install the latest NSIS:
-http://nsis.sourceforge.net/Download
-
-Run the package script in contrib:
-From the Tor build directory above, run:
-"./contrib/package_nsis-mingw.sh"
-
-The resulting Tor installer executable is in ./win_tmp/.
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 1f3afef2a..3f8f6da03 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -2,6 +2,8 @@
// See LICENSE for licensing information
// This is an asciidoc file used to generate the manpage/html reference.
// Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html
+:man source: Tor
+:man manual: Tor Manual
TOR(1)
======
@@ -30,47 +32,47 @@ difficulty tracking the source of the stream.
COMMAND-LINE OPTIONS
--------------------
-**-h**, **-help**::
+[[opt-h]] **-h**, **-help**::
Display a short help message and exit.
-**-f** __FILE__::
+[[opt-f]] **-f** __FILE__::
Specify a new configuration file to contain further Tor configuration
options. (Default: $HOME/.torrc, or @CONFDIR@/torrc if that file is not
found)
-**--defaults-torrc** __FILE__::
+[[opt-defaults-torrc]] **--defaults-torrc** __FILE__::
Specify a file in which to find default values for Tor options. The
contents of this file are overridden by those in the regular
configuration file, and by those on the command line. (Default:
@CONFDIR@/torrc-defaults.)
-**--hash-password**::
+[[opt-hash-password]] **--hash-password**::
Generates a hashed password for control port access.
-**--list-fingerprint**::
+[[opt-list-fingerprint]] **--list-fingerprint**::
Generate your keys and output your nickname and fingerprint.
-**--verify-config**::
+[[opt-verify-config]] **--verify-config**::
Verify the configuration file is valid.
-**--service install** [**--options** __command-line options__]::
+[[opt-serviceinstall]] **--service install** [**--options** __command-line options__]::
Install an instance of Tor as a Windows service, with the provided
command-line options. Current instructions can be found at
https://trac.torproject.org/projects/tor/wiki/doc/TorFAQ#HowdoIrunmyTorrelayasanNTservice
-**--service** **remove**|**start**|**stop**::
+[[opt-service]] **--service** **remove**|**start**|**stop**::
Remove, start, or stop a configured Tor Windows service.
-**--nt-service**::
+[[opt-nt-service]] **--nt-service**::
Used internally to implement a Windows service.
-**--list-torrc-options**::
+[[opt-list-torrc-options]] **--list-torrc-options**::
List all valid options.
-**--version**::
+[[opt-version]] **--version**::
Display Tor version and exit.
-**--quiet**|**--hush**::
+[[opt-quiet]] **--quiet**|**--hush**::
Override the default console log. By default, Tor starts out logging
messages at level "notice" and higher to the console. It stops doing so
after it parses its configuration, if the configuration tells it to log
@@ -122,47 +124,47 @@ option name with a forward slash.
GENERAL OPTIONS
---------------
-**BandwidthRate** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[BandwidthRate]] **BandwidthRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
A token bucket limits the average incoming bandwidth usage on this node to
the specified number of bytes per second, and the average outgoing
bandwidth usage to that same value. If you want to run a relay in the
- public network, this needs to be _at the very least_ 30 KB (that is,
- 30720 bytes). (Default: 5 MB)
+ public network, this needs to be _at the very least_ 30 KBytes (that is,
+ 30720 bytes). (Default: 1 GByte)
-**BandwidthBurst** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[BandwidthBurst]] **BandwidthBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
Limit the maximum token bucket size (also known as the burst) to the given
- number of bytes in each direction. (Default: 10 MB)
+ number of bytes in each direction. (Default: 1 GByte)
-**MaxAdvertisedBandwidth** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[MaxAdvertisedBandwidth]] **MaxAdvertisedBandwidth** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
If set, we will not advertise more than this amount of bandwidth for our
BandwidthRate. Server operators who want to reduce the number of clients
who ask to build circuits through them (since this is proportional to
advertised bandwidth rate) can thus reduce the CPU demands on their server
without impacting network performance.
-**RelayBandwidthRate** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[RelayBandwidthRate]] **RelayBandwidthRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
If not 0, a separate token bucket limits the average incoming bandwidth
usage for \_relayed traffic_ on this node to the specified number of bytes
per second, and the average outgoing bandwidth usage to that same value.
Relayed traffic currently is calculated to include answers to directory
requests, but that may change in future versions. (Default: 0)
-**RelayBandwidthBurst** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[RelayBandwidthBurst]] **RelayBandwidthBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
If not 0, limit the maximum token bucket size (also known as the burst) for
\_relayed traffic_ to the given number of bytes in each direction.
(Default: 0)
-**PerConnBWRate** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[PerConnBWRate]] **PerConnBWRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
If set, do separate rate limiting for each connection from a non-relay.
You should never need to change this value, since a network-wide value is
published in the consensus and your relay will use that value. (Default: 0)
-**PerConnBWBurst** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[PerConnBWBurst]] **PerConnBWBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
If set, do separate rate limiting for each connection from a non-relay.
You should never need to change this value, since a network-wide value is
published in the consensus and your relay will use that value. (Default: 0)
-**ClientTransportPlugin** __transport__ socks4|socks5 __IP__:__PORT__::
+[[ClientTransportPlugin]] **ClientTransportPlugin** __transport__ socks4|socks5 __IP__:__PORT__::
**ClientTransportPlugin** __transport__ exec __path-to-binary__ [options]::
In its first form, when set along with a corresponding Bridge line, the Tor
client forwards its traffic to a SOCKS-speaking proxy on "IP:PORT". It's the
@@ -174,12 +176,17 @@ GENERAL OPTIONS
forwards its traffic to it. It's the duty of that proxy to properly forward
the traffic to the bridge.
-**ServerTransportPlugin** __transport__ exec __path-to-binary__ [options]::
+[[ServerTransportPlugin]] **ServerTransportPlugin** __transport__ exec __path-to-binary__ [options]::
The Tor relay launches the pluggable transport proxy in __path-to-binary__
using __options__ as its command-line options, and expects to receive
proxied client traffic from it.
-**ConnLimit** __NUM__::
+[[ServerTransportListenAddr]] **ServerTransportListenAddr** __transport__ __IP__:__PORT__::
+ When this option is set, Tor will suggest __IP__:__PORT__ as the
+ listening address of any pluggable transport proxy that tries to
+ launch __transport__.
+
+[[ConnLimit]] **ConnLimit** __NUM__::
The minimum number of file descriptors that must be available to the Tor
process before it will start. Tor will ask the OS for as many file
descriptors as the OS will allow (you can find this by "ulimit -H -n").
@@ -188,13 +195,13 @@ GENERAL OPTIONS
You probably don't need to adjust this. It has no effect on Windows
since that platform lacks getrlimit(). (Default: 1000)
-**DisableNetwork** **0**|**1**::
+[[DisableNetwork]] **DisableNetwork** **0**|**1**::
When this option is set, we don't listen for or accept any connections
other than controller connections, and we don't make any outbound
connections. Controllers sometimes use this option to avoid using
the network until Tor is fully configured. (Default: 0)
-**ConstrainedSockets** **0**|**1**::
+[[ConstrainedSockets]] **ConstrainedSockets** **0**|**1**::
If set, Tor will tell the kernel to attempt to shrink the buffers for all
sockets to the size specified in **ConstrainedSockSize**. This is useful for
virtual servers and other environments where system level TCP buffers may
@@ -215,12 +222,12 @@ GENERAL OPTIONS
the TCP stream and will reduce throughput in proportion to round trip
time on long paths. (Default: 0)
-**ConstrainedSockSize** __N__ **bytes**|**KB**::
+[[ConstrainedSockSize]] **ConstrainedSockSize** __N__ **bytes**|**KBytes**::
When **ConstrainedSockets** is enabled the receive and transmit buffers for
all sockets will be set to this limit. Must be a value between 2048 and
262144, in 1024 byte increments. Default of 8192 is recommended.
-**ControlPort** __PORT__|**auto**::
+[[ControlPort]] **ControlPort** __PORT__|**auto**::
If set, Tor will accept connections on this port and allow those
connections to control the Tor process using the Tor Control Protocol
(described in control-spec.txt). Note: unless you also specify one or
@@ -231,7 +238,7 @@ GENERAL OPTIONS
option is required for many Tor controllers; most use the value of 9051.
Set it to "auto" to have Tor pick a port for you. (Default: 0)
-**ControlListenAddress** __IP__[:__PORT__]::
+[[ControlListenAddress]] **ControlListenAddress** __IP__[:__PORT__]::
Bind the controller listener to this address. If you specify a port, bind
to this port rather than the one specified in ControlPort. We strongly
recommend that you leave this alone unless you know what you're doing,
@@ -239,53 +246,58 @@ GENERAL OPTIONS
dangerous. This directive can be specified multiple
times to bind to multiple addresses/ports. (Default: 127.0.0.1)
-**ControlSocket** __Path__::
+[[ControlSocket]] **ControlSocket** __Path__::
Like ControlPort, but listens on a Unix domain socket, rather than a TCP
socket. (Unix and Unix-like systems only.)
-**ControlSocketsGroupWritable** **0**|**1**::
+[[ControlSocketsGroupWritable]] **ControlSocketsGroupWritable** **0**|**1**::
If this option is set to 0, don't allow the filesystem group to read and
write unix sockets (e.g. ControlSocket). If the option is set to 1, make
the control socket readable and writable by the default GID. (Default: 0)
-**HashedControlPassword** __hashed_password__::
+[[HashedControlPassword]] **HashedControlPassword** __hashed_password__::
Allow connections on the control port if they present
the password whose one-way hash is __hashed_password__. You
can compute the hash of a password by running "tor --hash-password
__password__". You can provide several acceptable passwords by using more
than one HashedControlPassword line.
-**CookieAuthentication** **0**|**1**::
+[[CookieAuthentication]] **CookieAuthentication** **0**|**1**::
If this option is set to 1, allow connections on the control port
when the connecting process knows the contents of a file named
"control_auth_cookie", which Tor will create in its data directory. This
authentication method should only be used on systems with good filesystem
security. (Default: 0)
-**CookieAuthFile** __Path__::
+[[CookieAuthFile]] **CookieAuthFile** __Path__::
If set, this option overrides the default location and file name
for Tor's cookie file. (See CookieAuthentication above.)
-**CookieAuthFileGroupReadable** **0**|**1**|__Groupname__::
+[[CookieAuthFileGroupReadable]] **CookieAuthFileGroupReadable** **0**|**1**|__Groupname__::
If this option is set to 0, don't allow the filesystem group to read the
cookie file. If the option is set to 1, make the cookie file readable by
the default GID. [Making the file readable by other groups is not yet
implemented; let us know if you need this for some reason.] (Default: 0)
-**ControlPortWriteToFile** __Path__::
+[[ControlPortWriteToFile]] **ControlPortWriteToFile** __Path__::
If set, Tor writes the address and port of any control port it opens to
this address. Usable by controllers to learn the actual control port
when ControlPort is set to "auto".
-**ControlPortFileGroupReadable** **0**|**1**::
+[[ControlPortFileGroupReadable]] **ControlPortFileGroupReadable** **0**|**1**::
If this option is set to 0, don't allow the filesystem group to read the
control port file. If the option is set to 1, make the control port
file readable by the default GID. (Default: 0)
-**DataDirectory** __DIR__::
+[[DataDirectory]] **DataDirectory** __DIR__::
Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor)
-**DirServer** [__nickname__] [**flags**] __address__:__port__ __fingerprint__::
+[[FallbackDir]] **FallbackDir** __address__:__port__ orport=__port__ id=__fingerprint__ [weight=__num__]::
+ When we're unable to connect to any directory cache for directory info
+ (usually because we don't know about any yet) we try a FallbackDir.
+ By default, the directory authorities are also FallbackDirs.
+
+[[DirAuthority]] **DirAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__::
Use a nonstandard authoritative directory server at the provided address
and port, with the specified key fingerprint. This option can be repeated
many times, for multiple authoritative directory servers. Flags are
@@ -298,28 +310,36 @@ GENERAL OPTIONS
flag is set, or if the "v1" flag is set and the "no-hs" flag is **not** set.
Tor will use this authority as a bridge authoritative directory if the
"bridge" flag is set. If a flag "orport=**port**" is given, Tor will use the
- given port when opening encrypted tunnels to the dirserver. Lastly, if a
+ given port when opening encrypted tunnels to the dirserver. If a flag
+ "weight=**num**" is given, then the directory server is chosen randomly
+ with probability proportional to that weight (default 1.0). Lastly, if a
flag "v3ident=**fp**" is given, the dirserver is a v3 directory authority
whose v3 long-term signing key has the fingerprint **fp**. +
+
- If no **dirserver** line is given, Tor will use the default directory
- servers. NOTE: this option is intended for setting up a private Tor
+ If no **DirAuthority** line is given, Tor will use the default directory
+ authorities. NOTE: this option is intended for setting up a private Tor
network with its own directory authorities. If you use it, you will be
distinguishable from other users, because you won't believe the same
authorities they do.
-**DynamicDHGroups** **0**|**1**::
+[[DirAuthorityFallbackRate]] **DirAuthorityFallbackRate** __NUM__::
+ When configured to use both directory authorities and fallback
+ directories, the directory authorities also work as fallbacks. They are
+ chosen with their regular weights, multiplied by this number, which
+ should be 1.0 or less. (Default: 1.0)
+
+[[DynamicDHGroups]] **DynamicDHGroups** **0**|**1**::
If this option is set to 1, when running as a server, generate our
own Diffie-Hellman group instead of using the one from Apache's mod_ssl.
This option may help circumvent censorship based on static
Diffie-Hellman parameters. (Default: 0)
-**AlternateDirAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__ +
+[[AlternateDirAuthority]] **AlternateDirAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__ +
-**AlternateHSAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__ +
+[[AlternateHSAuthority]] **AlternateHSAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__ +
-**AlternateBridgeAuthority** [__nickname__] [**flags**] __address__:__port__ __ fingerprint__::
- These options behave as DirServer, but they replace fewer of the
+[[AlternateBridgeAuthority]] **AlternateBridgeAuthority** [__nickname__] [**flags**] __address__:__port__ __ fingerprint__::
+ These options behave as DirAuthority, but they replace fewer of the
default directory authorities. Using
AlternateDirAuthority replaces the default Tor directory authorities, but
leaves the default hidden service authorities and bridge authorities in
@@ -328,7 +348,7 @@ GENERAL OPTIONS
AlternateBridgeAuthority replaces the default bridge authority,
but leaves the directory and hidden service authorities alone.
-**DisableAllSwap** **0**|**1**::
+[[DisableAllSwap]] **DisableAllSwap** **0**|**1**::
If set to 1, Tor will attempt to lock all current and future memory pages,
so that memory cannot be paged out. Windows, OS X and Solaris are currently
not supported. We believe that this feature works on modern Gnu/Linux
@@ -336,9 +356,10 @@ GENERAL OPTIONS
option requires that you start your Tor as root, and you should use the
**User** option to properly reduce Tor's privileges. (Default: 0)
-**DisableDebuggerAttachment** **0**|**1**::
+[[DisableDebuggerAttachment]] **DisableDebuggerAttachment** **0**|**1**::
If set to 1, Tor will attempt to prevent basic debugging attachment attempts
- by other processes. It has no impact for users who wish to attach if they
+ by other processes. This may also keep Tor from generating core files if
+ it crashes. It has no impact for users who wish to attach if they
have CAP_SYS_PTRACE or if they are root. We believe that this feature
works on modern Gnu/Linux distributions, and that it may also work on *BSD
systems (untested). Some modern Gnu/Linux systems such as Ubuntu have the
@@ -350,81 +371,81 @@ GENERAL OPTIONS
this to 0 for the duration of your debugging. Normal users should leave it
on. Disabling this option while Tor is running is prohibited. (Default: 1)
-**FetchDirInfoEarly** **0**|**1**::
+[[FetchDirInfoEarly]] **FetchDirInfoEarly** **0**|**1**::
If set to 1, Tor will always fetch directory information like other
directory caches, even if you don't meet the normal criteria for fetching
early. Normal users should leave it off. (Default: 0)
-**FetchDirInfoExtraEarly** **0**|**1**::
+[[FetchDirInfoExtraEarly]] **FetchDirInfoExtraEarly** **0**|**1**::
If set to 1, Tor will fetch directory information before other directory
caches. It will attempt to download directory information closer to the
start of the consensus period. Normal users should leave it off.
(Default: 0)
-**FetchHidServDescriptors** **0**|**1**::
+[[FetchHidServDescriptors]] **FetchHidServDescriptors** **0**|**1**::
If set to 0, Tor will never fetch any hidden service descriptors from the
rendezvous directories. This option is only useful if you're using a Tor
controller that handles hidden service fetches for you. (Default: 1)
-**FetchServerDescriptors** **0**|**1**::
+[[FetchServerDescriptors]] **FetchServerDescriptors** **0**|**1**::
If set to 0, Tor will never fetch any network status summaries or server
descriptors from the directory servers. This option is only useful if
you're using a Tor controller that handles directory fetches for you.
(Default: 1)
-**FetchUselessDescriptors** **0**|**1**::
+[[FetchUselessDescriptors]] **FetchUselessDescriptors** **0**|**1**::
If set to 1, Tor will fetch every non-obsolete descriptor from the
authorities that it hears about. Otherwise, it will avoid fetching useless
descriptors, for example for routers that are not running. This option is
useful if you're using the contributed "exitlist" script to enumerate Tor
nodes that exit to certain addresses. (Default: 0)
-**HTTPProxy** __host__[:__port__]::
+[[HTTPProxy]] **HTTPProxy** __host__[:__port__]::
Tor will make all its directory requests through this host:port (or host:80
if port is not specified), rather than connecting directly to any directory
servers.
-**HTTPProxyAuthenticator** __username:password__::
+[[HTTPProxyAuthenticator]] **HTTPProxyAuthenticator** __username:password__::
If defined, Tor will use this username:password for Basic HTTP proxy
authentication, as in RFC 2617. This is currently the only form of HTTP
proxy authentication that Tor supports; feel free to submit a patch if you
want it to support others.
-**HTTPSProxy** __host__[:__port__]::
+[[HTTPSProxy]] **HTTPSProxy** __host__[:__port__]::
Tor will make all its OR (SSL) connections through this host:port (or
host:443 if port is not specified), via HTTP CONNECT rather than connecting
directly to servers. You may want to set **FascistFirewall** to restrict
the set of ports you might try to connect to, if your HTTPS proxy only
allows connecting to certain ports.
-**HTTPSProxyAuthenticator** __username:password__::
+[[HTTPSProxyAuthenticator]] **HTTPSProxyAuthenticator** __username:password__::
If defined, Tor will use this username:password for Basic HTTPS proxy
authentication, as in RFC 2617. This is currently the only form of HTTPS
proxy authentication that Tor supports; feel free to submit a patch if you
want it to support others.
-**Socks4Proxy** __host__[:__port__]::
+[[Socks4Proxy]] **Socks4Proxy** __host__[:__port__]::
Tor will make all OR connections through the SOCKS 4 proxy at host:port
(or host:1080 if port is not specified).
-**Socks5Proxy** __host__[:__port__]::
+[[Socks5Proxy]] **Socks5Proxy** __host__[:__port__]::
Tor will make all OR connections through the SOCKS 5 proxy at host:port
(or host:1080 if port is not specified).
-**Socks5ProxyUsername** __username__ +
+[[Socks5ProxyUsername]] **Socks5ProxyUsername** __username__ +
-**Socks5ProxyPassword** __password__::
+[[Socks5ProxyPassword]] **Socks5ProxyPassword** __password__::
If defined, authenticate to the SOCKS 5 server using username and password
in accordance to RFC 1929. Both username and password must be between 1 and
255 characters.
-**KeepalivePeriod** __NUM__::
+[[KeepalivePeriod]] **KeepalivePeriod** __NUM__::
To keep firewalls from expiring connections, send a padding keepalive cell
every NUM seconds on open connections that are in use. If the connection
has no open circuits, it will instead be closed after NUM seconds of
idleness. (Default: 5 minutes)
-**Log** __minSeverity__[-__maxSeverity__] **stderr**|**stdout**|**syslog**::
+[[Log]] **Log** __minSeverity__[-__maxSeverity__] **stderr**|**stdout**|**syslog**::
Send all messages between __minSeverity__ and __maxSeverity__ to the standard
output stream, the standard error stream, or to the system log. (The
"syslog" value is only supported on Unix.) Recognized severity levels are
@@ -462,32 +483,34 @@ GENERAL OPTIONS
messages from domains other than networking and memory management, and all
messages of severity notice or higher.
-**LogMessageDomains** **0**|**1**::
+[[LogMessageDomains]] **LogMessageDomains** **0**|**1**::
If 1, Tor includes message domains with each log message. Every log
message currently has at least one domain; most currently have exactly
one. This doesn't affect controller log messages. (Default: 0)
-**OutboundBindAddress** __IP__::
+[[OutboundBindAddress]] **OutboundBindAddress** __IP__::
Make all outbound connections originate from the IP address specified. This
is only useful when you have multiple network interfaces, and you want all
- of Tor's outgoing connections to use a single one. This setting will be
- ignored for connections to the loopback addresses (127.0.0.0/8 and ::1).
+ of Tor's outgoing connections to use a single one. This option may
+ be used twice, once with an IPv4 address and once with an IPv6 address.
+ This setting will be ignored for connections to the loopback addresses
+ (127.0.0.0/8 and ::1).
-**PidFile** __FILE__::
+[[PidFile]] **PidFile** __FILE__::
On startup, write our PID to FILE. On clean shutdown, remove
FILE.
-**ProtocolWarnings** **0**|**1**::
+[[ProtocolWarnings]] **ProtocolWarnings** **0**|**1**::
If 1, Tor will log with severity \'warn' various cases of other parties not
following the Tor specification. Otherwise, they are logged with severity
\'info'. (Default: 0)
-**RunAsDaemon** **0**|**1**::
+[[RunAsDaemon]] **RunAsDaemon** **0**|**1**::
If 1, Tor forks and daemonizes to the background. This option has no effect
on Windows; instead you should use the --service command-line option.
(Default: 0)
-**LogTimeGranularity** __NUM__::
+[[LogTimeGranularity]] **LogTimeGranularity** __NUM__::
Set the resolution of timestamps in Tor's logs to NUM milliseconds.
NUM must be positive and either a divisor or a multiple of 1 second.
Note that this option only controls the granularity written by Tor to
@@ -495,7 +518,7 @@ GENERAL OPTIONS
messages to affect times logged by a controller, times attached to
syslog messages, or the mtime fields on log files. (Default: 1 second)
-**SafeLogging** **0**|**1**|**relay**::
+[[SafeLogging]] **SafeLogging** **0**|**1**|**relay**::
Tor can scrub potentially sensitive strings from log messages (e.g.
addresses) by replacing them with the string [scrubbed]. This way logs can
still be useful, but they don't leave behind personally identifying
@@ -506,37 +529,37 @@ GENERAL OPTIONS
relay, all log messages generated when acting as a relay are sanitized, but
all messages generated when acting as a client are not. (Default: 1)
-**User** __UID__::
+[[User]] **User** __UID__::
On startup, setuid to this user and setgid to their primary group.
-**HardwareAccel** **0**|**1**::
+[[HardwareAccel]] **HardwareAccel** **0**|**1**::
If non-zero, try to use built-in (static) crypto hardware acceleration when
available. (Default: 0)
-**AccelName** __NAME__::
+[[AccelName]] **AccelName** __NAME__::
When using OpenSSL hardware crypto acceleration attempt to load the dynamic
engine of this name. This must be used for any dynamic hardware engine.
Names can be verified with the openssl engine command.
-**AccelDir** __DIR__::
+[[AccelDir]] **AccelDir** __DIR__::
Specify this option if using dynamic hardware acceleration and the engine
implementation library resides somewhere other than the OpenSSL default.
-**AvoidDiskWrites** **0**|**1**::
+[[AvoidDiskWrites]] **AvoidDiskWrites** **0**|**1**::
If non-zero, try to write to disk less frequently than we would otherwise.
This is useful when running on flash memory or other media that support
only a limited number of writes. (Default: 0)
-**TunnelDirConns** **0**|**1**::
+[[TunnelDirConns]] **TunnelDirConns** **0**|**1**::
If non-zero, when a directory server we contact supports it, we will build
a one-hop circuit and make an encrypted connection via its ORPort.
(Default: 1)
-**PreferTunneledDirConns** **0**|**1**::
+[[PreferTunneledDirConns]] **PreferTunneledDirConns** **0**|**1**::
If non-zero, we will avoid directory servers that don't support tunneled
directory connections, when possible. (Default: 1)
-**CircuitPriorityHalflife** __NUM1__::
+[[CircuitPriorityHalflife]] **CircuitPriorityHalflife** __NUM1__::
If this value is set, we override the default algorithm for choosing which
circuit's cell to deliver or relay next. When the value is 0, we
round-robin between the active circuits on a connection, delivering one
@@ -548,19 +571,19 @@ GENERAL OPTIONS
networkstatus. This is an advanced option; you generally shouldn't have
to mess with it. (Default: not set)
-**DisableIOCP** **0**|**1**::
+[[DisableIOCP]] **DisableIOCP** **0**|**1**::
If Tor was built to use the Libevent's "bufferevents" networking code
and you're running on Windows, setting this option to 1 will tell Libevent
not to use the Windows IOCP networking API. (Default: 1)
-**UserspaceIOCPBuffers** **0**|**1**::
+[[UserspaceIOCPBuffers]] **UserspaceIOCPBuffers** **0**|**1**::
If IOCP is enabled (see DisableIOCP above), setting this option to 1
will tell Tor to disable kernel-space TCP buffers, in order to avoid
needless copy operations and try not to run out of non-paged RAM.
This feature is experimental; don't use it yet unless you're eager to
help tracking down bugs. (Default: 0)
-**_UseFilteringSSLBufferevents** **0**|**1**::
+[[_UseFilteringSSLBufferevents]] **_UseFilteringSSLBufferevents** **0**|**1**::
Tells Tor to do its SSL communication using a chain of
bufferevents: one for SSL and one for networking. This option has no
effect if bufferevents are disabled (in which case it can't turn on), or
@@ -568,7 +591,7 @@ GENERAL OPTIONS
option is useful for debugging only; most users shouldn't touch it.
(Default: 0)
-**CountPrivateBandwidth** **0**|**1**::
+[[CountPrivateBandwidth]] **CountPrivateBandwidth** **0**|**1**::
If this option is set, then Tor's rate-limiting applies not only to
remote connections, but also to connections to private addresses like
127.0.0.1 or 10.0.0.1. This is mostly useful for debugging
@@ -578,16 +601,16 @@ CLIENT OPTIONS
--------------
The following options are useful only for clients (that is, if
-**SocksPort**, **TransPort**, **DNSPort**, or **NATDPort** is non-zero):
+[[SocksPort]] **SocksPort**, **TransPort**, **DNSPort**, or **NATDPort** is non-zero):
-**AllowInvalidNodes** **entry**|**exit**|**middle**|**introduction**|**rendezvous**|**...**::
+[[AllowInvalidNodes]] **AllowInvalidNodes** **entry**|**exit**|**middle**|**introduction**|**rendezvous**|**...**::
If some Tor servers are obviously not working right, the directory
authorities can manually mark them as invalid, meaning that it's not
recommended you use them for entry or exit positions in your circuits. You
can opt to use them in some circuit positions, though. The default is
"middle,rendezvous", and other choices are not advised.
-**ExcludeSingleHopRelays** **0**|**1**::
+[[ExcludeSingleHopRelays]] **ExcludeSingleHopRelays** **0**|**1**::
This option controls whether circuits built by Tor will include relays with
the AllowSingleHopExits flag set to true. If ExcludeSingleHopRelays is set
to 0, these relays will be included. Note that these relays might be at
@@ -596,10 +619,10 @@ The following options are useful only for clients (that is, if
so using these relays might make your client stand out.
(Default: 1)
-**Bridge** [__transport__] __IP__:__ORPort__ [__fingerprint__]::
+[[Bridge]] **Bridge** [__transport__] __IP__:__ORPort__ [__fingerprint__]::
When set along with UseBridges, instructs Tor to use the relay at
"IP:ORPort" as a "bridge" relaying into the Tor network. If "fingerprint"
- is provided (using the same format as for DirServer), we will verify that
+ is provided (using the same format as for DirAuthority), we will verify that
the relay running at that location has the right fingerprint. We also use
fingerprint to look up the bridge descriptor at the bridge authority, if
it's provided and if UpdateBridgesFromAuthority is set too. +
@@ -608,10 +631,10 @@ The following options are useful only for clients (that is, if
line, we use that pluggable transports proxy to transfer data to
the bridge.
-**LearnCircuitBuildTimeout** **0**|**1**::
+[[LearnCircuitBuildTimeout]] **LearnCircuitBuildTimeout** **0**|**1**::
If 0, CircuitBuildTimeout adaptive learning is disabled. (Default: 1)
-**CircuitBuildTimeout** __NUM__::
+[[CircuitBuildTimeout]] **CircuitBuildTimeout** __NUM__::
Try for at most NUM seconds when building circuits. If the circuit isn't
open in that time, give up on it. If LearnCircuitBuildTimeout is 1, this
@@ -619,7 +642,7 @@ The following options are useful only for clients (that is, if
LearnCircuitBuildTimeout is 0, this value is the only value used.
(Default: 60 seconds)
-**CircuitIdleTimeout** __NUM__::
+[[CircuitIdleTimeout]] **CircuitIdleTimeout** __NUM__::
If we have kept a clean (never used) circuit around for NUM seconds, then
close it. This way when the Tor client is entirely idle, it can expire all
of its circuits, and then expire its TLS connections. Also, if we end up
@@ -627,13 +650,13 @@ The following options are useful only for clients (that is, if
receiving, it won't forever take up a slot in the circuit list. (Default: 1
hour)
-**CircuitStreamTimeout** __NUM__::
+[[CircuitStreamTimeout]] **CircuitStreamTimeout** __NUM__::
If non-zero, this option overrides our internal timeout schedule for how
many seconds until we detach a stream from a circuit and try a new circuit.
If your network is particularly slow, you might want to set this to a
number like 60. (Default: 0)
-**ClientOnly** **0**|**1**::
+[[ClientOnly]] **ClientOnly** **0**|**1**::
If set to 1, Tor will under no circumstances run as a relay or serve
directory requests. This config option is mostly meaningless: we
added it back when we were considering having Tor clients auto-promote
@@ -641,7 +664,7 @@ The following options are useful only for clients (that is, if
current behavior is simply that Tor is a client unless ORPort or
DirPort are configured. (Default: 0)
-**ExcludeNodes** __node__,__node__,__...__::
+[[ExcludeNodes]] **ExcludeNodes** __node__,__node__,__...__::
A list of identity fingerprints, nicknames, country codes and address
patterns of nodes to avoid when building a circuit.
(Example:
@@ -657,17 +680,29 @@ The following options are useful only for clients (that is, if
Note also that if you are a relay, this (and the other node selection
options below) only affects your own circuits that Tor builds for you.
Clients can still build circuits through you to any node. Controllers
- can tell Tor to build circuits through any node.
+ can tell Tor to build circuits through any node. +
+ +
+ Country codes are case-insensitive. The code "\{??}" refers to nodes whose
+ country can't be identified. No country code, including \{??}, works if
+ no GeoIPFile can be loaded. See also the GeoIPExcludeUnknown option below.
-**ExcludeExitNodes** __node__,__node__,__...__::
+[[ExcludeExitNodes]] **ExcludeExitNodes** __node__,__node__,__...__::
A list of identity fingerprints, nicknames, country codes and address
patterns of nodes to never use when picking an exit node---that is, a
node that delivers traffic for you outside the Tor network. Note that any
node listed in ExcludeNodes is automatically considered to be part of this
list too. See also the caveats on the "ExitNodes" option below.
-**ExitNodes** __node__,__node__,__...__::
+[[GeoIPExcludeUnknown]] **GeoIPExcludeUnknown** **0**|**1**|**auto**::
+ If this option is set to 'auto', then whenever any country code is set in
+ ExcludeNodes or ExcludeExitNodes, all nodes with unknown country (\{??} and
+ possibly \{A1}) are treated as excluded as well. If this option is set to
+ '1', then all unknown countries are treated as excluded in ExcludeNodes
+ and ExcludeExitNodes. This option has no effect when a GeoIP file isn't
+ configured or can't be found. (Default: auto)
+
+[[ExitNodes]] **ExitNodes** __node__,__node__,__...__::
A list of identity fingerprints, nicknames, country codes and address
patterns of nodes to use as exit node---that is, a
node that delivers traffic for you outside the Tor network. +
@@ -690,7 +725,7 @@ The following options are useful only for clients (that is, if
The .exit address notation, if enabled via AllowDotExit, overrides
this option.
-**EntryNodes** __node__,__node__,__...__::
+[[EntryNodes]] **EntryNodes** __node__,__node__,__...__::
A list of identity fingerprints, nicknames, and country codes of nodes
to use for the first hop in your normal circuits.
Normal circuits include all
@@ -701,7 +736,7 @@ The following options are useful only for clients (that is, if
The ExcludeNodes option overrides this option: any node listed in both
EntryNodes and ExcludeNodes is treated as excluded.
-**StrictNodes** **0**|**1**::
+[[StrictNodes]] **StrictNodes** **0**|**1**::
If StrictNodes is set to 1, Tor will treat the ExcludeNodes option as a
requirement to follow for all the circuits you generate, even if doing so
will break functionality for you. If StrictNodes is set to 0, Tor will
@@ -713,7 +748,7 @@ The following options are useful only for clients (that is, if
request, upload directory information, or download directory information.
(Default: 0)
-**FascistFirewall** **0**|**1**::
+[[FascistFirewall]] **FascistFirewall** **0**|**1**::
If 1, Tor will only create outgoing connections to ORs running on ports
that your firewall allows (defaults to 80 and 443; see **FirewallPorts**).
This will allow you to run Tor as a client behind a firewall with
@@ -721,12 +756,12 @@ The following options are useful only for clients (that is, if
a firewall. If you prefer more fine-grained control, use
ReachableAddresses instead.
-**FirewallPorts** __PORTS__::
+[[FirewallPorts]] **FirewallPorts** __PORTS__::
A list of ports that your firewall allows you to connect to. Only used when
**FascistFirewall** is set. This option is deprecated; use ReachableAddresses
instead. (Default: 80, 443)
-**ReachableAddresses** __ADDR__[/__MASK__][:__PORT__]...::
+[[ReachableAddresses]] **ReachableAddresses** __ADDR__[/__MASK__][:__PORT__]...::
A comma-separated list of IP addresses and ports that your firewall allows
you to connect to. The format is as for the addresses in ExitPolicy, except
that "accept" is understood unless "reject" is explicitly provided. For
@@ -735,14 +770,14 @@ The following options are useful only for clients (that is, if
99, rejects port 80 connections to net 18, and accepts connections to port
80 otherwise. (Default: \'accept \*:*'.)
-**ReachableDirAddresses** __ADDR__[/__MASK__][:__PORT__]...::
+[[ReachableDirAddresses]] **ReachableDirAddresses** __ADDR__[/__MASK__][:__PORT__]...::
Like **ReachableAddresses**, a list of addresses and ports. Tor will obey
these restrictions when fetching directory information, using standard HTTP
GET requests. If not set explicitly then the value of
**ReachableAddresses** is used. If **HTTPProxy** is set then these
connections will go through that proxy.
-**ReachableORAddresses** __ADDR__[/__MASK__][:__PORT__]...::
+[[ReachableORAddresses]] **ReachableORAddresses** __ADDR__[/__MASK__][:__PORT__]...::
Like **ReachableAddresses**, a list of addresses and ports. Tor will obey
these restrictions when connecting to Onion Routers, using TLS/SSL. If not
set explicitly then the value of **ReachableAddresses** is used. If
@@ -755,7 +790,7 @@ The following options are useful only for clients (that is, if
and some limit HTTP GET requests (which Tor uses for fetching directory
information) to port 80.
-**HidServAuth** __onion-address__ __auth-cookie__ [__service-name__]::
+[[HidServAuth]] **HidServAuth** __onion-address__ __auth-cookie__ [__service-name__]::
Client authorization for a hidden service. Valid onion addresses contain 16
characters in a-z2-7 plus ".onion", and valid auth cookies contain 22
characters in A-Za-z0-9+/. The service name is only used for internal
@@ -765,7 +800,7 @@ The following options are useful only for clients (that is, if
services can be configured to require authorization using the
**HiddenServiceAuthorizeClient** option.
-**CloseHSClientCircuitsImmediatelyOnTimeout** **0**|**1**::
+[[CloseHSClientCircuitsImmediatelyOnTimeout]] **CloseHSClientCircuitsImmediatelyOnTimeout** **0**|**1**::
If 1, Tor will close unfinished hidden service client circuits
which have not moved closer to connecting to their destination
hidden service when their internal state has not changed for the
@@ -775,7 +810,7 @@ The following options are useful only for clients (that is, if
another set of introduction and rendezvous circuits for the same
destination hidden service will be launched. (Default: 0)
-**CloseHSServiceRendCircuitsImmediatelyOnTimeout** **0**|**1**::
+[[CloseHSServiceRendCircuitsImmediatelyOnTimeout]] **CloseHSServiceRendCircuitsImmediatelyOnTimeout** **0**|**1**::
If 1, Tor will close unfinished hidden-service-side rendezvous
circuits after the current circuit-build timeout. Otherwise, such
circuits will be left open, in the hope that they will finish
@@ -783,7 +818,7 @@ The following options are useful only for clients (that is, if
rendezvous circuit for the same destination client will be
launched. (Default: 0)
-**LongLivedPorts** __PORTS__::
+[[LongLivedPorts]] **LongLivedPorts** __PORTS__::
A list of ports for services that tend to have long-running connections
(e.g. chat and interactive shells). Circuits for streams that use these
ports will contain only high-uptime nodes, to reduce the chance that a node
@@ -792,7 +827,7 @@ The following options are useful only for clients (that is, if
services whose virtual port is in this list. (Default: 21, 22, 706,
1863, 5050, 5190, 5222, 5223, 6523, 6667, 6697, 8300)
-**MapAddress** __address__ __newaddress__::
+[[MapAddress]] **MapAddress** __address__ __newaddress__::
When a request for address arrives to Tor, it will transform to newaddress
before processing it. For example, if you always want connections to
www.example.com to exit via __torserver__ (where __torserver__ is the
@@ -832,22 +867,22 @@ The following options are useful only for clients (that is, if
4. Using a wildcard to match only part of a string (as in *ample.com) is
also invalid.
-**NewCircuitPeriod** __NUM__::
+[[NewCircuitPeriod]] **NewCircuitPeriod** __NUM__::
Every NUM seconds consider whether to build a new circuit. (Default: 30
seconds)
-**MaxCircuitDirtiness** __NUM__::
+[[MaxCircuitDirtiness]] **MaxCircuitDirtiness** __NUM__::
Feel free to reuse a circuit that was first used at most NUM seconds ago,
but never attach a new stream to a circuit that is too old. For hidden
services, this applies to the __last__ time a circuit was used, not the
first. (Default: 10 minutes)
-**MaxClientCircuitsPending** __NUM__::
+[[MaxClientCircuitsPending]] **MaxClientCircuitsPending** __NUM__::
Do not allow more than NUM circuits to be pending at a time for handling
client streams. A circuit is pending if we have begun constructing it,
but it has not yet been completely constructed. (Default: 32)
-**NodeFamily** __node__,__node__,__...__::
+[[NodeFamily]] **NodeFamily** __node__,__node__,__...__::
The Tor servers, defined by their identity fingerprints or nicknames,
constitute a "family" of similar or co-administered servers, so never use
any two of them in the same circuit. Defining a NodeFamily is only needed
@@ -855,12 +890,12 @@ The following options are useful only for clients (that is, if
can be used multiple times. In addition to nodes, you can also list
IP address and ranges and country codes in {curly braces}.
-**EnforceDistinctSubnets** **0**|**1**::
+[[EnforceDistinctSubnets]] **EnforceDistinctSubnets** **0**|**1**::
If 1, Tor will not put two servers whose IP addresses are "too close" on
the same circuit. Currently, two addresses are "too close" if they lie in
the same /16 range. (Default: 1)
-**SOCKSPort** \['address':]__port__|**auto** [_isolation flags_]::
+[[SOCKSPort]] **SOCKSPort** \['address':]__port__|**auto** [_flags_] [_isolation flags_]::
Open this port to listen for connections from SOCKS-speaking
applications. Set this to 0 if you don't want to allow application
connections via SOCKS. Set it to "auto" to have Tor pick a port for
@@ -893,9 +928,62 @@ The following options are useful only for clients (that is, if
on this port to share circuits with streams from every other
port with the same session group. (By default, streams received
on different SOCKSPorts, TransPorts, etc are always isolated from one
- another. This option overrides that behavior.)
-
-**SOCKSListenAddress** __IP__[:__PORT__]::
+ another. This option overrides that behavior.) +
++
+ Other recognized _flags_ for a SOCKSPort are:
+ **NoIPv4Traffic**;;
+ Tell exits to not connect to IPv4 addresses in response to SOCKS
+ requests on this connection.
+ **IPv6Traffic**;;
+ Tell exits to allow IPv6 addresses in response to SOCKS requests on
+ this connection, so long as SOCKS5 is in use. (SOCKS4 can't handle
+ IPv6.)
+ **PreferIPv6**;;
+ Tells exits that, if a host has both an IPv4 and an IPv6 address,
+ we would prefer to connect to it via IPv6. (IPv4 is the default.) +
++
+ NOTE: Although this option allows you to specify an IP address
+ other than localhost, you should do so only with extreme caution.
+ The SOCKS protocol is unencrypted and (as we use it)
+ unauthenticated, so exposing it in this way could leak your
+ information to anybody watching your network, and allow anybody
+ to use your computer as an open proxy.
+ **CacheIPv4DNS**;;
+ Tells the client to remember IPv4 DNS answers we receive from exit
+ nodes via this connection. (On by default.)
+ **CacheIPv6DNS**;;
+ Tells the client to remember IPv6 DNS answers we receive from exit
+ nodes via this connection.
+ **CacheDNS**;;
+ Tells the client to remember all DNS answers we receive from exit
+ nodes via this connection.
+ **UseIPv4Cache**;;
+ Tells the client to use any cached IPv4 DNS answers we have when making
+ requests via this connection. (NOTE: This option, along UseIPv6Cache
+ and UseDNSCache, can harm your anonymity, and probably
+ won't help performance as much as you might expect. Use with care!)
+ **UseIPv6Cache**;;
+ Tells the client to use any cached IPv6 DNS answers we have when making
+ requests via this connection.
+ **UseDNSCache**;;
+ Tells the client to use any cached DNS answers we have when making
+ requests via this connection.
+ **PreferIPv6Automap**;;
+ When serving a hostname lookup request on this port that
+ should get automapped (according to AutomapHostsOnResove),
+ if we could return either an IPv4 or an IPv6 answer, prefer
+ an IPv6 answer. (On by default.)
+ **PreferSOCKSNoAuth**;;
+ Ordinarily, when an application offers both "username/password
+ authentication" and "no authentication" to Tor via SOCKS5, Tor
+ selects username/password authentication so that IsolateSOCKSAuth can
+ work. This can confuse some applications, if they offer a
+ username/password combination then get confused when asked for
+ one. You can disable this behavior, so that Tor will select "No
+ authentication" when IsolateSOCKSAuth is disabled, or when this
+ option is set.
+
+[[SOCKSListenAddress]] **SOCKSListenAddress** __IP__[:__PORT__]::
Bind to this address to listen for connections from Socks-speaking
applications. (Default: 127.0.0.1) You can also specify a port (e.g.
192.168.0.1:9100). This directive can be specified multiple times to bind
@@ -905,24 +993,24 @@ The following options are useful only for clients (that is, if
compatibility, SOCKSListenAddress is only allowed when SOCKSPort is just
a port number.)
-**SocksPolicy** __policy__,__policy__,__...__::
+[[SocksPolicy]] **SocksPolicy** __policy__,__policy__,__...__::
Set an entrance policy for this server, to limit who can connect to the
SocksPort and DNSPort ports. The policies have the same form as exit
policies below.
-**SocksTimeout** __NUM__::
+[[SocksTimeout]] **SocksTimeout** __NUM__::
Let a socks connection wait NUM seconds handshaking, and NUM seconds
unattached waiting for an appropriate circuit, before we fail it. (Default:
2 minutes)
-**TokenBucketRefillInterval** __NUM__ [**msec**|**second**]::
+[[TokenBucketRefillInterval]] **TokenBucketRefillInterval** __NUM__ [**msec**|**second**]::
Set the refill interval of Tor's token bucket to NUM milliseconds.
NUM must be between 1 and 1000, inclusive. Note that the configured
bandwidth limits are still expressed in bytes per second: this
option only affects the frequency with which Tor checks to see whether
previously exhausted connections may read again. (Default: 100 msec)
-**TrackHostExits** __host__,__.domain__,__...__::
+[[TrackHostExits]] **TrackHostExits** __host__,__.domain__,__...__::
For each value in the comma separated list, Tor will track recent
connections to hosts that match this value and attempt to reuse the same
exit node for each. If the value is prepended with a \'.\', it is treated as
@@ -934,76 +1022,100 @@ The following options are useful only for clients (that is, if
user. However, most people who would wish to observe this will observe it
through cookies or other protocol-specific means anyhow.
-**TrackHostExitsExpire** __NUM__::
+[[TrackHostExitsExpire]] **TrackHostExitsExpire** __NUM__::
Since exit servers go up and down, it is desirable to expire the
association between host and exit server after NUM seconds. The default is
1800 seconds (30 minutes).
-**UpdateBridgesFromAuthority** **0**|**1**::
+[[UpdateBridgesFromAuthority]] **UpdateBridgesFromAuthority** **0**|**1**::
When set (along with UseBridges), Tor will try to fetch bridge descriptors
from the configured bridge authorities when feasible. It will fall back to
a direct request if the authority responds with a 404. (Default: 0)
-**UseBridges** **0**|**1**::
+[[UseBridges]] **UseBridges** **0**|**1**::
When set, Tor will fetch descriptors for each bridge listed in the "Bridge"
config lines, and use these relays as both entry guards and directory
guards. (Default: 0)
-**UseEntryGuards** **0**|**1**::
+[[UseEntryGuards]] **UseEntryGuards** **0**|**1**::
If this option is set to 1, we pick a few long-term entry servers, and try
to stick with them. This is desirable because constantly changing servers
increases the odds that an adversary who owns some servers will observe a
fraction of your paths. (Default: 1)
-**NumEntryGuards** __NUM__::
+[[UseEntryGuardsAsDirectoryGuards]] **UseEntryGuardsAsDirectoryGuards** **0**|**1**::
+ If this option is set to 1, and UseEntryGuards is also set to 1,
+ we try to use our entry guards as directory
+ guards, and failing that, pick more nodes to act as our directory guards.
+ This helps prevent an adversary from enumerating clients. It's only
+ available for clients (non-relay, non-bridge) that aren't configured to
+ download any non-default directory material. It doesn't currently
+ do anything when we lack a live consensus. (Default: 1)
+
+[[NumEntryGuards]] **NumEntryGuards** __NUM__::
If UseEntryGuards is set to 1, we will try to pick a total of NUM routers
as long-term entries for our circuits. (Default: 3)
-**SafeSocks** **0**|**1**::
+[[NumDirectoryGuards]] **NumDirectoryGuards** __NUM__::
+ If UseEntryGuardsAsDirectoryGuards is enabled, we try to make sure we
+ have at least NUM routers to use as directory guards. If this option
+ is set to 0, use the value from NumEntryGuards. (Default: 0)
+
+[[GuardLifetime]] **GuardLifetime** __N__ **days**|**weeks**|**months**::
+ If nonzero, and UseEntryGuards is set, minimum time to keep a guard before
+ picking a new one. If zero, we use the GuardLifetime parameter from the
+ consensus directory. No value here may be less than 1 month or greater
+ than 5 years; out-of-range values are clamped. (Default: 0)
+
+[[SafeSocks]] **SafeSocks** **0**|**1**::
When this option is enabled, Tor will reject application connections that
use unsafe variants of the socks protocol -- ones that only provide an IP
address, meaning the application is doing a DNS resolve first.
Specifically, these are socks4 and socks5 when not doing remote DNS.
(Default: 0)
-**TestSocks** **0**|**1**::
+[[TestSocks]] **TestSocks** **0**|**1**::
When this option is enabled, Tor will make a notice-level log entry for
each connection to the Socks port indicating whether the request used a
safe socks protocol or an unsafe one (see above entry on SafeSocks). This
helps to determine whether an application using Tor is possibly leaking
DNS requests. (Default: 0)
-**WarnUnsafeSocks** **0**|**1**::
+[[WarnUnsafeSocks]] **WarnUnsafeSocks** **0**|**1**::
When this option is enabled, Tor will warn whenever a request is
received that only contains an IP address instead of a hostname. Allowing
applications to do DNS resolves themselves is usually a bad idea and
can leak your location to attackers. (Default: 1)
-**VirtualAddrNetwork** __Address__/__bits__::
+[[VirtualAddrNetworkIPv4]] **VirtualAddrNetworkIPv4** __Address__/__bits__ +
+
+[[VirtualAddrNetworkIPv6]] **VirtualAddrNetworkIPv6** [__Address__]/__bits__::
When Tor needs to assign a virtual (unused) address because of a MAPADDRESS
command from the controller or the AutomapHostsOnResolve feature, Tor
- picks an unassigned address from this range. (Default:
- 127.192.0.0/10) +
+ picks an unassigned address from this range. (Defaults:
+ 127.192.0.0/10 and [FE80::]/10 respectively.) +
+
When providing proxy server service to a network of computers using a tool
- like dns-proxy-tor, change this address to "10.192.0.0/10" or
- "172.16.0.0/12". The default **VirtualAddrNetwork** address range on a
- properly configured machine will route to the loopback interface. For
+ like dns-proxy-tor, change the IPv4 network to "10.192.0.0/10" or
+ "172.16.0.0/12" and change the IPv6 network to "[FC00]/7".
+ The default **VirtualAddrNetwork** address ranges on a
+ properly configured machine will route to the loopback or link-local
+ interface. For
local use, no change to the default VirtualAddrNetwork setting is needed.
-**AllowNonRFC953Hostnames** **0**|**1**::
+[[AllowNonRFC953Hostnames]] **AllowNonRFC953Hostnames** **0**|**1**::
When this option is disabled, Tor blocks hostnames containing illegal
characters (like @ and :) rather than sending them to an exit node to be
resolved. This helps trap accidental attempts to resolve URLs and so on.
(Default: 0)
-**AllowDotExit** **0**|**1**::
+[[AllowDotExit]] **AllowDotExit** **0**|**1**::
If enabled, we convert "www.google.com.foo.exit" addresses on the
SocksPort/TransPort/NATDPort into "www.google.com" addresses that exit from
the node "foo". Disabled by default since attacking websites and exit
relays can use it to manipulate your path selection. (Default: 0)
-**FastFirstHopPK** **0**|**1**::
+[[FastFirstHopPK]] **FastFirstHopPK** **0**|**1**::
When this option is disabled, Tor uses the public key step for the first
hop of creating circuits. Skipping it is generally safe since we have
already used TLS to authenticate the relay and to establish forward-secure
@@ -1013,7 +1125,7 @@ The following options are useful only for clients (that is, if
operating as a relay, and it will never use the public key step if it
doesn't yet know the onion key of the first hop. (Default: 1)
-**TransPort** \['address':]__port__|**auto** [_isolation flags_]::
+[[TransPort]] **TransPort** \['address':]__port__|**auto** [_isolation flags_]::
Open this port to listen for transparent proxy connections. Set this to
0 if you don't want to allow transparent proxy connections. Set the port
to "auto" to have Tor pick a port for you. This directive can be
@@ -1026,7 +1138,7 @@ The following options are useful only for clients (that is, if
default setting. You'll also want to set the TransListenAddress option for
the network you'd like to proxy. (Default: 0)
-**TransListenAddress** __IP__[:__PORT__]::
+[[TransListenAddress]] **TransListenAddress** __IP__[:__PORT__]::
Bind to this address to listen for transparent proxy connections. (Default:
127.0.0.1). This is useful for exporting a transparent proxy server to an
entire network. (DEPRECATED: As of 0.2.3.x-alpha, you can
@@ -1035,7 +1147,7 @@ The following options are useful only for clients (that is, if
compatibility, TransListenAddress is only allowed when TransPort is just
a port number.)
-**NATDPort** \['address':]__port__|**auto** [_isolation flags_]::
+[[NATDPort]] **NATDPort** \['address':]__port__|**auto** [_isolation flags_]::
Open this port to listen for connections from old versions of ipfw (as
included in old versions of FreeBSD, etc) using the NATD protocol.
Use 0 if you don't want to allow NATD connections. Set the port
@@ -1045,78 +1157,74 @@ The following options are useful only for clients (that is, if
+
This option is only for people who cannot use TransPort. (Default: 0)
-**NATDListenAddress** __IP__[:__PORT__]::
+[[NATDListenAddress]] **NATDListenAddress** __IP__[:__PORT__]::
Bind to this address to listen for NATD connections. (DEPRECATED: As of
0.2.3.x-alpha, you can now use multiple NATDPort entries, and provide
addresses for NATDPort entries, so NATDListenAddress no longer has a
purpose. For backward compatibility, NATDListenAddress is only allowed
when NATDPort is just a port number.)
-**AutomapHostsOnResolve** **0**|**1**::
+[[AutomapHostsOnResolve]] **AutomapHostsOnResolve** **0**|**1**::
When this option is enabled, and we get a request to resolve an address
that ends with one of the suffixes in **AutomapHostsSuffixes**, we map an
unused virtual address to that address, and return the new virtual address.
This is handy for making ".onion" addresses work with applications that
resolve an address and then connect to it. (Default: 0)
-**AutomapHostsSuffixes** __SUFFIX__,__SUFFIX__,__...__::
+[[AutomapHostsSuffixes]] **AutomapHostsSuffixes** __SUFFIX__,__SUFFIX__,__...__::
A comma-separated list of suffixes to use with **AutomapHostsOnResolve**.
The "." suffix is equivalent to "all addresses." (Default: .exit,.onion).
-**DNSPort** \['address':]__port__|**auto** [_isolation flags_]::
+[[DNSPort]] **DNSPort** \['address':]__port__|**auto** [_isolation flags_]::
If non-zero, open this port to listen for UDP DNS requests, and resolve
- them anonymously. Set the port to "auto" to have Tor pick a port for
+ them anonymously. This port only handles A, AAAA, and PTR requests---it
+ doesn't handle arbitrary DNS request types. Set the port to "auto" to
+ have Tor pick a port for
you. This directive can be specified multiple times to bind to multiple
addresses/ports. See SOCKSPort for an explanation of isolation
flags. (Default: 0)
-**DNSListenAddress** __IP__[:__PORT__]::
+[[DNSListenAddress]] **DNSListenAddress** __IP__[:__PORT__]::
Bind to this address to listen for DNS connections. (DEPRECATED: As of
0.2.3.x-alpha, you can now use multiple DNSPort entries, and provide
addresses for DNSPort entries, so DNSListenAddress no longer has a
purpose. For backward compatibility, DNSListenAddress is only allowed
when DNSPort is just a port number.)
-**ClientDNSRejectInternalAddresses** **0**|**1**::
+[[ClientDNSRejectInternalAddresses]] **ClientDNSRejectInternalAddresses** **0**|**1**::
If true, Tor does not believe any anonymously retrieved DNS answer that
tells it that an address resolves to an internal address (like 127.0.0.1 or
192.168.0.1). This option prevents certain browser-based attacks; don't
turn it off unless you know what you're doing. (Default: 1)
-**ClientRejectInternalAddresses** **0**|**1**::
+[[ClientRejectInternalAddresses]] **ClientRejectInternalAddresses** **0**|**1**::
If true, Tor does not try to fulfill requests to connect to an internal
address (like 127.0.0.1 or 192.168.0.1) __unless a exit node is
specifically requested__ (for example, via a .exit hostname, or a
controller request). (Default: 1)
-**DownloadExtraInfo** **0**|**1**::
+[[DownloadExtraInfo]] **DownloadExtraInfo** **0**|**1**::
If true, Tor downloads and caches "extra-info" documents. These documents
contain information about servers other than the information in their
regular router descriptors. Tor does not use this information for anything
itself; to save bandwidth, leave this option turned off. (Default: 0)
-**FallbackNetworkstatusFile** __FILENAME__::
- If Tor doesn't have a cached networkstatus file, it starts out using this
- one instead. Even if this file is out of date, Tor can still use it to
- learn about directory mirrors, so it doesn't need to put load on the
- authorities. (Default: None)
-
-**WarnPlaintextPorts** __port__,__port__,__...__::
+[[WarnPlaintextPorts]] **WarnPlaintextPorts** __port__,__port__,__...__::
Tells Tor to issue a warnings whenever the user tries to make an anonymous
connection to one of these ports. This option is designed to alert users
to services that risk sending passwords in the clear. (Default:
23,109,110,143)
-**RejectPlaintextPorts** __port__,__port__,__...__::
+[[RejectPlaintextPorts]] **RejectPlaintextPorts** __port__,__port__,__...__::
Like WarnPlaintextPorts, but instead of warning about risky port uses, Tor
will instead refuse to make the connection. (Default: None)
-**AllowSingleHopCircuits** **0**|**1**::
+[[AllowSingleHopCircuits]] **AllowSingleHopCircuits** **0**|**1**::
When this option is set, the attached Tor controller can use relays
that have the **AllowSingleHopExits** option turned on to build
one-hop Tor connections. (Default: 0)
-**OptimisticData** **0**|**1**|**auto**::
+[[OptimisticData]] **OptimisticData** **0**|**1**|**auto**::
When this option is set, and Tor is using an exit node that supports
the feature, it will try optimistically to send data to the exit node
without waiting for the exit node to report whether the connection
@@ -1125,7 +1233,7 @@ The following options are useful only for clients (that is, if
Tor will look at the UseOptimisticData parameter in the networkstatus.
(Default: auto)
-**Tor2webMode** **0**|**1**::
+[[Tor2webMode]] **Tor2webMode** **0**|**1**::
When this option is set, Tor connects to hidden services
**non-anonymously**. This option also disables client connections to
non-hidden-service hostnames through Tor. It **must only** be used when
@@ -1133,7 +1241,7 @@ The following options are useful only for clients (that is, if
To enable this option the compile time flag --enable-tor2webmode must be
specified. (Default: 0)
-**UseMicrodescriptors** **0**|**1**|**auto**::
+[[UseMicrodescriptors]] **UseMicrodescriptors** **0**|**1**|**auto**::
Microdescriptors are a smaller version of the information that Tor needs
in order to build its circuits. Using microdescriptors makes Tor clients
download less directory information, thus saving bandwidth. Directory
@@ -1142,32 +1250,102 @@ The following options are useful only for clients (that is, if
"auto" (recommended) then it is on for all clients that do not set
FetchUselessDescriptors. (Default: auto)
-**PathBiasCircThreshold** __NUM__ +
+[[UseNTorHandshake]] **UseNTorHandshake** **0**|**1**|**auto**::
+ The "ntor" circuit-creation handshake is faster and (we think) more
+ secure than the original ("TAP") circuit handshake, but starting to use
+ it too early might make your client stand out. If this option is 0, your
+ Tor client won't use the ntor handshake. If it's 1, your Tor client
+ will use the ntor handshake to extend circuits through servers that
+ support it. If this option is "auto" (recommended), then your client
+ will use the ntor handshake once enough directory authorities recommend
+ it. (Default: auto)
-**PathBiasNoticeRate** __NUM__ +
+[[PathBiasCircThreshold]] **PathBiasCircThreshold** __NUM__ +
-**PathBiasDisableRate** __NUM__ +
+[[PathBiasNoticeRate]] **PathBiasNoticeRate** __NUM__ +
-**PathBiasScaleThreshold** __NUM__ +
+[[PathBiasWarnRate]] **PathBiasWarnRate** __NUM__ +
-**PathBiasScaleFactor** __NUM__::
+[[PathBiasExtremeRate]] **PathBiasExtremeRate** __NUM__ +
+
+[[PathBiasDropGuards]] **PathBiasDropGuards** __NUM__ +
+
+[[PathBiasScaleThreshold]] **PathBiasScaleThreshold** __NUM__::
These options override the default behavior of Tor's (**currently
experimental**) path bias detection algorithm. To try to find broken or
misbehaving guard nodes, Tor looks for nodes where more than a certain
- fraction of circuits through that node fail after the first hop. The
- PathBiasCircThreshold option controls how many circuits we need to build
- through a guard before we make these checks. The PathBiasNoticeRate and
- PathBiasDisableRate options control what fraction of circuits must
- succeed through a guard so we won't warn about it or disable it,
- respectively. When we have seen more than PathBiasScaleThreshold
- circuits through a guard, we divide our observations by
- PathBiasScaleFactor, so that new observations don't get swamped by old
- ones. +
+ fraction of circuits through that guard fail to get built.
+ +
+ The PathBiasCircThreshold option controls how many circuits we need to build
+ through a guard before we make these checks. The PathBiasNoticeRate,
+ PathBiasWarnRate and PathBiasExtremeRate options control what fraction of
+ circuits must succeed through a guard so we won't write log messages.
+ If less than PathBiasExtremeRate circuits succeed *and* PathBiasDropGuards
+ is set to 1, we disable use of that guard. +
+ +
+ When we have seen more than PathBiasScaleThreshold
+ circuits through a guard, we scale our observations by 0.5 (governed by
+ the consensus) so that new observations don't get swamped by old ones. +
+
By default, or if a negative value is provided for one of these options,
Tor uses reasonable defaults from the networkstatus consensus document.
- If no defaults are available there, these options default to 20, .70,
- 0.0, 200, and 4 respectively.
+ If no defaults are available there, these options default to 150, .70,
+ .50, .30, 0, and 300 respectively.
+
+[[PathBiasUseThreshold]] **PathBiasUseThreshold** __NUM__ +
+
+[[PathBiasNoticeUseRate]] **PathBiasNoticeUseRate** __NUM__ +
+
+[[PathBiasExtremeUseRate]] **PathBiasExtremeUseRate** __NUM__ +
+
+[[PathBiasScaleUseThreshold]] **PathBiasScaleUseThreshold** __NUM__::
+ Similar to the above options, these options override the default behavior
+ of Tor's (**currently experimental**) path use bias detection algorithm.
+ +
+ Where as the path bias parameters govern thresholds for successfully
+ building circuits, these four path use bias parameters govern thresholds
+ only for circuit usage. Circuits which receive no stream usage
+ are not counted by this detection algorithm. A used circuit is considered
+ successful if it is capable of carrying streams or otherwise receiving
+ well-formed responses to RELAY cells.
+ +
+ By default, or if a negative value is provided for one of these options,
+ Tor uses reasonable defaults from the networkstatus consensus document.
+ If no defaults are available there, these options default to 20, .80,
+ .60, and 100, respectively.
+
+[[ClientUseIPv6]] **ClientUseIPv6** **0**|**1**::
+ If this option is set to 1, Tor might connect to entry nodes over
+ IPv6. Note that clients configured with an IPv6 address in a
+ **Bridge** line will try connecting over IPv6 even if
+ **ClientUseIPv6** is set to 0. (Default: 0)
+
+[[ClientPreferIPv6ORPort]] **ClientPreferIPv6ORPort** **0**|**1**::
+ If this option is set to 1, Tor prefers an OR port with an IPv6
+ address over one with IPv4 if a given entry node has both. Other
+ things may influence the choice. This option breaks a tie to the
+ favor of IPv6. (Default: 0)
+
+[[PathsNeededToBuildCircuits]] **PathsNeededToBuildCircuits** __NUM__::
+ Tor clients don't build circuits for user traffic until they know
+ about enough of the network so that they could potentially construct
+ enough of the possible paths through the network. If this option
+ is set to a fraction between 0.25 and 0.95, Tor won't build circuits
+ until it has enough descriptors or microdescriptors to construct
+ that fraction of possible paths. Note that setting this option too low
+ can make your Tor client less anonymous, and setting it too high can
+ prevent your Tor client from bootstrapping. If this option is negative,
+ Tor will use a default value chosen by the directory
+ authorities. (Default: -1.)
+
+[[Support022HiddenServices]] **Support022HiddenServices** **0**|**1**|**auto**::
+ Tor hidden services running versions before 0.2.3.x required clients to
+ send timestamps, which can potentially be used to distinguish clients
+ whose view of the current time is skewed. If this option is set to 0, we
+ do not send this timestamp, and hidden services on obsolete Tor versions
+ will not work. If this option is set to 1, we send the timestamp. If
+ this optoin is "auto", we take a recommendation from the latest consensus
+ document. (Default: auto)
SERVER OPTIONS
@@ -1176,7 +1354,7 @@ SERVER OPTIONS
The following options are useful only for servers (that is, if ORPort
is non-zero):
-**Address** __address__::
+[[Address]] **Address** __address__::
The IP address or fully qualified domain name of this server (e.g.
moria.mit.edu). You can leave this unset, and Tor will guess your IP
address. This IP address is the one used to tell clients and other
@@ -1184,32 +1362,36 @@ is non-zero):
Tor client binds to. To bind to a different address, use the
*ListenAddress and OutboundBindAddress options.
-**AllowSingleHopExits** **0**|**1**::
+[[AllowSingleHopExits]] **AllowSingleHopExits** **0**|**1**::
This option controls whether clients can use this server as a single hop
proxy. If set to 1, clients can use this server as an exit even if it is
the only hop in the circuit. Note that most clients will refuse to use
servers that set this option, since most clients have
ExcludeSingleHopRelays set. (Default: 0)
-**AssumeReachable** **0**|**1**::
+[[AssumeReachable]] **AssumeReachable** **0**|**1**::
This option is used when bootstrapping a new Tor network. If set to 1,
don't do self-reachability testing; just upload your server descriptor
immediately. If **AuthoritativeDirectory** is also set, this option
instructs the dirserver to bypass remote reachability testing too and list
all connected servers as running.
-**BridgeRelay** **0**|**1**::
+[[BridgeRelay]] **BridgeRelay** **0**|**1**::
Sets the relay to act as a "bridge" with respect to relaying connections
from bridge users to the Tor network. It mainly causes Tor to publish a
server descriptor to the bridge database, rather than publishing a relay
descriptor to the public directory authorities.
-**ContactInfo** __email_address__::
- Administrative contact information for server. This line might get picked
- up by spam harvesters, so you may want to obscure the fact that it's an
- email address.
+[[ContactInfo]] **ContactInfo** __email_address__::
+ Administrative contact information for this relay or bridge. This line
+ can be used to contact you if your relay or bridge is misconfigured or
+ something else goes wrong. Note that we archive and publish all
+ descriptors containing these lines and that Google indexes them, so
+ spammers might also collect them. You may want to obscure the fact
+ that it's an email address and/or generate a new address for this
+ purpose.
-**ExitPolicy** __policy__,__policy__,__...__::
+[[ExitPolicy]] **ExitPolicy** __policy__,__policy__,__...__::
Set an exit policy for this server. Each policy is of the form
"**accept**|**reject** __ADDR__[/__MASK__][:__PORT__]". If /__MASK__ is
omitted then this policy just applies to the host given. Instead of giving
@@ -1254,16 +1436,20 @@ is non-zero):
reject *:6881-6999
accept *:*
-**ExitPolicyRejectPrivate** **0**|**1**::
+[[ExitPolicyRejectPrivate]] **ExitPolicyRejectPrivate** **0**|**1**::
Reject all private (local) networks, along with your own public IP address,
at the beginning of your exit policy. See above entry on ExitPolicy.
(Default: 1)
-**MaxOnionsPending** __NUM__::
- If you have more than this number of onionskins queued for decrypt, reject
- new ones. (Default: 100)
+[[IPv6Exit]] **IPv6Exit** **0**|**1**::
+ If set, and we are an exit node, allow clients to use us for IPv6
+ traffic. (Default: 0)
-**MyFamily** __node__,__node__,__...__::
+[[MaxOnionQueueDelay]] **MaxOnionQueueDelay** __NUM__ [**msec**|**second**]::
+ If we have more onionskins queued for processing than we can process in
+ this amount of time, reject new ones. (Default: 1750 msec)
+
+[[MyFamily]] **MyFamily** __node__,__node__,__...__::
Declare that this Tor server is controlled or administered by a group or
organization identical or similar to that of the other servers, defined by
their identity fingerprints or nicknames. When two servers both declare
@@ -1271,17 +1457,20 @@ is non-zero):
same circuit. (Each server only needs to list the other servers in its
family; it doesn't need to list itself, but it won't hurt.) Do not list
any bridge relay as it would compromise its concealment.
+ +
+ When listing a node, it's better to list it by fingerprint than by
+ nickname: fingerprints are more reliable.
-**Nickname** __name__::
+[[Nickname]] **Nickname** __name__::
Set the server's nickname to \'name'. Nicknames must be between 1 and 19
characters inclusive, and must contain only the characters [a-zA-Z0-9].
-**NumCPUs** __num__::
+[[NumCPUs]] **NumCPUs** __num__::
How many processes to use at once for decrypting onionskins and other
parallelizable operations. If this is set to 0, Tor will try to detect
how many CPUs you have, defaulting to 1 if it can't tell. (Default: 0)
-**ORPort** \['address':]__PORT__|**auto** [_flags_]::
+[[ORPort]] **ORPort** \['address':]__PORT__|**auto** [_flags_]::
Advertise this port to listen for connections from Tor clients and
servers. This option is required to be a Tor server.
Set it to "auto" to have Tor pick a port for you. Set it to 0 to not
@@ -1308,7 +1497,7 @@ is non-zero):
For obvious reasons, NoAdvertise and NoListen are mutually exclusive, and
IPv4Only and IPv6Only are mutually exclusive.
-**ORListenAddress** __IP__[:__PORT__]::
+[[ORListenAddress]] **ORListenAddress** __IP__[:__PORT__]::
Bind to this IP address to listen for connections from Tor clients and
servers. If you specify a port, bind to this port rather than the one
specified in ORPort. (Default: 0.0.0.0) This directive can be specified
@@ -1317,19 +1506,19 @@ is non-zero):
This option is deprecated; you can get the same behavior with ORPort now
that it supports NoAdvertise and explicit addresses.
-**PortForwarding** **0**|**1**::
+[[PortForwarding]] **PortForwarding** **0**|**1**::
Attempt to automatically forward the DirPort and ORPort on a NAT router
connecting this Tor server to the Internet. If set, Tor will try both
NAT-PMP (common on Apple routers) and UPnP (common on routers from other
manufacturers). (Default: 0)
-**PortForwardingHelper** __filename__|__pathname__::
+[[PortForwardingHelper]] **PortForwardingHelper** __filename__|__pathname__::
If PortForwarding is set, use this executable to configure the forwarding.
If set to a filename, the system path will be searched for the executable.
If set to a path, only the specified path will be executed.
(Default: tor-fw-helper)
-**PublishServerDescriptor** **0**|**1**|**v1**|**v2**|**v3**|**bridge**,**...**::
+[[PublishServerDescriptor]] **PublishServerDescriptor** **0**|**1**|**v1**|**v2**|**v3**|**bridge**,**...**::
This option specifies which descriptors Tor will publish when acting as
a relay. You can
choose multiple arguments, separated by commas.
@@ -1342,26 +1531,31 @@ is non-zero):
which means "if running as a server, publish the
appropriate descriptors to the authorities".
-**ShutdownWaitLength** __NUM__::
+[[ShutdownWaitLength]] **ShutdownWaitLength** __NUM__::
When we get a SIGINT and we're a server, we begin shutting down:
we close listeners and start refusing new circuits. After **NUM**
- seconds, we exit. If we get a second SIGINT, we exit immedi-
- ately. (Default: 30 seconds)
+ seconds, we exit. If we get a second SIGINT, we exit immediately.
+ (Default: 30 seconds)
-**HeartbeatPeriod** __N__ **minutes**|**hours**|**days**|**weeks**::
+[[SSLKeyLifetime]] **SSLKeyLifetime** __N__ **minutes**|**hours**|**days**|**weeks**::
+ When creating a link certificate for our outermost SSL handshake,
+ set its lifetime to this amount of time. If set to 0, Tor will choose
+ some reasonable random defaults. (Default: 0)
+
+[[HeartbeatPeriod]] **HeartbeatPeriod** __N__ **minutes**|**hours**|**days**|**weeks**::
Log a heartbeat message every **HeartbeatPeriod** seconds. This is
- a log level __info__ message, designed to let you know your Tor
+ a log level __notice__ message, designed to let you know your Tor
server is still alive and doing useful things. Settings this
to 0 will disable the heartbeat. (Default: 6 hours)
-**AccountingMax** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
+[[AccountingMax]] **AccountingMax** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**TBytes**::
Never send more than the specified number of bytes in a given accounting
period, or receive more than that number in the period. For example, with
- AccountingMax set to 1 GB, a server could send 900 MB and receive 800 MB
- and continue running. It will only hibernate once one of the two reaches 1
- GB. When the number of bytes gets low, Tor will stop accepting new
- connections and circuits. When the number of bytes
- is exhausted, Tor will hibernate until some
+ AccountingMax set to 1 GByte, a server could send 900 MBytes and
+ receive 800 MBytes and continue running. It will only hibernate once
+ one of the two reaches 1 GByte. When the number of bytes gets low,
+ Tor will stop accepting new connections and circuits. When the
+ number of bytes is exhausted, Tor will hibernate until some
time in the next accounting period. To prevent all servers from waking at
the same time, Tor will also wait until a random point in each period
before waking up. If you have bandwidth cost issues, enabling hibernation
@@ -1369,7 +1563,7 @@ is non-zero):
collection of fast servers that are up some of the time, which is more
useful than a set of slow servers that are always "available".
-**AccountingStart** **day**|**week**|**month** [__day__] __HH:MM__::
+[[AccountingStart]] **AccountingStart** **day**|**week**|**month** [__day__] __HH:MM__::
Specify how long accounting periods last. If **month** is given, each
accounting period runs from the time __HH:MM__ on the __dayth__ day of one
month to the same day and time of the next. (The day must be between 1 and
@@ -1380,60 +1574,61 @@ is non-zero):
the next day. All times are local, and given in 24-hour time. (Default:
"month 1 0:00")
-**RefuseUnknownExits** **0**|**1**|**auto**::
+[[RefuseUnknownExits]] **RefuseUnknownExits** **0**|**1**|**auto**::
Prevent nodes that don't appear in the consensus from exiting using this
relay. If the option is 1, we always block exit attempts from such
nodes; if it's 0, we never do, and if the option is "auto", then we do
- whatever the authorities suggest in the consensus. (Default: auto)
+ whatever the authorities suggest in the consensus (and block if the consensus
+ is quiet on the issue). (Default: auto)
-**ServerDNSResolvConfFile** __filename__::
+[[ServerDNSResolvConfFile]] **ServerDNSResolvConfFile** __filename__::
Overrides the default DNS configuration with the configuration in
__filename__. The file format is the same as the standard Unix
"**resolv.conf**" file (7). This option, like all other ServerDNS options,
only affects name lookups that your server does on behalf of clients.
(Defaults to use the system DNS configuration.)
-**ServerDNSAllowBrokenConfig** **0**|**1**::
+[[ServerDNSAllowBrokenConfig]] **ServerDNSAllowBrokenConfig** **0**|**1**::
If this option is false, Tor exits immediately if there are problems
parsing the system DNS configuration or connecting to nameservers.
Otherwise, Tor continues to periodically retry the system nameservers until
it eventually succeeds. (Default: 1)
-**ServerDNSSearchDomains** **0**|**1**::
+[[ServerDNSSearchDomains]] **ServerDNSSearchDomains** **0**|**1**::
If set to 1, then we will search for addresses in the local search domain.
For example, if this system is configured to believe it is in
"example.com", and a client tries to connect to "www", the client will be
connected to "www.example.com". This option only affects name lookups that
your server does on behalf of clients. (Default: 0)
-**ServerDNSDetectHijacking** **0**|**1**::
+[[ServerDNSDetectHijacking]] **ServerDNSDetectHijacking** **0**|**1**::
When this option is set to 1, we will test periodically to determine
whether our local nameservers have been configured to hijack failing DNS
requests (usually to an advertising site). If they are, we will attempt to
correct this. This option only affects name lookups that your server does
on behalf of clients. (Default: 1)
-**ServerDNSTestAddresses** __address__,__address__,__...__::
+[[ServerDNSTestAddresses]] **ServerDNSTestAddresses** __address__,__address__,__...__::
When we're detecting DNS hijacking, make sure that these __valid__ addresses
aren't getting redirected. If they are, then our DNS is completely useless,
and we'll reset our exit policy to "reject *:*". This option only affects
name lookups that your server does on behalf of clients. (Default:
"www.google.com, www.mit.edu, www.yahoo.com, www.slashdot.org")
-**ServerDNSAllowNonRFC953Hostnames** **0**|**1**::
+[[ServerDNSAllowNonRFC953Hostnames]] **ServerDNSAllowNonRFC953Hostnames** **0**|**1**::
When this option is disabled, Tor does not try to resolve hostnames
containing illegal characters (like @ and :) rather than sending them to an
exit node to be resolved. This helps trap accidental attempts to resolve
URLs and so on. This option only affects name lookups that your server does
on behalf of clients. (Default: 0)
-**BridgeRecordUsageByCountry** **0**|**1**::
+[[BridgeRecordUsageByCountry]] **BridgeRecordUsageByCountry** **0**|**1**::
When this option is enabled and BridgeRelay is also enabled, and we have
GeoIP data, Tor keeps a keep a per-country count of how many client
addresses have contacted it so that it can help the bridge authority guess
which countries have blocked access to it. (Default: 1)
-**ServerDNSRandomizeCase** **0**|**1**::
+[[ServerDNSRandomizeCase]] **ServerDNSRandomizeCase** **0**|**1**::
When this option is set, Tor sets the case of each character randomly in
outgoing DNS requests, and makes sure that the case matches in DNS replies.
This so-called "0x20 hack" helps resist some types of DNS poisoning attack.
@@ -1441,47 +1636,56 @@ is non-zero):
0x20-Bit Encoding". This option only affects name lookups that your server
does on behalf of clients. (Default: 1)
-**GeoIPFile** __filename__::
- A filename containing GeoIP data, for use with BridgeRecordUsageByCountry.
+[[GeoIPFile]] **GeoIPFile** __filename__::
+ A filename containing IPv4 GeoIP data, for use with by-country statistics.
+
+[[GeoIPv6File]] **GeoIPv6File** __filename__::
+ A filename containing IPv6 GeoIP data, for use with by-country statistics.
-**CellStatistics** **0**|**1**::
+[[TLSECGroup]] **TLSECGroup** **P224**|**P256**::
+ What EC group should we try to use for incoming TLS connections?
+ P224 is faster, but makes us stand out more. Has no effect if
+ we're a client, or if our OpenSSL version lacks support for ECDHE.
+ (Default: P256)
+
+[[CellStatistics]] **CellStatistics** **0**|**1**::
When this option is enabled, Tor writes statistics on the mean time that
cells spend in circuit queues to disk every 24 hours. (Default: 0)
-**DirReqStatistics** **0**|**1**::
+[[DirReqStatistics]] **DirReqStatistics** **0**|**1**::
When this option is enabled, a Tor directory writes statistics on the
number and response time of network status requests to disk every 24
hours. (Default: 1)
-**EntryStatistics** **0**|**1**::
+[[EntryStatistics]] **EntryStatistics** **0**|**1**::
When this option is enabled, Tor writes statistics on the number of
directly connecting clients to disk every 24 hours. (Default: 0)
-**ExitPortStatistics** **0**|**1**::
+[[ExitPortStatistics]] **ExitPortStatistics** **0**|**1**::
When this option is enabled, Tor writes statistics on the number of relayed
bytes and opened stream per exit port to disk every 24 hours. (Default: 0)
-**ConnDirectionStatistics** **0**|**1**::
+[[ConnDirectionStatistics]] **ConnDirectionStatistics** **0**|**1**::
When this option is enabled, Tor writes statistics on the bidirectional use
of connections to disk every 24 hours. (Default: 0)
-**ExtraInfoStatistics** **0**|**1**::
+[[ExtraInfoStatistics]] **ExtraInfoStatistics** **0**|**1**::
When this option is enabled, Tor includes previously gathered statistics in
its extra-info documents that it uploads to the directory authorities.
(Default: 1)
-**ExtendAllowPrivateAddresses** **0**|**1**::
+[[ExtendAllowPrivateAddresses]] **ExtendAllowPrivateAddresses** **0**|**1**::
When this option is enabled, Tor routers allow EXTEND request to
localhost, RFC1918 addresses, and so on. This can create security issues;
you should probably leave it off. (Default: 0)
-**MaxMemInCellQueues** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[MaxMemInCellQueues]] **MaxMemInCellQueues** __N__ **bytes**|**KB**|**MB**|**GB**::
This option configures a threshold above which Tor will assume that it
needs to stop queueing cells because it's about to run out of memory.
If it hits this threshold, it will begin killing circuits until it
has recovered at least 10% of this memory. Do not set this option too
low, or your relay may be unreliable under load. This option only
- effects circuit queues, so the actual process size will be larger than
+ affects circuit queues, so the actual process size will be larger than
this. (Default: 8GB)
DIRECTORY SERVER OPTIONS
@@ -1490,7 +1694,7 @@ DIRECTORY SERVER OPTIONS
The following options are useful only for directory servers (that is,
if DirPort is non-zero):
-**AuthoritativeDirectory** **0**|**1**::
+[[AuthoritativeDirectory]] **AuthoritativeDirectory** **0**|**1**::
When this option is set to 1, Tor operates as an authoritative directory
server. Instead of caching the directory, it generates its own list of
good servers, signs it, and sends that to the clients. Unless the clients
@@ -1498,37 +1702,37 @@ if DirPort is non-zero):
to set this option. Please coordinate with the other admins at
tor-ops@torproject.org if you think you should be a directory.
-**DirPortFrontPage** __FILENAME__::
+[[DirPortFrontPage]] **DirPortFrontPage** __FILENAME__::
When this option is set, it takes an HTML file and publishes it as "/" on
the DirPort. Now relay operators can provide a disclaimer without needing
to set up a separate webserver. There's a sample disclaimer in
contrib/tor-exit-notice.html.
-**V1AuthoritativeDirectory** **0**|**1**::
+[[V1AuthoritativeDirectory]] **V1AuthoritativeDirectory** **0**|**1**::
When this option is set in addition to **AuthoritativeDirectory**, Tor
generates version 1 directory and running-routers documents (for legacy
Tor clients up to 0.1.0.x).
-**V2AuthoritativeDirectory** **0**|**1**::
+[[V2AuthoritativeDirectory]] **V2AuthoritativeDirectory** **0**|**1**::
When this option is set in addition to **AuthoritativeDirectory**, Tor
generates version 2 network statuses and serves descriptors, etc as
described in doc/spec/dir-spec-v2.txt (for Tor clients and servers running
0.1.1.x and 0.1.2.x).
-**V3AuthoritativeDirectory** **0**|**1**::
+[[V3AuthoritativeDirectory]] **V3AuthoritativeDirectory** **0**|**1**::
When this option is set in addition to **AuthoritativeDirectory**, Tor
generates version 3 network statuses and serves descriptors, etc as
described in doc/spec/dir-spec.txt (for Tor clients and servers running at
least 0.2.0.x).
-**VersioningAuthoritativeDirectory** **0**|**1**::
+[[VersioningAuthoritativeDirectory]] **VersioningAuthoritativeDirectory** **0**|**1**::
When this option is set to 1, Tor adds information on which versions of
Tor are still believed safe for use to the published directory. Each
version 1 authority is automatically a versioning authority; version 2
authorities provide this service optionally. See **RecommendedVersions**,
**RecommendedClientVersions**, and **RecommendedServerVersions**.
-**NamingAuthoritativeDirectory** **0**|**1**::
+[[NamingAuthoritativeDirectory]] **NamingAuthoritativeDirectory** **0**|**1**::
When this option is set to 1, then the server advertises that it has
opinions about nickname-to-fingerprint bindings. It will include these
opinions in its published network-status pages, by listing servers with
@@ -1537,33 +1741,34 @@ if DirPort is non-zero):
accept or publish descriptors that contradict a registered binding. See
**approved-routers** in the **FILES** section below.
-**HSAuthoritativeDir** **0**|**1**::
+[[HSAuthoritativeDir]] **HSAuthoritativeDir** **0**|**1**::
When this option is set in addition to **AuthoritativeDirectory**, Tor also
accepts and serves v0 hidden service descriptors,
which are produced and used by Tor 0.2.1.x and older. (Default: 0)
-**HidServDirectoryV2** **0**|**1**::
+[[HidServDirectoryV2]] **HidServDirectoryV2** **0**|**1**::
When this option is set, Tor accepts and serves v2 hidden service
descriptors. Setting DirPort is not required for this, because clients
connect via the ORPort by default. (Default: 1)
-**BridgeAuthoritativeDir** **0**|**1**::
+[[BridgeAuthoritativeDir]] **BridgeAuthoritativeDir** **0**|**1**::
When this option is set in addition to **AuthoritativeDirectory**, Tor
accepts and serves router descriptors, but it caches and serves the main
networkstatus documents rather than generating its own. (Default: 0)
-**MinUptimeHidServDirectoryV2** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
+[[MinUptimeHidServDirectoryV2]] **MinUptimeHidServDirectoryV2** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
Minimum uptime of a v2 hidden service directory to be accepted as such by
authoritative directories. (Default: 25 hours)
-**DirPort** \['address':]__PORT__|**auto** [_flags_]::
+[[DirPort]] **DirPort** \['address':]__PORT__|**auto** [_flags_]::
If this option is nonzero, advertise the directory service on this port.
Set it to "auto" to have Tor pick a port for you. This option can occur
- more than once. (Default: 0)
+ more than once, but only one advertised DirPort is supported: all
+ but one DirPort must have the **NoAdvertise** flag set. (Default: 0)
+
The same flags are supported here as are supported by ORPort.
-**DirListenAddress** __IP__[:__PORT__]::
+[[DirListenAddress]] **DirListenAddress** __IP__[:__PORT__]::
Bind the directory service to this address. If you specify a port, bind to
this port rather than the one specified in DirPort. (Default: 0.0.0.0)
This directive can be specified multiple times to bind to multiple
@@ -1572,11 +1777,11 @@ if DirPort is non-zero):
This option is deprecated; you can get the same behavior with DirPort now
that it supports NoAdvertise and explicit addresses.
-**DirPolicy** __policy__,__policy__,__...__::
+[[DirPolicy]] **DirPolicy** __policy__,__policy__,__...__::
Set an entrance policy for this server, to limit who can connect to the
directory ports. The policies have the same form as exit policies above.
-**FetchV2Networkstatus** **0**|**1**::
+[[FetchV2Networkstatus]] **FetchV2Networkstatus** **0**|**1**::
If set, we try to fetch the (obsolete, unused) version 2 network status
consensus documents from the directory authorities. No currently
supported Tor version uses them. (Default: 0)
@@ -1585,108 +1790,108 @@ if DirPort is non-zero):
DIRECTORY AUTHORITY SERVER OPTIONS
----------------------------------
-**RecommendedVersions** __STRING__::
+[[RecommendedVersions]] **RecommendedVersions** __STRING__::
STRING is a comma-separated list of Tor versions currently believed to be
safe. The list is included in each directory, and nodes which pull down the
directory learn whether they need to upgrade. This option can appear
multiple times: the values from multiple lines are spliced together. When
this is set then **VersioningAuthoritativeDirectory** should be set too.
-**RecommendedClientVersions** __STRING__::
+[[RecommendedClientVersions]] **RecommendedClientVersions** __STRING__::
STRING is a comma-separated list of Tor versions currently believed to be
safe for clients to use. This information is included in version 2
directories. If this is not set then the value of **RecommendedVersions**
is used. When this is set then **VersioningAuthoritativeDirectory** should
be set too.
-**RecommendedServerVersions** __STRING__::
+[[RecommendedServerVersions]] **RecommendedServerVersions** __STRING__::
STRING is a comma-separated list of Tor versions currently believed to be
safe for servers to use. This information is included in version 2
directories. If this is not set then the value of **RecommendedVersions**
is used. When this is set then **VersioningAuthoritativeDirectory** should
be set too.
-**ConsensusParams** __STRING__::
+[[ConsensusParams]] **ConsensusParams** __STRING__::
STRING is a space-separated list of key=value pairs that Tor will include
in the "params" line of its networkstatus vote.
-**DirAllowPrivateAddresses** **0**|**1**::
+[[DirAllowPrivateAddresses]] **DirAllowPrivateAddresses** **0**|**1**::
If set to 1, Tor will accept router descriptors with arbitrary "Address"
elements. Otherwise, if the address is not an IP address or is a private IP
address, it will reject the router descriptor. (Default: 0)
-**AuthDirBadDir** __AddressPattern...__::
+[[AuthDirBadDir]] **AuthDirBadDir** __AddressPattern...__::
Authoritative directories only. A set of address patterns for servers that
will be listed as bad directories in any network status document this
authority publishes, if **AuthDirListBadDirs** is set.
-**AuthDirBadExit** __AddressPattern...__::
+[[AuthDirBadExit]] **AuthDirBadExit** __AddressPattern...__::
Authoritative directories only. A set of address patterns for servers that
will be listed as bad exits in any network status document this authority
publishes, if **AuthDirListBadExits** is set.
-**AuthDirInvalid** __AddressPattern...__::
+[[AuthDirInvalid]] **AuthDirInvalid** __AddressPattern...__::
Authoritative directories only. A set of address patterns for servers that
will never be listed as "valid" in any network status document that this
authority publishes.
-**AuthDirReject** __AddressPattern__...::
+[[AuthDirReject]] **AuthDirReject** __AddressPattern__...::
Authoritative directories only. A set of address patterns for servers that
will never be listed at all in any network status document that this
authority publishes, or accepted as an OR address in any descriptor
submitted for publication by this authority.
-**AuthDirBadDirCCs** __CC__,... +
+[[AuthDirBadDirCCs]] **AuthDirBadDirCCs** __CC__,... +
-**AuthDirBadExitCCs** __CC__,... +
+[[AuthDirBadExitCCs]] **AuthDirBadExitCCs** __CC__,... +
-**AuthDirInvalidCCs** __CC__,... +
+[[AuthDirInvalidCCs]] **AuthDirInvalidCCs** __CC__,... +
-**AuthDirRejectCCs** __CC__,...::
+[[AuthDirRejectCCs]] **AuthDirRejectCCs** __CC__,...::
Authoritative directories only. These options contain a comma-separated
list of country codes such that any server in one of those country codes
will be marked as a bad directory/bad exit/invalid for use, or rejected
entirely.
-**AuthDirListBadDirs** **0**|**1**::
+[[AuthDirListBadDirs]] **AuthDirListBadDirs** **0**|**1**::
Authoritative directories only. If set to 1, this directory has some
opinion about which nodes are unsuitable as directory caches. (Do not set
this to 1 unless you plan to list non-functioning directories as bad;
otherwise, you are effectively voting in favor of every declared
directory.)
-**AuthDirListBadExits** **0**|**1**::
+[[AuthDirListBadExits]] **AuthDirListBadExits** **0**|**1**::
Authoritative directories only. If set to 1, this directory has some
opinion about which nodes are unsuitable as exit nodes. (Do not set this to
1 unless you plan to list non-functioning exits as bad; otherwise, you are
effectively voting in favor of every declared exit as an exit.)
-**AuthDirRejectUnlisted** **0**|**1**::
+[[AuthDirRejectUnlisted]] **AuthDirRejectUnlisted** **0**|**1**::
Authoritative directories only. If set to 1, the directory server rejects
all uploaded server descriptors that aren't explicitly listed in the
fingerprints file. This acts as a "panic button" if we get hit with a Sybil
attack. (Default: 0)
-**AuthDirMaxServersPerAddr** __NUM__::
+[[AuthDirMaxServersPerAddr]] **AuthDirMaxServersPerAddr** __NUM__::
Authoritative directories only. The maximum number of servers that we will
list as acceptable on a single IP address. Set this to "0" for "no limit".
(Default: 2)
-**AuthDirMaxServersPerAuthAddr** __NUM__::
+[[AuthDirMaxServersPerAuthAddr]] **AuthDirMaxServersPerAuthAddr** __NUM__::
Authoritative directories only. Like AuthDirMaxServersPerAddr, but applies
to addresses shared with directory authorities. (Default: 5)
-**AuthDirFastGuarantee** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[AuthDirFastGuarantee]] **AuthDirFastGuarantee** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
Authoritative directories only. If non-zero, always vote the
Fast flag for any relay advertising this amount of capacity or
- more. (Default: 100 KB)
+ more. (Default: 100 KBytes)
-**AuthDirGuardBWGuarantee** __N__ **bytes**|**KB**|**MB**|**GB**::
+[[AuthDirGuardBWGuarantee]] **AuthDirGuardBWGuarantee** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
Authoritative directories only. If non-zero, this advertised capacity
or more is always sufficient to satisfy the bandwidth requirement
- for the Guard flag. (Default: 250 KB)
+ for the Guard flag. (Default: 250 KBytes)
-**BridgePassword** __Password__::
+[[BridgePassword]] **BridgePassword** __Password__::
If set, contains an HTTP authenticator that tells a bridge authority to
serve all requested bridge information. Used by the (only partially
implemented) "bridge community" design, where a community of bridge
@@ -1694,26 +1899,26 @@ DIRECTORY AUTHORITY SERVER OPTIONS
and their target user audience can periodically fetch the list of
available community bridges to stay up-to-date. (Default: not set)
-**V3AuthVotingInterval** __N__ **minutes**|**hours**::
+[[V3AuthVotingInterval]] **V3AuthVotingInterval** __N__ **minutes**|**hours**::
V3 authoritative directories only. Configures the server's preferred voting
interval. Note that voting will __actually__ happen at an interval chosen
by consensus from all the authorities' preferred intervals. This time
SHOULD divide evenly into a day. (Default: 1 hour)
-**V3AuthVoteDelay** __N__ **minutes**|**hours**::
+[[V3AuthVoteDelay]] **V3AuthVoteDelay** __N__ **minutes**|**hours**::
V3 authoritative directories only. Configures the server's preferred delay
between publishing its vote and assuming it has all the votes from all the
other authorities. Note that the actual time used is not the server's
preferred time, but the consensus of all preferences. (Default: 5 minutes)
-**V3AuthDistDelay** __N__ **minutes**|**hours**::
+[[V3AuthDistDelay]] **V3AuthDistDelay** __N__ **minutes**|**hours**::
V3 authoritative directories only. Configures the server's preferred delay
between publishing its consensus and signature and assuming it has all the
signatures from all the other authorities. Note that the actual time used
is not the server's preferred time, but the consensus of all preferences.
(Default: 5 minutes)
-**V3AuthNIntervalsValid** __NUM__::
+[[V3AuthNIntervalsValid]] **V3AuthNIntervalsValid** __NUM__::
V3 authoritative directories only. Configures the number of VotingIntervals
for which each consensus should be valid for. Choosing high numbers
increases network partitioning risks; choosing low numbers increases
@@ -1721,38 +1926,44 @@ DIRECTORY AUTHORITY SERVER OPTIONS
server's preferred number, but the consensus of all preferences. Must be at
least 2. (Default: 3)
-**V3BandwidthsFile** __FILENAME__::
+[[V3BandwidthsFile]] **V3BandwidthsFile** __FILENAME__::
V3 authoritative directories only. Configures the location of the
bandwidth-authority generated file storing information on relays' measured
bandwidth capacities. (Default: unset)
-**V3AuthUseLegacyKey** **0**|**1**::
+[[V3AuthUseLegacyKey]] **V3AuthUseLegacyKey** **0**|**1**::
If set, the directory authority will sign consensuses not only with its
own signing key, but also with a "legacy" key and certificate with a
different identity. This feature is used to migrate directory authority
keys in the event of a compromise. (Default: 0)
-**RephistTrackTime** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
+[[RephistTrackTime]] **RephistTrackTime** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
Tells an authority, or other node tracking node reliability and history,
that fine-grained information about nodes can be discarded when it hasn't
changed for a given amount of time. (Default: 24 hours)
-**VoteOnHidServDirectoriesV2** **0**|**1**::
+[[VoteOnHidServDirectoriesV2]] **VoteOnHidServDirectoriesV2** **0**|**1**::
When this option is set in addition to **AuthoritativeDirectory**, Tor
votes on whether to accept relays as hidden service directories.
(Default: 1)
+[[AuthDirHasIPv6Connectivity]] **AuthDirHasIPv6Connectivity** **0**|**1**::
+ Authoritative directories only. When set to 0, OR ports with an
+ IPv6 address are being accepted without reachability testing.
+ When set to 1, IPv6 OR ports are being tested just like IPv4 OR
+ ports. (Default: 0)
+
HIDDEN SERVICE OPTIONS
----------------------
The following options are used to configure a hidden service.
-**HiddenServiceDir** __DIRECTORY__::
+[[HiddenServiceDir]] **HiddenServiceDir** __DIRECTORY__::
Store data files for a hidden service in DIRECTORY. Every hidden service
must have a separate directory. You may use this option multiple times to
specify multiple services. DIRECTORY must be an existing directory.
-**HiddenServicePort** __VIRTPORT__ [__TARGET__]::
+[[HiddenServicePort]] **HiddenServicePort** __VIRTPORT__ [__TARGET__]::
Configure a virtual port VIRTPORT for a hidden service. You may use this
option multiple times; each time applies to the service using the most
recent hiddenservicedir. By default, this option maps the virtual port to
@@ -1762,17 +1973,17 @@ The following options are used to configure a hidden service.
connects to that VIRTPORT, one of the TARGETs from those lines will be
chosen at random.
-**PublishHidServDescriptors** **0**|**1**::
+[[PublishHidServDescriptors]] **PublishHidServDescriptors** **0**|**1**::
If set to 0, Tor will run any hidden services you configure, but it won't
advertise them to the rendezvous directory. This option is only useful if
you're using a Tor controller that handles hidserv publishing for you.
(Default: 1)
-**HiddenServiceVersion** __version__,__version__,__...__::
+[[HiddenServiceVersion]] **HiddenServiceVersion** __version__,__version__,__...__::
A list of rendezvous service descriptor versions to publish for the hidden
service. Currently, only version 2 is supported. (Default: 2)
-**HiddenServiceAuthorizeClient** __auth-type__ __client-name__,__client-name__,__...__::
+[[HiddenServiceAuthorizeClient]] **HiddenServiceAuthorizeClient** __auth-type__ __client-name__,__client-name__,__...__::
If configured, the hidden service is accessible for authorized clients
only. The auth-type can either be \'basic' for a general-purpose
authorization protocol or \'stealth' for a less scalable protocol that also
@@ -1784,7 +1995,7 @@ The following options are used to configure a hidden service.
found in the hostname file. Clients need to put this authorization data in
their configuration file using **HidServAuth**.
-**RendPostPeriod** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
+[[RendPostPeriod]] **RendPostPeriod** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
Every time the specified period elapses, Tor uploads any rendezvous
service descriptors to the directory servers. This information is also
uploaded whenever it changes. (Default: 1 hour)
@@ -1794,10 +2005,11 @@ TESTING NETWORK OPTIONS
The following options are used for running a testing Tor network.
-**TestingTorNetwork** **0**|**1**::
+[[TestingTorNetwork]] **TestingTorNetwork** **0**|**1**::
If set to 1, Tor adjusts default values of the configuration options below,
so that it is easier to set up a testing Tor network. May only be set if
- non-default set of DirServers is set. Cannot be unset while Tor is running.
+ non-default set of DirAuthorities is set. Cannot be unset while Tor is
+ running.
(Default: 0) +
ServerDNSAllowBrokenConfig 1
@@ -1821,63 +2033,68 @@ The following options are used for running a testing Tor network.
TestingAuthDirTimeToLearnReachability 0 minutes
TestingEstimatedDescriptorPropagationTime 0 minutes
-**TestingV3AuthInitialVotingInterval** __N__ **minutes**|**hours**::
+[[TestingV3AuthInitialVotingInterval]] **TestingV3AuthInitialVotingInterval** __N__ **minutes**|**hours**::
Like V3AuthVotingInterval, but for initial voting interval before the first
consensus has been created. Changing this requires that
**TestingTorNetwork** is set. (Default: 30 minutes)
-**TestingV3AuthInitialVoteDelay** __N__ **minutes**|**hours**::
- Like TestingV3AuthInitialVoteDelay, but for initial voting interval before
+[[TestingV3AuthInitialVoteDelay]] **TestingV3AuthInitialVoteDelay** __N__ **minutes**|**hours**::
+ Like V3AuthVoteDelay, but for initial voting interval before
the first consensus has been created. Changing this requires that
**TestingTorNetwork** is set. (Default: 5 minutes)
-**TestingV3AuthInitialDistDelay** __N__ **minutes**|**hours**::
- Like TestingV3AuthInitialDistDelay, but for initial voting interval before
+[[TestingV3AuthInitialDistDelay]] **TestingV3AuthInitialDistDelay** __N__ **minutes**|**hours**::
+ Like V3AuthDistDelay, but for initial voting interval before
the first consensus has been created. Changing this requires that
**TestingTorNetwork** is set. (Default: 5 minutes)
-**TestingAuthDirTimeToLearnReachability** __N__ **minutes**|**hours**::
+[[TestingAuthDirTimeToLearnReachability]] **TestingAuthDirTimeToLearnReachability** __N__ **minutes**|**hours**::
After starting as an authority, do not make claims about whether routers
are Running until this much time has passed. Changing this requires
that **TestingTorNetwork** is set. (Default: 30 minutes)
-**TestingEstimatedDescriptorPropagationTime** __N__ **minutes**|**hours**::
+[[TestingEstimatedDescriptorPropagationTime]] **TestingEstimatedDescriptorPropagationTime** __N__ **minutes**|**hours**::
Clients try downloading router descriptors from directory caches after this
time. Changing this requires that **TestingTorNetwork** is set. (Default:
10 minutes)
+[[TestingMinFastFlagThreshold]] **TestingMinFastFlagThreshold** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
+ Minimum value for the Fast flag. Overrides the ordinary minimum taken
+ from the consensus when TestingTorNetwork is set. (Default: 0.)
+
+
SIGNALS
-------
Tor catches the following signals:
-**SIGTERM**::
+[[SIGTERM]] **SIGTERM**::
Tor will catch this, clean up and sync to disk if necessary, and exit.
-**SIGINT**::
+[[SIGINT]] **SIGINT**::
Tor clients behave as with SIGTERM; but Tor servers will do a controlled
slow shutdown, closing listeners and waiting 30 seconds before exiting.
(The delay can be configured with the ShutdownWaitLength config option.)
-**SIGHUP**::
+[[SIGHUP]] **SIGHUP**::
The signal instructs Tor to reload its configuration (including closing and
reopening logs), and kill and restart its helper processes if applicable.
-**SIGUSR1**::
+[[SIGUSR1]] **SIGUSR1**::
Log statistics about current connections, past connections, and throughput.
-**SIGUSR2**::
+[[SIGUSR2]] **SIGUSR2**::
Switch all logs to loglevel debug. You can go back to the old loglevels by
sending a SIGHUP.
-**SIGCHLD**::
+[[SIGCHLD]] **SIGCHLD**::
Tor receives this signal when one of its helper processes has exited, so it
can clean up.
-**SIGPIPE**::
+[[SIGPIPE]] **SIGPIPE**::
Tor catches this signal and ignores it.
-**SIGXFSZ**::
+[[SIGXFSZ]] **SIGXFSZ**::
If this signal exists on your platform, Tor catches and ignores it.
FILES
@@ -1972,7 +2189,7 @@ __HiddenServiceDirectory__**/client_keys**::
SEE ALSO
--------
-**privoxy**(1), **tsocks**(1), **torify**(1) +
+**privoxy**(1), **torsocks**(1), **torify**(1) +
**https://www.torproject.org/**
diff --git a/doc/torify.1.txt b/doc/torify.1.txt
index 4a4be1250..8dca90131 100644
--- a/doc/torify.1.txt
+++ b/doc/torify.1.txt
@@ -2,14 +2,14 @@
// See LICENSE for licensing information
// This is an asciidoc file used to generate the manpage/html reference.
// Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html
+:man source: Tor
+:man manual: Tor Manual
torify(1)
=========
-Peter Palfrader
-Jacob Appelbaum
NAME
----
-torify - wrapper for torsocks or tsocks and tor
+torify - wrapper for torsocks and tor
SYNOPSIS
--------
@@ -18,33 +18,25 @@ SYNOPSIS
DESCRIPTION
-----------
**torify** is a simple wrapper that attempts to find the best underlying Tor
-wrapper available on a system. It calls torsocks or tsocks with a tor specific
+wrapper available on a system. It calls torsocks with a tor specific
configuration file. +
torsocks is an improved wrapper that explicitly rejects UDP, safely resolves DNS
lookups and properly socksifies your TCP connections. +
-tsocks itself is a wrapper between the tsocks library and the application that
-you would like to run socksified. +
-
Please note that since both method use LD_PRELOAD, torify cannot be applied to
suid binaries.
WARNING
-------
-You should also be aware that the way tsocks currently works only TCP
-connections are socksified. Be aware that this will in most circumstances not
-include hostname lookups which would still be routed through your normal system
-resolver to your usual resolving nameservers. The **tor-resolve**(1) tool can be
-useful as a workaround in some cases. The Tor FAQ at
-https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ might have further
-information on this subject. +
-
When used with torsocks, torify should not leak DNS requests or UDP data. +
Both will leak ICMP data.
SEE ALSO
--------
-**tor**(1), **tor-resolve**(1), **torsocks**(1), **tsocks**(1),
-**tsocks.conf**(5).
+**tor**(1), **tor-resolve**(1), **torsocks**(1)
+
+AUTHORS
+-------
+Peter Palfrader and Jacob Appelbaum wrote this manual.
diff --git a/doc/translations.txt b/doc/translations.txt
deleted file mode 100644
index 06d16f446..000000000
--- a/doc/translations.txt
+++ /dev/null
@@ -1,182 +0,0 @@
-## Instructions for helping translate text for Vidalia, TorButton
-## and TorCheck
-## ( More translation information for Tor related apps will accumulate here )
-
-Our translations are handled in one of two places. The Tor Translation Portal
-handles all of the translations for Vidalia, Torbutton and TorCheck. The Tor
-website itself is currently handled by hand translations using subversion.
-
--------------------------------------------------------------------------
-
-For the Tor website, you'll need a Tor SVN account.
-If you do not have one and you need one, please run this command with your
-desired username in place of 'USERNAME':
- htdigest -c passwd.tmp "Tor subversion repository" USERNAME
-and send us the contents of passwd.tmp.
-
--------------------------------------------------------------------------
-
-For the Portal-based projects, all three check in their respective .po
-files into the following subversion urls:
-
- https://tor-svn.freehaven.net/svn/translation/trunk/projects/torbutton
- https://tor-svn.freehaven.net/svn/translation/trunk/projects/torcheck
- https://svn.vidalia-project.net/svn/vidalia/trunk/src/vidalia/i18n/
-
-The current pootle configuration is checked into subversion as well:
-
- https://tor-svn.freehaven.net/svn/translation/trunk/pootle
-
----------------------------- TorCheck -------------------------------
-
-TorCheck uses our translation portal to accept translations. Users use
-the portal to check in their changes. To make use of the translations
-that users have committed to the translations/ subversion module, you'll
-need to ensure that you have a current checked out copy of TorCheck:
-
- cd check/trunk/i18n/
- check/trunk/i18n$ svn up
-
-You should see something like the following:
-
- Fetching external item into 'pootle'
- External at revision 15300.
-
- At revision 15300.
-
-Now if you had changes, you'd simply want to move the newly updated .po files
-into the current stable directory. Moving the .po files from
-'check/trunk/i18n/pootle/' into 'check/trunk/i18n' properly naming the files
-for their respective locale.
-
-Here's an example of how to move all of the current pootle translations into
-the svn trunk area of TorCheck:
-
- cd check/trunk/i18n/
- for locale in `ls -1 pootle/|grep -v template`;
- do
- mv -v pootle/$locale/TorCheck_$locale.po TorCheck_$locale.po;
- done
-
-Now check the differences (ensure the output looks reasonable):
-
- svn diff
-
-Ensure that msgfmt has no errors:
-
- msgfmt -C *.po
-
-And finally check in the changes:
-
- svn commit
-
----------------------------- Torbutton -------------------------------
-
-Torbutton uses our translation portal to accept translations. Users use
-the portal to check in their changes.
-
-To make use of the translations that users have committed to the translations/
-subversion module, you'll need to ensure that you have a current checked out
-copy of them in your torbutton git checkout:
-
- cd torbutton.git/trans_tools
- torbutton.git/trans_tools$ svn co https://tor-svn.freehaven.net/svn/translation/trunk/projects/torbutton pootle
-
-You should see something like the following:
-
- Checked out revision 21092.
-
-If you made changes to strings in Torbutton, you need to rebuild the
-templates in torbutton.git/trans_tools/pootle/templates. This is done with
-the following command from within the torbutton.git checkout directory:
-
- moz2po -P -i src/chrome/locale/en/ -o trans_tools/pootle/templates/
-
-You now have two options:
-
-Option 1 (The [shitty] Pootle Web UI Way):
-
-View then commit the changes to the template with:
-
- cd trans_tools/pootle
- svn diff templates
- svn commit templates
-
-Then poke Jake to 'svn up' on the Pootle side. If you do this enough
-times, he may give you a button to click to update templates in Pootle,
-or maybe even an account on the Pootle server. Persistence is a virtue.
-
-You then need to go to the Pootle website and click the checkbox next to
-every language on:
-https://translation.torproject.org/projects/torbutton/admin.html
-and then click "Update Languages" at the bottom.
-
-You then need to go to each language and go to "Editing Options" and click
-"Commit" for each one.
-
-You then need to 'svn up' locally, and follow the procedure above for
-rebuilding your .dtd and .properties files.
-
-Yes, this sucks. :/
-
-Option 2 (Use your own msgmerge: YMMV, may change .po flags and formatting):
-
-Run msgmerge yourself for each language:
-
- cd trans_tools
- for i in `ls -1 pootle`
- do
- msgmerge -U ./pootle/$i/torbutton.dtd.po ./pootle/templates/torbutton.dtd.pot
- msgmerge -U ./pootle/$i/torbutton.properties.po ./pootle/templates/torbutton.properties.pot
- done
- svn diff pootle
- svn commit pootle
-
-Then poke Jake to 'svn up' on the Pootle side. If you do this enough times,
-he may give you a button on Pootle, or maybe even an account on the Pootle
-server. Persistence is a virtue.
-
-You may notice that some .po file flags and string formatting have changed
-with this method, depending on your gettext version. It is unclear if this
-is a problem. Please update this doc if you hit a landmine and everything
-breaks :)
-
-After this process is done, you then need to regenerate the mozilla
-.dtd and .properties files as specified above.
-
-
-Regardless of whether or not you had changes in the torbutton strings, if there
-were updated strings in pootle that you checked out from svn you now need to
-convert from .po and move the newly updated mozilla files into the current
-stable locale directory. First convert them with the 'mkmoz.sh' script and
-then move the proper mozilla files from 'torbutton.git/trans_tools/moz/' into
-'torbutton.git/src/chrome/locale/' directory while properly naming the files
-for their respective locale.
-
-Here's an example of how to move all of the current pootle translations into
-the svn trunk area of Torbutton:
-
- cd trans_tools
- ./mkmoz.sh
- for locale in `ls -1 moz/`;
- do
- mv -v moz/$locale/*.{dtd,properties} ../src/chrome/locale/$locale/
- done
-
-Now check the differences to your git branch to ensure the output looks
-reasonable:
-
- cd ..
- git diff
-
-And finally check in the changes:
-
- cd src/chrome/locale
- git commit .
-
----------------------------- Vidalia -------------------------------
-
-Vidalia uses our translation portal to accept translations. Users use the
-portal to check in their changes. No conversion or moving is required other
-than normal pootle usage.
-
diff --git a/doc/v3-authority-howto.txt b/doc/v3-authority-howto.txt
deleted file mode 100644
index e4470e8c8..000000000
--- a/doc/v3-authority-howto.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-
- How to add a v3 directory authority.
-
-What we'll be doing:
-
- We'll be configuring your Tor server as a v3 directory authority,
- generating a v3 identity key plus certificates, and adding your v3
- identity fingerprint to the list of default directory authorities.
-
-The steps:
-
-0) Make sure you're running ntp, and that your time is correct.
-
- Make sure you have Tor version at least r12724. In the short term,
- running a working authority may mean running the latest version of
- Tor from SVN trunk. Later on, we hope that it will become easier
- and you can just run a recent development release (and later still,
- a recent stable release).
-
-1) First, you'll need a certificate. Run ./src/tools/tor-gencert to
- generate one.
-
- Run tor-gencert in a separate, very secure directory. Maybe even on
- a more secure computer. The first time you run it, you will need to
- run it with the --create-identity-key option to make a v3 authority
- identity key. Subsequent times, you can just run it as-is.
-
- tor-gencert will make 3 files:
-
- authority_identity_key -- THIS IS VERY SECRET AND VERY SENSITIVE.
- DO NOT LEAK IT. DO NOT LOSE IT.
-
- authority_signing_key -- A key for signing votes and v3 conensuses.
-
- authority_certificate -- A document authenticating your signing key
- with your identity-key.
-
- You will need to rotate your signing key periodically. The current
- default lifetime is 1 year. We'll probably take this down to a month or
- two some time soon. To rotate your key, run tor-gencert as before,
- but without the --create-identity-key option.
-
-2) Copy authority_signing_key and authority_certificate to your Tor keys
- directory.
-
- For example if your data directory is /var/lib/tor/, you should run
- cp authority_signing_key authority_certificate /var/lib/tor/keys/
-
- You will need to repeat this every time you rotate your certificate.
-
-3) Tell your Tor to be a v3 authority by adding these lines to your torrc:
-
- AuthoritativeDirectory 1
- V3AuthoritativeDirectory 1
-
-4) Now your authority is generating a networkstatus opinion (called a
- "vote") every period, but none of the other authorities care yet. The
- next step is to get a Tor developer (likely Roger or Nick) to add
- your v3 identity fingerprint to the default list of dirservers.
-
- First, you need to learn your authority's v3 identity fingerprint.
- It should be in your authority_certificate file in a line like:
-
- fingerprint 3041632465FA8847A98B2C5742108C72325532D9
-
- One of the Tor developers then needs to add this fingerprint to
- the add_default_trusted_dirservers() function in config.c, using
- the syntax "v3ident=<fingerprint>". For example, if moria1's new v3
- identity fingerprint is FOO, the moria1 dirserver line should now be:
-
- DirServer moria1 v1 orport=9001 v3ident=FOO 128.31.0.34:9031 FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441
-
- The v3ident item must appear after the nickname and before the IP.
-
-5) Once your fingerprint has been added to config.c, we will try to
- get a majority of v3 authorities to upgrade, so they know about you
- too. At that point your vote will automatically be included in the
- networkstatus consensus, and you'll be a fully-functioning contributing
- v3 authority.
-
- Note also that a majority of the configured v3 authorities need to
- agree in order to generate a consensus: so this is also the point
- where extended downtime on your server means missing votes.
-
diff --git a/m4/ax_check_sign.m4 b/m4/ax_check_sign.m4
new file mode 100644
index 000000000..104b17014
--- /dev/null
+++ b/m4/ax_check_sign.m4
@@ -0,0 +1,54 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_check_sign.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_SIGN (TYPE, [ACTION-IF-SIGNED], [ACTION-IF-UNSIGNED], [INCLUDES])
+#
+# DESCRIPTION
+#
+# Checks whether TYPE is signed or not. If no INCLUDES are specified, the
+# default includes are used. If ACTION-IF-SIGNED is given, it is
+# additional shell code to execute when the type is signed. If
+# ACTION-IF-UNSIGNED is given, it is executed when the type is unsigned.
+#
+# This macro assumes that the type exists. Therefore the existence of the
+# type should be checked before calling this macro. For example:
+#
+# AC_CHECK_HEADERS([wchar.h])
+# AC_CHECK_TYPE([wchar_t],,[ AC_MSG_ERROR([Type wchar_t not found.]) ])
+# AX_CHECK_SIGN([wchar_t],
+# [ AC_DEFINE(WCHAR_T_SIGNED, 1, [Define if wchar_t is signed]) ],
+# [ AC_DEFINE(WCHAR_T_UNSIGNED, 1, [Define if wchar_t is unsigned]) ], [
+# #ifdef HAVE_WCHAR_H
+# #include <wchar.h>
+# #endif
+# ])
+#
+# LICENSE
+#
+# Copyright (c) 2008 Ville Laurikari <vl@iki.fi>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 6
+
+AU_ALIAS([VL_CHECK_SIGN], [AX_CHECK_SIGN])
+AC_DEFUN([AX_CHECK_SIGN], [
+ typename=`echo $1 | sed "s/@<:@^a-zA-Z0-9_@:>@/_/g"`
+ AC_CACHE_CHECK([whether $1 is signed], ax_cv_decl_${typename}_signed, [
+ AC_TRY_COMPILE([$4],
+ [ int foo @<:@ 1 - 2 * !((($1) -1) < 0) @:>@ ],
+ [ eval "ax_cv_decl_${typename}_signed=\"yes\"" ],
+ [ eval "ax_cv_decl_${typename}_signed=\"no\"" ])])
+ symbolname=`echo $1 | sed "s/@<:@^a-zA-Z0-9_@:>@/_/g" | tr "a-z" "A-Z"`
+ if eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"yes\""; then
+ $2
+ elif eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"no\""; then
+ $3
+ fi
+])dnl
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index fa2dd560a..000000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-
-# leave in dependency order, since common must be built first
-SUBDIRS = common or test tools win32 config
-DIST_SUBDIRS = common or test tools win32 config
-
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
deleted file mode 100644
index 5e7684259..000000000
--- a/src/common/Makefile.am
+++ /dev/null
@@ -1,67 +0,0 @@
-
-noinst_LIBRARIES = libor.a libor-crypto.a libor-event.a
-
-EXTRA_DIST = common_sha1.i sha256.c Makefile.nmake
-
-#CFLAGS = -Wall -Wpointer-arith -O2
-
-if USE_OPENBSD_MALLOC
-libor_extra_source=OpenBSD_malloc_Linux.c
-else
-libor_extra_source=
-endif
-
-libor_a_SOURCES = \
- address.c \
- compat.c \
- container.c \
- di_ops.c \
- log.c \
- memarea.c \
- mempool.c \
- procmon.c \
- util.c \
- util_codedigest.c \
- $(libor_extra_source)
-
-libor_crypto_a_SOURCES = \
- aes.c \
- crypto.c \
- torgzip.c \
- tortls.c
-
-libor_event_a_SOURCES = compat_libevent.c
-
-noinst_HEADERS = \
- address.h \
- aes.h \
- ciphers.inc \
- compat.h \
- compat_libevent.h \
- container.h \
- crypto.h \
- di_ops.h \
- ht.h \
- memarea.h \
- mempool.h \
- procmon.h \
- strlcat.c \
- strlcpy.c \
- torgzip.h \
- torint.h \
- torlog.h \
- tortls.h \
- util.h
-
-common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)
- if test "@SHA1SUM@" != none; then \
- (cd "$(srcdir)" && "@SHA1SUM@" $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > common_sha1.i; \
- elif test "@OPENSSL@" != none; then \
- (cd "$(srcdir)" && "@OPENSSL@" sha1 $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > common_sha1.i; \
- else \
- rm common_sha1.i; \
- touch common_sha1.i; \
- fi
-
-util_codedigest.o: common_sha1.i
-crypto.o: sha256.c
diff --git a/src/common/Makefile.nmake b/src/common/Makefile.nmake
index e54827367..0ebeaaaf7 100644
--- a/src/common/Makefile.nmake
+++ b/src/common/Makefile.nmake
@@ -1,15 +1,19 @@
all: libor.lib libor-crypto.lib libor-event.lib
-CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include
+CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\ext
LIBOR_OBJECTS = address.obj compat.obj container.obj di_ops.obj \
log.obj memarea.obj mempool.obj procmon.obj util.obj \
util_codedigest.obj
-LIBOR_CRYPTO_OBJECTS = aes.obj crypto.obj torgzip.obj tortls.obj
+LIBOR_CRYPTO_OBJECTS = aes.obj crypto.obj torgzip.obj tortls.obj \
+ crypto_curve25519.obj curve25519-donna.obj
LIBOR_EVENT_OBJECTS = compat_libevent.obj
+curve25519-donna.obj: ..\ext\curve25519_donna\curve25519-donna.c
+ $(CC) $(CFLAGS) /D inline=_inline /c ..\ext\curve25519_donna\curve25519-donna.c
+
libor.lib: $(LIBOR_OBJECTS)
lib $(LIBOR_OBJECTS) /out:libor.lib
@@ -18,3 +22,6 @@ libor-crypto.lib: $(LIBOR_CRYPTO_OBJECTS)
libor-event.lib: $(LIBOR_EVENT_OBJECTS)
lib $(LIBOR_EVENT_OBJECTS) /out:libor-event.lib
+
+clean:
+ del *.obj *.lib libor*.lib
diff --git a/src/common/address.c b/src/common/address.c
index df26f61f8..14a7b6bc9 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -181,6 +181,16 @@ tor_addr_make_unspec(tor_addr_t *a)
a->family = AF_UNSPEC;
}
+/** Set address <a>a</b> to the null address in address family <b>family</b>.
+ * The null address for AF_INET is 0.0.0.0. The null address for AF_INET6 is
+ * [::]. AF_UNSPEC is all null. */
+void
+tor_addr_make_null(tor_addr_t *a, sa_family_t family)
+{
+ memset(a, 0, sizeof(*a));
+ a->family = family;
+}
+
/** 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
@@ -305,7 +315,8 @@ tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr)
* also treated as internal for now.)
*/
int
-tor_addr_is_internal(const tor_addr_t *addr, int for_listening)
+tor_addr_is_internal_(const tor_addr_t *addr, int for_listening,
+ const char *filename, int lineno)
{
uint32_t iph4 = 0;
uint32_t iph6[4];
@@ -355,8 +366,8 @@ tor_addr_is_internal(const tor_addr_t *addr, int for_listening)
/* unknown address family... assume it's not safe for external use */
/* rather than tor_assert(0) */
- log_warn(LD_BUG, "tor_addr_is_internal() called with a non-IP address of "
- "type %d", (int)v_family);
+ log_warn(LD_BUG, "tor_addr_is_internal() called from %s:%d with a "
+ "non-IP address of type %d", filename, lineno, (int)v_family);
tor_fragile_assert();
return 1;
}
@@ -558,9 +569,22 @@ tor_addr_to_PTR_name(char *out, size_t outlen,
*
* Return an address family on success, or -1 if an invalid address string is
* provided.
+ *
+ * If 'flags & TAPMP_EXTENDED_STAR' is false, then the wildcard address '*'
+ * yield an IPv4 wildcard.
+ *
+ * If 'flags & TAPMP_EXTENDED_STAR' is true, then the wildcard address '*'
+ * yields an AF_UNSPEC wildcard address, and the following change is made
+ * in the grammar above:
+ * Address ::= IPv4Address / "[" IPv6Address "]" / "*" / "*4" / "*6"
+ * with the new "*4" and "*6" productions creating a wildcard to match
+ * IPv4 or IPv6 addresses.
+ *
*/
int
-tor_addr_parse_mask_ports(const char *s, tor_addr_t *addr_out,
+tor_addr_parse_mask_ports(const char *s,
+ unsigned flags,
+ tor_addr_t *addr_out,
maskbits_t *maskbits_out,
uint16_t *port_min_out, uint16_t *port_max_out)
{
@@ -617,9 +641,23 @@ tor_addr_parse_mask_ports(const char *s, tor_addr_t *addr_out,
memset(addr_out, 0, sizeof(tor_addr_t));
if (!strcmp(address, "*")) {
- family = AF_INET; /* AF_UNSPEC ???? XXXX_IP6 */
+ if (flags & TAPMP_EXTENDED_STAR) {
+ family = AF_UNSPEC;
+ tor_addr_make_unspec(addr_out);
+ } else {
+ family = AF_INET;
+ tor_addr_from_ipv4h(addr_out, 0);
+ }
+ any_flag = 1;
+ } else if (!strcmp(address, "*4") && (flags & TAPMP_EXTENDED_STAR)) {
+ family = AF_INET;
tor_addr_from_ipv4h(addr_out, 0);
any_flag = 1;
+ } else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) {
+ static char nil_bytes[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ family = AF_INET6;
+ tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
+ any_flag = 1;
} else if (tor_inet_pton(AF_INET6, address, &in6_tmp) > 0) {
family = AF_INET6;
tor_addr_from_in6(addr_out, &in6_tmp);
@@ -1007,6 +1045,19 @@ fmt_addr_impl(const tor_addr_t *addr, int decorate)
return "???";
}
+/** Return a string representing the pair <b>addr</b> and <b>port</b>.
+ * This calls fmt_and_decorate_addr internally, so IPv6 addresses will
+ * have brackets, and the caveats of fmt_addr_impl apply.
+ */
+const char *
+fmt_addrport(const tor_addr_t *addr, uint16_t port)
+{
+ /* Add space for a colon and up to 5 digits. */
+ static char buf[TOR_ADDR_BUF_LEN + 6];
+ tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port);
+ return buf;
+}
+
/** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4
* addresses. Also not thread-safe, also clobbers its return buffer on
* repeated calls. */
@@ -1136,6 +1187,8 @@ get_interface_addresses_raw(int severity)
result = smartlist_new();
for (i = ifa; i; i = i->ifa_next) {
tor_addr_t tmp;
+ if ((i->ifa_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
+ continue;
if (!i->ifa_addr)
continue;
if (i->ifa_addr->sa_family != AF_INET &&
@@ -1220,14 +1273,14 @@ get_interface_addresses_raw(int severity)
/* This interface, AFAICT, only supports AF_INET addresses */
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
- log(severity, LD_NET, "socket failed: %s", strerror(errno));
+ tor_log(severity, LD_NET, "socket failed: %s", strerror(errno));
goto done;
}
/* Guess how much space we need. */
ifc.ifc_len = sz = 15*1024;
ifc.ifc_ifcu.ifcu_req = tor_malloc(sz);
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
- log(severity, LD_NET, "ioctl failed: %s", strerror(errno));
+ tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno));
close(fd);
goto done;
}
@@ -1380,7 +1433,46 @@ is_internal_IP(uint32_t ip, int for_listening)
return tor_addr_is_internal(&myaddr, for_listening);
}
-/** Given an address of the form "host:port", try to divide it into its host
+/** Given an address of the form "ip:port", try to divide it into its
+ * ip 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.
+ *
+ * Don't do DNS lookups and don't allow domain names in the <ip> field.
+ * Don't accept <b>addrport</b> of the form "<ip>" or "<ip>:0".
+ *
+ * Return 0 on success, -1 on failure. */
+int
+tor_addr_port_parse(int severity, const char *addrport,
+ tor_addr_t *address_out, uint16_t *port_out)
+{
+ int retval = -1;
+ int r;
+ char *addr_tmp = NULL;
+
+ tor_assert(addrport);
+ tor_assert(address_out);
+ tor_assert(port_out);
+
+ r = tor_addr_port_split(severity, addrport, &addr_tmp, port_out);
+ if (r < 0)
+ goto done;
+
+ if (!*port_out)
+ goto done;
+
+ /* make sure that address_out is an IP address */
+ if (tor_addr_parse(address_out, addr_tmp) < 0)
+ goto done;
+
+ retval = 0;
+
+ done:
+ tor_free(addr_tmp);
+ return retval;
+}
+
+/** Given an address of the form "host[:port]", try to divide it into its host
* ane 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. */
@@ -1409,17 +1501,17 @@ addr_port_lookup(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out)
{
const char *colon;
- char *_address = NULL;
- int _port;
+ char *address_ = NULL;
+ int port_;
int ok = 1;
tor_assert(addrport);
colon = strrchr(addrport, ':');
if (colon) {
- _address = tor_strndup(addrport, colon-addrport);
- _port = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL);
- if (!_port) {
+ address_ = tor_strndup(addrport, colon-addrport);
+ port_ = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL);
+ if (!port_) {
log_fn(severity, LD_GENERAL, "Port %s out of range", escaped(colon+1));
ok = 0;
}
@@ -1432,28 +1524,28 @@ addr_port_lookup(int severity, const char *addrport, char **address,
ok = 0;
}
} else {
- _address = tor_strdup(addrport);
- _port = 0;
+ address_ = tor_strdup(addrport);
+ port_ = 0;
}
if (addr) {
/* There's an addr pointer, so we need to resolve the hostname. */
- if (tor_lookup_hostname(_address,addr)) {
- log_fn(severity, LD_NET, "Couldn't look up %s", escaped(_address));
+ if (tor_lookup_hostname(address_,addr)) {
+ log_fn(severity, LD_NET, "Couldn't look up %s", escaped(address_));
ok = 0;
*addr = 0;
}
}
if (address && ok) {
- *address = _address;
+ *address = address_;
} else {
if (address)
*address = NULL;
- tor_free(_address);
+ tor_free(address_);
}
if (port_out)
- *port_out = ok ? ((uint16_t) _port) : 0;
+ *port_out = ok ? ((uint16_t) port_) : 0;
return ok ? 0 : -1;
}
@@ -1476,32 +1568,6 @@ addr_mask_get_bits(uint32_t mask)
return -1;
}
-/** Compare two addresses <b>a1</b> and <b>a2</b> for equality under a
- * netmask of <b>mbits</b> bits. Return -1, 0, or 1.
- *
- * XXXX_IP6 Temporary function to allow masks as bitcounts everywhere. This
- * will be replaced with an IPv6-aware version as soon as 32-bit addresses are
- * no longer passed around.
- */
-int
-addr_mask_cmp_bits(uint32_t a1, uint32_t a2, maskbits_t bits)
-{
- if (bits > 32)
- bits = 32;
- else if (bits == 0)
- return 0;
-
- a1 >>= (32-bits);
- a2 >>= (32-bits);
-
- if (a1 < a2)
- return -1;
- else if (a1 > a2)
- return 1;
- else
- return 0;
-}
-
/** Parse a string <b>s</b> in the format of (*|port(-maxport)?)?, setting the
* various *out pointers as appropriate. Return 0 on success, -1 on failure.
*/
@@ -1554,93 +1620,6 @@ parse_port_range(const char *port, uint16_t *port_min_out,
return 0;
}
-/** Parse a string <b>s</b> in the format of
- * (IP(/mask|/mask-bits)?|*)(:(*|port(-maxport))?)?, setting the various
- * *out pointers as appropriate. Return 0 on success, -1 on failure.
- */
-int
-parse_addr_and_port_range(const char *s, uint32_t *addr_out,
- maskbits_t *maskbits_out, uint16_t *port_min_out,
- uint16_t *port_max_out)
-{
- char *address;
- char *mask, *port, *endptr;
- struct in_addr in;
- int bits;
-
- tor_assert(s);
- tor_assert(addr_out);
- tor_assert(maskbits_out);
- tor_assert(port_min_out);
- tor_assert(port_max_out);
-
- address = tor_strdup(s);
- /* Break 'address' into separate strings.
- */
- mask = strchr(address,'/');
- port = strchr(mask?mask:address,':');
- if (mask)
- *mask++ = '\0';
- if (port)
- *port++ = '\0';
- /* Now "address" is the IP|'*' part...
- * "mask" is the Mask|Maskbits part...
- * and "port" is the *|port|min-max part.
- */
-
- if (strcmp(address,"*")==0) {
- *addr_out = 0;
- } else if (tor_inet_aton(address, &in) != 0) {
- *addr_out = ntohl(in.s_addr);
- } else {
- log_warn(LD_GENERAL, "Malformed IP %s in address pattern; rejecting.",
- escaped(address));
- goto err;
- }
-
- if (!mask) {
- if (strcmp(address,"*")==0)
- *maskbits_out = 0;
- else
- *maskbits_out = 32;
- } else {
- endptr = NULL;
- bits = (int) strtol(mask, &endptr, 10);
- if (!*endptr) {
- /* strtol handled the whole mask. */
- if (bits < 0 || bits > 32) {
- log_warn(LD_GENERAL,
- "Bad number of mask bits on address range; rejecting.");
- goto err;
- }
- *maskbits_out = bits;
- } else if (tor_inet_aton(mask, &in) != 0) {
- bits = addr_mask_get_bits(ntohl(in.s_addr));
- if (bits < 0) {
- log_warn(LD_GENERAL,
- "Mask %s on address range isn't a prefix; dropping",
- escaped(mask));
- goto err;
- }
- *maskbits_out = bits;
- } else {
- log_warn(LD_GENERAL,
- "Malformed mask %s on address range; rejecting.",
- escaped(mask));
- goto err;
- }
- }
-
- if (parse_port_range(port, port_min_out, port_max_out)<0)
- goto err;
-
- tor_free(address);
- return 0;
- err:
- tor_free(address);
- return -1;
-}
-
/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual),
* write it as a string into the <b>buf_len</b>-byte buffer in
* <b>buf</b>.
@@ -1698,3 +1677,15 @@ tor_addr_hostname_is_local(const char *name)
!strcasecmpend(name, ".local");
}
+/** Return a newly allocated tor_addr_port_t with <b>addr</b> and
+ <b>port</b> filled in. */
+tor_addr_port_t *
+tor_addr_port_new(const tor_addr_t *addr, uint16_t port)
+{
+ tor_addr_port_t *ap = tor_malloc_zero(sizeof(tor_addr_port_t));
+ if (addr)
+ tor_addr_copy(&ap->addr, addr);
+ ap->port = port;
+ return ap;
+}
+
diff --git a/src/common/address.h b/src/common/address.h
index c6c126862..77e585534 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,8 +8,8 @@
* \brief Headers for address.h
**/
-#ifndef _TOR_ADDRESS_H
-#define _TOR_ADDRESS_H
+#ifndef TOR_ADDRESS_H
+#define TOR_ADDRESS_H
#include "orconfig.h"
#include "torint.h"
@@ -40,7 +40,7 @@ typedef struct tor_addr_port_t
uint16_t port;
} tor_addr_port_t;
-#define TOR_ADDR_NULL {AF_UNSPEC, {0}};
+#define TOR_ADDR_NULL {AF_UNSPEC, {0}}
static INLINE const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a);
static INLINE uint32_t tor_addr_to_ipv4n(const tor_addr_t *a);
@@ -55,6 +55,7 @@ socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port,
int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
uint16_t *port_out);
void tor_addr_make_unspec(tor_addr_t *a);
+void tor_addr_make_null(tor_addr_t *a, sa_family_t family);
char *tor_sockaddr_to_str(const struct sockaddr *sa);
/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
@@ -145,6 +146,7 @@ char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC;
* addresses. */
#define fmt_and_decorate_addr(a) fmt_addr_impl((a), 1)
const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
+const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
const char * fmt_addr32(uint32_t addr);
int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr);
@@ -167,7 +169,10 @@ int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
unsigned int tor_addr_hash(const tor_addr_t *addr);
int tor_addr_is_v4(const tor_addr_t *addr);
-int tor_addr_is_internal(const tor_addr_t *ip, int for_listening);
+int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening,
+ const char *filename, int lineno);
+#define tor_addr_is_internal(addr, for_listening) \
+ tor_addr_is_internal_((addr), (for_listening), SHORT_FILE__, __LINE__)
/** Longest length that can be required for a reverse lookup name. */
/* 32 nybbles, 32 dots, 8 characters of "ip6.arpa", 1 NUL: 73 characters. */
@@ -179,7 +184,8 @@ int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out,
uint16_t *port_out);
-int tor_addr_parse_mask_ports(const char *s,
+#define TAPMP_EXTENDED_STAR 1
+int tor_addr_parse_mask_ports(const char *s, unsigned flags,
tor_addr_t *addr_out, maskbits_t *mask_out,
uint16_t *port_min_out, uint16_t *port_max_out);
const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len,
@@ -202,6 +208,9 @@ int tor_addr_is_loopback(const tor_addr_t *addr);
int tor_addr_port_split(int severity, const char *addrport,
char **address_out, uint16_t *port_out);
+int tor_addr_port_parse(int severity, const char *addrport,
+ tor_addr_t *address_out, uint16_t *port_out);
+
int tor_addr_hostname_is_local(const char *name);
/* IPv4 helpers */
@@ -210,16 +219,14 @@ int addr_port_lookup(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out);
int parse_port_range(const char *port, uint16_t *port_min_out,
uint16_t *port_max_out);
-int parse_addr_and_port_range(const char *s, uint32_t *addr_out,
- maskbits_t *maskbits_out, uint16_t *port_min_out,
- uint16_t *port_max_out);
int addr_mask_get_bits(uint32_t mask);
-int addr_mask_cmp_bits(uint32_t a1, uint32_t a2, maskbits_t bits);
/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/
#define INET_NTOA_BUF_LEN 16
int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
int get_interface_address(int severity, uint32_t *addr);
+tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
+
#endif
diff --git a/src/common/aes.c b/src/common/aes.c
index 295a90749..f454a7f7b 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -41,6 +41,7 @@
#include "aes.h"
#include "util.h"
#include "torlog.h"
+#include "di_ops.h"
#ifdef ANDROID
/* Android's OpenSSL seems to have removed all of its Engine support. */
@@ -134,8 +135,8 @@ int
evaluate_evp_for_aes(int force_val)
{
(void) force_val;
- log_notice(LD_CRYPTO, "This version of OpenSSL has a known-good EVP "
- "counter-mode implementation. Using it.");
+ log_info(LD_CRYPTO, "This version of OpenSSL has a known-good EVP "
+ "counter-mode implementation. Using it.");
return 0;
}
int
@@ -212,11 +213,11 @@ evaluate_evp_for_aes(int force_val)
e = ENGINE_get_cipher_engine(NID_aes_128_ecb);
if (e) {
- log_notice(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.",
+ log_info(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.",
ENGINE_get_name(e));
should_use_EVP = 1;
} else {
- log_notice(LD_CRYPTO, "No AES engine found; using AES_* functions.");
+ log_info(LD_CRYPTO, "No AES engine found; using AES_* functions.");
should_use_EVP = 0;
}
#endif
@@ -257,18 +258,18 @@ evaluate_ctr_for_aes(void)
for (i=0; i<16; ++i)
AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos);
- if (memcmp(output, encrypt_zero, 16)) {
+ if (fast_memneq(output, encrypt_zero, 16)) {
/* Counter mode is buggy */
log_notice(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; "
"not using it.");
} else {
/* Counter mode is okay */
- log_notice(LD_CRYPTO, "This OpenSSL has a good implementation of counter "
+ log_info(LD_CRYPTO, "This OpenSSL has a good implementation of counter "
"mode; using it.");
should_use_openssl_CTR = 1;
}
#else
- log_notice(LD_CRYPTO, "This version of OpenSSL has a slow implementation of "
+ log_info(LD_CRYPTO, "This version of OpenSSL has a slow implementation of "
"counter mode; not using it.");
#endif
return 0;
@@ -285,7 +286,7 @@ evaluate_ctr_for_aes(void)
* value of the current counter.
*/
static INLINE void
-_aes_fill_buf(aes_cnt_cipher_t *cipher)
+aes_fill_buf_(aes_cnt_cipher_t *cipher)
{
/* We don't currently use OpenSSL's counter mode implementation because:
* 1) some versions have known bugs
@@ -340,7 +341,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
EVP_EncryptInit(&cipher->key.evp, c, (const unsigned char*)key, NULL);
cipher->using_evp = 1;
} else {
- AES_set_encrypt_key((const unsigned char *)key, key_bits, &cipher->key.aes);
+ AES_set_encrypt_key((const unsigned char *)key, key_bits,&cipher->key.aes);
cipher->using_evp = 0;
}
@@ -360,7 +361,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
memset(cipher->buf, 0, sizeof(cipher->buf));
else
#endif
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
/** Release storage held by <b>cipher</b>
@@ -387,9 +388,10 @@ aes_cipher_free(aes_cnt_cipher_t *cipher)
#ifdef CAN_USE_OPENSSL_CTR
/* Helper function to use EVP with openssl's counter-mode wrapper. */
-static void evp_block128_fn(const uint8_t in[16],
- uint8_t out[16],
- const void *key)
+static void
+evp_block128_fn(const uint8_t in[16],
+ uint8_t out[16],
+ const void *key)
{
EVP_CIPHER_CTX *ctx = (void*)key;
int inl=16, outl=16;
@@ -429,8 +431,7 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
&cipher->pos);
}
return;
- }
- else
+ } else
#endif
{
int c = cipher->pos;
@@ -453,7 +454,7 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
UPDATE_CTR_BUF(cipher, 1);
}
UPDATE_CTR_BUF(cipher, 0);
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
}
}
@@ -469,8 +470,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
if (should_use_openssl_CTR) {
aes_crypt(cipher, data, len, data);
return;
- }
- else
+ } else
#endif
{
int c = cipher->pos;
@@ -493,7 +493,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
UPDATE_CTR_BUF(cipher, 1);
}
UPDATE_CTR_BUF(cipher, 0);
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
}
}
@@ -515,7 +515,8 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv)
#ifdef CAN_USE_OPENSSL_CTR
if (!should_use_openssl_CTR)
#endif
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
#endif
+
diff --git a/src/common/aes.h b/src/common/aes.h
index bde567f87..8ff28a762 100644
--- a/src/common/aes.h
+++ b/src/common/aes.h
@@ -1,12 +1,12 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Implements a minimal interface to counter-mode AES. */
-#ifndef _TOR_AES_H
-#define _TOR_AES_H
+#ifndef TOR_AES_H
+#define TOR_AES_H
/**
* \file aes.h
diff --git a/src/common/compat.c b/src/common/compat.c
index 59e3898de..d88c5f92d 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,7 +18,7 @@
/* XXXX024 We should just use AC_USE_SYSTEM_EXTENSIONS in our autoconf,
* and get this (and other important stuff!) automatically. Once we do that,
* make sure to also change the extern char **environ detection in
- * configure.in, because whether that is declared or not depends on whether
+ * configure.ac, because whether that is declared or not depends on whether
* we have _GNU_SOURCE defined! Maybe that means that once we take this out,
* we can also take out the configure check. */
#define _GNU_SOURCE
@@ -137,8 +137,13 @@ tor_open_cloexec(const char *path, int flags, unsigned mode)
fd = open(path, flags, mode);
#ifdef FD_CLOEXEC
- if (fd >= 0)
- fcntl(fd, F_SETFD, FD_CLOEXEC);
+ if (fd >= 0) {
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ }
#endif
return fd;
}
@@ -150,8 +155,13 @@ tor_fopen_cloexec(const char *path, const char *mode)
{
FILE *result = fopen(path, mode);
#ifdef FD_CLOEXEC
- if (result != NULL)
- fcntl(fileno(result), F_SETFD, FD_CLOEXEC);
+ if (result != NULL) {
+ if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
+ fclose(result);
+ return NULL;
+ }
+ }
#endif
return result;
}
@@ -425,11 +435,10 @@ tor_vasprintf(char **strp, const char *fmt, va_list args)
else
*strp = strp_tmp;
return r;
-#elif defined(_MSC_VER)
+#elif defined(HAVE__VSCPRINTF)
/* On Windows, _vsnprintf won't tell us the length of the string if it
* overflows, so we need to use _vcsprintf to tell how much to allocate */
int len, r;
- char *res;
len = _vscprintf(fmt, args);
if (len < 0) {
*strp = NULL;
@@ -861,6 +870,9 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
/** @{ */
/** Some old versions of Unix didn't define constants for these values,
* and instead expect you to say 0, 1, or 2. */
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
@@ -891,6 +903,18 @@ tor_fd_seekend(int fd)
#endif
}
+/** Move <b>fd</b> to position <b>pos</b> in the file. Return -1 on error, 0
+ * on success. */
+int
+tor_fd_setpos(int fd, off_t pos)
+{
+#ifdef _WIN32
+ return _lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0;
+#else
+ return lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0;
+#endif
+}
+
#undef DEBUG_SOCKET_COUNTING
#ifdef DEBUG_SOCKET_COUNTING
/** A bitarray of all fds that should be passed to tor_socket_close(). Only
@@ -1025,7 +1049,15 @@ tor_open_socket(int domain, int type, int protocol)
return s;
#if defined(FD_CLOEXEC)
- fcntl(s, F_SETFD, FD_CLOEXEC);
+ if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
+#if defined(_WIN32)
+ closesocket(s);
+#else
+ close(s);
+#endif
+ return -1;
+ }
#endif
goto socket_ok; /* So that socket_ok will not be unused. */
@@ -1060,7 +1092,11 @@ tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
return s;
#if defined(FD_CLOEXEC)
- fcntl(s, F_SETFD, FD_CLOEXEC);
+ if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno));
+ close(s);
+ return TOR_INVALID_SOCKET;
+ }
#endif
goto socket_ok; /* So that socket_ok will not be unused. */
@@ -1084,17 +1120,31 @@ get_n_open_sockets(void)
return n;
}
-/** Turn <b>socket</b> into a nonblocking socket.
+/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1
+ * on failure.
*/
-void
+int
set_socket_nonblocking(tor_socket_t socket)
{
#if defined(_WIN32)
unsigned long nonblocking = 1;
ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking);
#else
- fcntl(socket, F_SETFL, O_NONBLOCK);
+ int flags;
+
+ flags = fcntl(socket, F_GETFL, 0);
+ if (flags == -1) {
+ log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno));
+ return -1;
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(socket, F_SETFL, flags) == -1) {
+ log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno));
+ return -1;
+ }
#endif
+
+ return 0;
}
/**
@@ -1137,10 +1187,22 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
return -errno;
#if defined(FD_CLOEXEC)
- if (SOCKET_OK(fd[0]))
- fcntl(fd[0], F_SETFD, FD_CLOEXEC);
- if (SOCKET_OK(fd[1]))
- fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+ if (SOCKET_OK(fd[0])) {
+ r = fcntl(fd[0], F_SETFD, FD_CLOEXEC);
+ if (r == -1) {
+ close(fd[0]);
+ close(fd[1]);
+ return -errno;
+ }
+ }
+ if (SOCKET_OK(fd[1])) {
+ r = fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+ if (r == -1) {
+ close(fd[0]);
+ close(fd[1]);
+ return -errno;
+ }
+ }
#endif
goto sockets_ok; /* So that sockets_ok will not be unused. */
@@ -1163,9 +1225,9 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
* for now, and really, when localhost is down sometimes, we
* have other problems too.
*/
- tor_socket_t listener = -1;
- tor_socket_t connector = -1;
- tor_socket_t acceptor = -1;
+ tor_socket_t listener = TOR_INVALID_SOCKET;
+ tor_socket_t connector = TOR_INVALID_SOCKET;
+ tor_socket_t acceptor = TOR_INVALID_SOCKET;
struct sockaddr_in listen_addr;
struct sockaddr_in connect_addr;
int size;
@@ -1219,7 +1281,6 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
goto tidy_up_and_fail;
if (size != sizeof(listen_addr))
goto abort_tidy_up_and_fail;
- tor_close_socket(listener);
/* Now check we are talking to ourself by matching port and host on the
two sockets. */
if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
@@ -1230,6 +1291,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
|| listen_addr.sin_port != connect_addr.sin_port) {
goto abort_tidy_up_and_fail;
}
+ tor_close_socket(listener);
fd[0] = connector;
fd[1] = acceptor;
@@ -1244,11 +1306,11 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
tidy_up_and_fail:
if (saved_errno < 0)
saved_errno = errno;
- if (listener != -1)
+ if (SOCKET_OK(listener))
tor_close_socket(listener);
- if (connector != -1)
+ if (SOCKET_OK(connector))
tor_close_socket(connector);
- if (acceptor != -1)
+ if (SOCKET_OK(acceptor))
tor_close_socket(acceptor);
return -saved_errno;
#endif
@@ -1256,7 +1318,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
/** Number of extra file descriptors to keep in reserve beyond those that we
* tell Tor it's allowed to use. */
-#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond _ConnLimit */
+#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */
/** Learn the maximum allowed number of file descriptors, and tell the system
* we want to use up to that number. (Some systems have a low soft limit, and
@@ -2060,30 +2122,6 @@ tor_lookup_hostname(const char *name, uint32_t *addr)
return -1;
}
-/** Initialize the insecure libc RNG. */
-void
-tor_init_weak_random(unsigned seed)
-{
-#ifdef _WIN32
- srand(seed);
-#else
- srandom(seed);
-#endif
-}
-
-/** Return a randomly chosen value in the range 0..TOR_RAND_MAX. This
- * entropy will not be cryptographically strong; do not rely on it
- * for anything an adversary should not be able to predict. */
-long
-tor_weak_random(void)
-{
-#ifdef _WIN32
- return rand();
-#else
- return random();
-#endif
-}
-
/** Hold the result of our call to <b>uname</b>. */
static char uname_result[256];
/** True iff uname_result is set. */
@@ -2290,8 +2328,33 @@ compute_num_cpus_impl(void)
return (int)info.dwNumberOfProcessors;
else
return -1;
-#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
- long cpus = sysconf(_SC_NPROCESSORS_CONF);
+#elif defined(HAVE_SYSCONF)
+#ifdef _SC_NPROCESSORS_CONF
+ long cpus_conf = sysconf(_SC_NPROCESSORS_CONF);
+#else
+ long cpus_conf = -1;
+#endif
+#ifdef _SC_NPROCESSORS_ONLN
+ long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ long cpus_onln = -1;
+#endif
+ long cpus = -1;
+
+ if (cpus_conf > 0 && cpus_onln < 0) {
+ cpus = cpus_conf;
+ } else if (cpus_onln > 0 && cpus_conf < 0) {
+ cpus = cpus_onln;
+ } else if (cpus_onln > 0 && cpus_conf > 0) {
+ if (cpus_onln < cpus_conf) {
+ log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them "
+ "are available. Telling Tor to only use %ld. You can over"
+ "ride this with the NumCPUs option",
+ cpus_conf, cpus_onln, cpus_onln);
+ }
+ cpus = cpus_onln;
+ }
+
if (cpus >= 1 && cpus < INT_MAX)
return (int)cpus;
else
@@ -2759,7 +2822,7 @@ tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex)
EnterCriticalSection(&cond->mutex);
tor_assert(WaitForSingleObject(event, 0) == WAIT_TIMEOUT);
- tor_assert(!smartlist_isin(cond->events, event));
+ tor_assert(!smartlist_contains(cond->events, event));
smartlist_add(cond->events, event);
LeaveCriticalSection(&cond->mutex);
diff --git a/src/common/compat.h b/src/common/compat.h
index 42648bb04..51fb8c527 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -1,10 +1,10 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_COMPAT_H
-#define _TOR_COMPAT_H
+#ifndef TOR_COMPAT_H
+#define TOR_COMPAT_H
#include "orconfig.h"
#include "torint.h"
@@ -53,13 +53,13 @@
#endif
#include <stdio.h>
+#include <errno.h>
#if defined (WINCE)
#include <fcntl.h>
#include <io.h>
#include <math.h>
#include <projects.h>
-#define snprintf _snprintf
/* this is not exported as W .... */
#define SHGetPathFromIDListW SHGetPathFromIDList
/* wcecompat has vasprintf */
@@ -74,6 +74,10 @@
#error "It seems your platform does not represent NULL as zero. We can't cope."
#endif
+#ifndef DOUBLE_0_REP_IS_ZERO_BYTES
+#error "It seems your platform does not represent 0.0 as zeros. We can't cope."
+#endif
+
#if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32
#error "It seems that you encode characters in something other than ASCII."
#endif
@@ -132,6 +136,16 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
#define DBL_TO_U64(x) ((uint64_t) (x))
#endif
+#ifdef ENUM_VALS_ARE_SIGNED
+#define ENUM_BF(t) unsigned
+#else
+/** Wrapper for having a bitfield of an enumerated type. Where possible, we
+ * just use the enumerated type (so the compiler can help us and notice
+ * problems), but if enumerated types are unsigned, we must use unsigned,
+ * so that the loss of precision doesn't make large values negative. */
+#define ENUM_BF(t) t
+#endif
+
/* GCC has several useful attributes. */
#if defined(__GNUC__) && __GNUC__ >= 3
#define ATTR_NORETURN __attribute__((noreturn))
@@ -148,6 +162,7 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
*
* #define ATTR_NONNULL(x) __attribute__((nonnull x)) */
#define ATTR_NONNULL(x)
+#define ATTR_UNUSED __attribute__ ((unused))
/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value
* of <b>exp</b> will probably be true.
@@ -171,6 +186,7 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
#define ATTR_MALLOC
#define ATTR_NORETURN
#define ATTR_NONNULL(x)
+#define ATTR_UNUSED
#define PREDICT_LIKELY(exp) (exp)
#define PREDICT_UNLIKELY(exp) (exp)
#endif
@@ -239,6 +255,19 @@ size_t strlcpy(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2));
#define I64_FORMAT "%lld"
#endif
+#if (SIZEOF_INTPTR_T == SIZEOF_INT)
+#define INTPTR_T_FORMAT "%d"
+#define INTPTR_PRINTF_ARG(x) ((int)(x))
+#elif (SIZEOF_INTPTR_T == SIZEOF_LONG)
+#define INTPTR_T_FORMAT "%ld"
+#define INTPTR_PRINTF_ARG(x) ((long)(x))
+#elif (SIZEOF_INTPTR_T == 8)
+#define INTPTR_T_FORMAT I64_FORMAT
+#define INTPTR_PRINTF_ARG(x) I64_PRINTF_ARG(x)
+#else
+#error Unknown: SIZEOF_INTPTR_T
+#endif
+
/** Represents an mmaped file. Allocated via tor_mmap_file; freed with
* tor_munmap_file. */
typedef struct tor_mmap_t {
@@ -308,10 +337,10 @@ char *tor_strtok_r_impl(char *str, const char *sep, char **lasts);
#endif
#ifdef _WIN32
-#define _SHORT_FILE_ (tor_fix_source_file(__FILE__))
+#define SHORT_FILE__ (tor_fix_source_file(__FILE__))
const char *tor_fix_source_file(const char *fname);
#else
-#define _SHORT_FILE_ (__FILE__)
+#define SHORT_FILE__ (__FILE__)
#define tor_fix_source_file(s) (s)
#endif
@@ -384,6 +413,7 @@ tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking,
void tor_lockfile_unlock(tor_lockfile_t *lockfile);
off_t tor_fd_getpos(int fd);
+int tor_fd_setpos(int fd, off_t pos);
int tor_fd_seekend(int fd);
#ifdef _WIN32
@@ -403,11 +433,13 @@ typedef int socklen_t;
* any inadvertant checks for the socket being <= 0 or > 0 will probably
* still work. */
#define tor_socket_t intptr_t
+#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT
#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET)
#define TOR_INVALID_SOCKET INVALID_SOCKET
#else
/** Type used for a network socket. */
#define tor_socket_t int
+#define TOR_SOCKET_T_FORMAT "%d"
/** Macro: true iff 's' is a possible value for a valid initialized socket. */
#define SOCKET_OK(s) ((s) >= 0)
/** Error/uninitialized value for a tor_socket_t. */
@@ -489,7 +521,7 @@ int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2));
const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len);
int tor_inet_pton(int af, const char *src, void *dst);
int tor_lookup_hostname(const char *name, uint32_t *addr) ATTR_NONNULL((1,2));
-void set_socket_nonblocking(tor_socket_t socket);
+int set_socket_nonblocking(tor_socket_t socket);
int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]);
int network_init(void);
@@ -523,10 +555,15 @@ int tor_socket_errno(tor_socket_t sock);
const char *tor_socket_strerror(int e);
#else
#define SOCK_ERRNO(e) e
+#if EAGAIN == EWOULDBLOCK
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN)
+#else
+#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK)
+#endif
#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS)
#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS)
-#define ERRNO_IS_ACCEPT_EAGAIN(e) ((e) == EAGAIN || (e) == ECONNABORTED)
+#define ERRNO_IS_ACCEPT_EAGAIN(e) \
+ (ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED)
#define ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e) \
((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM)
#define ERRNO_IS_EADDRINUSE(e) ((e) == EADDRINUSE)
@@ -547,11 +584,6 @@ typedef enum {
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08,
} socks5_reply_status_t;
-/* ===== Insecure rng */
-void tor_init_weak_random(unsigned seed);
-long tor_weak_random(void);
-#define TOR_RAND_MAX (RAND_MAX)
-
/* ===== OS compatibility */
const char *get_uname(void);
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 6655ca87d..200a7c65f 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Tor Project, Inc. */
+/* Copyright (c) 2009-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -54,7 +54,9 @@ typedef uint32_t le_version_t;
* it is. */
#define LE_OTHER V(0,0,99)
+#if 0
static le_version_t tor_get_libevent_version(const char **v_out);
+#endif
#if defined(HAVE_EVENT_SET_LOG_CALLBACK) || defined(RUNNING_DOXYGEN)
/** A string which, if it appears in a libevent log, should be ignored. */
@@ -74,19 +76,19 @@ libevent_logging_callback(int severity, const char *msg)
}
switch (severity) {
case _EVENT_LOG_DEBUG:
- log(LOG_DEBUG, LD_NOCB|LD_NET, "Message from libevent: %s", buf);
+ log_debug(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
break;
case _EVENT_LOG_MSG:
- log(LOG_INFO, LD_NOCB|LD_NET, "Message from libevent: %s", buf);
+ log_info(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
break;
case _EVENT_LOG_WARN:
- log(LOG_WARN, LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf);
+ log_warn(LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf);
break;
case _EVENT_LOG_ERR:
- log(LOG_ERR, LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf);
+ log_err(LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf);
break;
default:
- log(LOG_WARN, LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s",
+ log_warn(LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s",
severity, buf);
break;
}
@@ -185,13 +187,6 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
/* some paths below don't use torcfg, so avoid unused variable warnings */
(void)torcfg;
-#ifdef __APPLE__
- if (MACOSX_KQUEUE_IS_BROKEN ||
- tor_get_libevent_version(NULL) < V_OLD(1,1,'b')) {
- setenv("EVENT_NOKQUEUE","1",1);
- }
-#endif
-
#ifdef HAVE_EVENT2_EVENT_H
{
int attempts = 0;
@@ -266,13 +261,13 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
/* Making this a NOTICE for now so we can link bugs to a libevent versions
* or methods better. */
- log(LOG_NOTICE, LD_GENERAL,
+ log_info(LD_GENERAL,
"Initialized libevent version %s using method %s. Good.",
event_get_version(), tor_libevent_get_method());
#else
- log(LOG_NOTICE, LD_GENERAL,
+ log_notice(LD_GENERAL,
"Initialized old libevent (version 1.0b or earlier).");
- log(LOG_WARN, LD_GENERAL,
+ log_warn(LD_GENERAL,
"You have a *VERY* old version of libevent. It is likely to be buggy; "
"please build Tor with a more recent version.");
#endif
@@ -364,6 +359,7 @@ le_versions_compatibility(le_version_t v)
return 5;
}
+#if 0
/** Return the version number of the currently running version of Libevent.
* See le_version_t for info on the format.
*/
@@ -386,6 +382,7 @@ tor_get_libevent_version(const char **v_out)
*v_out = v;
return r;
}
+#endif
/** Return a string representation of the version of the currently running
* version of Libevent. */
@@ -407,77 +404,9 @@ void
tor_check_libevent_version(const char *m, int server,
const char **badness_out)
{
- int buggy = 0, iffy = 0, slow = 0, thread_unsafe = 0;
- le_version_t version;
- const char *v = NULL;
- const char *badness = NULL;
- const char *sad_os = "";
-
- version = tor_get_libevent_version(&v);
-
- /* It would be better to disable known-buggy methods rather than warning
- * about them. But the problem is that with older versions of Libevent,
- * it's not trivial to get them to change their methods once they're
- * initialized... and with newer versions of Libevent, they aren't actually
- * broken. But we should revisit this if we ever find a post-1.4 version
- * of Libevent where we need to disable a given method. */
- if (!strcmp(m, "kqueue")) {
- if (version < V_OLD(1,1,'b'))
- buggy = 1;
- } else if (!strcmp(m, "epoll")) {
- if (version < V(1,1,0))
- iffy = 1;
- } else if (!strcmp(m, "poll")) {
- if (version < V_OLD(1,0,'e'))
- buggy = 1;
- if (version < V(1,1,0))
- slow = 1;
- } else if (!strcmp(m, "select")) {
- if (version < V(1,1,0))
- slow = 1;
- } else if (!strcmp(m, "win32")) {
- if (version < V_OLD(1,1,'b'))
- buggy = 1;
- }
-
- /* Libevent versions before 1.3b do very badly on operating systems with
- * user-space threading implementations. */
-#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
- if (server && version < V_OLD(1,3,'b')) {
- thread_unsafe = 1;
- sad_os = "BSD variants";
- }
-#elif defined(__APPLE__) || defined(__darwin__)
- if (server && version < V_OLD(1,3,'b')) {
- thread_unsafe = 1;
- sad_os = "Mac OS X";
- }
-#endif
-
- if (thread_unsafe) {
- log(LOG_WARN, LD_GENERAL,
- "Libevent version %s often crashes when running a Tor server with %s. "
- "Please use the latest version of libevent (1.3b or later)",v,sad_os);
- badness = "BROKEN";
- } else if (buggy) {
- log(LOG_WARN, LD_GENERAL,
- "There are serious bugs in using %s with libevent %s. "
- "Please use the latest version of libevent.", m, v);
- badness = "BROKEN";
- } else if (iffy) {
- log(LOG_WARN, LD_GENERAL,
- "There are minor bugs in using %s with libevent %s. "
- "You may want to use the latest version of libevent.", m, v);
- badness = "BUGGY";
- } else if (slow && server) {
- log(LOG_WARN, LD_GENERAL,
- "libevent %s can be very slow with %s. "
- "When running a server, please use the latest version of libevent.",
- v,m);
- badness = "SLOW";
- }
-
- *badness_out = badness;
+ (void) m;
+ (void) server;
+ *badness_out = NULL;
}
#if defined(LIBEVENT_VERSION)
@@ -511,7 +440,7 @@ tor_check_libevent_header_compatibility(void)
verybad = compat1 != compat2;
- log(verybad ? LOG_WARN : LOG_NOTICE,
+ tor_log(verybad ? LOG_WARN : LOG_NOTICE,
LD_GENERAL, "We were compiled with headers from version %s "
"of Libevent, but we're using a Libevent library that says it's "
"version %s.", HEADER_VERSION, event_get_version());
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 56285ef80..2472e2c49 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -1,8 +1,8 @@
-/* Copyright (c) 2009-2012, The Tor Project, Inc. */
+/* Copyright (c) 2009-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_COMPAT_LIBEVENT_H
-#define _TOR_COMPAT_LIBEVENT_H
+#ifndef TOR_COMPAT_LIBEVENT_H
+#define TOR_COMPAT_LIBEVENT_H
#include "orconfig.h"
diff --git a/src/common/container.c b/src/common/container.c
index ede98eca5..eec497a3e 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -163,7 +163,7 @@ smartlist_string_remove(smartlist_t *sl, const char *element)
/** Return true iff some element E of sl has E==element.
*/
int
-smartlist_isin(const smartlist_t *sl, const void *element)
+smartlist_contains(const smartlist_t *sl, const void *element)
{
int i;
for (i=0; i < sl->num_used; i++)
@@ -176,7 +176,7 @@ smartlist_isin(const smartlist_t *sl, const void *element)
* !strcmp(E,<b>element</b>)
*/
int
-smartlist_string_isin(const smartlist_t *sl, const char *element)
+smartlist_contains_string(const smartlist_t *sl, const char *element)
{
int i;
if (!sl) return 0;
@@ -203,7 +203,7 @@ smartlist_string_pos(const smartlist_t *sl, const char *element)
* !strcasecmp(E,<b>element</b>)
*/
int
-smartlist_string_isin_case(const smartlist_t *sl, const char *element)
+smartlist_contains_string_case(const smartlist_t *sl, const char *element)
{
int i;
if (!sl) return 0;
@@ -217,11 +217,11 @@ smartlist_string_isin_case(const smartlist_t *sl, const char *element)
* to the decimal encoding of <b>num</b>.
*/
int
-smartlist_string_num_isin(const smartlist_t *sl, int num)
+smartlist_contains_int_as_string(const smartlist_t *sl, int num)
{
char buf[32]; /* long enough for 64-bit int, and then some. */
tor_snprintf(buf,sizeof(buf),"%d", num);
- return smartlist_string_isin(sl, buf);
+ return smartlist_contains_string(sl, buf);
}
/** Return true iff the two lists contain the same strings in the same
@@ -247,7 +247,7 @@ smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2)
* tor_memeq(E,<b>element</b>,DIGEST_LEN)
*/
int
-smartlist_digest_isin(const smartlist_t *sl, const char *element)
+smartlist_contains_digest(const smartlist_t *sl, const char *element)
{
int i;
if (!sl) return 0;
@@ -257,19 +257,19 @@ smartlist_digest_isin(const smartlist_t *sl, const char *element)
return 0;
}
-/** Return true iff some element E of sl2 has smartlist_isin(sl1,E).
+/** Return true iff some element E of sl2 has smartlist_contains(sl1,E).
*/
int
smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2)
{
int i;
for (i=0; i < sl2->num_used; i++)
- if (smartlist_isin(sl1, sl2->list[i]))
+ if (smartlist_contains(sl1, sl2->list[i]))
return 1;
return 0;
}
-/** Remove every element E of sl1 such that !smartlist_isin(sl2,E).
+/** Remove every element E of sl1 such that !smartlist_contains(sl2,E).
* Does not preserve the order of sl1.
*/
void
@@ -277,13 +277,13 @@ smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2)
{
int i;
for (i=0; i < sl1->num_used; i++)
- if (!smartlist_isin(sl2, sl1->list[i])) {
+ if (!smartlist_contains(sl2, sl1->list[i])) {
sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */
i--; /* so we process the new i'th element */
}
}
-/** Remove every element E of sl1 such that smartlist_isin(sl2,E).
+/** Remove every element E of sl1 such that smartlist_contains(sl2,E).
* Does not preserve the order of sl1.
*/
void
@@ -571,59 +571,116 @@ smartlist_bsearch_idx(const smartlist_t *sl, const void *key,
int (*compare)(const void *key, const void **member),
int *found_out)
{
- const int len = smartlist_len(sl);
- int hi, lo, cmp, mid;
+ int hi, lo, cmp, mid, len, diff;
+ tor_assert(sl);
+ tor_assert(compare);
+ tor_assert(found_out);
+
+ len = smartlist_len(sl);
+
+ /* Check for the trivial case of a zero-length list */
if (len == 0) {
*found_out = 0;
+ /* We already know smartlist_len(sl) is 0 in this case */
return 0;
- } else if (len == 1) {
- cmp = compare(key, (const void **) &sl->list[0]);
- if (cmp == 0) {
- *found_out = 1;
- return 0;
- } else if (cmp < 0) {
- *found_out = 0;
- return 0;
- } else {
- *found_out = 0;
- return 1;
- }
}
- hi = smartlist_len(sl) - 1;
+ /* Okay, we have a real search to do */
+ tor_assert(len > 0);
lo = 0;
+ hi = len - 1;
+
+ /*
+ * These invariants are always true:
+ *
+ * For all i such that 0 <= i < lo, sl[i] < key
+ * For all i such that hi < i <= len, sl[i] > key
+ */
while (lo <= hi) {
- mid = (lo + hi) / 2;
+ diff = hi - lo;
+ /*
+ * We want mid = (lo + hi) / 2, but that could lead to overflow, so
+ * instead diff = hi - lo (non-negative because of loop condition), and
+ * then hi = lo + diff, mid = (lo + lo + diff) / 2 = lo + (diff / 2).
+ */
+ mid = lo + (diff / 2);
cmp = compare(key, (const void**) &(sl->list[mid]));
- if (cmp>0) { /* key > sl[mid] */
- lo = mid+1;
- } else if (cmp<0) { /* key < sl[mid] */
- hi = mid-1;
- } else { /* key == sl[mid] */
+ if (cmp == 0) {
+ /* sl[mid] == key; we found it */
*found_out = 1;
return mid;
- }
- }
- /* lo > hi. */
- {
- tor_assert(lo >= 0);
- if (lo < smartlist_len(sl)) {
- cmp = compare(key, (const void**) &(sl->list[lo]));
+ } else if (cmp > 0) {
+ /*
+ * key > sl[mid] and an index i such that sl[i] == key must
+ * have i > mid if it exists.
+ */
+
+ /*
+ * Since lo <= mid <= hi, hi can only decrease on each iteration (by
+ * being set to mid - 1) and hi is initially len - 1, mid < len should
+ * always hold, and this is not symmetric with the left end of list
+ * mid > 0 test below. A key greater than the right end of the list
+ * should eventually lead to lo == hi == mid == len - 1, and then
+ * we set lo to len below and fall out to the same exit we hit for
+ * a key in the middle of the list but not matching. Thus, we just
+ * assert for consistency here rather than handle a mid == len case.
+ */
+ tor_assert(mid < len);
+ /* Move lo to the element immediately after sl[mid] */
+ lo = mid + 1;
+ } else {
+ /* This should always be true in this case */
tor_assert(cmp < 0);
- } else if (smartlist_len(sl)) {
- cmp = compare(key, (const void**) &(sl->list[smartlist_len(sl)-1]));
- tor_assert(cmp > 0);
+
+ /*
+ * key < sl[mid] and an index i such that sl[i] == key must
+ * have i < mid if it exists.
+ */
+
+ if (mid > 0) {
+ /* Normal case, move hi to the element immediately before sl[mid] */
+ hi = mid - 1;
+ } else {
+ /* These should always be true in this case */
+ tor_assert(mid == lo);
+ tor_assert(mid == 0);
+ /*
+ * We were at the beginning of the list and concluded that every
+ * element e compares e > key.
+ */
+ *found_out = 0;
+ return 0;
+ }
}
}
+
+ /*
+ * lo > hi; we have no element matching key but we have elements falling
+ * on both sides of it. The lo index points to the first element > key.
+ */
+ tor_assert(lo == hi + 1); /* All other cases should have been handled */
+ tor_assert(lo >= 0);
+ tor_assert(lo <= len);
+ tor_assert(hi >= 0);
+ tor_assert(hi <= len);
+
+ if (lo < len) {
+ cmp = compare(key, (const void **) &(sl->list[lo]));
+ tor_assert(cmp < 0);
+ } else {
+ cmp = compare(key, (const void **) &(sl->list[len-1]));
+ tor_assert(cmp > 0);
+ }
+
*found_out = 0;
return lo;
}
/** Helper: compare two const char **s. */
static int
-_compare_string_ptrs(const void **_a, const void **_b)
+compare_string_ptrs_(const void **_a, const void **_b)
{
return strcmp((const char*)*_a, (const char*)*_b);
}
@@ -633,14 +690,14 @@ _compare_string_ptrs(const void **_a, const void **_b)
void
smartlist_sort_strings(smartlist_t *sl)
{
- smartlist_sort(sl, _compare_string_ptrs);
+ smartlist_sort(sl, compare_string_ptrs_);
}
/** Return the most frequent string in the sorted list <b>sl</b> */
char *
smartlist_get_most_frequent_string(smartlist_t *sl)
{
- return smartlist_get_most_frequent(sl, _compare_string_ptrs);
+ return smartlist_get_most_frequent(sl, compare_string_ptrs_);
}
/** Remove duplicate strings from a sorted list, and free them with tor_free().
@@ -648,7 +705,7 @@ smartlist_get_most_frequent_string(smartlist_t *sl)
void
smartlist_uniq_strings(smartlist_t *sl)
{
- smartlist_uniq(sl, _compare_string_ptrs, _tor_free);
+ smartlist_uniq(sl, compare_string_ptrs_, tor_free_);
}
/* Heap-based priority queue implementation for O(lg N) insert and remove.
@@ -849,7 +906,7 @@ smartlist_pqueue_assert_ok(smartlist_t *sl,
/** Helper: compare two DIGEST_LEN digests. */
static int
-_compare_digests(const void **_a, const void **_b)
+compare_digests_(const void **_a, const void **_b)
{
return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST_LEN);
}
@@ -858,7 +915,7 @@ _compare_digests(const void **_a, const void **_b)
void
smartlist_sort_digests(smartlist_t *sl)
{
- smartlist_sort(sl, _compare_digests);
+ smartlist_sort(sl, compare_digests_);
}
/** Remove duplicate digests from a sorted list, and free them with tor_free().
@@ -866,12 +923,12 @@ smartlist_sort_digests(smartlist_t *sl)
void
smartlist_uniq_digests(smartlist_t *sl)
{
- smartlist_uniq(sl, _compare_digests, _tor_free);
+ smartlist_uniq(sl, compare_digests_, tor_free_);
}
/** Helper: compare two DIGEST256_LEN digests. */
static int
-_compare_digests256(const void **_a, const void **_b)
+compare_digests256_(const void **_a, const void **_b)
{
return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN);
}
@@ -880,7 +937,7 @@ _compare_digests256(const void **_a, const void **_b)
void
smartlist_sort_digests256(smartlist_t *sl)
{
- smartlist_sort(sl, _compare_digests256);
+ smartlist_sort(sl, compare_digests256_);
}
/** Return the most frequent member of the sorted list of DIGEST256_LEN
@@ -888,7 +945,7 @@ smartlist_sort_digests256(smartlist_t *sl)
char *
smartlist_get_most_frequent_digest256(smartlist_t *sl)
{
- return smartlist_get_most_frequent(sl, _compare_digests256);
+ return smartlist_get_most_frequent(sl, compare_digests256_);
}
/** Remove duplicate 256-bit digests from a sorted list, and free them with
@@ -897,7 +954,7 @@ smartlist_get_most_frequent_digest256(smartlist_t *sl)
void
smartlist_uniq_digests256(smartlist_t *sl)
{
- smartlist_uniq(sl, _compare_digests256, _tor_free);
+ smartlist_uniq(sl, compare_digests256_, tor_free_);
}
/** Helper: Declare an entry type and a map type to implement a mapping using
diff --git a/src/common/container.h b/src/common/container.h
index dab3b83f3..fb9374794 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -1,10 +1,10 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_CONTAINER_H
-#define _TOR_CONTAINER_H
+#ifndef TOR_CONTAINER_H
+#define TOR_CONTAINER_H
#include "util.h"
@@ -35,13 +35,13 @@ void smartlist_remove(smartlist_t *sl, const void *element);
void *smartlist_pop_last(smartlist_t *sl);
void smartlist_reverse(smartlist_t *sl);
void smartlist_string_remove(smartlist_t *sl, const char *element);
-int smartlist_isin(const smartlist_t *sl, const void *element);
-int smartlist_string_isin(const smartlist_t *sl, const char *element);
+int smartlist_contains(const smartlist_t *sl, const void *element);
+int smartlist_contains_string(const smartlist_t *sl, const char *element);
int smartlist_string_pos(const smartlist_t *, const char *elt);
-int smartlist_string_isin_case(const smartlist_t *sl, const char *element);
-int smartlist_string_num_isin(const smartlist_t *sl, int num);
+int smartlist_contains_string_case(const smartlist_t *sl, const char *element);
+int smartlist_contains_int_as_string(const smartlist_t *sl, int num);
int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2);
-int smartlist_digest_isin(const smartlist_t *sl, const char *element);
+int smartlist_contains_digest(const smartlist_t *sl, const char *element);
int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
@@ -471,64 +471,74 @@ void* strmap_remove_lc(strmap_t *map, const char *key);
#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \
typedef struct maptype maptype; \
typedef struct prefix##iter_t prefix##iter_t; \
- static INLINE maptype* prefix##new(void) \
+ ATTR_UNUSED static INLINE maptype* \
+ prefix##new(void) \
{ \
return (maptype*)digestmap_new(); \
} \
- static INLINE digestmap_t* prefix##to_digestmap(maptype *map) \
+ ATTR_UNUSED static INLINE digestmap_t* \
+ prefix##to_digestmap(maptype *map) \
{ \
return (digestmap_t*)map; \
} \
- static INLINE valtype* prefix##get(maptype *map, const char *key) \
+ ATTR_UNUSED static INLINE valtype* \
+ prefix##get(maptype *map, const char *key) \
{ \
return (valtype*)digestmap_get((digestmap_t*)map, key); \
} \
- static INLINE valtype* prefix##set(maptype *map, const char *key, \
- valtype *val) \
+ ATTR_UNUSED static INLINE valtype* \
+ prefix##set(maptype *map, const char *key, valtype *val) \
{ \
return (valtype*)digestmap_set((digestmap_t*)map, key, val); \
} \
- static INLINE valtype* prefix##remove(maptype *map, const char *key) \
+ ATTR_UNUSED static INLINE valtype* \
+ prefix##remove(maptype *map, const char *key) \
{ \
return (valtype*)digestmap_remove((digestmap_t*)map, key); \
} \
- static INLINE void prefix##free(maptype *map, void (*free_val)(void*)) \
+ ATTR_UNUSED static INLINE void \
+ prefix##free(maptype *map, void (*free_val)(void*)) \
{ \
digestmap_free((digestmap_t*)map, free_val); \
} \
- static INLINE int prefix##isempty(maptype *map) \
+ ATTR_UNUSED static INLINE int \
+ prefix##isempty(maptype *map) \
{ \
return digestmap_isempty((digestmap_t*)map); \
} \
- static INLINE int prefix##size(maptype *map) \
+ ATTR_UNUSED static INLINE int \
+ prefix##size(maptype *map) \
{ \
return digestmap_size((digestmap_t*)map); \
} \
- static INLINE prefix##iter_t *prefix##iter_init(maptype *map) \
+ ATTR_UNUSED static INLINE \
+ prefix##iter_t *prefix##iter_init(maptype *map) \
{ \
return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \
} \
- static INLINE prefix##iter_t *prefix##iter_next(maptype *map, \
- prefix##iter_t *iter) \
+ ATTR_UNUSED static INLINE \
+ prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter) \
{ \
return (prefix##iter_t*) digestmap_iter_next( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
} \
- static INLINE prefix##iter_t *prefix##iter_next_rmv(maptype *map, \
- prefix##iter_t *iter) \
+ ATTR_UNUSED static INLINE prefix##iter_t* \
+ prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter) \
{ \
return (prefix##iter_t*) digestmap_iter_next_rmv( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
} \
- static INLINE void prefix##iter_get(prefix##iter_t *iter, \
- const char **keyp, \
- valtype **valp) \
+ ATTR_UNUSED static INLINE void \
+ prefix##iter_get(prefix##iter_t *iter, \
+ const char **keyp, \
+ valtype **valp) \
{ \
void *v; \
digestmap_iter_get((digestmap_iter_t*) iter, keyp, &v); \
*valp = v; \
} \
- static INLINE int prefix##iter_done(prefix##iter_t *iter) \
+ ATTR_UNUSED static INLINE int \
+ prefix##iter_done(prefix##iter_t *iter) \
{ \
return digestmap_iter_done((digestmap_iter_t*)iter); \
}
@@ -623,7 +633,7 @@ digestset_add(digestset_t *set, const char *digest)
/** If <b>digest</b> is in <b>set</b>, return nonzero. Otherwise,
* <em>probably</em> return zero. */
static INLINE int
-digestset_isin(const digestset_t *set, const char *digest)
+digestset_contains(const digestset_t *set, const char *digest)
{
const uint32_t *p = (const uint32_t *)digest;
const uint32_t d1 = p[0] + (p[1]>>16);
@@ -675,11 +685,6 @@ median_int32(int32_t *array, int n_elements)
{
return find_nth_int32(array, n_elements, (n_elements-1)/2);
}
-static INLINE long
-median_long(long *array, int n_elements)
-{
- return find_nth_long(array, n_elements, (n_elements-1)/2);
-}
#endif
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 30990ecc8..925beb352 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -57,8 +57,8 @@
#include "container.h"
#include "compat.h"
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7)
-#error "We require OpenSSL >= 0.9.7"
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
+#error "We require OpenSSL >= 0.9.8"
#endif
#ifdef ANDROID
@@ -69,31 +69,6 @@
/** Longest recognized */
#define MAX_DNS_LABEL_SIZE 63
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8) && \
- !defined(RUNNING_DOXYGEN)
-/** @{ */
-/** On OpenSSL versions before 0.9.8, there is no working SHA256
- * implementation, so we use Tom St Denis's nice speedy one, slightly adapted
- * to our needs. These macros make it usable by us. */
-#define SHA256_CTX sha256_state
-#define SHA256_Init sha256_init
-#define SHA256_Update sha256_process
-#define LTC_ARGCHK(x) tor_assert(x)
-/** @} */
-#include "sha256.c"
-#define SHA256_Final(a,b) sha256_done(b,a)
-
-static unsigned char *
-SHA256(const unsigned char *m, size_t len, unsigned char *d)
-{
- SHA256_CTX ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, m, len);
- SHA256_Final(d, &ctx);
- return d;
-}
-#endif
-
/** Macro: is k a valid RSA public or private key? */
#define PUBLIC_KEY_OK(k) ((k) && (k)->key && (k)->key->n)
/** Macro: is k a valid RSA private key? */
@@ -101,9 +76,9 @@ SHA256(const unsigned char *m, size_t len, unsigned char *d)
#ifdef TOR_IS_MULTITHREADED
/** A number of preallocated mutexes for use by OpenSSL. */
-static tor_mutex_t **_openssl_mutexes = NULL;
+static tor_mutex_t **openssl_mutexes_ = NULL;
/** How many mutexes have we allocated for use by OpenSSL? */
-static int _n_openssl_mutexes = 0;
+static int n_openssl_mutexes_ = 0;
#endif
/** A public key, or a public/private key-pair. */
@@ -138,8 +113,8 @@ crypto_get_rsa_padding_overhead(int padding)
{
switch (padding)
{
- case RSA_PKCS1_OAEP_PADDING: return 42;
- case RSA_PKCS1_PADDING: return 11;
+ case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD;
+ case RSA_PKCS1_PADDING: return PKCS1_PADDING_OVERHEAD;
default: tor_assert(0); return -1;
}
}
@@ -158,7 +133,7 @@ crypto_get_rsa_padding(int padding)
}
/** Boolean: has OpenSSL's crypto been initialized? */
-static int _crypto_global_initialized = 0;
+static int crypto_global_initialized_ = 0;
/** Log all pending crypto errors at level <b>severity</b>. Use
* <b>doing</b> to describe our current activities.
@@ -176,10 +151,11 @@ crypto_log_errors(int severity, const char *doing)
if (!lib) lib = "(null)";
if (!func) func = "(null)";
if (doing) {
- log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
- doing, msg, lib, func);
+ tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
+ doing, msg, lib, func);
} else {
- log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", msg, lib, func);
+ tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)",
+ msg, lib, func);
}
}
}
@@ -193,10 +169,10 @@ log_engine(const char *fn, ENGINE *e)
const char *name, *id;
name = ENGINE_get_name(e);
id = ENGINE_get_id(e);
- log(LOG_NOTICE, LD_CRYPTO, "Using OpenSSL engine %s [%s] for %s",
- name?name:"?", id?id:"?", fn);
+ log_notice(LD_CRYPTO, "Default OpenSSL engine for %s is %s [%s]",
+ fn, name?name:"?", id?id:"?");
} else {
- log(LOG_INFO, LD_CRYPTO, "Using default implementation for %s", fn);
+ log_info(LD_CRYPTO, "Using default implementation for %s", fn);
}
}
#endif
@@ -221,16 +197,60 @@ try_load_engine(const char *path, const char *engine)
}
#endif
+static char *crypto_openssl_version_str = NULL;
+/* Return a human-readable version of the run-time openssl version number. */
+const char *
+crypto_openssl_get_version_str(void)
+{
+ if (crypto_openssl_version_str == NULL) {
+ const char *raw_version = SSLeay_version(SSLEAY_VERSION);
+ const char *end_of_version = NULL;
+ /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's
+ trim that down. */
+ if (!strcmpstart(raw_version, "OpenSSL ")) {
+ raw_version += strlen("OpenSSL ");
+ end_of_version = strchr(raw_version, ' ');
+ }
+
+ if (end_of_version)
+ crypto_openssl_version_str = tor_strndup(raw_version,
+ end_of_version-raw_version);
+ else
+ crypto_openssl_version_str = tor_strdup(raw_version);
+ }
+ return crypto_openssl_version_str;
+}
+
/** Initialize the crypto library. Return 0 on success, -1 on failure.
*/
int
crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
{
- if (!_crypto_global_initialized) {
+ if (!crypto_global_initialized_) {
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
- _crypto_global_initialized = 1;
+ crypto_global_initialized_ = 1;
setup_openssl_threading();
+
+ if (SSLeay() == OPENSSL_VERSION_NUMBER &&
+ !strcmp(SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_TEXT)) {
+ log_info(LD_CRYPTO, "OpenSSL version matches version from headers "
+ "(%lx: %s).", SSLeay(), SSLeay_version(SSLEAY_VERSION));
+ } else {
+ log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the "
+ "version we're running with. If you get weird crashes, that "
+ "might be why. (Compiled with %lx: %s; running with %lx: %s).",
+ (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT,
+ SSLeay(), SSLeay_version(SSLEAY_VERSION));
+ }
+
+ if (SSLeay() < OPENSSL_V_SERIES(1,0,0)) {
+ log_notice(LD_CRYPTO,
+ "Your OpenSSL version seems to be %s. We recommend 1.0.0 "
+ "or later.",
+ crypto_openssl_get_version_str());
+ }
+
if (useAccel > 0) {
#ifdef DISABLE_ENGINES
(void)accelName;
@@ -268,7 +288,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
}
log_engine("RSA", ENGINE_get_default_RSA());
log_engine("DH", ENGINE_get_default_DH());
- log_engine("RAND", ENGINE_get_default_RAND());
+ log_engine("RAND (which we will not use)", ENGINE_get_default_RAND());
log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1));
log_engine("3DES", ENGINE_get_cipher_engine(NID_des_ede3_ecb));
log_engine("AES", ENGINE_get_cipher_engine(NID_aes_128_ecb));
@@ -277,6 +297,13 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
log_info(LD_CRYPTO, "NOT using OpenSSL engine support.");
}
+ if (RAND_get_rand_method() != RAND_SSLeay()) {
+ log_notice(LD_CRYPTO, "It appears that one of our engines has provided "
+ "a replacement the OpenSSL RNG. Resetting it to the default "
+ "implementation.");
+ RAND_set_rand_method(RAND_SSLeay());
+ }
+
evaluate_evp_for_aes(-1);
evaluate_ctr_for_aes();
@@ -294,7 +321,7 @@ crypto_thread_cleanup(void)
/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */
crypto_pk_t *
-_crypto_new_pk_from_rsa(RSA *rsa)
+crypto_new_pk_from_rsa_(RSA *rsa)
{
crypto_pk_t *env;
tor_assert(rsa);
@@ -307,7 +334,7 @@ _crypto_new_pk_from_rsa(RSA *rsa)
/** Helper, used by tor-checkkey.c and tor-gencert.c. Return the RSA from a
* crypto_pk_t. */
RSA *
-_crypto_pk_get_rsa(crypto_pk_t *env)
+crypto_pk_get_rsa_(crypto_pk_t *env)
{
return env->key;
}
@@ -315,7 +342,7 @@ _crypto_pk_get_rsa(crypto_pk_t *env)
/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff
* private is set, include the private-key portion of the key. */
EVP_PKEY *
-_crypto_pk_get_evp_pkey(crypto_pk_t *env, int private)
+crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private)
{
RSA *key = NULL;
EVP_PKEY *pkey = NULL;
@@ -343,7 +370,7 @@ _crypto_pk_get_evp_pkey(crypto_pk_t *env, int private)
/** Used by tortls.c: Get the DH* from a crypto_dh_t.
*/
DH *
-_crypto_dh_get_dh(crypto_dh_t *dh)
+crypto_dh_get_dh_(crypto_dh_t *dh)
{
return dh->dh;
}
@@ -358,7 +385,7 @@ crypto_pk_new(void)
rsa = RSA_new();
tor_assert(rsa);
- return _crypto_new_pk_from_rsa(rsa);
+ return crypto_new_pk_from_rsa_(rsa);
}
/** Release a reference to an asymmetric key; when all the references
@@ -441,11 +468,7 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
if (env->key)
RSA_free(env->key);
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
- /* In OpenSSL 0.9.7, RSA_generate_key is all we have. */
- env->key = RSA_generate_key(bits, 65537, NULL, NULL);
-#else
- /* In OpenSSL 0.9.8, RSA_generate_key is deprecated. */
+
{
BIGNUM *e = BN_new();
RSA *r = NULL;
@@ -463,11 +486,11 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
r = NULL;
done:
if (e)
- BN_free(e);
+ BN_clear_free(e);
if (r)
RSA_free(r);
- }
-#endif
+ }
+
if (!env->key) {
crypto_log_errors(LOG_WARN, "generating RSA key");
return -1;
@@ -711,19 +734,23 @@ crypto_pk_public_exponent_ok(crypto_pk_t *env)
return BN_is_word(env->key->e, 65537);
}
-/** Compare the public-key components of a and b. Return -1 if a\<b, 0
- * if a==b, and 1 if a\>b.
+/** Compare the public-key components of a and b. Return less than 0
+ * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is
+ * considered to be less than all non-NULL keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
*/
int
crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
{
int result;
+ char a_is_non_null = (a != NULL) && (a->key != NULL);
+ char b_is_non_null = (b != NULL) && (b->key != NULL);
+ char an_argument_is_null = !a_is_non_null | !b_is_non_null;
- if (!a || !b)
- return -1;
-
- if (!a->key || !b->key)
- return -1;
+ result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null));
+ if (an_argument_is_null)
+ return result;
tor_assert(PUBLIC_KEY_OK(a));
tor_assert(PUBLIC_KEY_OK(b));
@@ -733,6 +760,18 @@ crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
return BN_cmp((a->key)->e, (b->key)->e);
}
+/** Compare the public-key components of a and b. Return non-zero iff
+ * a==b. A NULL key is considered to be distinct from all non-NULL
+ * keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
+ */
+int
+crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b)
+{
+ return (crypto_pk_cmp_keys(a, b) == 0);
+}
+
/** Return the size of the public key modulus in <b>env</b>, in bytes. */
size_t
crypto_pk_keysize(crypto_pk_t *env)
@@ -791,7 +830,7 @@ crypto_pk_copy_full(crypto_pk_t *env)
return NULL;
}
- return _crypto_new_pk_from_rsa(new_key);
+ return crypto_new_pk_from_rsa_(new_key);
}
/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key
@@ -1158,7 +1197,7 @@ crypto_pk_asn1_decode(const char *str, size_t len)
crypto_log_errors(LOG_WARN,"decoding public key");
return NULL;
}
- return _crypto_new_pk_from_rsa(rsa);
+ return crypto_new_pk_from_rsa_(rsa);
}
/** Given a private or public key <b>pk</b>, put a SHA1 hash of the
@@ -1262,23 +1301,6 @@ crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
return 0;
}
-/** Return true iff <b>s</b> is in the correct format for a fingerprint.
- */
-int
-crypto_pk_check_fingerprint_syntax(const char *s)
-{
- int i;
- for (i = 0; i < FINGERPRINT_LEN; ++i) {
- if ((i%5) == 4) {
- if (!TOR_ISSPACE(s[i])) return 0;
- } else {
- if (!TOR_ISXDIGIT(s[i])) return 0;
- }
- }
- if (s[FINGERPRINT_LEN]) return 0;
- return 1;
-}
-
/* symmetric crypto */
/** Return a pointer to the key set for the cipher in <b>env</b>.
@@ -1427,7 +1449,7 @@ crypto_digest256(char *digest, const char *m, size_t len,
int
crypto_digest_all(digests_t *ds_out, const char *m, size_t len)
{
- digest_algorithm_t i;
+ int i;
tor_assert(ds_out);
memset(ds_out, 0, sizeof(*ds_out));
if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0)
@@ -1474,7 +1496,7 @@ struct crypto_digest_t {
SHA256_CTX sha2; /**< state for SHA256 */
} d; /**< State for the digest we're using. Only one member of the
* union is usable, depending on the value of <b>algorithm</b>. */
- digest_algorithm_t algorithm : 8; /**< Which algorithm is in use? */
+ ENUM_BF(digest_algorithm_t) algorithm : 8; /**< Which algorithm is in use? */
};
/** Allocate and return a new digest object to compute SHA1 digests.
@@ -1599,6 +1621,29 @@ crypto_digest_assign(crypto_digest_t *into,
memcpy(into,from,sizeof(crypto_digest_t));
}
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of those strings,
+ * plus the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>out_len</b> must be \<= DIGEST256_LEN. */
+void
+crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const smartlist_t *lst, const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_t *d;
+ if (alg == DIGEST_SHA1)
+ d = crypto_digest_new();
+ else
+ d = crypto_digest256_new(alg);
+ SMARTLIST_FOREACH(lst, const char *, cp,
+ crypto_digest_add_bytes(d, cp, strlen(cp)));
+ if (append)
+ crypto_digest_add_bytes(d, append, strlen(append));
+ crypto_digest_get_digest(d, digest_out, len_out);
+ crypto_digest_free(d);
+}
+
/** Compute the HMAC-SHA-1 of the <b>msg_len</b> bytes in <b>msg</b>, using
* the <b>key</b> of length <b>key_len</b>. Store the DIGEST_LEN-byte result
* in <b>hmac_out</b>.
@@ -1623,63 +1668,11 @@ crypto_hmac_sha256(char *hmac_out,
const char *key, size_t key_len,
const char *msg, size_t msg_len)
{
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,8)
/* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
tor_assert(key_len < INT_MAX);
tor_assert(msg_len < INT_MAX);
HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
(unsigned char*)hmac_out, NULL);
-#else
- /* OpenSSL doesn't have an EVP implementation for SHA256. We'll need
- to do HMAC on our own.
-
- HMAC isn't so hard: To compute HMAC(key, msg):
- 1. If len(key) > blocksize, key = H(key).
- 2. If len(key) < blocksize, right-pad key up to blocksize with 0 bytes.
- 3. let ipad = key xor 0x363636363636....36
- let opad = key xor 0x5c5c5c5c5c5c....5c
- The result is H(opad | H( ipad | msg ) )
- */
-#define BLOCKSIZE 64
-#define DIGESTSIZE 32
- uint8_t k[BLOCKSIZE];
- uint8_t pad[BLOCKSIZE];
- uint8_t d[DIGESTSIZE];
- int i;
- SHA256_CTX st;
-
- tor_assert(key_len < INT_MAX);
- tor_assert(msg_len < INT_MAX);
-
- if (key_len <= BLOCKSIZE) {
- memset(k, 0, sizeof(k));
- memcpy(k, key, key_len); /* not time invariant in key_len */
- } else {
- SHA256((const uint8_t *)key, key_len, k);
- memset(k+DIGESTSIZE, 0, sizeof(k)-DIGESTSIZE);
- }
- for (i = 0; i < BLOCKSIZE; ++i)
- pad[i] = k[i] ^ 0x36;
- SHA256_Init(&st);
- SHA256_Update(&st, pad, BLOCKSIZE);
- SHA256_Update(&st, (uint8_t*)msg, msg_len);
- SHA256_Final(d, &st);
-
- for (i = 0; i < BLOCKSIZE; ++i)
- pad[i] = k[i] ^ 0x5c;
- SHA256_Init(&st);
- SHA256_Update(&st, pad, BLOCKSIZE);
- SHA256_Update(&st, d, DIGESTSIZE);
- SHA256_Final((uint8_t*)hmac_out, &st);
-
- /* Now clear everything. */
- memwipe(k, 0, sizeof(k));
- memwipe(pad, 0, sizeof(pad));
- memwipe(d, 0, sizeof(d));
- memwipe(&st, 0, sizeof(st));
-#undef BLOCKSIZE
-#undef DIGESTSIZE
-#endif
}
/* DH */
@@ -1929,7 +1922,7 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname)
/* If the space is occupied, free the previous TLS DH prime */
if (dh_param_p_tls) {
- BN_free(dh_param_p_tls);
+ BN_clear_free(dh_param_p_tls);
dh_param_p_tls = NULL;
}
@@ -2057,6 +2050,16 @@ crypto_dh_new(int dh_type)
return NULL;
}
+/** Return a copy of <b>dh</b>, sharing its internal state. */
+crypto_dh_t *
+crypto_dh_dup(const crypto_dh_t *dh)
+{
+ crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t));
+ dh_new->dh = dh->dh;
+ DH_up_ref(dh->dh);
+ return dh_new;
+}
+
/** Return the length of the DH key in <b>dh</b>, in bytes.
*/
int
@@ -2081,8 +2084,8 @@ crypto_dh_generate_public(crypto_dh_t *dh)
log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-"
"the-universe chances really do happen. Trying again.");
/* Free and clear the keys, so OpenSSL will actually try again. */
- BN_free(dh->dh->pub_key);
- BN_free(dh->dh->priv_key);
+ BN_clear_free(dh->dh->pub_key);
+ BN_clear_free(dh->dh->priv_key);
dh->dh->pub_key = dh->dh->priv_key = NULL;
goto again;
}
@@ -2144,10 +2147,10 @@ tor_check_dh_key(int severity, BIGNUM *bn)
log_fn(severity, LD_CRYPTO, "DH key must be at most p-2.");
goto err;
}
- BN_free(x);
+ BN_clear_free(x);
return 0;
err:
- BN_free(x);
+ BN_clear_free(x);
s = BN_bn2hex(bn);
log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s);
OPENSSL_free(s);
@@ -2195,8 +2198,8 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
goto error;
}
secret_len = result;
- if (crypto_expand_key_material(secret_tmp, secret_len,
- secret_out, secret_bytes_out)<0)
+ if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len,
+ (uint8_t*)secret_out, secret_bytes_out)<0)
goto error;
secret_len = secret_bytes_out;
@@ -2206,7 +2209,7 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
done:
crypto_log_errors(LOG_WARN, "completing DH handshake");
if (pubkey_bn)
- BN_free(pubkey_bn);
+ BN_clear_free(pubkey_bn);
if (secret_tmp) {
memwipe(secret_tmp, 0, secret_tmp_len);
tor_free(secret_tmp);
@@ -2222,15 +2225,18 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
* <b>key_out</b> by taking the first <b>key_out_len</b> bytes of
* H(K | [00]) | H(K | [01]) | ....
*
+ * This is the key expansion algorithm used in the "TAP" circuit extension
+ * mechanism; it shouldn't be used for new protocols.
+ *
* Return 0 on success, -1 on failure.
*/
int
-crypto_expand_key_material(const char *key_in, size_t key_in_len,
- char *key_out, size_t key_out_len)
+crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len,
+ uint8_t *key_out, size_t key_out_len)
{
int i;
- char *cp, *tmp = tor_malloc(key_in_len+1);
- char digest[DIGEST_LEN];
+ uint8_t *cp, *tmp = tor_malloc(key_in_len+1);
+ uint8_t digest[DIGEST_LEN];
/* If we try to get more than this amount of key data, we'll repeat blocks.*/
tor_assert(key_out_len <= DIGEST_LEN*256);
@@ -2239,7 +2245,7 @@ crypto_expand_key_material(const char *key_in, size_t key_in_len,
for (cp = key_out, i=0; cp < key_out+key_out_len;
++i, cp += DIGEST_LEN) {
tmp[key_in_len] = i;
- if (crypto_digest(digest, tmp, key_in_len+1))
+ if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1))
goto err;
memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out)));
}
@@ -2255,6 +2261,65 @@ crypto_expand_key_material(const char *key_in, size_t key_in_len,
return -1;
}
+/** Expand some secret key material according to RFC5869, using SHA256 as the
+ * underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the
+ * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the
+ * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt"
+ * and "info" parameters respectively. On success, write <b>key_out_len</b>
+ * bytes to <b>key_out</b> and return 0. On failure, return -1.
+ */
+int
+crypto_expand_key_material_rfc5869_sha256(
+ const uint8_t *key_in, size_t key_in_len,
+ const uint8_t *salt_in, size_t salt_in_len,
+ const uint8_t *info_in, size_t info_in_len,
+ uint8_t *key_out, size_t key_out_len)
+{
+ uint8_t prk[DIGEST256_LEN];
+ uint8_t tmp[DIGEST256_LEN + 128 + 1];
+ uint8_t mac[DIGEST256_LEN];
+ int i;
+ uint8_t *outp;
+ size_t tmp_len;
+
+ crypto_hmac_sha256((char*)prk,
+ (const char*)salt_in, salt_in_len,
+ (const char*)key_in, key_in_len);
+
+ /* If we try to get more than this amount of key data, we'll repeat blocks.*/
+ tor_assert(key_out_len <= DIGEST256_LEN * 256);
+ tor_assert(info_in_len <= 128);
+ memset(tmp, 0, sizeof(tmp));
+ outp = key_out;
+ i = 1;
+
+ while (key_out_len) {
+ size_t n;
+ if (i > 1) {
+ memcpy(tmp, mac, DIGEST256_LEN);
+ memcpy(tmp+DIGEST256_LEN, info_in, info_in_len);
+ tmp[DIGEST256_LEN+info_in_len] = i;
+ tmp_len = DIGEST256_LEN + info_in_len + 1;
+ } else {
+ memcpy(tmp, info_in, info_in_len);
+ tmp[info_in_len] = i;
+ tmp_len = info_in_len + 1;
+ }
+ crypto_hmac_sha256((char*)mac,
+ (const char*)prk, DIGEST256_LEN,
+ (const char*)tmp, tmp_len);
+ n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN;
+ memcpy(outp, mac, n);
+ key_out_len -= n;
+ outp += n;
+ ++i;
+ }
+
+ memwipe(tmp, 0, sizeof(tmp));
+ memwipe(mac, 0, sizeof(mac));
+ return 0;
+}
+
/** Free a DH key exchange object.
*/
void
@@ -2282,35 +2347,27 @@ crypto_dh_free(crypto_dh_t *dh)
* that fd without checking whether it fit in the fd_set. Thus, if the
* system has not just been started up, it is unsafe to call */
#define RAND_POLL_IS_SAFE \
- ((OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,7,'j') && \
- OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)) || \
- OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
+ (OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
/** Set the seed of the weak RNG to a random value. */
-static void
-seed_weak_rng(void)
+void
+crypto_seed_weak_rng(tor_weak_rng_t *rng)
{
unsigned seed;
crypto_rand((void*)&seed, sizeof(seed));
- tor_init_weak_random(seed);
+ tor_init_weak_random(rng, seed);
}
-/** Seed OpenSSL's random number generator with bytes from the operating
- * system. <b>startup</b> should be true iff we have just started Tor and
- * have not yet allocated a bunch of fds. Return 0 on success, -1 on failure.
+/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
+ * storing it into <b>out</b>.
*/
int
-crypto_seed_rng(int startup)
+crypto_strongest_rand(uint8_t *out, size_t out_len)
{
- int rand_poll_status = 0;
-
- /* local variables */
#ifdef _WIN32
- unsigned char buf[ADD_ENTROPY];
static int provider_set = 0;
static HCRYPTPROV provider;
#else
- char buf[ADD_ENTROPY];
static const char *filenames[] = {
"/dev/srandom", "/dev/urandom", "/dev/random", NULL
};
@@ -2318,58 +2375,77 @@ crypto_seed_rng(int startup)
size_t n;
#endif
- /* OpenSSL has a RAND_poll function that knows about more kinds of
- * entropy than we do. We'll try calling that, *and* calling our own entropy
- * functions. If one succeeds, we'll accept the RNG as seeded. */
- if (startup || RAND_POLL_IS_SAFE) {
- rand_poll_status = RAND_poll();
- if (rand_poll_status == 0)
- log_warn(LD_CRYPTO, "RAND_poll() failed.");
- }
-
#ifdef _WIN32
if (!provider_set) {
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) {
log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]");
- return rand_poll_status ? 0 : -1;
+ return -1;
}
}
provider_set = 1;
}
- if (!CryptGenRandom(provider, sizeof(buf), buf)) {
+ if (!CryptGenRandom(provider, out_len, out)) {
log_warn(LD_CRYPTO, "Can't get entropy from CryptoAPI.");
- return rand_poll_status ? 0 : -1;
+ return -1;
}
- RAND_seed(buf, sizeof(buf));
- memwipe(buf, 0, sizeof(buf));
- seed_weak_rng();
+
return 0;
#else
for (i = 0; filenames[i]; ++i) {
fd = open(filenames[i], O_RDONLY, 0);
if (fd<0) continue;
- log_info(LD_CRYPTO, "Seeding RNG from \"%s\"", filenames[i]);
- n = read_all(fd, buf, sizeof(buf), 0);
+ log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]);
+ n = read_all(fd, (char*)out, out_len, 0);
close(fd);
- if (n != sizeof(buf)) {
+ if (n != out_len) {
log_warn(LD_CRYPTO,
"Error reading from entropy source (read only %lu bytes).",
(unsigned long)n);
return -1;
}
- RAND_seed(buf, (int)sizeof(buf));
- memwipe(buf, 0, sizeof(buf));
- seed_weak_rng();
+
return 0;
}
- log_warn(LD_CRYPTO, "Cannot seed RNG -- no entropy source found.");
- return rand_poll_status ? 0 : -1;
+ log_warn(LD_CRYPTO, "Cannot get strong entropy: no entropy source found.");
+ return -1;
#endif
}
+/** Seed OpenSSL's random number generator with bytes from the operating
+ * system. <b>startup</b> should be true iff we have just started Tor and
+ * have not yet allocated a bunch of fds. Return 0 on success, -1 on failure.
+ */
+int
+crypto_seed_rng(int startup)
+{
+ int rand_poll_ok = 0, load_entropy_ok = 0;
+ uint8_t buf[ADD_ENTROPY];
+
+ /* OpenSSL has a RAND_poll function that knows about more kinds of
+ * entropy than we do. We'll try calling that, *and* calling our own entropy
+ * functions. If one succeeds, we'll accept the RNG as seeded. */
+ if (startup || RAND_POLL_IS_SAFE) {
+ rand_poll_ok = RAND_poll();
+ if (rand_poll_ok == 0)
+ log_warn(LD_CRYPTO, "RAND_poll() failed.");
+ }
+
+ load_entropy_ok = !crypto_strongest_rand(buf, sizeof(buf));
+ if (load_entropy_ok) {
+ RAND_seed(buf, sizeof(buf));
+ }
+
+ memwipe(buf, 0, sizeof(buf));
+
+ if (rand_poll_ok || load_entropy_ok)
+ return 0;
+ else
+ return -1;
+}
+
/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on
* success, -1 on failure.
*/
@@ -2517,7 +2593,7 @@ smartlist_shuffle(smartlist_t *sl)
}
}
-/** Base-64 encode <b>srclen</b> bytes of data from <b>src</b>. Write
+/** Base64 encode <b>srclen</b> bytes of data from <b>src</b>. Write
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
* bytes. Return the number of bytes written on success; -1 if
* destlen is too short, or other failure.
@@ -2576,7 +2652,7 @@ static const uint8_t base64_decode_table[256] = {
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
};
-/** Base-64 decode <b>srclen</b> bytes of data from <b>src</b>. Write
+/** Base64 decode <b>srclen</b> bytes of data from <b>src</b>. Write
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
* bytes. Return the number of bytes written on success; -1 if
* destlen is too short, or other failure.
@@ -2683,7 +2759,7 @@ base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
#undef SP
#undef PAD
-/** Base-64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
+/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
* and newline characters, and store the nul-terminated result in the first
* BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */
int
@@ -2696,7 +2772,7 @@ digest_to_base64(char *d64, const char *digest)
return 0;
}
-/** Given a base-64 encoded, nul-terminated digest in <b>d64</b> (without
+/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
* trailing newline or = characters), decode it and store the result in the
* first DIGEST_LEN bytes at <b>digest</b>. */
int
@@ -2721,7 +2797,7 @@ digest_from_base64(char *digest, const char *d64)
#endif
}
-/** Base-64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
+/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
* trailing = and newline characters, and store the nul-terminated result in
* the first BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
int
@@ -2734,7 +2810,7 @@ digest256_to_base64(char *d64, const char *digest)
return 0;
}
-/** Given a base-64 encoded, nul-terminated digest in <b>d64</b> (without
+/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
* trailing newline or = characters), decode it and store the result in the
* first DIGEST256_LEN bytes at <b>digest</b>. */
int
@@ -2759,7 +2835,7 @@ digest256_from_base64(char *digest, const char *d64)
#endif
}
-/** Implements base32 encoding as in rfc3548. Limitation: Requires
+/** Implements base32 encoding as in RFC 4648. Limitation: Requires
* that srclen*8 is a multiple of 5.
*/
void
@@ -2784,7 +2860,7 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
dest[i] = '\0';
}
-/** Implements base32 decoding as in rfc3548. Limitation: Requires
+/** Implements base32 decoding as in RFC 4648. Limitation: Requires
* that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
*/
int
@@ -2937,21 +3013,27 @@ memwipe(void *mem, uint8_t byte, size_t sz)
}
#ifdef TOR_IS_MULTITHREADED
+
+#ifndef OPENSSL_THREADS
+#error OpenSSL has been built without thread support. Tor requires an \
+ OpenSSL library with thread support enabled.
+#endif
+
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
static void
-_openssl_locking_cb(int mode, int n, const char *file, int line)
+openssl_locking_cb_(int mode, int n, const char *file, int line)
{
(void)file;
(void)line;
- if (!_openssl_mutexes)
+ if (!openssl_mutexes_)
/* This is not a really good fix for the
* "release-freed-lock-from-separate-thread-on-shutdown" problem, but
* it can't hurt. */
return;
if (mode & CRYPTO_LOCK)
- tor_mutex_acquire(_openssl_mutexes[n]);
+ tor_mutex_acquire(openssl_mutexes_[n]);
else
- tor_mutex_release(_openssl_mutexes[n]);
+ tor_mutex_release(openssl_mutexes_[n]);
}
/** OpenSSL helper type: wraps a Tor mutex so that OpenSSL can use it
@@ -2963,7 +3045,7 @@ struct CRYPTO_dynlock_value {
/** OpenSSL callback function to allocate a lock: see CRYPTO_set_dynlock_*
* documentation in OpenSSL's docs for more info. */
static struct CRYPTO_dynlock_value *
-_openssl_dynlock_create_cb(const char *file, int line)
+openssl_dynlock_create_cb_(const char *file, int line)
{
struct CRYPTO_dynlock_value *v;
(void)file;
@@ -2976,7 +3058,7 @@ _openssl_dynlock_create_cb(const char *file, int line)
/** OpenSSL callback function to acquire or release a lock: see
* CRYPTO_set_dynlock_* documentation in OpenSSL's docs for more info. */
static void
-_openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v,
+openssl_dynlock_lock_cb_(int mode, struct CRYPTO_dynlock_value *v,
const char *file, int line)
{
(void)file;
@@ -2990,7 +3072,7 @@ _openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v,
/** OpenSSL callback function to free a lock: see CRYPTO_set_dynlock_*
* documentation in OpenSSL's docs for more info. */
static void
-_openssl_dynlock_destroy_cb(struct CRYPTO_dynlock_value *v,
+openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
const char *file, int line)
{
(void)file;
@@ -3007,15 +3089,15 @@ setup_openssl_threading(void)
{
int i;
int n = CRYPTO_num_locks();
- _n_openssl_mutexes = n;
- _openssl_mutexes = tor_malloc(n*sizeof(tor_mutex_t *));
+ n_openssl_mutexes_ = n;
+ openssl_mutexes_ = tor_malloc(n*sizeof(tor_mutex_t *));
for (i=0; i < n; ++i)
- _openssl_mutexes[i] = tor_mutex_new();
- CRYPTO_set_locking_callback(_openssl_locking_cb);
+ openssl_mutexes_[i] = tor_mutex_new();
+ CRYPTO_set_locking_callback(openssl_locking_cb_);
CRYPTO_set_id_callback(tor_get_thread_id);
- CRYPTO_set_dynlock_create_callback(_openssl_dynlock_create_cb);
- CRYPTO_set_dynlock_lock_callback(_openssl_dynlock_lock_cb);
- CRYPTO_set_dynlock_destroy_callback(_openssl_dynlock_destroy_cb);
+ CRYPTO_set_dynlock_create_callback(openssl_dynlock_create_cb_);
+ CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock_cb_);
+ CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_);
return 0;
}
#else
@@ -3036,11 +3118,11 @@ crypto_global_cleanup(void)
ERR_free_strings();
if (dh_param_p)
- BN_free(dh_param_p);
+ BN_clear_free(dh_param_p);
if (dh_param_p_tls)
- BN_free(dh_param_p_tls);
+ BN_clear_free(dh_param_p_tls);
if (dh_param_g)
- BN_free(dh_param_g);
+ BN_clear_free(dh_param_g);
#ifndef DISABLE_ENGINES
ENGINE_cleanup();
@@ -3049,18 +3131,19 @@ crypto_global_cleanup(void)
CONF_modules_unload(1);
CRYPTO_cleanup_all_ex_data();
#ifdef TOR_IS_MULTITHREADED
- if (_n_openssl_mutexes) {
- int n = _n_openssl_mutexes;
- tor_mutex_t **ms = _openssl_mutexes;
+ if (n_openssl_mutexes_) {
+ int n = n_openssl_mutexes_;
+ tor_mutex_t **ms = openssl_mutexes_;
int i;
- _openssl_mutexes = NULL;
- _n_openssl_mutexes = 0;
+ openssl_mutexes_ = NULL;
+ n_openssl_mutexes_ = 0;
for (i=0;i<n;++i) {
tor_mutex_free(ms[i]);
}
tor_free(ms);
}
#endif
+ tor_free(crypto_openssl_version_str);
return 0;
}
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 7d5627178..2fbca4c26 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,8 +10,8 @@
* \brief Headers for crypto.c
**/
-#ifndef _TOR_CRYPTO_H
-#define _TOR_CRYPTO_H
+#ifndef TOR_CRYPTO_H
+#define TOR_CRYPTO_H
#include <stdio.h>
#include "torint.h"
@@ -51,7 +51,7 @@
/** Length of the output of our message digest. */
#define DIGEST_LEN 20
/** Length of the output of our second (improved) message digests. (For now
- * this is just sha256, but any it can be any other 256-byte digest). */
+ * this is just sha256, but it could be any other 256-bit digest.) */
#define DIGEST256_LEN 32
/** Length of our symmetric cipher's keys. */
#define CIPHER_KEY_LEN 16
@@ -111,6 +111,7 @@ typedef struct crypto_digest_t crypto_digest_t;
typedef struct crypto_dh_t crypto_dh_t;
/* global state */
+const char * crypto_openssl_get_version_str(void);
int crypto_global_init(int hardwareAccel,
const char *accelName,
const char *accelPath);
@@ -147,6 +148,7 @@ int crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
int crypto_pk_check_key(crypto_pk_t *env);
int crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b);
+int crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b);
size_t crypto_pk_keysize(crypto_pk_t *env);
int crypto_pk_num_bits(crypto_pk_t *env);
crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig);
@@ -181,7 +183,6 @@ crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len);
int crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out);
int crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out);
int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space);
-int crypto_pk_check_fingerprint_syntax(const char *s);
/* symmetric crypto */
const char *crypto_cipher_get_key(crypto_cipher_t *env);
@@ -204,6 +205,10 @@ int crypto_digest(char *digest, const char *m, size_t len);
int crypto_digest256(char *digest, const char *m, size_t len,
digest_algorithm_t algorithm);
int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
+struct smartlist_t;
+void crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const struct smartlist_t *lst, const char *append,
+ digest_algorithm_t alg);
const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
int crypto_digest_algorithm_parse_name(const char *name);
crypto_digest_t *crypto_digest_new(void);
@@ -228,6 +233,7 @@ void crypto_hmac_sha256(char *hmac_out,
#define DH_TYPE_REND 2
#define DH_TYPE_TLS 3
crypto_dh_t *crypto_dh_new(int dh_type);
+crypto_dh_t *crypto_dh_dup(const crypto_dh_t *dh);
int crypto_dh_get_bytes(crypto_dh_t *dh);
int crypto_dh_generate_public(crypto_dh_t *dh);
int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out,
@@ -236,15 +242,25 @@ ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
const char *pubkey, size_t pubkey_len,
char *secret_out, size_t secret_out_len);
void crypto_dh_free(crypto_dh_t *dh);
-int crypto_expand_key_material(const char *key_in, size_t in_len,
- char *key_out, size_t key_out_len);
+
+int crypto_expand_key_material_TAP(const uint8_t *key_in,
+ size_t key_in_len,
+ uint8_t *key_out, size_t key_out_len);
+int crypto_expand_key_material_rfc5869_sha256(
+ const uint8_t *key_in, size_t key_in_len,
+ const uint8_t *salt_in, size_t salt_in_len,
+ const uint8_t *info_in, size_t info_in_len,
+ uint8_t *key_out, size_t key_out_len);
/* random numbers */
int crypto_seed_rng(int startup);
int crypto_rand(char *to, size_t n);
+int crypto_strongest_rand(uint8_t *out, size_t out_len);
int crypto_rand_int(unsigned int max);
uint64_t crypto_rand_uint64(uint64_t max);
double crypto_rand_double(void);
+struct tor_weak_rng_t;
+void crypto_seed_weak_rng(struct tor_weak_rng_t *rng);
char *crypto_random_hostname(int min_rand_len, int max_rand_len,
const char *prefix, const char *suffix);
@@ -255,7 +271,7 @@ void smartlist_shuffle(struct smartlist_t *sl);
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen);
-/** Characters that can appear (case-insensitively) in a base-32 encoding. */
+/** Characters that can appear (case-insensitively) in a base32 encoding. */
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen);
@@ -280,11 +296,11 @@ void memwipe(void *mem, uint8_t byte, size_t sz);
struct rsa_st;
struct evp_pkey_st;
struct dh_st;
-struct rsa_st *_crypto_pk_get_rsa(crypto_pk_t *env);
-crypto_pk_t *_crypto_new_pk_from_rsa(struct rsa_st *rsa);
-struct evp_pkey_st *_crypto_pk_get_evp_pkey(crypto_pk_t *env,
+struct rsa_st *crypto_pk_get_rsa_(crypto_pk_t *env);
+crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa);
+struct evp_pkey_st *crypto_pk_get_evp_pkey_(crypto_pk_t *env,
int private);
-struct dh_st *_crypto_dh_get_dh(crypto_dh_t *dh);
+struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh);
/* Prototypes for private functions only used by crypto.c and test.c*/
void add_spaces_to_fp(char *out, size_t outlen, const char *in);
#endif
diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c
new file mode 100644
index 000000000..88c723f37
--- /dev/null
+++ b/src/common/crypto_curve25519.c
@@ -0,0 +1,191 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Wrapper code for a curve25519 implementation. */
+
+#define CRYPTO_CURVE25519_PRIVATE
+#include "orconfig.h"
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "crypto.h"
+#include "crypto_curve25519.h"
+#include "util.h"
+#include "torlog.h"
+
+/* ==============================
+ Part 1: wrap a suitable curve25519 implementation as curve25519_impl
+ ============================== */
+
+#ifdef USE_CURVE25519_DONNA
+int curve25519_donna(uint8_t *mypublic,
+ const uint8_t *secret, const uint8_t *basepoint);
+#endif
+#ifdef USE_CURVE25519_NACL
+#ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H
+#include <crypto_scalarmult_curve25519.h>
+#elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H)
+#include <nacl/crypto_scalarmult_curve25519.h>
+#endif
+#endif
+
+int
+curve25519_impl(uint8_t *output, const uint8_t *secret,
+ const uint8_t *basepoint)
+{
+ uint8_t bp[CURVE25519_PUBKEY_LEN];
+ int r;
+ memcpy(bp, basepoint, CURVE25519_PUBKEY_LEN);
+ /* Clear the high bit, in case our backend foolishly looks at it. */
+ bp[31] &= 0x7f;
+#ifdef USE_CURVE25519_DONNA
+ r = curve25519_donna(output, secret, bp);
+#elif defined(USE_CURVE25519_NACL)
+ r = crypto_scalarmult_curve25519(output, secret, bp);
+#else
+#error "No implementation of curve25519 is available."
+#endif
+ memwipe(bp, 0, sizeof(bp));
+ return r;
+}
+
+/* ==============================
+ Part 2: Wrap curve25519_impl with some convenience types and functions.
+ ============================== */
+
+/**
+ * Return true iff a curve25519_public_key_t seems valid. (It's not necessary
+ * to see if the point is on the curve, since the twist is also secure, but we
+ * do need to make sure that it isn't the point at infinity.) */
+int
+curve25519_public_key_is_ok(const curve25519_public_key_t *key)
+{
+ return !safe_mem_is_zero(key->public_key, CURVE25519_PUBKEY_LEN);
+}
+
+/** Generate a new keypair and return the secret key. If <b>extra_strong</b>
+ * is true, this key is possibly going to get used more than once, so
+ * use a better-than-usual RNG. Return 0 on success, -1 on failure. */
+int
+curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
+ int extra_strong)
+{
+ uint8_t k_tmp[CURVE25519_SECKEY_LEN];
+
+ if (crypto_rand((char*)key_out->secret_key, CURVE25519_SECKEY_LEN) < 0)
+ return -1;
+ if (extra_strong && !crypto_strongest_rand(k_tmp, CURVE25519_SECKEY_LEN)) {
+ /* If they asked for extra-strong entropy and we have some, use it as an
+ * HMAC key to improve not-so-good entropy rather than using it directly,
+ * just in case the extra-strong entropy is less amazing than we hoped. */
+ crypto_hmac_sha256((char *)key_out->secret_key,
+ (const char *)k_tmp, sizeof(k_tmp),
+ (const char *)key_out->secret_key, CURVE25519_SECKEY_LEN);
+ }
+ memwipe(k_tmp, 0, sizeof(k_tmp));
+ key_out->secret_key[0] &= 248;
+ key_out->secret_key[31] &= 127;
+ key_out->secret_key[31] |= 64;
+
+ return 0;
+}
+
+void
+curve25519_public_key_generate(curve25519_public_key_t *key_out,
+ const curve25519_secret_key_t *seckey)
+{
+ static const uint8_t basepoint[32] = {9};
+
+ curve25519_impl(key_out->public_key, seckey->secret_key, basepoint);
+}
+
+int
+curve25519_keypair_generate(curve25519_keypair_t *keypair_out,
+ int extra_strong)
+{
+ if (curve25519_secret_key_generate(&keypair_out->seckey, extra_strong) < 0)
+ return -1;
+ curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey);
+ return 0;
+}
+
+int
+curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
+ const char *fname,
+ const char *tag)
+{
+ char contents[32 + CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN];
+ int r;
+
+ memset(contents, 0, sizeof(contents));
+ tor_snprintf(contents, sizeof(contents), "== c25519v1: %s ==", tag);
+ tor_assert(strlen(contents) <= 32);
+ memcpy(contents+32, keypair->seckey.secret_key, CURVE25519_SECKEY_LEN);
+ memcpy(contents+32+CURVE25519_SECKEY_LEN,
+ keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+
+ r = write_bytes_to_file(fname, contents, sizeof(contents), 1);
+
+ memwipe(contents, 0, sizeof(contents));
+ return r;
+}
+
+int
+curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
+ char **tag_out,
+ const char *fname)
+{
+ char prefix[33];
+ char *content;
+ struct stat st;
+ int r = -1;
+
+ *tag_out = NULL;
+
+ st.st_size = 0;
+ content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
+ if (! content)
+ goto end;
+ if (st.st_size != 32 + CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN)
+ goto end;
+
+ memcpy(prefix, content, 32);
+ prefix[32] = '\0';
+ if (strcmpstart(prefix, "== c25519v1: ") ||
+ strcmpend(prefix, " =="))
+ goto end;
+
+ *tag_out = tor_strndup(prefix+strlen("== c25519v1: "),
+ strlen(prefix) - strlen("== c25519v1: =="));
+
+ memcpy(keypair_out->seckey.secret_key, content+32, CURVE25519_SECKEY_LEN);
+ curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey);
+ if (tor_memneq(keypair_out->pubkey.public_key,
+ content + 32 + CURVE25519_SECKEY_LEN,
+ CURVE25519_PUBKEY_LEN))
+ goto end;
+
+ r = 0;
+
+ end:
+ if (content) {
+ memwipe(content, 0, (size_t) st.st_size);
+ tor_free(content);
+ }
+ if (r != 0) {
+ memset(keypair_out, 0, sizeof(*keypair_out));
+ tor_free(*tag_out);
+ }
+ return r;
+}
+
+/** Perform the curve25519 ECDH handshake with <b>skey</b> and <b>pkey</b>,
+ * writing CURVE25519_OUTPUT_LEN bytes of output into <b>output</b>. */
+void
+curve25519_handshake(uint8_t *output,
+ const curve25519_secret_key_t *skey,
+ const curve25519_public_key_t *pkey)
+{
+ curve25519_impl(output, skey->secret_key, pkey->public_key);
+}
+
diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h
new file mode 100644
index 000000000..652f1883c
--- /dev/null
+++ b/src/common/crypto_curve25519.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_CRYPTO_CURVE25519_H
+#define TOR_CRYPTO_CURVE25519_H
+
+#include "torint.h"
+
+/** Length of a curve25519 public key when encoded. */
+#define CURVE25519_PUBKEY_LEN 32
+/** Length of a curve25519 secret key when encoded. */
+#define CURVE25519_SECKEY_LEN 32
+/** Length of the result of a curve25519 handshake. */
+#define CURVE25519_OUTPUT_LEN 32
+
+/** Wrapper type for a curve25519 public key */
+typedef struct curve25519_public_key_t {
+ uint8_t public_key[CURVE25519_PUBKEY_LEN];
+} curve25519_public_key_t;
+
+/** Wrapper type for a curve25519 secret key */
+typedef struct curve25519_secret_key_t {
+ uint8_t secret_key[CURVE25519_SECKEY_LEN];
+} curve25519_secret_key_t;
+
+/** A paired public and private key for curve25519. **/
+typedef struct curve25519_keypair_t {
+ curve25519_public_key_t pubkey;
+ curve25519_secret_key_t seckey;
+} curve25519_keypair_t;
+
+#ifdef CURVE25519_ENABLED
+int curve25519_public_key_is_ok(const curve25519_public_key_t *);
+
+int curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
+ int extra_strong);
+void curve25519_public_key_generate(curve25519_public_key_t *key_out,
+ const curve25519_secret_key_t *seckey);
+int curve25519_keypair_generate(curve25519_keypair_t *keypair_out,
+ int extra_strong);
+
+void curve25519_handshake(uint8_t *output,
+ const curve25519_secret_key_t *,
+ const curve25519_public_key_t *);
+
+int curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
+ const char *fname,
+ const char *tag);
+
+int curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
+ char **tag_out,
+ const char *fname);
+
+#ifdef CRYPTO_CURVE25519_PRIVATE
+int curve25519_impl(uint8_t *output, const uint8_t *secret,
+ const uint8_t *basepoint);
+#endif
+#endif
+
+#define CURVE25519_BASE64_PADDED_LEN 44
+
+int curve25519_public_from_base64(curve25519_public_key_t *pkey,
+ const char *input);
+int curve25519_public_to_base64(char *output,
+ const curve25519_public_key_t *pkey);
+
+#endif
+
diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c
new file mode 100644
index 000000000..93932f839
--- /dev/null
+++ b/src/common/crypto_format.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Formatting and parsing code for crypto-related data structures. */
+
+#define CRYPTO_CURVE25519_PRIVATE
+#include "orconfig.h"
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "crypto.h"
+#include "crypto_curve25519.h"
+#include "util.h"
+#include "torlog.h"
+
+int
+curve25519_public_to_base64(char *output,
+ const curve25519_public_key_t *pkey)
+{
+ char buf[128];
+ base64_encode(buf, sizeof(buf),
+ (const char*)pkey->public_key, CURVE25519_PUBKEY_LEN);
+ buf[CURVE25519_BASE64_PADDED_LEN] = '\0';
+ memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1);
+ return 0;
+}
+
+int
+curve25519_public_from_base64(curve25519_public_key_t *pkey,
+ const char *input)
+{
+ size_t len = strlen(input);
+ if (len == CURVE25519_BASE64_PADDED_LEN - 1) {
+ /* not padded */
+ return digest256_from_base64((char*)pkey->public_key, input);
+ } else if (len == CURVE25519_BASE64_PADDED_LEN) {
+ char buf[128];
+ if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN)
+ return -1;
+ memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
diff --git a/src/common/di_ops.c b/src/common/di_ops.c
index 7683c59de..14a144340 100644
--- a/src/common/di_ops.c
+++ b/src/common/di_ops.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* Copyright (c) 2011-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,6 +8,8 @@
#include "orconfig.h"
#include "di_ops.h"
+#include "torlog.h"
+#include "util.h"
/**
* Timing-safe version of memcmp. As memcmp, compare the <b>sz</b> bytes at
@@ -123,7 +125,7 @@ tor_memeq(const void *a, const void *b, size_t sz)
*
* If any_difference != 0:
* 0 < any_difference < 256, so
- * 0 < any_difference - 1 < 255
+ * 0 <= any_difference - 1 < 255
* (any_difference - 1) >> 8 == 0
* 1 & ((any_difference - 1) >> 8) == 0
*/
@@ -131,3 +133,90 @@ tor_memeq(const void *a, const void *b, size_t sz)
return 1 & ((any_difference - 1) >> 8);
}
+/* Implement di_digest256_map_t as a linked list of entries. */
+struct di_digest256_map_t {
+ struct di_digest256_map_t *next;
+ uint8_t key[32];
+ void *val;
+};
+
+/** Release all storage held in <b>map</b>, calling free_fn on each value
+ * as we go. */
+void
+dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn)
+{
+ while (map) {
+ di_digest256_map_t *victim = map;
+ map = map->next;
+ if (free_fn)
+ free_fn(victim->val);
+ tor_free(victim);
+ }
+}
+
+/** Adjust the map at *<b>map</b>, adding an entry for <b>key</b> ->
+ * <b>val</b>, where <b>key</b> is a DIGEST256_LEN-byte key.
+ *
+ * The caller MUST NOT add a key that already appears in the map.
+ */
+void
+dimap_add_entry(di_digest256_map_t **map,
+ const uint8_t *key, void *val)
+{
+ di_digest256_map_t *new_ent;
+ {
+ void *old_val = dimap_search(*map, key, NULL);
+ tor_assert(! old_val);
+ tor_assert(val);
+ }
+ new_ent = tor_malloc_zero(sizeof(di_digest256_map_t));
+ new_ent->next = *map;
+ memcpy(new_ent->key, key, 32);
+ new_ent->val = val;
+ *map = new_ent;
+}
+
+/** Search the map at <b>map</b> for an entry whose key is <b>key</b> (a
+ * DIGEST256_LEN-byte key) returning the corresponding value if we found one,
+ * and returning <b>dflt_val</b> if the key wasn't found.
+ *
+ * This operation takes an amount of time dependent only on the length of
+ * <b>map</b>, not on the position or presence of <b>key</b> within <b>map</b>.
+ */
+void *
+dimap_search(const di_digest256_map_t *map, const uint8_t *key,
+ void *dflt_val)
+{
+ uintptr_t result = (uintptr_t)dflt_val;
+
+ while (map) {
+ uintptr_t r = (uintptr_t) tor_memeq(map->key, key, 32);
+ r -= 1; /* Now r is (uintptr_t)-1 if memeq returned false, and
+ * 0 if memeq returned true. */
+
+ result &= r;
+ result |= ((uintptr_t)(map->val)) & ~r;
+
+ map = map->next;
+ }
+
+ return (void *)result;
+}
+
+/**
+ * Return true iff the <b>sz</b> bytes at <b>mem</b> are all zero. Runs in
+ * time independent of the contents of <b>mem</b>.
+ */
+int
+safe_mem_is_zero(const void *mem, size_t sz)
+{
+ uint32_t total = 0;
+ const uint8_t *ptr = mem;
+
+ while (sz--) {
+ total |= *ptr++;
+ }
+
+ return 1 & ((total - 1) >> 8);
+}
+
diff --git a/src/common/di_ops.h b/src/common/di_ops.h
index 8f0bb698f..d93534b69 100644
--- a/src/common/di_ops.h
+++ b/src/common/di_ops.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,5 +27,21 @@ int tor_memeq(const void *a, const void *b, size_t sz);
#define fast_memeq(a,b,c) (0==memcmp((a),(b),(c)))
#define fast_memneq(a,b,c) (0!=memcmp((a),(b),(c)))
+int safe_mem_is_zero(const void *mem, size_t sz);
+
+/** A type for a map from DIGEST256_LEN-byte blobs to void*, such that
+ * data lookups take an amount of time proportional only to the size
+ * of the map, and not to the position or presence of the item in the map.
+ *
+ * Not efficient for large maps! */
+typedef struct di_digest256_map_t di_digest256_map_t;
+typedef void (*dimap_free_fn)(void *);
+
+void dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn);
+void dimap_add_entry(di_digest256_map_t **map,
+ const uint8_t *key, void *val);
+void *dimap_search(const di_digest256_map_t *map, const uint8_t *key,
+ void *dflt_val);
+
#endif
diff --git a/src/common/include.am b/src/common/include.am
new file mode 100644
index 000000000..b796ebfae
--- /dev/null
+++ b/src/common/include.am
@@ -0,0 +1,96 @@
+
+noinst_LIBRARIES+= src/common/libor.a src/common/libor-crypto.a src/common/libor-event.a
+
+EXTRA_DIST+= \
+ src/common/common_sha1.i \
+ src/common/Makefile.nmake
+
+#CFLAGS = -Wall -Wpointer-arith -O2
+AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common
+
+if USE_OPENBSD_MALLOC
+libor_extra_source=src/ext/OpenBSD_malloc_Linux.c
+else
+libor_extra_source=
+endif
+
+if BUILD_CURVE25519_DONNA
+src_common_libcurve25519_donna_a_SOURCES=\
+ src/ext/curve25519_donna/curve25519-donna.c
+noinst_LIBRARIES+=src/common/libcurve25519_donna.a
+LIBDONNA=src/common/libcurve25519_donna.a
+else
+if BUILD_CURVE25519_DONNA_C64
+src_common_libcurve25519_donna_a_SOURCES=\
+ src/ext/curve25519_donna/curve25519-donna-c64.c
+noinst_LIBRARIES+=src/common/libcurve25519_donna.a
+LIBDONNA=src/common/libcurve25519_donna.a
+else
+LIBDONNA=
+endif
+endif
+
+src_common_libcurve25519_donna_a_CFLAGS =
+
+if CURVE25519_ENABLED
+libcrypto_extra_source=src/common/crypto_curve25519.c
+endif
+
+src_common_libor_a_SOURCES = \
+ src/common/address.c \
+ src/common/compat.c \
+ src/common/container.c \
+ src/common/di_ops.c \
+ src/common/log.c \
+ src/common/memarea.c \
+ src/common/mempool.c \
+ src/common/procmon.c \
+ src/common/util.c \
+ src/common/util_codedigest.c \
+ $(libor_extra_source)
+
+src_common_libor_crypto_a_SOURCES = \
+ src/common/aes.c \
+ src/common/crypto.c \
+ src/common/crypto_format.c \
+ src/common/torgzip.c \
+ src/common/tortls.c \
+ $(libcrypto_extra_source)
+
+src_common_libor_event_a_SOURCES = src/common/compat_libevent.c
+
+COMMONHEADERS = \
+ src/common/address.h \
+ src/common/aes.h \
+ src/common/ciphers.inc \
+ src/common/compat.h \
+ src/common/compat_libevent.h \
+ src/common/container.h \
+ src/common/crypto.h \
+ src/common/crypto_curve25519.h \
+ src/common/di_ops.h \
+ src/common/memarea.h \
+ src/common/mempool.h \
+ src/common/procmon.h \
+ src/common/torgzip.h \
+ src/common/torint.h \
+ src/common/torlog.h \
+ src/common/tortls.h \
+ src/common/util.h
+
+noinst_HEADERS+= $(COMMONHEADERS)
+
+DISTCLEANFILES+= src/common/common_sha1.i
+
+src/common/common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(COMMONHEADERS)
+ $(AM_V_GEN)if test "@SHA1SUM@" != none; then \
+ (cd "$(srcdir)" && "@SHA1SUM@" $(src_common_libor_SOURCES) $(src_common_libor_crypto_a_SOURCES) $(COMMONHEADERS)) | "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > $@; \
+ elif test "@OPENSSL@" != none; then \
+ (cd "$(srcdir)" && "@OPENSSL@" sha1 $(src_common_libor_SOURCES) $(src_Common_libor_crypto_a_SOURCES) $(COMMONHEADERS)) | "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > $@; \
+ else \
+ rm $@; \
+ touch $@; \
+ fi
+
+src/common/util_codedigest.o: src/common/common_sha1.i
+
diff --git a/src/common/log.c b/src/common/log.c
index 5e2e6b5b5..e196a1128 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -131,7 +131,7 @@ static smartlist_t *pending_cb_messages = NULL;
/** What's the lowest log level anybody cares about? Checking this lets us
* bail out early from log_debug if we aren't debugging. */
-int _log_global_min_severity = LOG_NOTICE;
+int log_global_min_severity_ = LOG_NOTICE;
static void delete_log(logfile_t *victim);
static void close_log(logfile_t *victim);
@@ -140,11 +140,12 @@ static char *domain_to_string(log_domain_mask_t domain,
char *buf, size_t buflen);
static INLINE char *format_msg(char *buf, size_t buf_len,
log_domain_mask_t domain, int severity, const char *funcname,
+ const char *suffix,
const char *format, va_list ap, size_t *msg_len_out)
- CHECK_PRINTF(6,0);
+ CHECK_PRINTF(7,0);
static void logv(int severity, log_domain_mask_t domain, const char *funcname,
- const char *format, va_list ap)
- CHECK_PRINTF(4,0);
+ const char *suffix, const char *format, va_list ap)
+ CHECK_PRINTF(5,0);
/** Name of the application: used to generate the message we write at the
* start of each new log. */
@@ -177,7 +178,7 @@ set_log_time_granularity(int granularity_msec)
* <b>buf_len</b> character buffer in <b>buf</b>.
*/
static INLINE size_t
-_log_prefix(char *buf, size_t buf_len, int severity)
+log_prefix_(char *buf, size_t buf_len, int severity)
{
time_t t;
struct timeval now;
@@ -230,7 +231,7 @@ log_tor_version(logfile_t *lf, int reset)
/* We are resetting, but we aren't at the start of the file; no
* need to log again. */
return 0;
- n = _log_prefix(buf, sizeof(buf), LOG_NOTICE);
+ n = log_prefix_(buf, sizeof(buf), LOG_NOTICE);
if (appname) {
tor_snprintf(buf+n, sizeof(buf)-n,
"%s opening %slog file.\n", appname, is_new?"new ":"");
@@ -251,6 +252,7 @@ log_tor_version(logfile_t *lf, int reset)
static INLINE char *
format_msg(char *buf, size_t buf_len,
log_domain_mask_t domain, int severity, const char *funcname,
+ const char *suffix,
const char *format, va_list ap, size_t *msg_len_out)
{
size_t n;
@@ -262,7 +264,7 @@ format_msg(char *buf, size_t buf_len,
buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
buf_end = buf+buf_len; /* point *after* the last char we can write to */
- n = _log_prefix(buf, buf_len, severity);
+ n = log_prefix_(buf, buf_len, severity);
end_of_prefix = buf+n;
if (log_domains_are_logged) {
@@ -312,6 +314,13 @@ format_msg(char *buf, size_t buf_len,
n = buf_len;
} else {
n += r;
+ if (suffix) {
+ size_t suffix_len = strlen(suffix);
+ if (buf_len-n >= suffix_len) {
+ memcpy(buf+n, suffix, suffix_len);
+ n += suffix_len;
+ }
+ }
}
buf[n]='\n';
buf[n+1]='\0';
@@ -325,7 +334,7 @@ format_msg(char *buf, size_t buf_len,
*/
static void
logv(int severity, log_domain_mask_t domain, const char *funcname,
- const char *format, va_list ap)
+ const char *suffix, const char *format, va_list ap)
{
char buf[10024];
size_t msg_len = 0;
@@ -361,8 +370,8 @@ logv(int severity, log_domain_mask_t domain, const char *funcname,
if (!formatted) {
end_of_prefix =
- format_msg(buf, sizeof(buf), domain, severity, funcname, format, ap,
- &msg_len);
+ format_msg(buf, sizeof(buf), domain, severity, funcname, suffix,
+ format, ap, &msg_len);
formatted = 1;
}
@@ -423,10 +432,10 @@ void
tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (severity > _log_global_min_severity)
+ if (severity > log_global_min_severity_)
return;
va_start(ap,format);
- logv(severity, domain, NULL, format, ap);
+ logv(severity, domain, NULL, NULL, format, ap);
va_end(ap);
}
@@ -436,89 +445,121 @@ tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
* variadic macros. All arguments are as for log_fn, except for
* <b>fn</b>, which is the name of the calling functions. */
void
-_log_fn(int severity, log_domain_mask_t domain, const char *fn,
+log_fn_(int severity, log_domain_mask_t domain, const char *fn,
const char *format, ...)
{
va_list ap;
- if (severity > _log_global_min_severity)
+ if (severity > log_global_min_severity_)
return;
va_start(ap,format);
- logv(severity, domain, fn, format, ap);
+ logv(severity, domain, fn, NULL, format, ap);
+ va_end(ap);
+}
+void
+log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
+ const char *fn, const char *format, ...)
+{
+ va_list ap;
+ char *m;
+ if (severity > log_global_min_severity_)
+ return;
+ m = rate_limit_log(ratelim, approx_time());
+ if (m == NULL)
+ return;
+ va_start(ap, format);
+ logv(severity, domain, fn, m, format, ap);
va_end(ap);
+ tor_free(m);
}
#else
/** @{ */
/** Variant implementation of log_fn, log_debug, log_info,... for C compilers
* without variadic macros. In this case, the calling function sets
- * _log_fn_function_name to the name of the function, then invokes the
- * appropriate _log_fn, _log_debug, etc. */
-const char *_log_fn_function_name=NULL;
+ * log_fn_function_name_ to the name of the function, then invokes the
+ * appropriate log_fn_, log_debug_, etc. */
+const char *log_fn_function_name_=NULL;
void
-_log_fn(int severity, log_domain_mask_t domain, const char *format, ...)
+log_fn_(int severity, log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (severity > _log_global_min_severity)
+ if (severity > log_global_min_severity_)
return;
va_start(ap,format);
- logv(severity, domain, _log_fn_function_name, format, ap);
+ logv(severity, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_debug(log_domain_mask_t domain, const char *format, ...)
+log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
+ const char *format, ...)
+{
+ va_list ap;
+ char *m;
+ if (severity > log_global_min_severity_)
+ return;
+ m = rate_limit_log(ratelim, approx_time());
+ if (m == NULL)
+ return;
+ va_start(ap, format);
+ logv(severity, domain, log_fn_function_name_, m, format, ap);
+ va_end(ap);
+ tor_free(m);
+}
+void
+log_debug_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
/* For GCC we do this check in the macro. */
- if (PREDICT_LIKELY(LOG_DEBUG > _log_global_min_severity))
+ if (PREDICT_LIKELY(LOG_DEBUG > log_global_min_severity_))
return;
va_start(ap,format);
- logv(LOG_DEBUG, domain, _log_fn_function_name, format, ap);
+ logv(LOG_DEBUG, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_info(log_domain_mask_t domain, const char *format, ...)
+log_info_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_INFO > _log_global_min_severity)
+ if (LOG_INFO > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_INFO, domain, _log_fn_function_name, format, ap);
+ logv(LOG_INFO, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_notice(log_domain_mask_t domain, const char *format, ...)
+log_notice_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_NOTICE > _log_global_min_severity)
+ if (LOG_NOTICE > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_NOTICE, domain, _log_fn_function_name, format, ap);
+ logv(LOG_NOTICE, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_warn(log_domain_mask_t domain, const char *format, ...)
+log_warn_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_WARN > _log_global_min_severity)
+ if (LOG_WARN > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_WARN, domain, _log_fn_function_name, format, ap);
+ logv(LOG_WARN, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_err(log_domain_mask_t domain, const char *format, ...)
+log_err_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_ERR > _log_global_min_severity)
+ if (LOG_ERR > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_ERR, domain, _log_fn_function_name, format, ap);
+ logv(LOG_ERR, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
/** @} */
#endif
@@ -638,7 +679,7 @@ add_stream_log_impl(const log_severity_list_t *severity,
lf->next = logfiles;
logfiles = lf;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
}
/** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
@@ -706,7 +747,7 @@ add_callback_log(const log_severity_list_t *severity, log_callback cb)
LOCK_LOGS();
logfiles = lf;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
return 0;
}
@@ -726,7 +767,7 @@ change_callback_log_severity(int loglevelMin, int loglevelMax,
memcpy(lf->severities, &severities, sizeof(severities));
}
}
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
}
@@ -792,7 +833,7 @@ close_temp_logs(void)
}
}
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
}
@@ -833,14 +874,16 @@ add_file_log(const log_severity_list_t *severity, const char *filename)
fd = tor_open_cloexec(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
if (fd<0)
return -1;
- if (tor_fd_seekend(fd)<0)
+ if (tor_fd_seekend(fd)<0) {
+ close(fd);
return -1;
+ }
LOCK_LOGS();
add_stream_log_impl(severity, filename, fd);
logfiles->needs_close = 1;
lf = logfiles;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
if (log_tor_version(lf, 0) < 0) {
delete_log(lf);
@@ -871,7 +914,7 @@ add_syslog_log(const log_severity_list_t *severity)
LOCK_LOGS();
lf->next = logfiles;
logfiles = lf;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
return 0;
}
@@ -907,7 +950,7 @@ log_level_to_string(int level)
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
- "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", NULL
+ "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
@@ -1106,7 +1149,7 @@ switch_logs_debug(void)
for (i = LOG_DEBUG; i >= LOG_ERR; --i)
lf->severities->masks[SEVERITY_MASK_IDX(i)] = ~0u;
}
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
}
diff --git a/src/common/memarea.c b/src/common/memarea.c
index 07bd593cc..0ae0ccca1 100644
--- a/src/common/memarea.c
+++ b/src/common/memarea.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Tor Project, Inc. */
+/* Copyright (c) 2008-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** \file memarea.c
@@ -77,7 +77,7 @@ typedef struct memarea_chunk_t {
* full. */
union {
char mem[1]; /**< Memory space in this chunk. */
- void *_void_for_alignment; /**< Dummy; used to make sure mem is aligned. */
+ void *void_for_alignment_; /**< Dummy; used to make sure mem is aligned. */
} u;
} memarea_chunk_t;
@@ -118,7 +118,7 @@ alloc_chunk(size_t sz, int freelist_ok)
size_t chunk_size = freelist_ok ? CHUNK_SIZE : sz;
memarea_chunk_t *res;
chunk_size += SENTINEL_LEN;
- res = tor_malloc_roundup(&chunk_size);
+ res = tor_malloc(chunk_size);
res->next_chunk = NULL;
res->mem_size = chunk_size - CHUNK_HEADER_SIZE - SENTINEL_LEN;
res->next_mem = res->u.mem;
diff --git a/src/common/memarea.h b/src/common/memarea.h
index b3c76d8d0..8b88585d3 100644
--- a/src/common/memarea.h
+++ b/src/common/memarea.h
@@ -1,9 +1,9 @@
-/* Copyright (c) 2008-2012, The Tor Project, Inc. */
+/* Copyright (c) 2008-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Tor dependencies */
-#ifndef _TOR_MEMAREA_H
-#define _TOR_MEMAREA_H
+#ifndef TOR_MEMAREA_H
+#define TOR_MEMAREA_H
typedef struct memarea_t memarea_t;
diff --git a/src/common/mempool.c b/src/common/mempool.c
index 637f081c8..438988876 100644
--- a/src/common/mempool.c
+++ b/src/common/mempool.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#if 1
/* Tor dependencies */
@@ -71,7 +71,6 @@
#define ASSERT(x) tor_assert(x)
#undef ALLOC_CAN_RETURN_NULL
#define TOR
-//#define ALLOC_ROUNDUP(p) tor_malloc_roundup(p)
/* End Tor dependencies */
#else
/* If you're not building this as part of Tor, you'll want to define the
@@ -115,7 +114,7 @@ struct mp_allocated_t {
* (Not actual size.) */
char mem[1];
/** An extra element to the union to insure correct alignment. */
- ALIGNMENT_TYPE _dummy;
+ ALIGNMENT_TYPE dummy_;
} u;
};
@@ -166,25 +165,16 @@ static mp_chunk_t *
mp_chunk_new(mp_pool_t *pool)
{
size_t sz = pool->new_chunk_capacity * pool->item_alloc_size;
-#ifdef ALLOC_ROUNDUP
- size_t alloc_size = CHUNK_OVERHEAD + sz;
- mp_chunk_t *chunk = ALLOC_ROUNDUP(&alloc_size);
-#else
mp_chunk_t *chunk = ALLOC(CHUNK_OVERHEAD + sz);
-#endif
+
#ifdef MEMPOOL_STATS
++pool->total_chunks_allocated;
#endif
CHECK_ALLOC(chunk);
memset(chunk, 0, sizeof(mp_chunk_t)); /* Doesn't clear the whole thing. */
chunk->magic = MP_CHUNK_MAGIC;
-#ifdef ALLOC_ROUNDUP
- chunk->mem_size = alloc_size - CHUNK_OVERHEAD;
- chunk->capacity = chunk->mem_size / pool->item_alloc_size;
-#else
chunk->capacity = pool->new_chunk_capacity;
chunk->mem_size = sz;
-#endif
chunk->next_mem = chunk->mem;
chunk->pool = pool;
return chunk;
diff --git a/src/common/mempool.h b/src/common/mempool.h
index bc424acde..0fc1e4c67 100644
--- a/src/common/mempool.h
+++ b/src/common/mempool.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,8 +6,8 @@
* \brief Headers for mempool.c
**/
-#ifndef _TOR_MEMPOOL_H
-#define _TOR_MEMPOOL_H
+#ifndef TOR_MEMPOOL_H
+#define TOR_MEMPOOL_H
/** A memory pool is a context in which a large number of fixed-sized
* objects can be allocated efficiently. See mempool.c for implementation
diff --git a/src/common/procmon.c b/src/common/procmon.c
index 36b1a4855..0a49689e3 100644
--- a/src/common/procmon.c
+++ b/src/common/procmon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* Copyright (c) 2011-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,9 +25,21 @@
#ifdef _WIN32
#include <windows.h>
+#endif
-/* Windows does not define pid_t, but _getpid() returns an int. */
+#if (0 == SIZEOF_PID_T) && defined(_WIN32)
+/* Windows does not define pid_t sometimes, but _getpid() returns an int.
+ * Everybody else needs to have a pid_t. */
typedef int pid_t;
+#define PID_T_FORMAT "%d"
+#elif (SIZEOF_PID_T == SIZEOF_INT) || (SIZEOF_PID_T == SIZEOF_SHORT)
+#define PID_T_FORMAT "%d"
+#elif (SIZEOF_PID_T == SIZEOF_LONG)
+#define PID_T_FORMAT "%ld"
+#elif (SIZEOF_PID_T == SIZEOF_INT64_T)
+#define PID_T_FORMAT I64_FORMAT
+#else
+#error Unknown: SIZEOF_PID_T
#endif
/* Define to 1 if process-termination monitors on this OS and Libevent
@@ -204,15 +216,17 @@ tor_process_monitor_new(struct event_base *base,
if (procmon->hproc != NULL) {
procmon->poll_hproc = 1;
- log_info(procmon->log_domain, "Successfully opened handle to process %d; "
+ log_info(procmon->log_domain, "Successfully opened handle to process "
+ PID_T_FORMAT"; "
"monitoring it.",
- (int)(procmon->pid));
+ procmon->pid);
} else {
/* If we couldn't get a handle to the process, we'll try again the
* first time we poll. */
- log_info(procmon->log_domain, "Failed to open handle to process %d; will "
+ log_info(procmon->log_domain, "Failed to open handle to process "
+ PID_T_FORMAT"; will "
"try again later.",
- (int)(procmon->pid));
+ procmon->pid);
}
#endif
@@ -257,7 +271,8 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
if (!GetExitCodeProcess(procmon->hproc, &exit_code)) {
char *errmsg = format_win32_error(GetLastError());
log_warn(procmon->log_domain, "Error \"%s\" occurred while polling "
- "handle for monitored process %d; assuming it's dead.",
+ "handle for monitored process "PID_T_FORMAT"; assuming "
+ "it's dead.",
errmsg, procmon->pid);
tor_free(errmsg);
its_dead_jim = 1;
@@ -273,7 +288,7 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
if (procmon->hproc != NULL) {
log_info(procmon->log_domain, "Successfully opened handle to monitored "
- "process %d.",
+ "process "PID_T_FORMAT".",
procmon->pid);
its_dead_jim = 0;
procmon->poll_hproc = 1;
@@ -292,8 +307,8 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
if (!its_dead_jim)
log_info(procmon->log_domain, "Failed to open handle to monitored "
- "process %d, and error code %lu (%s) is not 'invalid "
- "parameter' -- assuming the process is still alive.",
+ "process "PID_T_FORMAT", and error code %lu (%s) is not "
+ "'invalid parameter' -- assuming the process is still alive.",
procmon->pid,
err_code, errmsg);
@@ -306,9 +321,9 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
its_dead_jim = its_dead_jim && (errno == ESRCH);
#endif
- log(its_dead_jim ? LOG_NOTICE : LOG_INFO,
- procmon->log_domain, "Monitored process %d is %s.",
- (int)procmon->pid,
+ tor_log(its_dead_jim ? LOG_NOTICE : LOG_INFO,
+ procmon->log_domain, "Monitored process "PID_T_FORMAT" is %s.",
+ procmon->pid,
its_dead_jim ? "dead" : "still alive");
if (its_dead_jim) {
diff --git a/src/common/procmon.h b/src/common/procmon.h
index 88d64d6a1..b9388e2e9 100644
--- a/src/common/procmon.h
+++ b/src/common/procmon.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* Copyright (c) 2011-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/sha256.c b/src/common/sha256.c
deleted file mode 100644
index 813c68d2a..000000000
--- a/src/common/sha256.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/* Copyright (c) 2009-2012, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-/* This SHA256 implementation is adapted from the public domain one in
- LibTomCrypt, version 1.6. Tor uses it on platforms where OpenSSL doesn't
- have a SHA256. */
-
-
-typedef struct sha256_state {
- uint64_t length;
- uint32_t state[8], curlen;
- unsigned char buf[64];
-} sha256_state;
-
-#define CRYPT_OK 0
-#define CRYPT_NOP -1
-#define CRYPT_INVALID_ARG -2
-
-#define LOAD32H(x,y) STMT_BEGIN x = ntohl(get_uint32((const char*)y)); STMT_END
-#define STORE32H(x,y) STMT_BEGIN set_uint32((char*)y, htonl(x)); STMT_END
-#define STORE64H(x,y) STMT_BEGIN \
- set_uint32((char*)y, htonl((uint32_t)((x)>>32))); \
- set_uint32(((char*)y)+4, htonl((uint32_t)((x)&0xffffffff))); \
- STMT_END
-#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#ifndef MIN
- #define MIN(x, y) ( ((x)<(y))?(x):(y) )
-#endif
-
-
-/* LibTomCrypt, modular cryptographic library -- Tom St Denis
- *
- * LibTomCrypt is a library that provides various cryptographic
- * algorithms in a highly modular and flexible manner.
- *
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
- */
-
-/**
- @file sha256.c
- SHA256 by Tom St Denis
-*/
-
-
-#ifdef LTC_SMALL_CODE
-/* the K array */
-static const uint32_t K[64] = {
- 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
- 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
- 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
- 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
- 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
- 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
- 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
- 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
- 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
- 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
- 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
- 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
- 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
-};
-#endif
-
-/* Various logical functions */
-#define Ch(x,y,z) (z ^ (x & (y ^ z)))
-#define Maj(x,y,z) (((x | y) & z) | (x & y))
-#define S(x, n) RORc((x),(n))
-#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
-#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
-#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
-#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
-#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
-
-/* compress 512-bits */
-#ifdef LTC_CLEAN_STACK
-static int _sha256_compress(sha256_state * md, unsigned char *buf)
-#else
-static int sha256_compress(sha256_state * md, unsigned char *buf)
-#endif
-{
- uint32_t S[8], W[64], t0, t1;
-#ifdef LTC_SMALL_CODE
- uint32_t t;
-#endif
- int i;
-
- /* copy state into S */
- for (i = 0; i < 8; i++) {
- S[i] = md->state[i];
- }
-
- /* copy the state into 512-bits into W[0..15] */
- for (i = 0; i < 16; i++) {
- LOAD32H(W[i], buf + (4*i));
- }
-
- /* fill W[16..63] */
- for (i = 16; i < 64; i++) {
- W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
- }
-
- /* Compress */
-#ifdef LTC_SMALL_CODE
-#define RND(a,b,c,d,e,f,g,h,i) \
- t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
- t1 = Sigma0(a) + Maj(a, b, c); \
- d += t0; \
- h = t0 + t1;
-
- for (i = 0; i < 64; ++i) {
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i);
- t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
- S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
- }
-#else
-#define RND(a,b,c,d,e,f,g,h,i,ki) \
- t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
- t1 = Sigma0(a) + Maj(a, b, c); \
- d += t0; \
- h = t0 + t1;
-
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
-
-#undef RND
-
-#endif
-
- /* feedback */
- for (i = 0; i < 8; i++) {
- md->state[i] = md->state[i] + S[i];
- }
- return CRYPT_OK;
-}
-
-#ifdef LTC_CLEAN_STACK
-static int sha256_compress(sha256_state * md, unsigned char *buf)
-{
- int err;
- err = _sha256_compress(md, buf);
- burn_stack(sizeof(uint32_t) * 74);
- return err;
-}
-#endif
-
-/**
- Initialize the hash state
- @param md The hash state you wish to initialize
- @return CRYPT_OK if successful
-*/
-static int sha256_init(sha256_state * md)
-{
- LTC_ARGCHK(md != NULL);
-
- md->curlen = 0;
- md->length = 0;
- md->state[0] = 0x6A09E667UL;
- md->state[1] = 0xBB67AE85UL;
- md->state[2] = 0x3C6EF372UL;
- md->state[3] = 0xA54FF53AUL;
- md->state[4] = 0x510E527FUL;
- md->state[5] = 0x9B05688CUL;
- md->state[6] = 0x1F83D9ABUL;
- md->state[7] = 0x5BE0CD19UL;
- return CRYPT_OK;
-}
-
-/**
- Process a block of memory though the hash
- @param md The hash state
- @param in The data to hash
- @param inlen The length of the data (octets)
- @return CRYPT_OK if successful
-*/
-static int sha256_process (sha256_state * md, const unsigned char *in, unsigned long inlen)
-{
- unsigned long n;
- int err;
- LTC_ARGCHK(md != NULL);
- LTC_ARGCHK(in != NULL);
- if (md->curlen > sizeof(md->buf)) {
- return CRYPT_INVALID_ARG;
- }
- while (inlen > 0) {
- if (md->curlen == 0 && inlen >= 64) {
- if ((err = sha256_compress (md, (unsigned char *)in)) != CRYPT_OK) {
- return err;
- }
- md->length += 64 * 8;
- in += 64;
- inlen -= 64;
- } else {
- n = MIN(inlen, (64 - md->curlen));
- memcpy(md->buf + md->curlen, in, (size_t)n);
- md->curlen += n;
- in += n;
- inlen -= n;
- if (md->curlen == 64) {
- if ((err = sha256_compress (md, md->buf)) != CRYPT_OK) {
- return err;
- }
- md->length += 8*64;
- md->curlen = 0;
- }
- }
- }
- return CRYPT_OK;
-}
-
-/**
- Terminate the hash to get the digest
- @param md The hash state
- @param out [out] The destination of the hash (32 bytes)
- @return CRYPT_OK if successful
-*/
-static int sha256_done(sha256_state * md, unsigned char *out)
-{
- int i;
-
- LTC_ARGCHK(md != NULL);
- LTC_ARGCHK(out != NULL);
-
- if (md->curlen >= sizeof(md->buf)) {
- return CRYPT_INVALID_ARG;
- }
-
-
- /* increase the length of the message */
- md->length += md->curlen * 8;
-
- /* append the '1' bit */
- md->buf[md->curlen++] = (unsigned char)0x80;
-
- /* if the length is currently above 56 bytes we append zeros
- * then compress. Then we can fall back to padding zeros and length
- * encoding like normal.
- */
- if (md->curlen > 56) {
- while (md->curlen < 64) {
- md->buf[md->curlen++] = (unsigned char)0;
- }
- sha256_compress(md, md->buf);
- md->curlen = 0;
- }
-
- /* pad upto 56 bytes of zeroes */
- while (md->curlen < 56) {
- md->buf[md->curlen++] = (unsigned char)0;
- }
-
- /* store length */
- STORE64H(md->length, md->buf+56);
- sha256_compress(md, md->buf);
-
- /* copy output */
- for (i = 0; i < 8; i++) {
- STORE32H(md->state[i], out+(4*i));
- }
-#ifdef LTC_CLEAN_STACK
- zeromem(md, sizeof(sha256_state));
-#endif
- return CRYPT_OK;
-}
-
-/* $Source: /cvs/libtom/libtomcrypt/src/hashes/sha2/sha256.c,v $ */
-/* $Revision: 1.9 $ */
-/* $Date: 2006/11/01 09:28:17 $ */
diff --git a/src/common/torgzip.c b/src/common/torgzip.c
index da4136228..4328c63c8 100644
--- a/src/common/torgzip.c
+++ b/src/common/torgzip.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/torgzip.h b/src/common/torgzip.h
index d3ded81f9..be1016445 100644
--- a/src/common/torgzip.h
+++ b/src/common/torgzip.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,8 +8,8 @@
* \brief Headers for torgzip.h
**/
-#ifndef _TOR_TORGZIP_H
-#define _TOR_TORGZIP_H
+#ifndef TOR_TORGZIP_H
+#define TOR_TORGZIP_H
/** Enumeration of what kind of compression to use. Only ZLIB_METHOD is
* guaranteed to be supported by the compress/uncompress functions here;
diff --git a/src/common/torint.h b/src/common/torint.h
index 8771802d7..a993d7649 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,8 +8,8 @@
* \brief Header file to define uint32_t and friends
**/
-#ifndef _TOR_TORINT_H
-#define _TOR_TORINT_H
+#ifndef TOR_TORINT_H
+#define TOR_TORINT_H
#include "orconfig.h"
@@ -214,16 +214,20 @@ typedef int32_t ssize_t;
#if (SIZEOF_VOID_P > 4 && SIZEOF_VOID_P <= 8)
#ifndef HAVE_INTPTR_T
typedef int64_t intptr_t;
+#define SIZEOF_INTPTR_T 8
#endif
#ifndef HAVE_UINTPTR_T
typedef uint64_t uintptr_t;
+#define SIZEOF_UINTPTR_T 8
#endif
#elif (SIZEOF_VOID_P > 2 && SIZEOF_VOID_P <= 4)
#ifndef HAVE_INTPTR_T
typedef int32_t intptr_t;
+#define SIZEOF_INTPTR_T 4
#endif
#ifndef HAVE_UINTPTR_T
typedef uint32_t uintptr_t;
+#define SIZEOF_UINTPTR_T 4
#endif
#else
#error "void * is either >8 bytes or <= 2. In either case, I am confused."
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 28890a44a..8675d7b6e 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,7 +10,7 @@
* \brief Headers for log.c
**/
-#ifndef _TOR_LOG_H
+#ifndef TOR_TORLOG_H
#include "compat.h"
@@ -94,8 +94,10 @@
#define LD_HANDSHAKE (1u<<19)
/** Heartbeat messages */
#define LD_HEARTBEAT (1u<<20)
+/** Abstract channel_t code */
+#define LD_CHANNEL (1u<<21)
/** Number of logging domains in the code. */
-#define N_LOGGING_DOMAINS 21
+#define N_LOGGING_DOMAINS 22
/** This log message is not safe to send to a callback-based logger
* immediately. Used as a flag, not a log domain. */
@@ -151,66 +153,80 @@ void set_log_time_granularity(int granularity_msec);
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
CHECK_PRINTF(3,4);
-#define log tor_log /* hack it so we don't conflict with log() as much */
#if defined(__GNUC__) || defined(RUNNING_DOXYGEN)
-extern int _log_global_min_severity;
+extern int log_global_min_severity_;
-void _log_fn(int severity, log_domain_mask_t domain,
+void log_fn_(int severity, log_domain_mask_t domain,
const char *funcname, const char *format, ...)
CHECK_PRINTF(4,5);
+struct ratelim_t;
+void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
+ log_domain_mask_t domain, const char *funcname,
+ const char *format, ...)
+ CHECK_PRINTF(5,6);
/** Log a message at level <b>severity</b>, using a pretty-printed version
* of the current function name. */
#define log_fn(severity, domain, args...) \
- _log_fn(severity, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(severity, domain, __PRETTY_FUNCTION__, args)
+/** As log_fn, but use <b>ratelim</b> (an instance of ratelim_t) to control
+ * the frequency at which messages can appear.
+ */
+#define log_fn_ratelim(ratelim, severity, domain, args...) \
+ log_fn_ratelim_(ratelim, severity, domain, __PRETTY_FUNCTION__, args)
#define log_debug(domain, args...) \
STMT_BEGIN \
- if (PREDICT_UNLIKELY(_log_global_min_severity == LOG_DEBUG)) \
- _log_fn(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \
+ if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \
+ log_fn_(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \
STMT_END
#define log_info(domain, args...) \
- _log_fn(LOG_INFO, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_INFO, domain, __PRETTY_FUNCTION__, args)
#define log_notice(domain, args...) \
- _log_fn(LOG_NOTICE, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_NOTICE, domain, __PRETTY_FUNCTION__, args)
#define log_warn(domain, args...) \
- _log_fn(LOG_WARN, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_WARN, domain, __PRETTY_FUNCTION__, args)
#define log_err(domain, args...) \
- _log_fn(LOG_ERR, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_ERR, domain, __PRETTY_FUNCTION__, args)
#else /* ! defined(__GNUC__) */
-void _log_fn(int severity, log_domain_mask_t domain, const char *format, ...);
-void _log_debug(log_domain_mask_t domain, const char *format, ...);
-void _log_info(log_domain_mask_t domain, const char *format, ...);
-void _log_notice(log_domain_mask_t domain, const char *format, ...);
-void _log_warn(log_domain_mask_t domain, const char *format, ...);
-void _log_err(log_domain_mask_t domain, const char *format, ...);
+void log_fn_(int severity, log_domain_mask_t domain, const char *format, ...);
+struct ratelim_t;
+void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
+ log_domain_mask_t domain, const char *format, ...);
+void log_debug_(log_domain_mask_t domain, const char *format, ...);
+void log_info_(log_domain_mask_t domain, const char *format, ...);
+void log_notice_(log_domain_mask_t domain, const char *format, ...);
+void log_warn_(log_domain_mask_t domain, const char *format, ...);
+void log_err_(log_domain_mask_t domain, const char *format, ...);
#if defined(_MSC_VER) && _MSC_VER < 1300
/* MSVC 6 and earlier don't have __func__, or even __LINE__. */
-#define log_fn _log_fn
-#define log_debug _log_debug
-#define log_info _log_info
-#define log_notice _log_notice
-#define log_warn _log_warn
-#define log_err _log_err
+#define log_fn log_fn_
+#define log_fn_ratelim log_fn_ratelim_
+#define log_debug log_debug_
+#define log_info log_info_
+#define log_notice log_notice_
+#define log_warn log_warn_
+#define log_err log_err_
#else
/* We don't have GCC's varargs macros, so use a global variable to pass the
* function name to log_fn */
-extern const char *_log_fn_function_name;
+extern const char *log_fn_function_name_;
/* We abuse the comma operator here, since we can't use the standard
* do {...} while (0) trick to wrap this macro, since the macro can't take
* arguments. */
-#define log_fn (_log_fn_function_name=__func__),_log_fn
-#define log_debug (_log_fn_function_name=__func__),_log_debug
-#define log_info (_log_fn_function_name=__func__),_log_info
-#define log_notice (_log_fn_function_name=__func__),_log_notice
-#define log_warn (_log_fn_function_name=__func__),_log_warn
-#define log_err (_log_fn_function_name=__func__),_log_err
+#define log_fn (log_fn_function_name_=__func__),log_fn_
+#define log_fn_ratelim (log_fn_function_name_=__func__),log_fn_ratelim_
+#define log_debug (log_fn_function_name_=__func__),log_debug_
+#define log_info (log_fn_function_name_=__func__),log_info_
+#define log_notice (log_fn_function_name_=__func__),log_notice_
+#define log_warn (log_fn_function_name_=__func__),log_warn_
+#define log_err (log_fn_function_name_=__func__),log_err_
#endif
#endif /* !GNUC */
-# define _TOR_LOG_H
+# define TOR_TORLOG_H
#endif
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 60aac6492..886ee0dda 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,8 +58,8 @@
#include "container.h"
#include <string.h>
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7)
-#error "We require OpenSSL >= 0.9.7"
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
+#error "We require OpenSSL >= 0.9.8"
#endif
/* Enable the "v2" TLS handshake.
@@ -127,8 +127,32 @@ typedef struct tor_tls_context_t {
crypto_pk_t *auth_key;
} tor_tls_context_t;
+/** Return values for tor_tls_classify_client_ciphers.
+ *
+ * @{
+ */
+/** An error occurred when examining the client ciphers */
+#define CIPHERS_ERR -1
+/** The client cipher list indicates that a v1 handshake was in use. */
+#define CIPHERS_V1 1
+/** The client cipher list indicates that the client is using the v2 or the
+ * v3 handshake, but that it is (probably!) lying about what ciphers it
+ * supports */
+#define CIPHERS_V2 2
+/** The client cipher list indicates that the client is using the v2 or the
+ * v3 handshake, and that it is telling the truth about what ciphers it
+ * supports */
+#define CIPHERS_UNRESTRICTED 3
+/** @} */
+
#define TOR_TLS_MAGIC 0x71571571
+typedef enum {
+ TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE,
+ TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE,
+ TOR_TLS_ST_BUFFEREVENT
+} tor_tls_state_t;
+
/** Holds a SSL object and its associated data. Members are only
* accessed from within tortls.c.
*/
@@ -138,12 +162,9 @@ struct tor_tls_t {
SSL *ssl; /**< An OpenSSL SSL object. */
int socket; /**< The underlying file descriptor for this TLS connection. */
char *address; /**< An address to log when describing this connection. */
- enum {
- TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE,
- TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE,
- TOR_TLS_ST_BUFFEREVENT
- } state : 3; /**< The current SSL state, depending on which operations have
- * completed successfully. */
+ ENUM_BF(tor_tls_state_t) state : 3; /**< The current SSL state,
+ * depending on which operations
+ * have completed successfully. */
unsigned int isServer:1; /**< True iff this is a server-side connection */
unsigned int wasV2Handshake:1; /**< True iff the original handshake for
* this connection used the updated version
@@ -152,6 +173,9 @@ struct tor_tls_t {
* one certificate). */
/** True iff we should call negotiated_callback when we're done reading. */
unsigned int got_renegotiate:1;
+ /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't
+ * called that function yet. */
+ int8_t client_cipher_list_type;
/** Incremented every time we start the server side of a handshake. */
uint8_t server_handshake_count;
size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
@@ -210,14 +234,16 @@ static X509* tor_tls_create_certificate(crypto_pk_t *rsa,
crypto_pk_t *rsa_sign,
const char *cname,
const char *cname_sign,
- unsigned int lifetime);
+ unsigned int cert_lifetime);
static int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
crypto_pk_t *identity,
unsigned int key_lifetime,
+ unsigned int flags,
int is_client);
static tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity,
unsigned int key_lifetime,
+ unsigned int flags,
int is_client);
static int check_cert_lifetime_internal(int severity, const X509 *cert,
int past_tolerance, int future_tolerance);
@@ -234,8 +260,8 @@ static tor_tls_context_t *client_tls_context = NULL;
static int tls_library_is_initialized = 0;
/* Module-internal error codes. */
-#define _TOR_TLS_SYSCALL (_MIN_TOR_TLS_ERROR_VAL - 2)
-#define _TOR_TLS_ZERORETURN (_MIN_TOR_TLS_ERROR_VAL - 1)
+#define TOR_TLS_SYSCALL_ (MIN_TOR_TLS_ERROR_VAL_ - 2)
+#define TOR_TLS_ZERORETURN_ (MIN_TOR_TLS_ERROR_VAL_ - 1)
/** Write a description of the current state of <b>tls</b> into the
* <b>sz</b>-byte buffer at <b>buf</b>. */
@@ -308,11 +334,11 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
if (!lib) lib = "(null)";
if (!func) func = "(null)";
if (doing) {
- log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
+ tor_log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
doing, addr?" with ":"", addr?addr:"",
msg, lib, func, state);
} else {
- log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
+ tor_log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
addr?" with ":"", addr?addr:"",
msg, lib, func, state);
}
@@ -336,35 +362,19 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
static int
tor_errno_to_tls_error(int e)
{
-#if defined(_WIN32)
- switch (e) {
- case WSAECONNRESET: // most common
- return TOR_TLS_ERROR_CONNRESET;
- case WSAETIMEDOUT:
- return TOR_TLS_ERROR_TIMEOUT;
- case WSAENETUNREACH:
- case WSAEHOSTUNREACH:
- return TOR_TLS_ERROR_NO_ROUTE;
- case WSAECONNREFUSED:
- return TOR_TLS_ERROR_CONNREFUSED; // least common
- default:
- return TOR_TLS_ERROR_MISC;
- }
-#else
switch (e) {
- case ECONNRESET: // most common
+ case SOCK_ERRNO(ECONNRESET): // most common
return TOR_TLS_ERROR_CONNRESET;
- case ETIMEDOUT:
+ case SOCK_ERRNO(ETIMEDOUT):
return TOR_TLS_ERROR_TIMEOUT;
- case EHOSTUNREACH:
- case ENETUNREACH:
+ case SOCK_ERRNO(EHOSTUNREACH):
+ case SOCK_ERRNO(ENETUNREACH):
return TOR_TLS_ERROR_NO_ROUTE;
- case ECONNREFUSED:
+ case SOCK_ERRNO(ECONNREFUSED):
return TOR_TLS_ERROR_CONNREFUSED; // least common
default:
return TOR_TLS_ERROR_MISC;
}
-#endif
}
/** Given a TOR_TLS_* error code, return a string equivalent. */
@@ -393,9 +403,9 @@ tor_tls_err_to_string(int err)
/** Given a TLS object and the result of an SSL_* call, use
* SSL_get_error to determine whether an error has occurred, and if so
* which one. Return one of TOR_TLS_{DONE|WANTREAD|WANTWRITE|ERROR}.
- * If extra&CATCH_SYSCALL is true, return _TOR_TLS_SYSCALL instead of
+ * If extra&CATCH_SYSCALL is true, return TOR_TLS_SYSCALL_ instead of
* reporting syscall errors. If extra&CATCH_ZERO is true, return
- * _TOR_TLS_ZERORETURN instead of reporting zero-return errors.
+ * TOR_TLS_ZERORETURN_ instead of reporting zero-return errors.
*
* If an error has occurred, log it at level <b>severity</b> and describe the
* current action as <b>doing</b>.
@@ -415,14 +425,14 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
return TOR_TLS_WANTWRITE;
case SSL_ERROR_SYSCALL:
if (extra&CATCH_SYSCALL)
- return _TOR_TLS_SYSCALL;
+ return TOR_TLS_SYSCALL_;
if (r == 0) {
- log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
+ tor_log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
doing, SSL_state_string_long(tls->ssl));
tor_error = TOR_TLS_ERROR_IO;
} else {
int e = tor_socket_errno(tls->socket);
- log(severity, LD_NET,
+ tor_log(severity, LD_NET,
"TLS error: <syscall error while %s> (errno=%d: %s; state=%s)",
doing, e, tor_socket_strerror(e),
SSL_state_string_long(tls->ssl));
@@ -432,8 +442,8 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
return tor_error;
case SSL_ERROR_ZERO_RETURN:
if (extra&CATCH_ZERO)
- return _TOR_TLS_ZERORETURN;
- log(severity, LD_NET, "TLS connection closed while %s in state %s",
+ return TOR_TLS_ZERORETURN_;
+ tor_log(severity, LD_NET, "TLS connection closed while %s in state %s",
doing, SSL_state_string_long(tls->ssl));
tls_log_errors(tls, severity, domain, doing);
return TOR_TLS_CLOSE;
@@ -478,7 +488,7 @@ tor_tls_init(void)
* a test of intelligence and determination.
*/
if (version > OPENSSL_V(0,9,8,'k') && version <= OPENSSL_V(0,9,8,'l')) {
- log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but "
+ log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but "
"some vendors have backported renegotiation code from "
"0.9.8m without updating the version number. "
"I will try SSL3_FLAGS and SSL_OP to enable renegotation.",
@@ -486,12 +496,12 @@ tor_tls_init(void)
use_unsafe_renegotiation_flag = 1;
use_unsafe_renegotiation_op = 1;
} else if (version > OPENSSL_V(0,9,8,'l')) {
- log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; "
+ log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; "
"I will try SSL_OP to enable renegotiation",
SSLeay_version(SSLEAY_VERSION));
use_unsafe_renegotiation_op = 1;
} else if (version <= OPENSSL_V(0,9,8,'k')) {
- log_notice(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than "
+ log_info(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than "
"0.9.8l, but some vendors have backported 0.9.8l's "
"renegotiation code to earlier versions, and some have "
"backported the code from 0.9.8m or 0.9.8n. I'll set both "
@@ -505,6 +515,37 @@ tor_tls_init(void)
SSLeay_version(SSLEAY_VERSION), version);
}
+#if (SIZEOF_VOID_P >= 8 && \
+ !defined(OPENSSL_NO_EC) && \
+ OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1))
+ if (version >= OPENSSL_V_SERIES(1,0,1)) {
+ /* Warn if we could *almost* be running with much faster ECDH.
+ If we're built for a 64-bit target, using OpenSSL 1.0.1, but we
+ don't have one of the built-in __uint128-based speedups, we are
+ just one build operation away from an accelerated handshake.
+
+ (We could be looking at OPENSSL_NO_EC_NISTP_64_GCC_128 instead of
+ doing this test, but that gives compile-time options, not runtime
+ behavior.)
+ */
+ EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ const EC_GROUP *g = key ? EC_KEY_get0_group(key) : NULL;
+ const EC_METHOD *m = g ? EC_GROUP_method_of(g) : NULL;
+ const int warn = (m == EC_GFp_simple_method() ||
+ m == EC_GFp_mont_method() ||
+ m == EC_GFp_nist_method());
+ EC_KEY_free(key);
+
+ if (warn)
+ log_notice(LD_GENERAL, "We were built to run on a 64-bit CPU, with "
+ "OpenSSL 1.0.1 or later, but with a version of OpenSSL "
+ "that apparently lacks accelerated support for the NIST "
+ "P-224 and P-256 groups. Building openssl with such "
+ "support (using the enable-ec_nistp_64_gcc_128 option "
+ "when configuring it) would make ECDH much faster.");
+ }
+#endif
+
tor_tls_allocate_tor_tls_object_ex_data_index();
tls_library_is_initialized = 1;
@@ -567,9 +608,10 @@ tor_x509_name_new(const char *cname)
/** Generate and sign an X509 certificate with the public key <b>rsa</b>,
* signed by the private key <b>rsa_sign</b>. The commonName of the
* certificate will be <b>cname</b>; the commonName of the issuer will be
- * <b>cname_sign</b>. The cert will be valid for <b>cert_lifetime</b> seconds
- * starting from now. Return a certificate on success, NULL on
- * failure.
+ * <b>cname_sign</b>. The cert will be valid for <b>cert_lifetime</b>
+ * seconds, starting from some time in the past.
+ *
+ * Return a certificate on success, NULL on failure.
*/
static X509 *
tor_tls_create_certificate(crypto_pk_t *rsa,
@@ -591,15 +633,20 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
tor_tls_init();
- start_time = time(NULL);
+ /* Make sure we're part-way through the certificate lifetime, rather
+ * than having it start right now. Don't choose quite uniformly, since
+ * then we might pick a time where we're about to expire. Lastly, be
+ * sure to start on a day boundary. */
+ start_time = time(NULL) - crypto_rand_int(cert_lifetime) + 2*24*3600;
+ start_time -= start_time % (24*3600);
tor_assert(rsa);
tor_assert(cname);
tor_assert(rsa_sign);
tor_assert(cname_sign);
- if (!(sign_pkey = _crypto_pk_get_evp_pkey(rsa_sign,1)))
+ if (!(sign_pkey = crypto_pk_get_evp_pkey_(rsa_sign,1)))
goto error;
- if (!(pkey = _crypto_pk_get_evp_pkey(rsa,0)))
+ if (!(pkey = crypto_pk_get_evp_pkey_(rsa,0)))
goto error;
if (!(x509 = X509_new()))
goto error;
@@ -647,7 +694,7 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
if (pkey)
EVP_PKEY_free(pkey);
if (serial_number)
- BN_free(serial_number);
+ BN_clear_free(serial_number);
if (name)
X509_NAME_free(name);
if (name_issuer)
@@ -657,11 +704,42 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
#undef SERIAL_NUMBER_SIZE
}
-/** List of ciphers that servers should select from.*/
+/** List of ciphers that servers should select from when the client might be
+ * claiming extra unsupported ciphers in order to avoid fingerprinting. */
#define SERVER_CIPHER_LIST \
(TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" \
TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" \
SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
+
+/** List of ciphers that servers should select from when we actually have
+ * our choice of what cipher to use. */
+const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CHC_SHA
+ TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256
+ TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+#endif
+//#if TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA
+// TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA ":"
+//#endif
+ /* These next two are mandatory. */
+ TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"
+ TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":"
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA
+ TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA ":"
+#endif
+ SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA;
+
/* Note: to set up your own private testing network with link crypto
* disabled, set your Tors' cipher list to
* (SSL3_TXT_RSA_NULL_SHA). If you do this, you won't be able to communicate
@@ -754,7 +832,7 @@ tor_cert_new(X509 *x509_cert)
if ((pkey = X509_get_pubkey(x509_cert)) &&
(rsa = EVP_PKEY_get1_RSA(pkey))) {
- crypto_pk_t *pk = _crypto_new_pk_from_rsa(rsa);
+ crypto_pk_t *pk = crypto_new_pk_from_rsa_(rsa);
crypto_pk_get_all_digests(pk, &cert->pkey_digests);
cert->pkey_digests_set = 1;
crypto_pk_free(pk);
@@ -778,13 +856,8 @@ tor_cert_decode(const uint8_t *certificate, size_t certificate_len)
if (certificate_len > INT_MAX)
return NULL;
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
- /* This ifdef suppresses a type warning. Take out this case once everybody
- * is using OpenSSL 0.9.8 or later. */
- x509 = d2i_X509(NULL, (unsigned char**)&cp, (int)certificate_len);
-#else
x509 = d2i_X509(NULL, &cp, (int)certificate_len);
-#endif
+
if (!x509)
return NULL; /* Couldn't decode */
if (cp - certificate != (int)certificate_len) {
@@ -901,7 +974,7 @@ tor_tls_cert_get_key(tor_cert_t *cert)
EVP_PKEY_free(pkey);
return NULL;
}
- result = _crypto_new_pk_from_rsa(rsa);
+ result = crypto_new_pk_from_rsa_(rsa);
EVP_PKEY_free(pkey);
return result;
}
@@ -1019,17 +1092,20 @@ tor_tls_context_incref(tor_tls_context_t *ctx)
/** Create new global client and server TLS contexts.
*
* If <b>server_identity</b> is NULL, this will not generate a server
- * TLS context. If <b>is_public_server</b> is non-zero, this will use
+ * TLS context. If TOR_TLS_CTX_IS_PUBLIC_SERVER is set in <b>flags</b>, use
* the same TLS context for incoming and outgoing connections, and
- * ignore <b>client_identity</b>. */
+ * ignore <b>client_identity</b>. If one of TOR_TLS_CTX_USE_ECDHE_P{224,256}
+ * is set in <b>flags</b>, use that ECDHE group if possible; otherwise use
+ * the default ECDHE group. */
int
-tor_tls_context_init(int is_public_server,
+tor_tls_context_init(unsigned flags,
crypto_pk_t *client_identity,
crypto_pk_t *server_identity,
unsigned int key_lifetime)
{
int rv1 = 0;
int rv2 = 0;
+ const int is_public_server = flags & TOR_TLS_CTX_IS_PUBLIC_SERVER;
if (is_public_server) {
tor_tls_context_t *new_ctx;
@@ -1039,7 +1115,7 @@ tor_tls_context_init(int is_public_server,
rv1 = tor_tls_context_init_one(&server_tls_context,
server_identity,
- key_lifetime, 0);
+ key_lifetime, flags, 0);
if (rv1 >= 0) {
new_ctx = server_tls_context;
@@ -1056,6 +1132,7 @@ tor_tls_context_init(int is_public_server,
rv1 = tor_tls_context_init_one(&server_tls_context,
server_identity,
key_lifetime,
+ flags,
0);
} else {
tor_tls_context_t *old_ctx = server_tls_context;
@@ -1069,6 +1146,7 @@ tor_tls_context_init(int is_public_server,
rv2 = tor_tls_context_init_one(&client_tls_context,
client_identity,
key_lifetime,
+ flags,
1);
}
@@ -1085,10 +1163,12 @@ static int
tor_tls_context_init_one(tor_tls_context_t **ppcontext,
crypto_pk_t *identity,
unsigned int key_lifetime,
+ unsigned int flags,
int is_client)
{
tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
key_lifetime,
+ flags,
is_client);
tor_tls_context_t *old_ctx = *ppcontext;
@@ -1112,7 +1192,7 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext,
*/
static tor_tls_context_t *
tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
- int is_client)
+ unsigned flags, int is_client)
{
crypto_pk_t *rsa = NULL, *rsa_auth = NULL;
EVP_PKEY *pkey = NULL;
@@ -1150,7 +1230,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2,
key_lifetime);
if (!cert || !idcert || !authcert) {
- log(LOG_WARN, LD_CRYPTO, "Error creating certificate");
+ log_warn(LD_CRYPTO, "Error creating certificate");
goto error;
}
}
@@ -1189,19 +1269,29 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
* version. Once some version of OpenSSL does TLS1.1 and TLS1.2
* renegotiation properly, we can turn them back on when built with
* that version. */
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,1,'e')
#ifdef SSL_OP_NO_TLSv1_2
SSL_CTX_set_options(result->ctx, SSL_OP_NO_TLSv1_2);
#endif
#ifdef SSL_OP_NO_TLSv1_1
SSL_CTX_set_options(result->ctx, SSL_OP_NO_TLSv1_1);
#endif
+#endif
+
/* Disable TLS tickets if they're supported. We never want to use them;
* using them can make our perfect forward secrecy a little worse, *and*
* create an opportunity to fingerprint us (since it's unusual to use them
* with TLS sessions turned off).
+ *
+ * In 0.2.4, clients advertise support for them though, to avoid a TLS
+ * distinguishability vector. This can give us worse PFS, though, if we
+ * get a server that doesn't set SSL_OP_NO_TICKET. With luck, there will
+ * be few such servers by the time 0.2.4 is more stable.
*/
#ifdef SSL_OP_NO_TICKET
- SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET);
+ if (! is_client) {
+ SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET);
+ }
#endif
if (
@@ -1222,6 +1312,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
}
SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE);
+ SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_ECDH_USE);
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
SSL_CTX_set_options(result->ctx,
@@ -1257,7 +1348,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
if (!is_client) {
tor_assert(rsa);
- if (!(pkey = _crypto_pk_get_evp_pkey(rsa,1)))
+ if (!(pkey = crypto_pk_get_evp_pkey_(rsa,1)))
goto error;
if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
goto error;
@@ -1269,9 +1360,29 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
{
crypto_dh_t *dh = crypto_dh_new(DH_TYPE_TLS);
tor_assert(dh);
- SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_get_dh(dh));
+ SSL_CTX_set_tmp_dh(result->ctx, crypto_dh_get_dh_(dh));
crypto_dh_free(dh);
}
+#if (!defined(OPENSSL_NO_EC) && \
+ OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0))
+ if (! is_client) {
+ int nid;
+ EC_KEY *ec_key;
+ if (flags & TOR_TLS_CTX_USE_ECDHE_P224)
+ nid = NID_secp224r1;
+ else if (flags & TOR_TLS_CTX_USE_ECDHE_P256)
+ nid = NID_X9_62_prime256v1;
+ else
+ nid = NID_X9_62_prime256v1;
+ /* Use P-256 for ECDHE. */
+ ec_key = EC_KEY_new_by_curve_name(nid);
+ if (ec_key != NULL) /*XXXX Handle errors? */
+ SSL_CTX_set_tmp_ecdh(result->ctx, ec_key);
+ EC_KEY_free(ec_key);
+ }
+#else
+ (void)flags;
+#endif
SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER,
always_accept_verify_cb);
/* let us realloc bufs that we're writing from */
@@ -1308,28 +1419,108 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
}
#ifdef V2_HANDSHAKE_SERVER
-/** Return true iff the cipher list suggested by the client for <b>ssl</b> is
- * a list that indicates that the client knows how to do the v2 TLS connection
- * handshake. */
+
+/* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to
+ * 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers
+ * that it claims to support. We'll prune this list to remove the ciphers
+ * *we* don't recognize. */
+static uint16_t v2_cipher_list[] = {
+ 0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */
+ 0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */
+ 0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */
+ 0x0038, /* TLS1_TXT_DHE_DSS_WITH_AES_256_SHA */
+ 0xc00f, /* TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA */
+ 0xc005, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA */
+ 0x0035, /* TLS1_TXT_RSA_WITH_AES_256_SHA */
+ 0xc007, /* TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA */
+ 0xc009, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */
+ 0xc011, /* TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA */
+ 0xc013, /* TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA */
+ 0x0033, /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA */
+ 0x0032, /* TLS1_TXT_DHE_DSS_WITH_AES_128_SHA */
+ 0xc00c, /* TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA */
+ 0xc00e, /* TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA */
+ 0xc002, /* TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA */
+ 0xc004, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA */
+ 0x0004, /* SSL3_TXT_RSA_RC4_128_MD5 */
+ 0x0005, /* SSL3_TXT_RSA_RC4_128_SHA */
+ 0x002f, /* TLS1_TXT_RSA_WITH_AES_128_SHA */
+ 0xc008, /* TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA */
+ 0xc012, /* TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA */
+ 0x0016, /* SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA */
+ 0x0013, /* SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA */
+ 0xc00d, /* TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA */
+ 0xc003, /* TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA */
+ 0xfeff, /* SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA */
+ 0x000a, /* SSL3_TXT_RSA_DES_192_CBC3_SHA */
+ 0
+};
+/** Have we removed the unrecognized ciphers from v2_cipher_list yet? */
+static int v2_cipher_list_pruned = 0;
+
+/** Remove from v2_cipher_list every cipher that we don't support, so that
+ * comparing v2_cipher_list to a client's cipher list will give a sensible
+ * result. */
+static void
+prune_v2_cipher_list(void)
+{
+ uint16_t *inp, *outp;
+ const SSL_METHOD *m = SSLv23_method();
+
+ inp = outp = v2_cipher_list;
+ while (*inp) {
+ unsigned char cipherid[2];
+ const SSL_CIPHER *cipher;
+ /* Is there no better way to do this? */
+ set_uint16(cipherid, htons(*inp));
+ cipher = m->get_cipher_by_char(cipherid);
+ if (cipher) {
+ tor_assert((cipher->id & 0xffff) == *inp);
+ *outp++ = *inp++;
+ } else {
+ inp++;
+ }
+ }
+ *outp = 0;
+
+ v2_cipher_list_pruned = 1;
+}
+
+/* Return the name of the negotiated ciphersuite in use on <b>tls</b> */
+const char *
+tor_tls_get_ciphersuite_name(tor_tls_t *tls)
+{
+ return SSL_get_cipher(tls->ssl);
+}
+
+/** Examine the client cipher list in <b>ssl</b>, and determine what kind of
+ * client it is. Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2,
+ * CIPHERS_UNRESTRICTED.
+ **/
static int
-tor_tls_client_is_using_v2_ciphers(const SSL *ssl, const char *address)
+tor_tls_classify_client_ciphers(const SSL *ssl,
+ STACK_OF(SSL_CIPHER) *peer_ciphers)
{
- int i;
- SSL_SESSION *session;
+ int i, res;
+ tor_tls_t *tor_tls;
+ if (PREDICT_UNLIKELY(!v2_cipher_list_pruned))
+ prune_v2_cipher_list();
+
+ tor_tls = tor_tls_get_by_ssl(ssl);
+ if (tor_tls && tor_tls->client_cipher_list_type)
+ return tor_tls->client_cipher_list_type;
+
/* If we reached this point, we just got a client hello. See if there is
* a cipher list. */
- if (!(session = SSL_get_session((SSL *)ssl))) {
- log_info(LD_NET, "No session on TLS?");
- return 0;
- }
- if (!session->ciphers) {
+ if (!peer_ciphers) {
log_info(LD_NET, "No ciphers on session");
- return 0;
+ res = CIPHERS_ERR;
+ goto done;
}
/* Now we need to see if there are any ciphers whose presence means we're
* dealing with an updated Tor. */
- for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
- SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
+ for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
+ SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
const char *ciphername = SSL_CIPHER_get_name(cipher);
if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) &&
strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) &&
@@ -1337,27 +1528,110 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl, const char *address)
strcmp(ciphername, "(NONE)")) {
log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername);
// return 1;
- goto dump_list;
+ goto v2_or_higher;
}
}
- return 0;
- dump_list:
+ res = CIPHERS_V1;
+ goto done;
+ v2_or_higher:
+ {
+ const uint16_t *v2_cipher = v2_cipher_list;
+ for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
+ SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
+ uint16_t id = cipher->id & 0xffff;
+ if (id == 0x00ff) /* extended renegotiation indicator. */
+ continue;
+ if (!id || id != *v2_cipher) {
+ res = CIPHERS_UNRESTRICTED;
+ goto dump_ciphers;
+ }
+ ++v2_cipher;
+ }
+ if (*v2_cipher != 0) {
+ res = CIPHERS_UNRESTRICTED;
+ goto dump_ciphers;
+ }
+ res = CIPHERS_V2;
+ }
+
+ dump_ciphers:
{
smartlist_t *elts = smartlist_new();
char *s;
- for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
- SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
+ for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
+ SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
const char *ciphername = SSL_CIPHER_get_name(cipher);
smartlist_add(elts, (char*)ciphername);
}
s = smartlist_join_strings(elts, ":", 0, NULL);
- log_debug(LD_NET, "Got a non-version-1 cipher list from %s. It is: '%s'",
- address, s);
+ log_debug(LD_NET, "Got a %s V2/V3 cipher list from %s. It is: '%s'",
+ (res == CIPHERS_V2) ? "fictitious" : "real", ADDR(tor_tls), s);
tor_free(s);
smartlist_free(elts);
}
- return 1;
+ done:
+ if (tor_tls)
+ return tor_tls->client_cipher_list_type = res;
+
+ return res;
+}
+
+/** Return true iff the cipher list suggested by the client for <b>ssl</b> is
+ * a list that indicates that the client knows how to do the v2 TLS connection
+ * handshake. */
+static int
+tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
+{
+ SSL_SESSION *session;
+ if (!(session = SSL_get_session((SSL *)ssl))) {
+ log_info(LD_NET, "No session on TLS?");
+ return CIPHERS_ERR;
+ }
+
+ return tor_tls_classify_client_ciphers(ssl, session->ciphers) >= CIPHERS_V2;
+}
+
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
+/** Callback to get invoked on a server after we've read the list of ciphers
+ * the client supports, but before we pick our own ciphersuite.
+ *
+ * We can't abuse an info_cb for this, since by the time one of the
+ * client_hello info_cbs is called, we've already picked which ciphersuite to
+ * use.
+ *
+ * Technically, this function is an abuse of this callback, since the point of
+ * a session_secret_cb is to try to set up and/or verify a shared-secret for
+ * authentication on the fly. But as long as we return 0, we won't actually be
+ * setting up a shared secret, and all will be fine.
+ */
+static int
+tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
+ SSL_CIPHER **cipher, void *arg)
+{
+ (void) secret;
+ (void) secret_len;
+ (void) peer_ciphers;
+ (void) cipher;
+ (void) arg;
+
+ if (tor_tls_classify_client_ciphers(ssl, peer_ciphers) ==
+ CIPHERS_UNRESTRICTED) {
+ SSL_set_cipher_list(ssl, UNRESTRICTED_SERVER_CIPHER_LIST);
+ }
+
+ SSL_set_session_secret_cb(ssl, NULL, NULL);
+
+ return 0;
+}
+static void
+tor_tls_setup_session_secret_cb(tor_tls_t *tls)
+{
+ SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
}
+#else
+#define tor_tls_setup_session_secret_cb(tls) STMT_NIL
+#endif
/** Invoked when a TLS state changes: log the change at severity 'debug' */
static void
@@ -1400,7 +1674,7 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
}
/* Now check the cipher list. */
- if (tor_tls_client_is_using_v2_ciphers(ssl, ADDR(tls))) {
+ if (tor_tls_client_is_using_v2_ciphers(ssl)) {
if (tls->wasV2Handshake)
return; /* We already turned this stuff off for the first handshake;
* This is a renegotiation. */
@@ -1625,6 +1899,9 @@ tor_tls_new(int sock, int isServer)
SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback);
}
+ if (isServer)
+ tor_tls_setup_session_secret_cb(result);
+
/* Not expected to get called. */
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
return result;
@@ -1721,6 +1998,10 @@ tor_tls_free(tor_tls_t *tls)
if (!tls)
return;
tor_assert(tls->ssl);
+ {
+ size_t r,w;
+ tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */
+ }
#ifdef SSL_set_tlsext_host_name
SSL_set_tlsext_host_name(tls->ssl, NULL);
#endif
@@ -1761,7 +2042,7 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
return r;
}
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET);
- if (err == _TOR_TLS_ZERORETURN || err == TOR_TLS_CLOSE) {
+ if (err == TOR_TLS_ZERORETURN_ || err == TOR_TLS_CLOSE) {
log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
tls->state = TOR_TLS_ST_CLOSED;
return TOR_TLS_CLOSE;
@@ -1772,6 +2053,13 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
}
}
+/** Total number of bytes that we've used TLS to send. Used to track TLS
+ * overhead. */
+static uint64_t total_bytes_written_over_tls = 0;
+/** Total number of bytes that TLS has put on the network for us. Used to
+ * track TLS overhead. */
+static uint64_t total_bytes_written_by_tls = 0;
+
/** Underlying function for TLS writing. Write up to <b>n</b>
* characters from <b>cp</b> onto <b>tls</b>. On success, returns the
* number of characters written. On failure, returns TOR_TLS_ERROR,
@@ -1798,6 +2086,7 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
r = SSL_write(tls->ssl, cp, (int)n);
err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET);
if (err == TOR_TLS_DONE) {
+ total_bytes_written_over_tls += r;
return r;
}
if (err == TOR_TLS_WANTWRITE || err == TOR_TLS_WANTREAD) {
@@ -1866,7 +2155,7 @@ tor_tls_finish_handshake(tor_tls_t *tls)
/* There doesn't seem to be a clear OpenSSL API to clear mode flags. */
tls->ssl->mode &= ~SSL_MODE_NO_AUTO_CHAIN;
#ifdef V2_HANDSHAKE_SERVER
- if (tor_tls_client_is_using_v2_ciphers(tls->ssl, ADDR(tls))) {
+ if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) {
/* This check is redundant, but back when we did it in the callback,
* we might have not been able to look up the tor_tls_t if the code
* was buggy. Fixing that. */
@@ -1974,7 +2263,7 @@ tor_tls_shutdown(tor_tls_t *tls)
} while (r>0);
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down",
LOG_INFO, LD_NET);
- if (err == _TOR_TLS_ZERORETURN) {
+ if (err == TOR_TLS_ZERORETURN_) {
tls->state = TOR_TLS_ST_GOTCLOSE;
/* fall through... */
} else {
@@ -1990,11 +2279,11 @@ tor_tls_shutdown(tor_tls_t *tls)
}
err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down",
LOG_INFO, LD_NET);
- if (err == _TOR_TLS_SYSCALL) {
+ if (err == TOR_TLS_SYSCALL_) {
/* The underlying TCP connection closed while we were shutting down. */
tls->state = TOR_TLS_ST_CLOSED;
return TOR_TLS_DONE;
- } else if (err == _TOR_TLS_ZERORETURN) {
+ } else if (err == TOR_TLS_ZERORETURN_) {
/* The TLS connection says that it sent a shutdown record, but
* isn't done shutting down yet. Make sure that this hasn't
* happened before, then go back to the start of the function
@@ -2002,7 +2291,7 @@ tor_tls_shutdown(tor_tls_t *tls)
*/
if (tls->state == TOR_TLS_ST_GOTCLOSE ||
tls->state == TOR_TLS_ST_SENTCLOSE) {
- log(LOG_WARN, LD_NET,
+ log_warn(LD_NET,
"TLS returned \"half-closed\" value while already half-closed");
return TOR_TLS_ERROR_MISC;
}
@@ -2052,7 +2341,7 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem)
struct tm tm;
if (problem)
- log(severity, LD_GENERAL,
+ tor_log(severity, LD_GENERAL,
"Certificate %s. Either their clock is set wrong, or your clock "
"is wrong.",
problem);
@@ -2075,9 +2364,9 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem)
BIO_get_mem_ptr(bio, &buf);
s2 = tor_strndup(buf->data, buf->length);
- strftime(mytime, 32, "%b %d %H:%M:%S %Y GMT", tor_gmtime_r(&now, &tm));
+ strftime(mytime, 32, "%b %d %H:%M:%S %Y UTC", tor_gmtime_r(&now, &tm));
- log(severity, LD_GENERAL,
+ tor_log(severity, LD_GENERAL,
"(certificate lifetime runs from %s through %s. Your time is %s.)",
s1,s2,mytime);
@@ -2164,7 +2453,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
rsa = EVP_PKEY_get1_RSA(id_pkey);
if (!rsa)
goto done;
- *identity_key = _crypto_new_pk_from_rsa(rsa);
+ *identity_key = crypto_new_pk_from_rsa_(rsa);
r = 0;
@@ -2287,18 +2576,31 @@ tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written)
"r=%lu, last_read=%lu, w=%lu, last_written=%lu",
r, tls->last_read_count, w, tls->last_write_count);
}
+ total_bytes_written_by_tls += *n_written;
tls->last_read_count = r;
tls->last_write_count = w;
}
+/** Return a ratio of the bytes that TLS has sent to the bytes that we've told
+ * it to send. Used to track whether our TLS records are getting too tiny. */
+double
+tls_get_write_overhead_ratio(void)
+{
+ if (total_bytes_written_over_tls == 0)
+ return 1.0;
+
+ return U64_TO_DBL(total_bytes_written_by_tls) /
+ U64_TO_DBL(total_bytes_written_over_tls);
+}
+
/** Implement check_no_tls_errors: If there are any pending OpenSSL
* errors, log an error message. */
void
-_check_no_tls_errors(const char *fname, int line)
+check_no_tls_errors_(const char *fname, int line)
{
if (ERR_peek_error() == 0)
return;
- log(LOG_WARN, LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ",
+ log_warn(LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ",
tor_fix_source_file(fname), line);
tls_log_errors(NULL, LOG_WARN, LD_NET, NULL);
}
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 491a5419d..49c488b36 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -1,10 +1,10 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_TORTLS_H
-#define _TOR_TORTLS_H
+#ifndef TOR_TORTLS_H
+#define TOR_TORTLS_H
/**
* \file tortls.h
@@ -21,7 +21,7 @@ typedef struct tor_tls_t tor_tls_t;
typedef struct tor_cert_t tor_cert_t;
/* Possible return values for most tor_tls_* functions. */
-#define _MIN_TOR_TLS_ERROR_VAL -9
+#define MIN_TOR_TLS_ERROR_VAL_ -9
#define TOR_TLS_ERROR_MISC -9
/* Rename to unexpected close or something. XXXX */
#define TOR_TLS_ERROR_IO -8
@@ -54,7 +54,12 @@ const char *tor_tls_err_to_string(int err);
void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz);
void tor_tls_free_all(void);
-int tor_tls_context_init(int is_public_server,
+
+#define TOR_TLS_CTX_IS_PUBLIC_SERVER (1u<<0)
+#define TOR_TLS_CTX_USE_ECDHE_P256 (1u<<1)
+#define TOR_TLS_CTX_USE_ECDHE_P224 (1u<<2)
+
+int tor_tls_context_init(unsigned flags,
crypto_pk_t *client_identity,
crypto_pk_t *server_identity,
unsigned int key_lifetime);
@@ -90,6 +95,8 @@ void tor_tls_get_buffer_sizes(tor_tls_t *tls,
size_t *rbuf_capacity, size_t *rbuf_bytes,
size_t *wbuf_capacity, size_t *wbuf_bytes);
+double tls_get_write_overhead_ratio(void);
+
int tor_tls_used_v1_handshake(tor_tls_t *tls);
int tor_tls_received_v3_certificate(tor_tls_t *tls);
int tor_tls_get_num_server_handshakes(tor_tls_t *tls);
@@ -98,9 +105,9 @@ int tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out);
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
*/
-#define check_no_tls_errors() _check_no_tls_errors(__FILE__,__LINE__)
+#define check_no_tls_errors() check_no_tls_errors_(__FILE__,__LINE__)
-void _check_no_tls_errors(const char *fname, int line);
+void check_no_tls_errors_(const char *fname, int line);
void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
int severity, int domain, const char *doing);
@@ -129,6 +136,7 @@ int tor_tls_cert_is_valid(int severity,
const tor_cert_t *cert,
const tor_cert_t *signing_cert,
int check_rsa_1024);
+const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls);
#endif
diff --git a/src/common/util.c b/src/common/util.c
index b16afa13e..5eb0f9a69 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,7 +20,6 @@
#define UTIL_PRIVATE
#include "util.h"
#include "torlog.h"
-#undef log
#include "crypto.h"
#include "torint.h"
#include "container.h"
@@ -39,8 +38,8 @@
#endif
/* math.h needs this on Linux */
-#ifndef __USE_ISOC99
-#define __USE_ISOC99 1
+#ifndef _USE_ISOC99_
+#define _USE_ISOC99_ 1
#endif
#include <math.h>
#include <stdlib.h>
@@ -125,7 +124,7 @@
* ignored otherwise.
*/
void *
-_tor_malloc(size_t size DMALLOC_PARAMS)
+tor_malloc_(size_t size DMALLOC_PARAMS)
{
void *result;
@@ -159,7 +158,7 @@ _tor_malloc(size_t size DMALLOC_PARAMS)
* the process on error. (Same as calloc(size,1), but never returns NULL.)
*/
void *
-_tor_malloc_zero(size_t size DMALLOC_PARAMS)
+tor_malloc_zero_(size_t size DMALLOC_PARAMS)
{
/* You may ask yourself, "wouldn't it be smart to use calloc instead of
* malloc+memset? Perhaps libc's calloc knows some nifty optimization trick
@@ -167,7 +166,7 @@ _tor_malloc_zero(size_t size DMALLOC_PARAMS)
* we're allocating something very big (it knows if it just got the memory
* from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero
* for big stuff, so we don't bother with calloc. */
- void *result = _tor_malloc(size DMALLOC_FN_ARGS);
+ void *result = tor_malloc_(size DMALLOC_FN_ARGS);
memset(result, 0, size);
return result;
}
@@ -184,7 +183,7 @@ _tor_malloc_zero(size_t size DMALLOC_PARAMS)
* smaller than size). Don't do that then.
*/
void *
-_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
+tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS)
{
/* You may ask yourself, "wouldn't it be smart to use calloc instead of
* malloc+memset? Perhaps libc's calloc knows some nifty optimization trick
@@ -197,7 +196,7 @@ _tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
tor_assert(nmemb < max_nmemb);
- result = _tor_malloc_zero((nmemb * size) DMALLOC_FN_ARGS);
+ result = tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS);
return result;
}
@@ -206,7 +205,7 @@ _tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
* terminate. (Like realloc(ptr,size), but never returns NULL.)
*/
void *
-_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS)
+tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS)
{
void *result;
@@ -230,7 +229,7 @@ _tor_realloc(void *ptr, size_t size DMALLOC_PARAMS)
* NULL.)
*/
char *
-_tor_strdup(const char *s DMALLOC_PARAMS)
+tor_strdup_(const char *s DMALLOC_PARAMS)
{
char *dup;
tor_assert(s);
@@ -254,12 +253,12 @@ _tor_strdup(const char *s DMALLOC_PARAMS)
* NULL.)
*/
char *
-_tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
+tor_strndup_(const char *s, size_t n DMALLOC_PARAMS)
{
char *dup;
tor_assert(s);
tor_assert(n < SIZE_T_CEILING);
- dup = _tor_malloc((n+1) DMALLOC_FN_ARGS);
+ dup = tor_malloc_((n+1) DMALLOC_FN_ARGS);
/* Performance note: Ordinarily we prefer strlcpy to strncpy. But
* this function gets called a whole lot, and platform strncpy is
* much faster than strlcpy when strlen(s) is much longer than n.
@@ -272,55 +271,38 @@ _tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
/** Allocate a chunk of <b>len</b> bytes, with the same contents as the
* <b>len</b> bytes starting at <b>mem</b>. */
void *
-_tor_memdup(const void *mem, size_t len DMALLOC_PARAMS)
+tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS)
{
char *dup;
tor_assert(len < SIZE_T_CEILING);
tor_assert(mem);
- dup = _tor_malloc(len DMALLOC_FN_ARGS);
+ dup = tor_malloc_(len DMALLOC_FN_ARGS);
memcpy(dup, mem, len);
return dup;
}
+/** As tor_memdup(), but add an extra 0 byte at the end of the resulting
+ * memory. */
+void *
+tor_memdup_nulterm(const void *mem, size_t len DMALLOC_PARAMS)
+{
+ char *dup;
+ tor_assert(len < SIZE_T_CEILING+1);
+ tor_assert(mem);
+ dup = tor_malloc_(len+1 DMALLOC_FN_ARGS);
+ memcpy(dup, mem, len);
+ dup[len] = '\0';
+ return dup;
+}
+
/** Helper for places that need to take a function pointer to the right
* spelling of "free()". */
void
-_tor_free(void *mem)
+tor_free_(void *mem)
{
tor_free(mem);
}
-#if defined(HAVE_MALLOC_GOOD_SIZE) && !defined(HAVE_MALLOC_GOOD_SIZE_PROTOTYPE)
-/* Some version of Mac OSX have malloc_good_size in their libc, but not
- * actually defined in malloc/malloc.h. We detect this and work around it by
- * prototyping.
- */
-extern size_t malloc_good_size(size_t size);
-#endif
-
-/** Allocate and return a chunk of memory of size at least *<b>size</b>, using
- * the same resources we would use to malloc *<b>sizep</b>. Set *<b>sizep</b>
- * to the number of usable bytes in the chunk of memory. */
-void *
-_tor_malloc_roundup(size_t *sizep DMALLOC_PARAMS)
-{
-#ifdef HAVE_MALLOC_GOOD_SIZE
- tor_assert(*sizep < SIZE_T_CEILING);
- *sizep = malloc_good_size(*sizep);
- return _tor_malloc(*sizep DMALLOC_FN_ARGS);
-#elif 0 && defined(HAVE_MALLOC_USABLE_SIZE) && !defined(USE_DMALLOC)
- /* Never use malloc_usable_size(); it makes valgrind really unhappy,
- * and doesn't win much in terms of usable space where it exists. */
- void *result;
- tor_assert(*sizep < SIZE_T_CEILING);
- result = _tor_malloc(*sizep DMALLOC_FN_ARGS);
- *sizep = malloc_usable_size(result);
- return result;
-#else
- return _tor_malloc(*sizep DMALLOC_FN_ARGS);
-#endif
-}
-
/** Call the platform malloc info function, and dump the results to the log at
* level <b>severity</b>. If no such function exists, do nothing. */
void
@@ -354,8 +336,8 @@ tor_log_mallinfo(int severity)
* ===== */
/**
- * Returns the natural logarithm of d base 2. We define this wrapper here so
- * as to make it easier not to conflict with Tor's log() macro.
+ * Returns the natural logarithm of d base e. We defined this wrapper here so
+ * to avoid conflicts with old versions of tor_log(), which were named log().
*/
double
tor_mathlog(double d)
@@ -363,9 +345,9 @@ tor_mathlog(double d)
return log(d);
}
-/** Return the long integer closest to d. We define this wrapper here so
- * that not all users of math.h need to use the right incancations to get
- * the c99 functions. */
+/** Return the long integer closest to <b>d</b>. We define this wrapper
+ * here so that not all users of math.h need to use the right incantations
+ * to get the c99 functions. */
long
tor_lround(double d)
{
@@ -378,6 +360,21 @@ tor_lround(double d)
#endif
}
+/** Return the 64-bit integer closest to d. We define this wrapper here so
+ * that not all users of math.h need to use the right incantations to get the
+ * c99 functions. */
+int64_t
+tor_llround(double d)
+{
+#if defined(HAVE_LLROUND)
+ return (int64_t)llround(d);
+#elif defined(HAVE_RINT)
+ return (int64_t)rint(d);
+#else
+ return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5));
+#endif
+}
+
/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */
int
tor_log2(uint64_t u64)
@@ -410,12 +407,24 @@ tor_log2(uint64_t u64)
return r;
}
-/** Return the power of 2 closest to <b>u64</b>. */
+/** Return the power of 2 in range [1,UINT64_MAX] closest to <b>u64</b>. If
+ * there are two powers of 2 equally close, round down. */
uint64_t
round_to_power_of_2(uint64_t u64)
{
- int lg2 = tor_log2(u64);
- uint64_t low = U64_LITERAL(1) << lg2, high = U64_LITERAL(1) << (lg2+1);
+ int lg2;
+ uint64_t low;
+ uint64_t high;
+ if (u64 == 0)
+ return 1;
+
+ lg2 = tor_log2(u64);
+ low = U64_LITERAL(1) << lg2;
+
+ if (lg2 == 63)
+ return low;
+
+ high = U64_LITERAL(1) << (lg2+1);
if (high - u64 < u64 - low)
return high;
else
@@ -655,6 +664,16 @@ fast_memcmpstart(const void *mem, size_t memlen,
return fast_memcmp(mem, prefix, plen);
}
+/** Given a nul-terminated string s, set every character before the nul
+ * to zero. */
+void
+tor_strclear(char *s)
+{
+ while (*s) {
+ *s++ = '\0';
+ }
+}
+
/** Return a pointer to the first char of s that is not whitespace and
* not a comment, or to the terminating NUL if no such character exists.
*/
@@ -1013,7 +1032,7 @@ base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */
static INLINE int
-_hex_decode_digit(char c)
+hex_decode_digit_(char c)
{
switch (c) {
case '0': return 0;
@@ -1041,7 +1060,7 @@ _hex_decode_digit(char c)
int
hex_decode_digit(char c)
{
- return _hex_decode_digit(c);
+ return hex_decode_digit_(c);
}
/** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode it
@@ -1059,8 +1078,8 @@ base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
return -1;
end = src+srclen;
while (src<end) {
- v1 = _hex_decode_digit(*src);
- v2 = _hex_decode_digit(*(src+1));
+ v1 = hex_decode_digit_(*src);
+ v2 = hex_decode_digit_(*(src+1));
if (v1<0||v2<0)
return -1;
*(uint8_t*)dest = (v1<<4)|v2;
@@ -1160,130 +1179,21 @@ esc_for_log(const char *s)
const char *
escaped(const char *s)
{
- static char *_escaped_val = NULL;
- tor_free(_escaped_val);
+ static char *escaped_val_ = NULL;
+ tor_free(escaped_val_);
if (s)
- _escaped_val = esc_for_log(s);
+ escaped_val_ = esc_for_log(s);
else
- _escaped_val = NULL;
+ escaped_val_ = NULL;
- return _escaped_val;
-}
-
-/** Rudimentary string wrapping code: given a un-wrapped <b>string</b> (no
- * newlines!), break the string into newline-terminated lines of no more than
- * <b>width</b> characters long (not counting newline) and insert them into
- * <b>out</b> in order. Precede the first line with prefix0, and subsequent
- * lines with prefixRest.
- */
-/* This uses a stupid greedy wrapping algorithm right now:
- * - For each line:
- * - Try to fit as much stuff as possible, but break on a space.
- * - If the first "word" of the line will extend beyond the allowable
- * width, break the word at the end of the width.
- */
-void
-wrap_string(smartlist_t *out, const char *string, size_t width,
- const char *prefix0, const char *prefixRest)
-{
- size_t p0Len, pRestLen, pCurLen;
- const char *eos, *prefixCur;
- tor_assert(out);
- tor_assert(string);
- tor_assert(width);
- if (!prefix0)
- prefix0 = "";
- if (!prefixRest)
- prefixRest = "";
-
- p0Len = strlen(prefix0);
- pRestLen = strlen(prefixRest);
- tor_assert(width > p0Len && width > pRestLen);
- eos = strchr(string, '\0');
- tor_assert(eos);
- pCurLen = p0Len;
- prefixCur = prefix0;
-
- while ((eos-string)+pCurLen > width) {
- const char *eol = string + width - pCurLen;
- while (eol > string && *eol != ' ')
- --eol;
- /* eol is now the last space that can fit, or the start of the string. */
- if (eol > string) {
- size_t line_len = (eol-string) + pCurLen + 2;
- char *line = tor_malloc(line_len);
- memcpy(line, prefixCur, pCurLen);
- memcpy(line+pCurLen, string, eol-string);
- line[line_len-2] = '\n';
- line[line_len-1] = '\0';
- smartlist_add(out, line);
- string = eol + 1;
- } else {
- size_t line_len = width + 2;
- char *line = tor_malloc(line_len);
- memcpy(line, prefixCur, pCurLen);
- memcpy(line+pCurLen, string, width - pCurLen);
- line[line_len-2] = '\n';
- line[line_len-1] = '\0';
- smartlist_add(out, line);
- string += width-pCurLen;
- }
- prefixCur = prefixRest;
- pCurLen = pRestLen;
- }
-
- if (string < eos) {
- size_t line_len = (eos-string) + pCurLen + 2;
- char *line = tor_malloc(line_len);
- memcpy(line, prefixCur, pCurLen);
- memcpy(line+pCurLen, string, eos-string);
- line[line_len-2] = '\n';
- line[line_len-1] = '\0';
- smartlist_add(out, line);
- }
+ return escaped_val_;
}
/* =====
* Time
* ===== */
-/**
- * Converts struct timeval to a double value.
- * Preserves microsecond precision, but just barely.
- * Error is approx +/- 0.1 usec when dealing with epoch values.
- */
-double
-tv_to_double(const struct timeval *tv)
-{
- double conv = tv->tv_sec;
- conv += tv->tv_usec/1000000.0;
- return conv;
-}
-
-/**
- * Converts timeval to milliseconds.
- */
-int64_t
-tv_to_msec(const struct timeval *tv)
-{
- int64_t conv = ((int64_t)tv->tv_sec)*1000L;
- /* Round ghetto-style */
- conv += ((int64_t)tv->tv_usec+500)/1000L;
- return conv;
-}
-
-/**
- * Converts timeval to microseconds.
- */
-int64_t
-tv_to_usec(const struct timeval *tv)
-{
- int64_t conv = ((int64_t)tv->tv_sec)*1000000L;
- conv += tv->tv_usec;
- return conv;
-}
-
/** Return the number of microseconds elapsed between *start and *end.
*/
long
@@ -1322,6 +1232,18 @@ tv_mdiff(const struct timeval *start, const struct timeval *end)
return mdiff;
}
+/**
+ * Converts timeval to milliseconds.
+ */
+int64_t
+tv_to_msec(const struct timeval *tv)
+{
+ int64_t conv = ((int64_t)tv->tv_sec)*1000L;
+ /* Round ghetto-style */
+ conv += ((int64_t)tv->tv_usec+500)/1000L;
+ return conv;
+}
+
/** Yield true iff <b>y</b> is a leap-year. */
#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400)))
/** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */
@@ -1336,7 +1258,7 @@ n_leapdays(int y1, int y2)
static const int days_per_month[] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-/** Compute a time_t given a struct tm. The result is given in GMT, and
+/** Compute a time_t given a struct tm. The result is given in UTC, and
* does not account for leap seconds. Return 0 on success, -1 on failure.
*/
int
@@ -1377,10 +1299,11 @@ static const char *MONTH_NAMES[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-/** Set <b>buf</b> to the RFC1123 encoding of the GMT value of <b>t</b>.
+/** Set <b>buf</b> to the RFC1123 encoding of the UTC value of <b>t</b>.
* The buffer must be at least RFC1123_TIME_LEN+1 bytes long.
*
- * (RFC1123 format is Fri, 29 Sep 2006 15:54:20 GMT)
+ * (RFC1123 format is "Fri, 29 Sep 2006 15:54:20 GMT". Note the "GMT"
+ * rather than "UTC".)
*/
void
format_rfc1123_time(char *buf, time_t t)
@@ -1398,8 +1321,11 @@ format_rfc1123_time(char *buf, time_t t)
memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
}
-/** Parse the RFC1123 encoding of some time (in GMT) from <b>buf</b>,
- * and store the result in *<b>t</b>.
+/** Parse the (a subset of) the RFC1123 encoding of some time (in UTC) from
+ * <b>buf</b>, and store the result in *<b>t</b>.
+ *
+ * Note that we only accept the subset generated by format_rfc1123_time above,
+ * not the full range of formats suggested by RFC 1123.
*
* Return 0 on success, -1 on failure.
*/
@@ -1827,6 +1753,10 @@ file_status(const char *fname)
return FN_DIR;
else if (st.st_mode & S_IFREG)
return FN_FILE;
+#ifndef _WIN32
+ else if (st.st_mode & S_IFIFO)
+ return FN_FILE;
+#endif
else
return FN_ERROR;
}
@@ -2257,6 +2187,46 @@ write_bytes_to_new_file(const char *fname, const char *str, size_t len,
(bin?O_BINARY:O_TEXT));
}
+/**
+ * Read the contents of the open file <b>fd</b> presuming it is a FIFO
+ * (or similar) file descriptor for which the size of the file isn't
+ * known ahead of time. Return NULL on failure, and a NUL-terminated
+ * string on success. On success, set <b>sz_out</b> to the number of
+ * bytes read.
+ */
+char *
+read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out)
+{
+ ssize_t r;
+ size_t pos = 0;
+ char *string = NULL;
+ size_t string_max = 0;
+
+ if (max_bytes_to_read+1 >= SIZE_T_CEILING)
+ return NULL;
+
+ do {
+ /* XXXX This "add 1K" approach is a little goofy; if we care about
+ * performance here, we should be doubling. But in practice we shouldn't
+ * be using this function on big files anyway. */
+ string_max = pos + 1024;
+ if (string_max > max_bytes_to_read)
+ string_max = max_bytes_to_read + 1;
+ string = tor_realloc(string, string_max);
+ r = read(fd, string + pos, string_max - pos - 1);
+ if (r < 0) {
+ tor_free(string);
+ return NULL;
+ }
+
+ pos += r;
+ } while (r > 0 && pos < max_bytes_to_read);
+
+ *sz_out = pos;
+ string[pos] = '\0';
+ return string;
+}
+
/** Read the contents of <b>filename</b> into a newly allocated
* string; return the string on success or NULL on failure.
*
@@ -2305,8 +2275,26 @@ read_file_to_str(const char *filename, int flags, struct stat *stat_out)
return NULL;
}
- if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING)
+#ifndef _WIN32
+/** When we detect that we're reading from a FIFO, don't read more than
+ * this many bytes. It's insane overkill for most uses. */
+#define FIFO_READ_MAX (1024*1024)
+ if (S_ISFIFO(statbuf.st_mode)) {
+ size_t sz = 0;
+ string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz);
+ if (string && stat_out) {
+ statbuf.st_size = sz;
+ memcpy(stat_out, &statbuf, sizeof(struct stat));
+ }
+ close(fd);
+ return string;
+ }
+#endif
+
+ if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING) {
+ close(fd);
return NULL;
+ }
string = tor_malloc((size_t)(statbuf.st_size+1));
@@ -2466,10 +2454,13 @@ unescape_string(const char *s, char **result, size_t *size_out)
* key portion and *<b>value_out</b> to a new string holding the value portion
* of the line, and return a pointer to the start of the next line. If we run
* out of data, return a pointer to the end of the string. If we encounter an
- * error, return NULL.
+ * error, return NULL and set *<b>err_out</b> (if provided) to an error
+ * message.
*/
const char *
-parse_config_line_from_str(const char *line, char **key_out, char **value_out)
+parse_config_line_from_str_verbose(const char *line, char **key_out,
+ char **value_out,
+ const char **err_out)
{
/* I believe the file format here is supposed to be:
FILE = (EMPTYLINE | LINE)* (EMPTYLASTLINE | LASTLINE)?
@@ -2543,12 +2534,18 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
/* Find the end of the line. */
if (*line == '\"') { // XXX No continuation handling is done here
- if (!(line = unescape_string(line, value_out, NULL)))
- return NULL;
+ if (!(line = unescape_string(line, value_out, NULL))) {
+ if (err_out)
+ *err_out = "Invalid escape sequence in quoted string";
+ return NULL;
+ }
while (*line == ' ' || *line == '\t')
++line;
- if (*line && *line != '#' && *line != '\n')
+ if (*line && *line != '#' && *line != '\n') {
+ if (err_out)
+ *err_out = "Excess data after quoted string";
return NULL;
+ }
} else {
/* Look for the end of the line. */
while (*line && *line != '\n' && (*line != '#' || continuation)) {
@@ -2683,9 +2680,9 @@ digit_to_num(char d)
* success, store the result in <b>out</b>, advance bufp to the next
* character, and return 0. On failure, return -1. */
static int
-scan_unsigned(const char **bufp, unsigned *out, int width, int base)
+scan_unsigned(const char **bufp, unsigned long *out, int width, int base)
{
- unsigned result = 0;
+ unsigned long result = 0;
int scanned_so_far = 0;
const int hex = base==16;
tor_assert(base == 10 || base == 16);
@@ -2697,8 +2694,8 @@ scan_unsigned(const char **bufp, unsigned *out, int width, int base)
while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
&& scanned_so_far < width) {
int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
- unsigned new_result = result * base + digit;
- if (new_result > UINT32_MAX || new_result < result)
+ unsigned long new_result = result * base + digit;
+ if (new_result < result)
return -1; /* over/underflow. */
result = new_result;
++scanned_so_far;
@@ -2711,6 +2708,89 @@ scan_unsigned(const char **bufp, unsigned *out, int width, int base)
return 0;
}
+/** Helper: Read an signed int from *<b>bufp</b> of up to <b>width</b>
+ * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On
+ * success, store the result in <b>out</b>, advance bufp to the next
+ * character, and return 0. On failure, return -1. */
+static int
+scan_signed(const char **bufp, long *out, int width)
+{
+ int neg = 0;
+ unsigned long result = 0;
+
+ if (!bufp || !*bufp || !out)
+ return -1;
+ if (width<0)
+ width=MAX_SCANF_WIDTH;
+
+ if (**bufp == '-') {
+ neg = 1;
+ ++*bufp;
+ --width;
+ }
+
+ if (scan_unsigned(bufp, &result, width, 10) < 0)
+ return -1;
+
+ if (neg) {
+ if (result > ((unsigned long)LONG_MAX) + 1)
+ return -1; /* Underflow */
+ *out = -(long)result;
+ } else {
+ if (result > LONG_MAX)
+ return -1; /* Overflow */
+ *out = (long)result;
+ }
+
+ return 0;
+}
+
+/** Helper: Read a decimal-formatted double from *<b>bufp</b> of up to
+ * <b>width</b> characters. (Handle arbitrary width if <b>width</b> is less
+ * than 0.) On success, store the result in <b>out</b>, advance bufp to the
+ * next character, and return 0. On failure, return -1. */
+static int
+scan_double(const char **bufp, double *out, int width)
+{
+ int neg = 0;
+ double result = 0;
+ int scanned_so_far = 0;
+
+ if (!bufp || !*bufp || !out)
+ return -1;
+ if (width<0)
+ width=MAX_SCANF_WIDTH;
+
+ if (**bufp == '-') {
+ neg = 1;
+ ++*bufp;
+ }
+
+ while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
+ const int digit = digit_to_num(*(*bufp)++);
+ result = result * 10 + digit;
+ ++scanned_so_far;
+ }
+ if (**bufp == '.') {
+ double fracval = 0, denominator = 1;
+ ++*bufp;
+ ++scanned_so_far;
+ while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
+ const int digit = digit_to_num(*(*bufp)++);
+ fracval = fracval * 10 + digit;
+ denominator *= 10;
+ ++scanned_so_far;
+ }
+ result += fracval / denominator;
+ }
+
+ if (!scanned_so_far) /* No actual digits scanned */
+ return -1;
+
+ *out = neg ? -result : result;
+ return 0;
+}
+
/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to
* <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b>
* to the next non-space character or the EOS. */
@@ -2747,6 +2827,7 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
}
} else {
int width = -1;
+ int longmod = 0;
++pattern;
if (TOR_ISDIGIT(*pattern)) {
width = digit_to_num(*pattern++);
@@ -2759,17 +2840,57 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
if (!width) /* No zero-width things. */
return -1;
}
+ if (*pattern == 'l') {
+ longmod = 1;
+ ++pattern;
+ }
if (*pattern == 'u' || *pattern == 'x') {
- unsigned *u = va_arg(ap, unsigned *);
+ unsigned long u;
const int base = (*pattern == 'u') ? 10 : 16;
if (!*buf)
return n_matched;
- if (scan_unsigned(&buf, u, width, base)<0)
+ if (scan_unsigned(&buf, &u, width, base)<0)
+ return n_matched;
+ if (longmod) {
+ unsigned long *out = va_arg(ap, unsigned long *);
+ *out = u;
+ } else {
+ unsigned *out = va_arg(ap, unsigned *);
+ if (u > UINT_MAX)
+ return n_matched;
+ *out = (unsigned) u;
+ }
+ ++pattern;
+ ++n_matched;
+ } else if (*pattern == 'f') {
+ double *d = va_arg(ap, double *);
+ if (!longmod)
+ return -1; /* float not supported */
+ if (!*buf)
+ return n_matched;
+ if (scan_double(&buf, d, width)<0)
return n_matched;
++pattern;
++n_matched;
+ } else if (*pattern == 'd') {
+ long lng=0;
+ if (scan_signed(&buf, &lng, width)<0)
+ return n_matched;
+ if (longmod) {
+ long *out = va_arg(ap, long *);
+ *out = lng;
+ } else {
+ int *out = va_arg(ap, int *);
+ if (lng < INT_MIN || lng > INT_MAX)
+ return n_matched;
+ *out = (int)lng;
+ }
+ ++pattern;
+ ++n_matched;
} else if (*pattern == 's') {
char *s = va_arg(ap, char *);
+ if (longmod)
+ return -1;
if (width < 0)
return -1;
if (scan_string(&buf, s, width)<0)
@@ -2778,6 +2899,8 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
++n_matched;
} else if (*pattern == 'c') {
char *ch = va_arg(ap, char *);
+ if (longmod)
+ return -1;
if (width != -1)
return -1;
if (!*buf)
@@ -2788,6 +2911,8 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
} else if (*pattern == '%') {
if (*buf != '%')
return n_matched;
+ if (longmod)
+ return -1;
++buf;
++pattern;
} else {
@@ -2801,9 +2926,14 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b>
* and store the results in the corresponding argument fields. Differs from
- * sscanf in that it: Only handles %u, %x, %c and %Ns. Does not handle
- * arbitrarily long widths. %u and %x do not consume any space. Is
- * locale-independent. Returns -1 on malformed patterns.
+ * sscanf in that:
+ * <ul><li>It only handles %u, %lu, %x, %lx, %<NUM>s, %d, %ld, %lf, and %c.
+ * <li>It only handles decimal inputs for %lf. (12.3, not 1.23e1)
+ * <li>It does not handle arbitrarily long widths.
+ * <li>Numbers do not consume any space characters.
+ * <li>It is locale-independent.
+ * <li>%u and %x do not consume any space.
+ * <li>It returns -1 on malformed patterns.</ul>
*
* (As with other locale-independent functions, we need this to parse data that
* is in ASCII without worrying that the C library's locale-handling will make
@@ -3630,12 +3760,13 @@ tor_spawn_background(const char *const filename, const char **argv,
child_state = CHILD_STATE_MAXFD;
#ifdef _SC_OPEN_MAX
- if (-1 != max_fd) {
+ if (-1 == max_fd) {
max_fd = (int) sysconf(_SC_OPEN_MAX);
- if (max_fd == -1)
+ if (max_fd == -1) {
max_fd = DEFAULT_MAX_FD;
log_warn(LD_GENERAL,
"Cannot find maximum file descriptor, assuming %d", max_fd);
+ }
}
#else
max_fd = DEFAULT_MAX_FD;
@@ -3784,10 +3915,17 @@ tor_process_handle_destroy(process_handle_t *process_handle,
if (also_terminate_process) {
if (tor_terminate_process(process_handle) < 0) {
- log_notice(LD_GENERAL, "Failed to terminate process with PID '%d'",
- tor_process_get_pid(process_handle));
+ const char *errstr =
+#ifdef _WIN32
+ format_win32_error(GetLastError());
+#else
+ strerror(errno);
+#endif
+ log_notice(LD_GENERAL, "Failed to terminate process with "
+ "PID '%d' ('%s').", tor_process_get_pid(process_handle),
+ errstr);
} else {
- log_info(LD_GENERAL, "Terminated process with PID '%d'",
+ log_info(LD_GENERAL, "Terminated process with PID '%d'.",
tor_process_get_pid(process_handle));
}
}
@@ -4255,7 +4393,70 @@ tor_split_lines(smartlist_t *sl, char *buf, int len)
return smartlist_len(sl);
}
+/** Return a string corresponding to <b>stream_status</b>. */
+const char *
+stream_status_to_string(enum stream_status stream_status)
+{
+ switch (stream_status) {
+ case IO_STREAM_OKAY:
+ return "okay";
+ case IO_STREAM_EAGAIN:
+ return "temporarily unavailable";
+ case IO_STREAM_TERM:
+ return "terminated";
+ case IO_STREAM_CLOSED:
+ return "closed";
+ default:
+ tor_fragile_assert();
+ return "unknown";
+ }
+}
+
#ifdef _WIN32
+
+/** Return a smartlist containing lines outputted from
+ * <b>handle</b>. Return NULL on error, and set
+ * <b>stream_status_out</b> appropriately. */
+smartlist_t *
+tor_get_lines_from_handle(HANDLE *handle,
+ enum stream_status *stream_status_out)
+{
+ int pos;
+ char stdout_buf[600] = {0};
+ smartlist_t *lines = NULL;
+
+ tor_assert(stream_status_out);
+
+ *stream_status_out = IO_STREAM_TERM;
+
+ pos = tor_read_all_handle(handle, stdout_buf, sizeof(stdout_buf) - 1, NULL);
+ if (pos < 0) {
+ *stream_status_out = IO_STREAM_TERM;
+ return NULL;
+ }
+ if (pos == 0) {
+ *stream_status_out = IO_STREAM_EAGAIN;
+ return NULL;
+ }
+
+ /* End with a null even if there isn't a \r\n at the end */
+ /* TODO: What if this is a partial line? */
+ stdout_buf[pos] = '\0';
+
+ /* Split up the buffer */
+ lines = smartlist_new();
+ tor_split_lines(lines, stdout_buf, pos);
+
+ /* Currently 'lines' is populated with strings residing on the
+ stack. Replace them with their exact copies on the heap: */
+ SMARTLIST_FOREACH(lines, char *, line,
+ SMARTLIST_REPLACE_CURRENT(lines, line, tor_strdup(line)));
+
+ *stream_status_out = IO_STREAM_OKAY;
+
+ return lines;
+}
+
/** Read from stream, and send lines to log at the specified log level.
* Returns -1 if there is a error reading, and 0 otherwise.
* If the generated stream is flushed more often than on new lines, or
@@ -4303,6 +4504,33 @@ log_from_handle(HANDLE *pipe, int severity)
#else
+/** Return a smartlist containing lines outputted from
+ * <b>handle</b>. Return NULL on error, and set
+ * <b>stream_status_out</b> appropriately. */
+smartlist_t *
+tor_get_lines_from_handle(FILE *handle, enum stream_status *stream_status_out)
+{
+ enum stream_status stream_status;
+ char stdout_buf[400];
+ smartlist_t *lines = NULL;
+
+ while (1) {
+ memset(stdout_buf, 0, sizeof(stdout_buf));
+
+ stream_status = get_string_from_pipe(handle,
+ stdout_buf, sizeof(stdout_buf) - 1);
+ if (stream_status != IO_STREAM_OKAY)
+ goto done;
+
+ if (!lines) lines = smartlist_new();
+ smartlist_add(lines, tor_strdup(stdout_buf));
+ }
+
+ done:
+ *stream_status_out = stream_status;
+ return lines;
+}
+
/** Read from stream, and send lines to log at the specified log level.
* Returns 1 if stream is closed normally, -1 if there is a error reading, and
* 0 otherwise. Handles lines from tor-fw-helper and
@@ -4421,9 +4649,130 @@ get_string_from_pipe(FILE *stream, char *buf_out, size_t count)
return IO_STREAM_TERM;
}
-/* DOCDOC tor_check_port_forwarding */
+/** Parse a <b>line</b> from tor-fw-helper and issue an appropriate
+ * log message to our user. */
+static void
+handle_fw_helper_line(const char *line)
+{
+ smartlist_t *tokens = smartlist_new();
+ char *message = NULL;
+ char *message_for_log = NULL;
+ const char *external_port = NULL;
+ const char *internal_port = NULL;
+ const char *result = NULL;
+ int port = 0;
+ int success = 0;
+
+ smartlist_split_string(tokens, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(tokens) < 5)
+ goto err;
+
+ if (strcmp(smartlist_get(tokens, 0), "tor-fw-helper") ||
+ strcmp(smartlist_get(tokens, 1), "tcp-forward"))
+ goto err;
+
+ external_port = smartlist_get(tokens, 2);
+ internal_port = smartlist_get(tokens, 3);
+ result = smartlist_get(tokens, 4);
+
+ if (smartlist_len(tokens) > 5) {
+ /* If there are more than 5 tokens, they are part of [<message>].
+ Let's use a second smartlist to form the whole message;
+ strncat loops suck. */
+ int i;
+ int message_words_n = smartlist_len(tokens) - 5;
+ smartlist_t *message_sl = smartlist_new();
+ for (i = 0; i < message_words_n; i++)
+ smartlist_add(message_sl, smartlist_get(tokens, 5+i));
+
+ tor_assert(smartlist_len(message_sl) > 0);
+ message = smartlist_join_strings(message_sl, " ", 0, NULL);
+
+ /* wrap the message in log-friendly wrapping */
+ tor_asprintf(&message_for_log, " ('%s')", message);
+
+ smartlist_free(message_sl);
+ }
+
+ port = atoi(external_port);
+ if (port < 1 || port > 65535)
+ goto err;
+
+ port = atoi(internal_port);
+ if (port < 1 || port > 65535)
+ goto err;
+
+ if (!strcmp(result, "SUCCESS"))
+ success = 1;
+ else if (!strcmp(result, "FAIL"))
+ success = 0;
+ else
+ goto err;
+
+ if (!success) {
+ log_warn(LD_GENERAL, "Tor was unable to forward TCP port '%s' to '%s'%s. "
+ "Please make sure that your router supports port "
+ "forwarding protocols (like NAT-PMP). Note that if '%s' is "
+ "your ORPort, your relay will be unable to receive inbound "
+ "traffic.", external_port, internal_port,
+ message_for_log ? message_for_log : "",
+ internal_port);
+ } else {
+ log_info(LD_GENERAL,
+ "Tor successfully forwarded TCP port '%s' to '%s'%s.",
+ external_port, internal_port,
+ message_for_log ? message_for_log : "");
+ }
+
+ goto done;
+
+ err:
+ log_warn(LD_GENERAL, "tor-fw-helper sent us a string we could not "
+ "parse (%s).", line);
+
+ done:
+ SMARTLIST_FOREACH(tokens, char *, cp, tor_free(cp));
+ smartlist_free(tokens);
+ tor_free(message);
+ tor_free(message_for_log);
+}
+
+/** Read what tor-fw-helper has to say in its stdout and handle it
+ * appropriately */
+static int
+handle_fw_helper_output(process_handle_t *process_handle)
+{
+ smartlist_t *fw_helper_output = NULL;
+ enum stream_status stream_status = 0;
+
+ fw_helper_output =
+ tor_get_lines_from_handle(tor_process_get_stdout_pipe(process_handle),
+ &stream_status);
+ if (!fw_helper_output) { /* didn't get any output from tor-fw-helper */
+ /* if EAGAIN we should retry in the future */
+ return (stream_status == IO_STREAM_EAGAIN) ? 0 : -1;
+ }
+
+ /* Handle the lines we got: */
+ SMARTLIST_FOREACH_BEGIN(fw_helper_output, char *, line) {
+ handle_fw_helper_line(line);
+ tor_free(line);
+ } SMARTLIST_FOREACH_END(line);
+
+ smartlist_free(fw_helper_output);
+
+ return 0;
+}
+
+/** Spawn tor-fw-helper and ask it to forward the ports in
+ * <b>ports_to_forward</b>. <b>ports_to_forward</b> contains strings
+ * of the form "<external port>:<internal port>", which is the format
+ * that tor-fw-helper expects. */
void
-tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
+tor_check_port_forwarding(const char *filename,
+ smartlist_t *ports_to_forward,
time_t now)
{
/* When fw-helper succeeds, how long do we wait until running it again */
@@ -4437,32 +4786,51 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
static process_handle_t *child_handle=NULL;
static time_t time_to_run_helper = 0;
- int stdout_status, stderr_status, retval;
- const char *argv[10];
- char s_dirport[6], s_orport[6];
+ int stderr_status, retval;
+ int stdout_status = 0;
tor_assert(filename);
- /* Set up command line for tor-fw-helper */
- snprintf(s_dirport, sizeof s_dirport, "%d", dir_port);
- snprintf(s_orport, sizeof s_orport, "%d", or_port);
-
- /* TODO: Allow different internal and external ports */
- argv[0] = filename;
- argv[1] = "--internal-or-port";
- argv[2] = s_orport;
- argv[3] = "--external-or-port";
- argv[4] = s_orport;
- argv[5] = "--internal-dir-port";
- argv[6] = s_dirport;
- argv[7] = "--external-dir-port";
- argv[8] = s_dirport;
- argv[9] = NULL;
-
/* Start the child, if it is not already running */
if ((!child_handle || child_handle->status != PROCESS_STATUS_RUNNING) &&
time_to_run_helper < now) {
- int status;
+ /*tor-fw-helper cli looks like this: tor_fw_helper -p :5555 -p 4555:1111 */
+ const char **argv; /* cli arguments */
+ int args_n, status;
+ int argv_index = 0; /* index inside 'argv' */
+
+ tor_assert(smartlist_len(ports_to_forward) > 0);
+
+ /* check for overflow during 'argv' allocation:
+ (len(ports_to_forward)*2 + 2)*sizeof(char*) > SIZE_MAX ==
+ len(ports_to_forward) > (((SIZE_MAX/sizeof(char*)) - 2)/2) */
+ if ((size_t) smartlist_len(ports_to_forward) >
+ (((SIZE_MAX/sizeof(char*)) - 2)/2)) {
+ log_warn(LD_GENERAL,
+ "Overflow during argv allocation. This shouldn't happen.");
+ return;
+ }
+ /* check for overflow during 'argv_index' increase:
+ ((len(ports_to_forward)*2 + 2) > INT_MAX) ==
+ len(ports_to_forward) > (INT_MAX - 2)/2 */
+ if (smartlist_len(ports_to_forward) > (INT_MAX - 2)/2) {
+ log_warn(LD_GENERAL,
+ "Overflow during argv_index increase. This shouldn't happen.");
+ return;
+ }
+
+ /* Calculate number of cli arguments: one for the filename, two
+ for each smartlist element (one for "-p" and one for the
+ ports), and one for the final NULL. */
+ args_n = 1 + 2*smartlist_len(ports_to_forward) + 1;
+ argv = tor_malloc_zero(sizeof(char*)*args_n);
+
+ argv[argv_index++] = filename;
+ SMARTLIST_FOREACH_BEGIN(ports_to_forward, const char *, port) {
+ argv[argv_index++] = "-p";
+ argv[argv_index++] = port;
+ } SMARTLIST_FOREACH_END(port);
+ argv[argv_index] = NULL;
/* Assume tor-fw-helper will succeed, start it later*/
time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_SUCCESS;
@@ -4479,6 +4847,9 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
status = tor_spawn_background(filename, argv, NULL, &child_handle);
#endif
+ tor_free_((void*)argv);
+ argv=NULL;
+
if (PROCESS_STATUS_ERROR == status) {
log_warn(LD_GENERAL, "Failed to start port forwarding helper %s",
filename);
@@ -4496,16 +4867,17 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
/* Read from stdout/stderr and log result */
retval = 0;
#ifdef _WIN32
- stdout_status = log_from_handle(child_handle->stdout_pipe, LOG_INFO);
- stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_WARN);
- /* If we got this far (on Windows), the process started */
- retval = 0;
+ stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_INFO);
#else
- stdout_status = log_from_pipe(child_handle->stdout_handle,
- LOG_INFO, filename, &retval);
stderr_status = log_from_pipe(child_handle->stderr_handle,
- LOG_WARN, filename, &retval);
+ LOG_INFO, filename, &retval);
#endif
+ if (handle_fw_helper_output(child_handle) < 0) {
+ log_warn(LD_GENERAL, "Failed to handle fw helper output.");
+ stdout_status = -1;
+ retval = -1;
+ }
+
if (retval) {
/* There was a problem in the child process */
time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
@@ -4551,3 +4923,45 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
}
}
+/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */
+void
+tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed)
+{
+ rng->state = (uint32_t)(seed & 0x7fffffff);
+}
+
+/** Return a randomly chosen value in the range 0..TOR_WEAK_RANDOM_MAX based
+ * on the RNG state of <b>rng</b>. This entropy will not be cryptographically
+ * strong; do not rely on it for anything an adversary should not be able to
+ * predict. */
+int32_t
+tor_weak_random(tor_weak_rng_t *rng)
+{
+ /* Here's a linear congruential generator. OpenBSD and glibc use these
+ * parameters; they aren't too bad, and should have maximal period over the
+ * range 0..INT32_MAX. We don't want to use the platform rand() or random(),
+ * since some platforms have bad weak RNGs that only return values in the
+ * range 0..INT16_MAX, which just isn't enough. */
+ rng->state = (rng->state * 1103515245 + 12345) & 0x7fffffff;
+ return (int32_t) rng->state;
+}
+
+/** Return a random number in the range [0 , <b>top</b>). {That is, the range
+ * of integers i such that 0 <= i < top.} Chooses uniformly. Requires that
+ * top is greater than 0. This randomness is not cryptographically strong; do
+ * not rely on it for anything an adversary should not be able to predict. */
+int32_t
+tor_weak_random_range(tor_weak_rng_t *rng, int32_t top)
+{
+ /* We don't want to just do tor_weak_random() % top, since random() is often
+ * implemented with an LCG whose modulus is a power of 2, and those are
+ * cyclic in their low-order bits. */
+ int divisor, result;
+ tor_assert(top > 0);
+ divisor = TOR_WEAK_RANDOM_MAX / top;
+ do {
+ result = (int32_t)(tor_weak_random(rng) / divisor);
+ } while (result >= top);
+ return result;
+}
+
diff --git a/src/common/util.h b/src/common/util.h
index 8977d273c..73daa6e2a 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,8 +8,8 @@
* \brief Headers for util.c
**/
-#ifndef _TOR_UTIL_H
-#define _TOR_UTIL_H
+#ifndef TOR_UTIL_H
+#define TOR_UTIL_H
#include "orconfig.h"
#include "torint.h"
@@ -49,9 +49,9 @@
#define tor_assert(expr) STMT_BEGIN \
if (PREDICT_UNLIKELY(!(expr))) { \
log_err(LD_BUG, "%s:%d: %s: Assertion %s failed; aborting.", \
- _SHORT_FILE_, __LINE__, __func__, #expr); \
+ SHORT_FILE__, __LINE__, __func__, #expr); \
fprintf(stderr,"%s:%d %s: Assertion %s failed; aborting.\n", \
- _SHORT_FILE_, __LINE__, __func__, #expr); \
+ SHORT_FILE__, __LINE__, __func__, #expr); \
abort(); \
} STMT_END
@@ -62,7 +62,7 @@
* to calls. */
#ifdef USE_DMALLOC
#define DMALLOC_PARAMS , const char *file, const int line
-#define DMALLOC_ARGS , _SHORT_FILE_, __LINE__
+#define DMALLOC_ARGS , SHORT_FILE__, __LINE__
#else
#define DMALLOC_PARAMS
#define DMALLOC_ARGS
@@ -74,23 +74,24 @@
#define tor_fragile_assert()
/* Memory management */
-void *_tor_malloc(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_malloc_zero(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_malloc_roundup(size_t *size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS);
-char *_tor_strdup(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1));
-char *_tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
+void *tor_malloc_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
+void *tor_malloc_zero_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
+void *tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC;
+void *tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS);
+char *tor_strdup_(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1));
+char *tor_strndup_(const char *s, size_t n DMALLOC_PARAMS)
ATTR_MALLOC ATTR_NONNULL((1));
-void *_tor_memdup(const void *mem, size_t len DMALLOC_PARAMS)
+void *tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS)
ATTR_MALLOC ATTR_NONNULL((1));
-void _tor_free(void *mem);
+void *tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS)
+ ATTR_MALLOC ATTR_NONNULL((1));
+void tor_free_(void *mem);
#ifdef USE_DMALLOC
extern int dmalloc_free(const char *file, const int line, void *pnt,
const int func_id);
#define tor_free(p) STMT_BEGIN \
if (PREDICT_LIKELY((p)!=NULL)) { \
- dmalloc_free(_SHORT_FILE_, __LINE__, (p), 0); \
+ dmalloc_free(SHORT_FILE__, __LINE__, (p), 0); \
(p)=NULL; \
} \
STMT_END
@@ -100,7 +101,7 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
* and it sets the pointer value to NULL after freeing it.
*
* This is a macro. If you need a function pointer to release memory from
- * tor_malloc(), use _tor_free().
+ * tor_malloc(), use tor_free_().
*/
#define tor_free(p) STMT_BEGIN \
if (PREDICT_LIKELY((p)!=NULL)) { \
@@ -110,14 +111,14 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
STMT_END
#endif
-#define tor_malloc(size) _tor_malloc(size DMALLOC_ARGS)
-#define tor_malloc_zero(size) _tor_malloc_zero(size DMALLOC_ARGS)
-#define tor_calloc(nmemb,size) _tor_calloc(nmemb, size DMALLOC_ARGS)
-#define tor_malloc_roundup(szp) _tor_malloc_roundup(szp DMALLOC_ARGS)
-#define tor_realloc(ptr, size) _tor_realloc(ptr, size DMALLOC_ARGS)
-#define tor_strdup(s) _tor_strdup(s DMALLOC_ARGS)
-#define tor_strndup(s, n) _tor_strndup(s, n DMALLOC_ARGS)
-#define tor_memdup(s, n) _tor_memdup(s, n DMALLOC_ARGS)
+#define tor_malloc(size) tor_malloc_(size DMALLOC_ARGS)
+#define tor_malloc_zero(size) tor_malloc_zero_(size DMALLOC_ARGS)
+#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size DMALLOC_ARGS)
+#define tor_realloc(ptr, size) tor_realloc_(ptr, size DMALLOC_ARGS)
+#define tor_strdup(s) tor_strdup_(s DMALLOC_ARGS)
+#define tor_strndup(s, n) tor_strndup_(s, n DMALLOC_ARGS)
+#define tor_memdup(s, n) tor_memdup_(s, n DMALLOC_ARGS)
+#define tor_memdup_nulterm(s, n) tor_memdup_nulterm_(s, n DMALLOC_ARGS)
void tor_log_mallinfo(int severity);
@@ -161,6 +162,7 @@ void tor_log_mallinfo(int severity);
/* Math functions */
double tor_mathlog(double d) ATTR_CONST;
long tor_lround(double d) ATTR_CONST;
+int64_t tor_llround(double d) ATTR_CONST;
int tor_log2(uint64_t u64) ATTR_CONST;
uint64_t round_to_power_of_2(uint64_t u64);
unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
@@ -173,6 +175,17 @@ int n_bits_set_u8(uint8_t v);
* overflow. */
#define CEIL_DIV(a,b) (((a)+(b)-1)/(b))
+/* Return <b>v</b> if it's between <b>min</b> and <b>max</b>. Otherwise
+ * return <b>min</b> if <b>v</b> is smaller than <b>min</b>, or <b>max</b> if
+ * <b>b</b> is larger than <b>max</b>.
+ *
+ * Requires that <b>min</b> is no more than <b>max</b>. May evaluate any of
+ * its arguments more than once! */
+#define CLAMP(min,v,max) \
+ ( ((v) < (min)) ? (min) : \
+ ((v) > (max)) ? (max) : \
+ (v) )
+
/* String manipulation */
/** Allowable characters in a hexadecimal string. */
@@ -188,6 +201,7 @@ int strcasecmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2));
int strcmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
int strcasecmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix);
+void tor_strclear(char *s);
void tor_strstrip(char *s, const char *strip) ATTR_NONNULL((1,2));
long tor_parse_long(const char *s, int base, long min,
@@ -215,8 +229,6 @@ int tor_digest256_is_zero(const char *digest);
char *esc_for_log(const char *string) ATTR_MALLOC;
const char *escaped(const char *string);
struct smartlist_t;
-void wrap_string(struct smartlist_t *out, const char *string, size_t width,
- const char *prefix0, const char *prefixRest);
int tor_vsscanf(const char *buf, const char *pattern, va_list ap)
#ifdef __GNUC__
__attribute__((format(scanf, 2, 0)))
@@ -239,11 +251,9 @@ void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
/* Time helpers */
-double tv_to_double(const struct timeval *tv);
-int64_t tv_to_msec(const struct timeval *tv);
-int64_t tv_to_usec(const struct timeval *tv);
long tv_udiff(const struct timeval *start, const struct timeval *end);
long tv_mdiff(const struct timeval *start, const struct timeval *end);
+int64_t tv_to_msec(const struct timeval *tv);
int tor_timegm(const struct tm *tm, time_t *time_out);
#define RFC1123_TIME_LEN 29
void format_rfc1123_time(char *buf, time_t t);
@@ -283,6 +293,15 @@ void update_approx_time(time_t now);
}
}
</pre>
+
+ As a convenience wrapper for logging, you can replace the above with:
+ <pre>
+ if (possibly_very_frequent_event()) {
+ static ratelim_t warning_limit = RATELIM_INIT(300);
+ log_fn_ratelim(&warning_limit, LOG_WARN, LD_GENERAL,
+ "The event occurred!");
+ }
+ </pre>
*/
typedef struct ratelim_t {
int rate;
@@ -306,6 +325,8 @@ enum stream_status {
IO_STREAM_CLOSED
};
+const char *stream_status_to_string(enum stream_status stream_status);
+
enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count);
/** Return values from file_status(); see that function's documentation
@@ -360,8 +381,14 @@ struct stat;
#endif
char *read_file_to_str(const char *filename, int flags, struct stat *stat_out)
ATTR_MALLOC;
-const char *parse_config_line_from_str(const char *line,
- char **key_out, char **value_out);
+char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read,
+ size_t *sz_out)
+ ATTR_MALLOC;
+const char *parse_config_line_from_str_verbose(const char *line,
+ char **key_out, char **value_out,
+ const char **err_out);
+#define parse_config_line_from_str(line,key_out,value_out) \
+ parse_config_line_from_str_verbose((line),(key_out),(value_out),NULL)
char *expand_filename(const char *filename);
struct smartlist_t *tor_listdir(const char *dirname);
int path_is_relative(const char *filename);
@@ -373,7 +400,8 @@ void write_pidfile(char *filename);
/* Port forwarding */
void tor_check_port_forwarding(const char *filename,
- int dir_port, int or_port, time_t now);
+ struct smartlist_t *ports_to_forward,
+ time_t now);
typedef struct process_handle_t process_handle_t;
typedef struct process_environment_t process_environment_t;
@@ -464,10 +492,34 @@ HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle);
FILE *tor_process_get_stdout_pipe(process_handle_t *process_handle);
#endif
+#ifdef _WIN32
+struct smartlist_t *
+tor_get_lines_from_handle(HANDLE *handle,
+ enum stream_status *stream_status);
+#else
+struct smartlist_t *
+tor_get_lines_from_handle(FILE *handle,
+ enum stream_status *stream_status);
+#endif
+
int tor_terminate_process(process_handle_t *process_handle);
void tor_process_handle_destroy(process_handle_t *process_handle,
int also_terminate_process);
+/* ===== Insecure rng */
+typedef struct tor_weak_rng_t {
+ uint32_t state;
+} tor_weak_rng_t;
+
+#define TOR_WEAK_RNG_INIT {383745623}
+#define TOR_WEAK_RANDOM_MAX (INT_MAX)
+void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed);
+int32_t tor_weak_random(tor_weak_rng_t *weak_rng);
+int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top);
+/** Randomly return true according to <b>rng</b> with probability 1 in
+ * <b>n</b> */
+#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n)))
+
#ifdef UTIL_PRIVATE
/* Prototypes for private functions only used by util.c (and unit tests) */
diff --git a/src/config/Makefile.am b/src/config/Makefile.am
deleted file mode 100644
index 90dd218b4..000000000
--- a/src/config/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-confdir = $(sysconfdir)/tor
-
-tordatadir = $(datadir)/tor
-
-EXTRA_DIST = geoip
-# fallback-consensus
-
-conf_DATA = torrc.sample
-
-tordata_DATA = geoip
-# fallback_consensus
-
-# If we don't have it, fake it.
-fallback-consensus:
- touch fallback-consensus
-
diff --git a/src/config/README.geoip b/src/config/README.geoip
new file mode 100644
index 000000000..852050140
--- /dev/null
+++ b/src/config/README.geoip
@@ -0,0 +1,90 @@
+README.geoip -- information on the IP-to-country-code file shipped with tor
+===========================================================================
+
+The IP-to-country-code file in src/config/geoip is based on MaxMind's
+GeoLite Country database with the following modifications:
+
+ - Those "A1" ("Anonymous Proxy") entries lying inbetween two entries with
+ the same country code are automatically changed to that country code.
+ These changes can be overriden by specifying a different country code
+ in src/config/geoip-manual.
+
+ - Other "A1" entries are replaced with country codes specified in
+ src/config/geoip-manual, or are left as is if there is no corresponding
+ entry in that file. Even non-"A1" entries can be modified by adding a
+ replacement entry to src/config/geoip-manual. Handle with care.
+
+
+1. Updating the geoip file from a MaxMind database file
+-------------------------------------------------------
+
+Download the most recent MaxMind GeoLite Country database:
+http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip
+
+Run `python deanonymind.py` in the local directory. Review the output to
+learn about applied automatic/manual changes and watch out for any
+warnings.
+
+Possibly edit geoip-manual to make more/fewer/different manual changes and
+re-run `python deanonymind.py`.
+
+When done, prepend the new geoip file with a comment like this:
+
+ # Last updated based on $DATE Maxmind GeoLite Country
+ # See README.geoip for details on the conversion.
+
+
+2. Verifying automatic and manual changes using diff
+----------------------------------------------------
+
+To unzip the original MaxMind file and look at the automatic changes, run:
+
+ unzip GeoIPCountryCSV.zip
+ diff -U1 GeoIPCountryWhois.csv AutomaticGeoIPCountryWhois.csv
+
+To look at subsequent manual changes, run:
+
+ diff -U1 AutomaticGeoIPCountryWhois.csv ManualGeoIPCountryWhois.csv
+
+To manually generate the geoip file and compare it to the automatically
+created one, run:
+
+ cut -d, -f3-5 < ManualGeoIPCountryWhois.csv | sed 's/"//g' > mygeoip
+ diff -U1 geoip mygeoip
+
+
+3. Verifying automatic and manual changes using blockfinder
+-----------------------------------------------------------
+
+Blockfinder is a powerful tool to handle multiple IP-to-country data
+sources. Blockfinder has a function to specify a country code and compare
+conflicting country code assignments in different data sources.
+
+We can use blockfinder to compare A1 entries in the original MaxMind file
+with the same or overlapping blocks in the file generated above and in the
+RIR delegation files:
+
+ git clone https://github.com/ioerror/blockfinder
+ cd blockfinder/
+ python blockfinder -i
+ python blockfinder -r ../GeoIPCountryWhois.csv
+ python blockfinder -r ../ManualGeoIPCountryWhois.csv
+ python blockfinder -p A1 > A1-comparison.txt
+
+The output marks conflicts between assignments using either '*' in case of
+two different opinions or '#' for three or more different opinions about
+the country code for a given block.
+
+The '*' conflicts are most likely harmless, because there will always be
+at least two opinions with the original MaxMind file saying A1 and the
+other two sources saying something more meaningful.
+
+However, watch out for '#' conflicts. In these cases, the original
+MaxMind file ("A1"), the updated MaxMind file (hopefully the correct
+country code), and the RIR delegation files (some other country code) all
+disagree.
+
+There are perfectly valid cases where the updated MaxMind file and the RIR
+delegation files don't agree. But each of those cases must be verified
+manually.
+
diff --git a/src/config/deanonymind.py b/src/config/deanonymind.py
new file mode 100755
index 000000000..c86dadca9
--- /dev/null
+++ b/src/config/deanonymind.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python
+import optparse
+import os
+import sys
+import zipfile
+
+"""
+Take a MaxMind GeoLite Country database as input and replace A1 entries
+with the country code and name of the preceding entry iff the preceding
+(subsequent) entry ends (starts) directly before (after) the A1 entry and
+both preceding and subsequent entries contain the same country code.
+
+Then apply manual changes, either replacing A1 entries that could not be
+replaced automatically or overriding previously made automatic changes.
+"""
+
+def main():
+ options = parse_options()
+ assignments = read_file(options.in_maxmind)
+ assignments = apply_automatic_changes(assignments)
+ write_file(options.out_automatic, assignments)
+ manual_assignments = read_file(options.in_manual, must_exist=False)
+ assignments = apply_manual_changes(assignments, manual_assignments)
+ write_file(options.out_manual, assignments)
+ write_file(options.out_geoip, assignments, long_format=False)
+
+def parse_options():
+ parser = optparse.OptionParser()
+ parser.add_option('-i', action='store', dest='in_maxmind',
+ default='GeoIPCountryCSV.zip', metavar='FILE',
+ help='use the specified MaxMind GeoLite Country .zip or .csv '
+ 'file as input [default: %default]')
+ parser.add_option('-g', action='store', dest='in_manual',
+ default='geoip-manual', metavar='FILE',
+ help='use the specified .csv file for manual changes or to '
+ 'override automatic changes [default: %default]')
+ parser.add_option('-a', action='store', dest='out_automatic',
+ default="AutomaticGeoIPCountryWhois.csv", metavar='FILE',
+ help='write full input file plus automatic changes to the '
+ 'specified .csv file [default: %default]')
+ parser.add_option('-m', action='store', dest='out_manual',
+ default='ManualGeoIPCountryWhois.csv', metavar='FILE',
+ help='write full input file plus automatic and manual '
+ 'changes to the specified .csv file [default: %default]')
+ parser.add_option('-o', action='store', dest='out_geoip',
+ default='geoip', metavar='FILE',
+ help='write full input file plus automatic and manual '
+ 'changes to the specified .csv file that can be shipped '
+ 'with tor [default: %default]')
+ (options, args) = parser.parse_args()
+ return options
+
+def read_file(path, must_exist=True):
+ if not os.path.exists(path):
+ if must_exist:
+ print 'File %s does not exist. Exiting.' % (path, )
+ sys.exit(1)
+ else:
+ return
+ if path.endswith('.zip'):
+ zip_file = zipfile.ZipFile(path)
+ csv_content = zip_file.read('GeoIPCountryWhois.csv')
+ zip_file.close()
+ else:
+ csv_file = open(path)
+ csv_content = csv_file.read()
+ csv_file.close()
+ assignments = []
+ for line in csv_content.split('\n'):
+ stripped_line = line.strip()
+ if len(stripped_line) > 0 and not stripped_line.startswith('#'):
+ assignments.append(stripped_line)
+ return assignments
+
+def apply_automatic_changes(assignments):
+ print '\nApplying automatic changes...'
+ result_lines = []
+ prev_line = None
+ a1_lines = []
+ for line in assignments:
+ if '"A1"' in line:
+ a1_lines.append(line)
+ else:
+ if len(a1_lines) > 0:
+ new_a1_lines = process_a1_lines(prev_line, a1_lines, line)
+ for new_a1_line in new_a1_lines:
+ result_lines.append(new_a1_line)
+ a1_lines = []
+ result_lines.append(line)
+ prev_line = line
+ if len(a1_lines) > 0:
+ new_a1_lines = process_a1_lines(prev_line, a1_lines, None)
+ for new_a1_line in new_a1_lines:
+ result_lines.append(new_a1_line)
+ return result_lines
+
+def process_a1_lines(prev_line, a1_lines, next_line):
+ if not prev_line or not next_line:
+ return a1_lines # Can't merge first or last line in file.
+ if len(a1_lines) > 1:
+ return a1_lines # Can't merge more than 1 line at once.
+ a1_line = a1_lines[0].strip()
+ prev_entry = parse_line(prev_line)
+ a1_entry = parse_line(a1_line)
+ next_entry = parse_line(next_line)
+ touches_prev_entry = int(prev_entry['end_num']) + 1 == \
+ int(a1_entry['start_num'])
+ touches_next_entry = int(a1_entry['end_num']) + 1 == \
+ int(next_entry['start_num'])
+ same_country_code = prev_entry['country_code'] == \
+ next_entry['country_code']
+ if touches_prev_entry and touches_next_entry and same_country_code:
+ new_line = format_line_with_other_country(a1_entry, prev_entry)
+ print '-%s\n+%s' % (a1_line, new_line, )
+ return [new_line]
+ else:
+ return a1_lines
+
+def parse_line(line):
+ if not line:
+ return None
+ keys = ['start_str', 'end_str', 'start_num', 'end_num',
+ 'country_code', 'country_name']
+ stripped_line = line.replace('"', '').strip()
+ parts = stripped_line.split(',')
+ entry = dict((k, v) for k, v in zip(keys, parts))
+ return entry
+
+def format_line_with_other_country(original_entry, other_entry):
+ return '"%s","%s","%s","%s","%s","%s"' % (original_entry['start_str'],
+ original_entry['end_str'], original_entry['start_num'],
+ original_entry['end_num'], other_entry['country_code'],
+ other_entry['country_name'], )
+
+def apply_manual_changes(assignments, manual_assignments):
+ if not manual_assignments:
+ return assignments
+ print '\nApplying manual changes...'
+ manual_dict = {}
+ for line in manual_assignments:
+ start_num = parse_line(line)['start_num']
+ if start_num in manual_dict:
+ print ('Warning: duplicate start number in manual '
+ 'assignments:\n %s\n %s\nDiscarding first entry.' %
+ (manual_dict[start_num], line, ))
+ manual_dict[start_num] = line
+ result = []
+ for line in assignments:
+ entry = parse_line(line)
+ start_num = entry['start_num']
+ if start_num in manual_dict:
+ manual_line = manual_dict[start_num]
+ manual_entry = parse_line(manual_line)
+ if entry['start_str'] == manual_entry['start_str'] and \
+ entry['end_str'] == manual_entry['end_str'] and \
+ entry['end_num'] == manual_entry['end_num']:
+ if len(manual_entry['country_code']) != 2:
+ print '-%s' % (line, ) # only remove, don't replace
+ else:
+ new_line = format_line_with_other_country(entry,
+ manual_entry)
+ print '-%s\n+%s' % (line, new_line, )
+ result.append(new_line)
+ del manual_dict[start_num]
+ else:
+ print ('Warning: only partial match between '
+ 'original/automatically replaced assignment and '
+ 'manual assignment:\n %s\n %s\nNot applying '
+ 'manual change.' % (line, manual_line, ))
+ result.append(line)
+ else:
+ result.append(line)
+ if len(manual_dict) > 0:
+ print ('Warning: could not apply all manual assignments: %s' %
+ ('\n '.join(manual_dict.values())), )
+ return result
+
+def write_file(path, assignments, long_format=True):
+ if long_format:
+ output_lines = assignments
+ else:
+ output_lines = []
+ for long_line in assignments:
+ entry = parse_line(long_line)
+ short_line = "%s,%s,%s" % (entry['start_num'],
+ entry['end_num'], entry['country_code'], )
+ output_lines.append(short_line)
+ out_file = open(path, 'w')
+ out_file.write('\n'.join(output_lines))
+ out_file.close()
+
+if __name__ == '__main__':
+ main()
+
diff --git a/src/config/geoip-manual b/src/config/geoip-manual
new file mode 100644
index 000000000..99c897ff4
--- /dev/null
+++ b/src/config/geoip-manual
@@ -0,0 +1,116 @@
+# This file contains manual overrides of A1 entries (and possibly others)
+# in MaxMind's GeoLite Country database. Use deanonymind.py in the same
+# directory to process this file when producing a new geoip file. See
+# README.geoip in the same directory for details.
+
+# Remove MaxMind entry 0.116.0.0-0.119.255.255 which MaxMind says is AT,
+# but which is part of reserved range 0.0.0.0/8. -KL 2012-06-13
+# Disabled, because MaxMind apparently removed this range from their
+# database. -KL 2013-02-08
+#"0.116.0.0","0.119.255.255","7602176","7864319","",""
+
+# NL, because previous MaxMind entry 31.171.128.0-31.171.133.255 is NL,
+# and RIR delegation files say 31.171.128.0-31.171.135.255 is NL.
+# -KL 2012-11-27
+"31.171.134.0","31.171.135.255","531334656","531335167","NL","Netherlands"
+
+# EU, because next MaxMind entry 37.139.64.1-37.139.64.9 is EU, because
+# RIR delegation files say 37.139.64.0-37.139.71.255 is EU, and because it
+# just makes more sense for the next entry to start at .0 and not .1.
+# -KL 2012-11-27
+"37.139.64.0","37.139.64.0","629882880","629882880","EU","Europe"
+
+# CH, because previous MaxMind entry 46.19.141.0-46.19.142.255 is CH, and
+# RIR delegation files say 46.19.136.0-46.19.143.255 is CH.
+# -KL 2012-11-27
+"46.19.143.0","46.19.143.255","773033728","773033983","CH","Switzerland"
+
+# GB, because next MaxMind entry 46.166.129.0-46.166.134.255 is GB, and
+# RIR delegation files say 46.166.128.0-46.166.191.255 is GB.
+# -KL 2012-11-27
+"46.166.128.0","46.166.128.255","782663680","782663935","GB","United Kingdom"
+
+# US, though could as well be CA. Previous MaxMind entry
+# 64.237.32.52-64.237.34.127 is US, next MaxMind entry
+# 64.237.34.144-64.237.34.151 is CA, and RIR delegation files say the
+# entire block 64.237.32.0-64.237.63.255 is US. -KL 2012-11-27
+"64.237.34.128","64.237.34.143","1089282688","1089282703","US","United States"
+
+# US, though could as well be UY. Previous MaxMind entry
+# 67.15.170.0-67.15.182.255 is US, next MaxMind entry
+# 67.15.183.128-67.15.183.159 is UY, and RIR delegation files say the
+# entire block 67.15.0.0-67.15.255.255 is US. -KL 2012-11-27
+"67.15.183.0","67.15.183.127","1125103360","1125103487","US","United States"
+
+# US, because next MaxMind entry 67.43.145.0-67.43.155.255 is US, and RIR
+# delegation files say 67.43.144.0-67.43.159.255 is US.
+# -KL 2012-11-27
+"67.43.144.0","67.43.144.255","1126928384","1126928639","US","United States"
+
+# US, because previous MaxMind entry 70.159.21.51-70.232.244.255 is US,
+# because next MaxMind entry 70.232.245.58-70.232.245.59 is A2 ("Satellite
+# Provider") which is a country information about as useless as A1, and
+# because RIR delegation files say 70.224.0.0-70.239.255.255 is US.
+# -KL 2012-11-27
+"70.232.245.0","70.232.245.57","1189672192","1189672249","US","United States"
+
+# US, because next MaxMind entry 70.232.246.0-70.240.141.255 is US,
+# because previous MaxMind entry 70.232.245.58-70.232.245.59 is A2
+# ("Satellite Provider") which is a country information about as useless
+# as A1, and because RIR delegation files say 70.224.0.0-70.239.255.255 is
+# US. -KL 2012-11-27
+"70.232.245.60","70.232.245.255","1189672252","1189672447","US","United States"
+
+# GB, despite neither previous (GE) nor next (LV) MaxMind entry being GB,
+# but because RIR delegation files agree with both previous and next
+# MaxMind entry and say GB for 91.228.0.0-91.228.3.255. -KL 2012-11-27
+"91.228.0.0","91.228.3.255","1541668864","1541669887","GB","United Kingdom"
+
+# GB, because next MaxMind entry 91.232.125.0-91.232.125.255 is GB, and
+# RIR delegation files say 91.232.124.0-91.232.125.255 is GB.
+# -KL 2012-11-27
+"91.232.124.0","91.232.124.255","1541962752","1541963007","GB","United Kingdom"
+
+# GB, despite neither previous (RU) nor next (PL) MaxMind entry being GB,
+# but because RIR delegation files agree with both previous and next
+# MaxMind entry and say GB for 91.238.214.0-91.238.215.255.
+# -KL 2012-11-27
+"91.238.214.0","91.238.215.255","1542379008","1542379519","GB","United Kingdom"
+
+# US, because next MaxMind entry 173.0.16.0-173.0.65.255 is US, and RIR
+# delegation files say 173.0.0.0-173.0.15.255 is US. -KL 2012-11-27
+"173.0.0.0","173.0.15.255","2902458368","2902462463","US","United States"
+
+# US, because next MaxMind entry 176.67.84.0-176.67.84.79 is US, and RIR
+# delegation files say 176.67.80.0-176.67.87.255 is US. -KL 2012-11-27
+"176.67.80.0","176.67.83.255","2957201408","2957202431","US","United States"
+
+# US, because previous MaxMind entry 176.67.84.192-176.67.85.255 is US,
+# and RIR delegation files say 176.67.80.0-176.67.87.255 is US.
+# -KL 2012-11-27
+"176.67.86.0","176.67.87.255","2957202944","2957203455","US","United States"
+
+# EU, despite neither previous (RU) nor next (UA) MaxMind entry being EU,
+# but because RIR delegation files agree with both previous and next
+# MaxMind entry and say EU for 193.200.150.0-193.200.150.255.
+# -KL 2012-11-27
+"193.200.150.0","193.200.150.255","3251148288","3251148543","EU","Europe"
+
+# US, because previous MaxMind entry 199.96.68.0-199.96.87.127 is US, and
+# RIR delegation files say 199.96.80.0-199.96.87.255 is US.
+# -KL 2012-11-27
+"199.96.87.128","199.96.87.255","3344979840","3344979967","US","United States"
+
+# US, because previous MaxMind entry 209.58.176.144-209.59.31.255 is US,
+# and RIR delegation files say 209.59.32.0-209.59.63.255 is US.
+# -KL 2012-11-27
+"209.59.32.0","209.59.63.255","3510312960","3510321151","US","United States"
+
+# FR, because previous MaxMind entry 217.15.166.0-217.15.166.255 is FR,
+# and RIR delegation files contain a block 217.15.160.0-217.15.175.255
+# which, however, is EU, not FR. But merging with next MaxMind entry
+# 217.15.176.0-217.15.191.255 which is KZ and which fully matches what
+# the RIR delegation files say seems unlikely to be correct.
+# -KL 2012-11-27
+"217.15.167.0","217.15.175.255","3641681664","3641683967","FR","France"
+
diff --git a/src/config/geoip6 b/src/config/geoip6
new file mode 100644
index 000000000..be70b2961
--- /dev/null
+++ b/src/config/geoip6
@@ -0,0 +1,11638 @@
+# Last updated based on October 16 2012 Maxmind GeoLite IPv6 Country
+# wget http://geolite.maxmind.com/download/geoip/database/GeoIPv6.csv.gz
+# cut -d, -f1,2,5 < GeoIPv6.csv|sed 's/[ "]//g' > geoip6
+2001:200::,2001:200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:208::,2001:208:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:218::,2001:218:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:220::,2001:220:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:230::,2001:230:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:238::,2001:238:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:240::,2001:240:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:250::,2001:252:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:254::,2001:254:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:256::,2001:256:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:258::,2001:258:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:260::,2001:260:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:268::,2001:268:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:270::,2001:270:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:278::,2001:278:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:280::,2001:280:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:288::,2001:288:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:290::,2001:290:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:298::,2001:298:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2a0::,2001:2a0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2a8::,2001:2a8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2b0::,2001:2b0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:2b8::,2001:2b8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:2c0::,2001:2c0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2c8::,2001:2c8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2d8::,2001:2d8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:2e0::,2001:2e0:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:2e8::,2001:2e8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2f0::,2001:2f0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:2f8::,2001:2f8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:300::,2001:300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:308::,2001:308:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:310::,2001:310:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:318::,2001:318:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:320::,2001:320:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:328::,2001:328:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:330::,2001:330:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:338::,2001:338:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:340::,2001:340:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:348::,2001:348:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:350::,2001:350:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:358::,2001:358:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:360::,2001:360:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:368::,2001:368:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:370::,2001:370:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:378::,2001:378:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:380::,2001:380:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:388::,2001:388:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:390::,2001:390:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:398::,2001:398:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3a0::,2001:3a0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3a8::,2001:3a8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:3b0::,2001:3b0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3b8::,2001:3b8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3c0::,2001:3c0:1fff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3c8::,2001:3c8:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:3d0::,2001:3d0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3d8::,2001:3d8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3e0::,2001:3e0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:3e8::,2001:3e8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:400::,2001:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:408::,2001:408:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:410::,2001:410:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:418::,2001:418:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:420::,2001:420:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:428::,2001:428:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:430::,2001:430:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:438::,2001:438:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:440::,2001:440:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:448::,2001:448:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:450::,2001:450:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:458::,2001:458:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:460::,2001:460:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:468::,2001:468:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:470::,2001:470:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:478::,2001:478:ffff:ffff:ffff:ffff:ffff:ffff,KN
+2001:480::,2001:480:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:490::,2001:490:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4a0::,2001:4a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4b0::,2001:4b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4b8::,2001:4b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4c0::,2001:4c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4c8::,2001:4c8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4d0::,2001:4d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4d8::,2001:4d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4e0::,2001:4e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4e8::,2001:4e8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4f0::,2001:4f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4f8::,2001:4f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:500:1::,2001:500:4:ffff:ffff:ffff:ffff:ffff,US
+2001:500:6::,2001:500:f:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:10::,2001:500:10:ffff:ffff:ffff:ffff:ffff,PR
+2001:500:11::,2001:500:15:ffff:ffff:ffff:ffff:ffff,US
+2001:500:16::,2001:500:2c:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:2d::,2001:500:31:ffff:ffff:ffff:ffff:ffff,US
+2001:500:40::,2001:500:56:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:60::,2001:500:7d:ffff:ffff:ffff:ffff:ffff,US
+2001:500:80::,2001:500:83:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:84::,2001:500:89:ffff:ffff:ffff:ffff:ffff,US
+2001:500:8c::,2001:500:9a:ffff:ffff:ffff:ffff:ffff,US
+2001:500:9c::,2001:500:9f:ffff:ffff:ffff:ffff:ffff,US
+2001:500:a0::,2001:500:a6:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:c0::,2001:500:ef:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:f0::,2001:500:f0:ffff:ffff:ffff:ffff:ffff,US
+2001:500:f1::,2001:500:f1:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:100::,2001:500:109:ffff:ffff:ffff:ffff:ffff,CA
+2001:500:3e5::,2001:500:3e5:ffff:ffff:ffff:ffff:ffff,US
+2001:500:30ff::,2001:500:30ff:ffff:ffff:ffff:ffff:ffff,US
+2001:500:3682::,2001:500:3682:ffff:ffff:ffff:ffff:ffff,US
+2001:500:4431::,2001:500:4431:ffff:ffff:ffff:ffff:ffff,US
+2001:500:7967::,2001:500:7967:ffff:ffff:ffff:ffff:ffff,US
+2001:500:856e::,2001:500:856e:ffff:ffff:ffff:ffff:ffff,US
+2001:500:d937::,2001:500:d937:ffff:ffff:ffff:ffff:ffff,US
+2001:500:ed30::,2001:500:ed30:ffff:ffff:ffff:ffff:ffff,US
+2001:501:8a29::,2001:501:8a29:ffff:ffff:ffff:ffff:ffff,US
+2001:501:973c::,2001:501:973c:ffff:ffff:ffff:ffff:ffff,US
+2001:501:b1f9::,2001:501:b1f9:ffff:ffff:ffff:ffff:ffff,US
+2001:502:8cc::,2001:502:8cc:ffff:ffff:ffff:ffff:ffff,US
+2001:502:100e::,2001:502:100e:ffff:ffff:ffff:ffff:ffff,US
+2001:502:1ca1::,2001:502:1ca1:ffff:ffff:ffff:ffff:ffff,US
+2001:502:2eda::,2001:502:2eda:ffff:ffff:ffff:ffff:ffff,US
+2001:502:4612::,2001:502:4612:ffff:ffff:ffff:ffff:ffff,US
+2001:502:63bd::,2001:502:63bd:ffff:ffff:ffff:ffff:ffff,US
+2001:502:7094::,2001:502:7094:ffff:ffff:ffff:ffff:ffff,US
+2001:502:7a71::,2001:502:7a71:ffff:ffff:ffff:ffff:ffff,US
+2001:502:8c25::,2001:502:8c25:ffff:ffff:ffff:ffff:ffff,US
+2001:502:ad09::,2001:502:ad09:ffff:ffff:ffff:ffff:ffff,US
+2001:502:be98::,2001:502:be98:ffff:ffff:ffff:ffff:ffff,US
+2001:502:cbe4::,2001:502:cbe4:ffff:ffff:ffff:ffff:ffff,US
+2001:502:cfb5::,2001:502:cfb5:ffff:ffff:ffff:ffff:ffff,US
+2001:502:d399::,2001:502:d399:ffff:ffff:ffff:ffff:ffff,US
+2001:502:f3ff::,2001:502:f3ff:ffff:ffff:ffff:ffff:ffff,US
+2001:503:c27::,2001:503:c27:ffff:ffff:ffff:ffff:ffff,US
+2001:503:d2d::,2001:503:d2d:ffff:ffff:ffff:ffff:ffff,US
+2001:503:231d::,2001:503:231d:ffff:ffff:ffff:ffff:ffff,US
+2001:503:3227::,2001:503:3227:ffff:ffff:ffff:ffff:ffff,US
+2001:503:39c1::,2001:503:39c1:ffff:ffff:ffff:ffff:ffff,US
+2001:503:4872::,2001:503:4872:ffff:ffff:ffff:ffff:ffff,US
+2001:503:5419::,2001:503:5419:ffff:ffff:ffff:ffff:ffff,US
+2001:503:5ae2::,2001:503:5ae2:ffff:ffff:ffff:ffff:ffff,US
+2001:503:6810::,2001:503:6810:ffff:ffff:ffff:ffff:ffff,US
+2001:503:7bbb::,2001:503:7bbb:ffff:ffff:ffff:ffff:ffff,US
+2001:503:7bbf::,2001:503:7bbf:ffff:ffff:ffff:ffff:ffff,US
+2001:503:8028::,2001:503:8028:ffff:ffff:ffff:ffff:ffff,US
+2001:503:83eb::,2001:503:83eb:ffff:ffff:ffff:ffff:ffff,US
+2001:503:91ef::,2001:503:91ef:ffff:ffff:ffff:ffff:ffff,US
+2001:503:a124::,2001:503:a124:ffff:ffff:ffff:ffff:ffff,US
+2001:503:a83e::,2001:503:a83e:ffff:ffff:ffff:ffff:ffff,US
+2001:503:ba3e::,2001:503:ba3e:ffff:ffff:ffff:ffff:ffff,US
+2001:503:bfb0::,2001:503:bfb0:ffff:ffff:ffff:ffff:ffff,US
+2001:503:c779::,2001:503:c779:ffff:ffff:ffff:ffff:ffff,US
+2001:503:cc2c::,2001:503:cc2c:ffff:ffff:ffff:ffff:ffff,US
+2001:503:d1ae::,2001:503:d1ae:ffff:ffff:ffff:ffff:ffff,US
+2001:503:d414::,2001:503:d414:ffff:ffff:ffff:ffff:ffff,US
+2001:503:e239::,2001:503:e239:ffff:ffff:ffff:ffff:ffff,US
+2001:503:e8ef::,2001:503:e8ef:ffff:ffff:ffff:ffff:ffff,US
+2001:503:eea3::,2001:503:eea3:ffff:ffff:ffff:ffff:ffff,US
+2001:503:f189::,2001:503:f189:ffff:ffff:ffff:ffff:ffff,US
+2001:503:f261::,2001:503:f261:ffff:ffff:ffff:ffff:ffff,US
+2001:503:f3da::,2001:503:f3da:ffff:ffff:ffff:ffff:ffff,US
+2001:503:ff39::,2001:503:ff39:ffff:ffff:ffff:ffff:ffff,US
+2001:504::,2001:504:14:ffff:ffff:ffff:ffff:ffff,US
+2001:504:15::,2001:504:15:ffff:ffff:ffff:ffff:ffff,CA
+2001:504:16::,2001:504:19:ffff:ffff:ffff:ffff:ffff,US
+2001:504:1a::,2001:504:1a:ffff:ffff:ffff:ffff:ffff,CA
+2001:504:1b::,2001:504:1c:ffff:ffff:ffff:ffff:ffff,US
+2001:504:1d::,2001:504:1d:ffff:ffff:ffff:ffff:ffff,PR
+2001:504:20::,2001:504:23:ffff:ffff:ffff:ffff:ffff,CA
+2001:504:24::,2001:504:24:ffff:ffff:ffff:ffff:ffff,US
+2001:504:25::,2001:504:26:ffff:ffff:ffff:ffff:ffff,CA
+2001:504:27::,2001:504:28:ffff:ffff:ffff:ffff:ffff,US
+2001:506::,2001:506:1:ffff:ffff:ffff:ffff:ffff,US
+2001:506:8::,2001:506:8:ffff:ffff:ffff:ffff:ffff,US
+2001:506:20::,2001:506:20:ffff:ffff:ffff:ffff:ffff,CA
+2001:506:28::,2001:506:28:ffff:ffff:ffff:ffff:ffff,US
+2001:506:100::,2001:506:100:ffff:ffff:ffff:ffff:ffff,US
+2001:506:1000::,2001:506:2fff:ffff:ffff:ffff:ffff:ffff,US
+2001:506:4000::,2001:506:5fff:ffff:ffff:ffff:ffff:ffff,US
+2001:508::,2001:508:ffff:ffff:ffff:ffff:ffff:ffff,BM
+2001:510::,2001:510:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:518::,2001:518:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:520::,2001:520:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:528::,2001:528:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:530::,2001:530:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:538::,2001:538:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:540::,2001:540:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:548::,2001:548:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:550::,2001:550:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:558::,2001:560:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:568::,2001:56f:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:570::,2001:570:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:578::,2001:57b:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:580::,2001:580:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:590::,2001:590:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:598::,2001:598:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:5a0::,2001:5a0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:5a8::,2001:5a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5b0::,2001:5b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5b8::,2001:5b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5c0::,2001:5c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:5c8::,2001:5c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5d0::,2001:5d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5d8::,2001:5d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5e0::,2001:5e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5e8::,2001:5e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5f0::,2001:5f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:5f8::,2001:5f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:600::,2001:600:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:608::,2001:608:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:610::,2001:610:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:618::,2001:618:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:620::,2001:620:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:628::,2001:62f:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:630::,2001:630:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:638::,2001:638:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:640::,2001:640:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:648::,2001:648:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2001:650::,2001:650:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:658::,2001:658:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:660::,2001:667:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:668::,2001:66f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:670::,2001:670:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:678:1::,2001:678:1:ffff:ffff:ffff:ffff:ffff,CZ
+2001:678:2::,2001:678:2:ffff:ffff:ffff:ffff:ffff,DE
+2001:678:3::,2001:678:3:ffff:ffff:ffff:ffff:ffff,CH
+2001:678:4::,2001:678:5:ffff:ffff:ffff:ffff:ffff,GB
+2001:678:6::,2001:678:6:ffff:ffff:ffff:ffff:ffff,LT
+2001:678:7::,2001:678:7:ffff:ffff:ffff:ffff:ffff,GR
+2001:678:8::,2001:678:8:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:9::,2001:678:a:ffff:ffff:ffff:ffff:ffff,BE
+2001:678:b::,2001:678:b:ffff:ffff:ffff:ffff:ffff,LV
+2001:678:c::,2001:678:c:ffff:ffff:ffff:ffff:ffff,FR
+2001:678:d::,2001:678:d:ffff:ffff:ffff:ffff:ffff,AT
+2001:678:e::,2001:678:e:ffff:ffff:ffff:ffff:ffff,DE
+2001:678:f::,2001:678:11:ffff:ffff:ffff:ffff:ffff,CZ
+2001:678:12::,2001:678:12:ffff:ffff:ffff:ffff:ffff,IT
+2001:678:13::,2001:678:18:ffff:ffff:ffff:ffff:ffff,RU
+2001:678:19::,2001:678:19:ffff:ffff:ffff:ffff:ffff,LT
+2001:678:1a::,2001:678:1a:ffff:ffff:ffff:ffff:ffff,DK
+2001:678:1b::,2001:678:1b:ffff:ffff:ffff:ffff:ffff,LU
+2001:678:1c::,2001:678:1c:ffff:ffff:ffff:ffff:ffff,AT
+2001:678:20::,2001:678:20:ffff:ffff:ffff:ffff:ffff,AT
+2001:678:24::,2001:678:24:ffff:ffff:ffff:ffff:ffff,AT
+2001:678:28::,2001:678:28:ffff:ffff:ffff:ffff:ffff,SM
+2001:678:2c::,2001:678:2c:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:30::,2001:678:30:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:34::,2001:678:34:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:38::,2001:678:38:ffff:ffff:ffff:ffff:ffff,NL
+2001:678:3c::,2001:678:3c:ffff:ffff:ffff:ffff:ffff,BG
+2001:678:40::,2001:678:40:ffff:ffff:ffff:ffff:ffff,ES
+2001:678:44::,2001:678:44:ffff:ffff:ffff:ffff:ffff,ES
+2001:678:48::,2001:678:48:ffff:ffff:ffff:ffff:ffff,ES
+2001:678:4c::,2001:678:4c:ffff:ffff:ffff:ffff:ffff,FR
+2001:678:50::,2001:678:50:ffff:ffff:ffff:ffff:ffff,TK
+2001:678:54::,2001:678:54:ffff:ffff:ffff:ffff:ffff,TK
+2001:678:58::,2001:678:58:ffff:ffff:ffff:ffff:ffff,TK
+2001:678:5c::,2001:678:5c:ffff:ffff:ffff:ffff:ffff,TK
+2001:678:60::,2001:678:60:ffff:ffff:ffff:ffff:ffff,LU
+2001:678:64::,2001:678:64:ffff:ffff:ffff:ffff:ffff,BE
+2001:678:68::,2001:678:68:ffff:ffff:ffff:ffff:ffff,BE
+2001:678:6c::,2001:678:6c:ffff:ffff:ffff:ffff:ffff,BE
+2001:678:70::,2001:678:70:ffff:ffff:ffff:ffff:ffff,SK
+2001:678:74::,2001:678:74:ffff:ffff:ffff:ffff:ffff,DK
+2001:678:78::,2001:678:78:ffff:ffff:ffff:ffff:ffff,DK
+2001:678:7c::,2001:678:7c:ffff:ffff:ffff:ffff:ffff,LV
+2001:678:80::,2001:678:80:ffff:ffff:ffff:ffff:ffff,LV
+2001:678:84::,2001:678:84:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c::,2001:67c:0:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:4::,2001:67c:4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:8::,2001:67c:8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:c::,2001:67c:c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:10::,2001:67c:10:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:14::,2001:67c:14:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:18::,2001:67c:18:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1c::,2001:67c:1c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:20::,2001:67c:20:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:24::,2001:67c:24:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2c::,2001:67c:2c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:30::,2001:67c:30:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:34::,2001:67c:34:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:38::,2001:67c:38:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:40::,2001:67c:40:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:44::,2001:67c:44:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:4c::,2001:67c:4c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:50::,2001:67c:50:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:54::,2001:67c:54:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:58::,2001:67c:58:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:5c::,2001:67c:5c:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:60::,2001:67c:60:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:64::,2001:67c:64:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:68::,2001:67c:68:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:6c::,2001:67c:6c:ffff:ffff:ffff:ffff:ffff,IS
+2001:67c:70::,2001:67c:70:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:74::,2001:67c:74:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:78::,2001:67c:78:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:84::,2001:67c:84:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:88::,2001:67c:88:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:8c::,2001:67c:8c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:90::,2001:67c:90:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:94::,2001:67c:94:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:98::,2001:67c:98:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:9c::,2001:67c:9c:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:a0::,2001:67c:a0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:a4::,2001:67c:a4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:a8::,2001:67c:a8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:ac::,2001:67c:ac:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:b0::,2001:67c:b0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:b4::,2001:67c:b4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:b8::,2001:67c:b8:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:bc::,2001:67c:bc:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:c0::,2001:67c:c0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:c4::,2001:67c:c4:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:c8::,2001:67c:c8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:cc::,2001:67c:cc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:d0::,2001:67c:d0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:d4::,2001:67c:d4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:d8::,2001:67c:d8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:dc::,2001:67c:dc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:e0::,2001:67c:e0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:e4::,2001:67c:e4:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:e8::,2001:67c:e8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:ec::,2001:67c:ec:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:f0::,2001:67c:f0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:f4::,2001:67c:f4:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:f8::,2001:67c:f8:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:fc::,2001:67c:fc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:100::,2001:67c:100:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:108::,2001:67c:108:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:10c::,2001:67c:10c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:110::,2001:67c:110:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:114::,2001:67c:114:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:118::,2001:67c:118:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:11c::,2001:67c:11c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:120::,2001:67c:120:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:124::,2001:67c:124:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:128::,2001:67c:128:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:12c::,2001:67c:12c:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:130::,2001:67c:130:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:134::,2001:67c:134:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:138::,2001:67c:138:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:13c::,2001:67c:13c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:140::,2001:67c:140:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:144::,2001:67c:144:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:148::,2001:67c:148:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:14c::,2001:67c:14d:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:150::,2001:67c:150:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:154::,2001:67c:154:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:158::,2001:67c:158:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:15c::,2001:67c:15c:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:160::,2001:67c:160:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:164::,2001:67c:164:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:168::,2001:67c:168:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:16c::,2001:67c:16c:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:170::,2001:67c:170:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:174::,2001:67c:174:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:178::,2001:67c:178:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:17c::,2001:67c:17c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:180::,2001:67c:180:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:184::,2001:67c:184:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:188::,2001:67c:188:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:18c::,2001:67c:18c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:190::,2001:67c:190:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:194::,2001:67c:194:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:19c::,2001:67c:19c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1a0::,2001:67c:1a0:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:1a4::,2001:67c:1a4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1a8::,2001:67c:1a8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1ac::,2001:67c:1ac:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1b0::,2001:67c:1b0:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:1b4::,2001:67c:1b4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:1b8::,2001:67c:1b8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1bc::,2001:67c:1bc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1c0::,2001:67c:1c0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1c4::,2001:67c:1c4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1c8::,2001:67c:1c8:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:1cc::,2001:67c:1cc:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:1d0::,2001:67c:1d0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1d4::,2001:67c:1d4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1d8::,2001:67c:1d8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1dc::,2001:67c:1dc:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1e0::,2001:67c:1e0:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:1e4::,2001:67c:1e4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1e8::,2001:67c:1e8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1ec::,2001:67c:1ec:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:1f0::,2001:67c:1f0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1f4::,2001:67c:1f4:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:1f8::,2001:67c:1f8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1fc::,2001:67c:1fc:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:200::,2001:67c:200:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:204::,2001:67c:204:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:208::,2001:67c:208:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:20c::,2001:67c:20c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:210::,2001:67c:210:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:214::,2001:67c:214:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:218::,2001:67c:218:ffff:ffff:ffff:ffff:ffff,LT
+2001:67c:21c::,2001:67c:21c:ffff:ffff:ffff:ffff:ffff,AM
+2001:67c:220::,2001:67c:220:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:224::,2001:67c:224:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:228::,2001:67c:228:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:22c::,2001:67c:22c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:230::,2001:67c:230:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:234::,2001:67c:234:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:238::,2001:67c:238:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:23c::,2001:67c:23c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:240::,2001:67c:240:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:244::,2001:67c:244:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:248::,2001:67c:248:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:24c::,2001:67c:24c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:250::,2001:67c:250:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:254::,2001:67c:254:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:258::,2001:67c:258:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:25c::,2001:67c:25c:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:260::,2001:67c:260:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:264::,2001:67c:264:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:268::,2001:67c:268:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:26c::,2001:67c:26c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:270::,2001:67c:270:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:274::,2001:67c:274:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:278::,2001:67c:278:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:27c::,2001:67c:27c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:280::,2001:67c:280:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:284::,2001:67c:284:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:288::,2001:67c:288:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:28c::,2001:67c:28c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:294::,2001:67c:294:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:298::,2001:67c:298:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:29c::,2001:67c:29c:ffff:ffff:ffff:ffff:ffff,IT
+2001:67c:2a0::,2001:67c:2a0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2a4::,2001:67c:2a4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a8::,2001:67c:2a8:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2ac::,2001:67c:2ac:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2b0::,2001:67c:2b0:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2b8::,2001:67c:2b8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2bc::,2001:67c:2bc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2c0::,2001:67c:2c0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2c4::,2001:67c:2c4:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2c8::,2001:67c:2c8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2cc::,2001:67c:2cc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2d0::,2001:67c:2d0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2d4::,2001:67c:2d4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2d8::,2001:67c:2d8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2dc::,2001:67c:2dc:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2e0::,2001:67c:2e0:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2e4::,2001:67c:2e4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2e8::,2001:67c:2e8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2ec::,2001:67c:2ec:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2f0::,2001:67c:2f0:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2f4::,2001:67c:2f4:ffff:ffff:ffff:ffff:ffff,LU
+2001:67c:2f8::,2001:67c:2f8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2fc::,2001:67c:2fc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:300::,2001:67c:300:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:304::,2001:67c:304:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:308::,2001:67c:308:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:30c::,2001:67c:30c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:310::,2001:67c:310:ffff:ffff:ffff:ffff:ffff,CY
+2001:67c:314::,2001:67c:314:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:318::,2001:67c:318:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:31c::,2001:67c:31c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:324::,2001:67c:324:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:328::,2001:67c:328:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:32c::,2001:67c:32c:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:330::,2001:67c:330:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:334::,2001:67c:334:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:338::,2001:67c:338:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:33c::,2001:67c:33c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:340::,2001:67c:340:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:344::,2001:67c:344:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:348::,2001:67c:348:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:34c::,2001:67c:34c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:350::,2001:67c:350:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:354::,2001:67c:354:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:358::,2001:67c:358:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:35c::,2001:67c:35c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:360::,2001:67c:360:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:364::,2001:67c:364:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:368::,2001:67c:368:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c:36c::,2001:67c:36c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:370::,2001:67c:370:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:374::,2001:67c:374:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:378::,2001:67c:378:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:37c::,2001:67c:37c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:380::,2001:67c:380:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:384::,2001:67c:384:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:388::,2001:67c:388:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:38c::,2001:67c:38c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:390::,2001:67c:390:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:394::,2001:67c:394:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:398::,2001:67c:398:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:39c::,2001:67c:39c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:3a0::,2001:67c:3a0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:3a4::,2001:67c:3a4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:3a8::,2001:67c:3a8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:3ac::,2001:67c:3ac:ffff:ffff:ffff:ffff:ffff,RS
+2001:67c:3b0::,2001:67c:3b0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:3b4::,2001:67c:3b4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:3b8::,2001:67c:3b8:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:3bc::,2001:67c:3bc:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:3c0::,2001:67c:3c0:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:3c4::,2001:67c:3c4:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:3c8::,2001:67c:3c8:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:3cc::,2001:67c:3cc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:3d0::,2001:67c:3d0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:3d4::,2001:67c:3d4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:3d8::,2001:67c:3d8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3dc::,2001:67c:3dc:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3e0::,2001:67c:3e0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3e4::,2001:67c:3e4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3e8::,2001:67c:3e9:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:3f0::,2001:67c:3f0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:3f4::,2001:67c:3f4:ffff:ffff:ffff:ffff:ffff,HR
+2001:67c:3f8::,2001:67c:3f8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:3fc::,2001:67c:3fc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1000::,2001:67c:1001:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1008::,2001:67c:1009:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:1010::,2001:67c:1011:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1018::,2001:67c:1019:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1020::,2001:67c:1021:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1028::,2001:67c:1029:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1030::,2001:67c:1030:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1034::,2001:67c:1034:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:1038::,2001:67c:1038:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:103c::,2001:67c:103c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:1040::,2001:67c:1040:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:1044::,2001:67c:1044:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1048::,2001:67c:1048:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:104c::,2001:67c:104c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1050::,2001:67c:1050:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1054::,2001:67c:1054:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1058::,2001:67c:1058:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:105c::,2001:67c:105c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1060::,2001:67c:1060:ffff:ffff:ffff:ffff:ffff,LU
+2001:67c:1064::,2001:67c:1064:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1068::,2001:67c:1068:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:106c::,2001:67c:106c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1070::,2001:67c:1071:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:1078::,2001:67c:1078:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:107c::,2001:67c:107c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1080::,2001:67c:1080:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1084::,2001:67c:1084:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1088::,2001:67c:1089:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1090::,2001:67c:1090:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1094::,2001:67c:1094:ffff:ffff:ffff:ffff:ffff,IT
+2001:67c:1098::,2001:67c:1098:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:109c::,2001:67c:109c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10a0::,2001:67c:10a0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10a4::,2001:67c:10a4:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:10a8::,2001:67c:10a9:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:10b0::,2001:67c:10b0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:10b4::,2001:67c:10b4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:10b8::,2001:67c:10b8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:10bc::,2001:67c:10bc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:10c0::,2001:67c:10c0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10c4::,2001:67c:10c4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10c8::,2001:67c:10c8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10cc::,2001:67c:10cc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10d0::,2001:67c:10d0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10d4::,2001:67c:10d4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10d8::,2001:67c:10d8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:10dc::,2001:67c:10dc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10e0::,2001:67c:10e0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:10e4::,2001:67c:10e4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:10e8::,2001:67c:10e8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:10ec::,2001:67c:10ec:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:10f0::,2001:67c:10f0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:10f4::,2001:67c:10f4:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:10f8::,2001:67c:10f8:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:10fc::,2001:67c:10fc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1200::,2001:67c:1203:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1210::,2001:67c:1213:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:1220::,2001:67c:1223:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:1230::,2001:67c:1233:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1240::,2001:67c:1240:ffff:ffff:ffff:ffff:ffff,IE
+2001:67c:1244::,2001:67c:1244:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1248::,2001:67c:1248:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:124c::,2001:67c:124c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1250::,2001:67c:1250:ffff:ffff:ffff:ffff:ffff,LU
+2001:67c:1254::,2001:67c:1254:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1258::,2001:67c:1258:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:125c::,2001:67c:125c:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:1260::,2001:67c:1260:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:1264::,2001:67c:1264:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:1268::,2001:67c:1268:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:126c::,2001:67c:126c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:1270::,2001:67c:1270:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:1274::,2001:67c:1274:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1278::,2001:67c:1278:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:127c::,2001:67c:127c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1280::,2001:67c:1280:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1284::,2001:67c:1284:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:1288::,2001:67c:1288:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:128c::,2001:67c:128c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1290::,2001:67c:1290:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1294::,2001:67c:1294:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:1298::,2001:67c:1298:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:129c::,2001:67c:129c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:12a0::,2001:67c:12a0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:12a4::,2001:67c:12a4:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:12a8::,2001:67c:12a8:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:12ac::,2001:67c:12ac:ffff:ffff:ffff:ffff:ffff,LU
+2001:67c:12b0::,2001:67c:12b0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:1400::,2001:67c:1407:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1420::,2001:67c:1427:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1440::,2001:67c:1447:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:1460::,2001:67c:1467:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1600::,2001:67c:160f:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:1640::,2001:67c:164f:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:1a00::,2001:67c:1a3f:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:1c00::,2001:67c:1cff:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2004::,2001:67c:2004:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2008::,2001:67c:2008:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:200c::,2001:67c:200c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2010::,2001:67c:2010:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2014::,2001:67c:2014:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2018::,2001:67c:2018:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:201c::,2001:67c:201c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2020::,2001:67c:2020:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2024::,2001:67c:2024:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2028::,2001:67c:2028:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:202c::,2001:67c:202c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2030::,2001:67c:2030:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2034::,2001:67c:2034:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2038::,2001:67c:2038:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:203c::,2001:67c:203c:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2040::,2001:67c:2040:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2044::,2001:67c:2044:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2048::,2001:67c:2048:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:204c::,2001:67c:204c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2050::,2001:67c:2050:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:205c::,2001:67c:205c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2060::,2001:67c:2060:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2064::,2001:67c:2064:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2068::,2001:67c:2068:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:206c::,2001:67c:206c:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2070::,2001:67c:2070:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2074::,2001:67c:2074:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2078::,2001:67c:2078:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:207c::,2001:67c:207c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2080::,2001:67c:2080:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2084::,2001:67c:2084:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2088::,2001:67c:2088:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:208c::,2001:67c:208c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2090::,2001:67c:2090:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2098::,2001:67c:2099:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:20a0::,2001:67c:20a1:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:20a8::,2001:67c:20a8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:20ac::,2001:67c:20ac:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:20b0::,2001:67c:20b0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:20b4::,2001:67c:20b4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:20b8::,2001:67c:20b9:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:20c0::,2001:67c:20c0:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:20c4::,2001:67c:20c4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:20c8::,2001:67c:20c8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:20cc::,2001:67c:20cc:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:20d0::,2001:67c:20d1:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:20d8::,2001:67c:20d8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:20dc::,2001:67c:20dc:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:20e0::,2001:67c:20e0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:20e4::,2001:67c:20e4:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:20e8::,2001:67c:20e8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:20ec::,2001:67c:20ec:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:20f0::,2001:67c:20f0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:20f4::,2001:67c:20f4:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:20f8::,2001:67c:20f8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:20fc::,2001:67c:20fc:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2100::,2001:67c:2100:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2104::,2001:67c:2104:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2108::,2001:67c:2108:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:210c::,2001:67c:210c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2110::,2001:67c:2110:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2114::,2001:67c:2114:ffff:ffff:ffff:ffff:ffff,IS
+2001:67c:2118::,2001:67c:2118:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:211c::,2001:67c:211c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2120::,2001:67c:2120:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2124::,2001:67c:2124:ffff:ffff:ffff:ffff:ffff,HU
+2001:67c:2128::,2001:67c:2128:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:212c::,2001:67c:212c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2130::,2001:67c:2130:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2134::,2001:67c:2134:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2138::,2001:67c:2138:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:213c::,2001:67c:213c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2140::,2001:67c:2140:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2144::,2001:67c:2144:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2148::,2001:67c:2148:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:214c::,2001:67c:214c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2150::,2001:67c:2150:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2154::,2001:67c:2154:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:2158::,2001:67c:2158:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:215c::,2001:67c:215c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2160::,2001:67c:2160:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2164::,2001:67c:2164:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:2168::,2001:67c:2168:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:216c::,2001:67c:216c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2170::,2001:67c:2170:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2174::,2001:67c:2174:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2178::,2001:67c:2178:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:217c::,2001:67c:217c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2180::,2001:67c:2180:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2188::,2001:67c:2188:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:218c::,2001:67c:218c:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2190::,2001:67c:2190:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2194::,2001:67c:2194:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2198::,2001:67c:2198:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c:219c::,2001:67c:219c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:21a0::,2001:67c:21a0:ffff:ffff:ffff:ffff:ffff,IT
+2001:67c:21a4::,2001:67c:21a4:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:21a8::,2001:67c:21a8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:21ac::,2001:67c:21ac:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:21b0::,2001:67c:21b0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:21b4::,2001:67c:21b4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:21b8::,2001:67c:21b8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:21bc::,2001:67c:21bc:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:21c0::,2001:67c:21c0:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:21c4::,2001:67c:21c4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:21c8::,2001:67c:21c8:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:21cc::,2001:67c:21cc:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:21d0::,2001:67c:21d0:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:21d8::,2001:67c:21d8:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:21dc::,2001:67c:21dc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:21e0::,2001:67c:21e0:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:21e4::,2001:67c:21e4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:21e8::,2001:67c:21e8:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:21ec::,2001:67c:21ec:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:21f0::,2001:67c:21f0:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:21f4::,2001:67c:21f4:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:21f8::,2001:67c:21f8:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:21fc::,2001:67c:21fc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2200::,2001:67c:2200:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2204::,2001:67c:2204:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2208::,2001:67c:2208:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:220c::,2001:67c:220c:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:2210::,2001:67c:2210:ffff:ffff:ffff:ffff:ffff,RS
+2001:67c:2214::,2001:67c:2214:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2218::,2001:67c:2219:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2220::,2001:67c:2220:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2224::,2001:67c:2224:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2228::,2001:67c:2228:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:222c::,2001:67c:222c:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:2230::,2001:67c:2230:ffff:ffff:ffff:ffff:ffff,HR
+2001:67c:2234::,2001:67c:2234:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2238::,2001:67c:2238:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:223c::,2001:67c:223c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2240::,2001:67c:2240:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2244::,2001:67c:2244:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2248::,2001:67c:2248:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2250::,2001:67c:2250:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2254::,2001:67c:2254:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2258::,2001:67c:2258:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:225c::,2001:67c:225c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2260::,2001:67c:2260:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2264::,2001:67c:2264:ffff:ffff:ffff:ffff:ffff,KG
+2001:67c:2268::,2001:67c:2268:ffff:ffff:ffff:ffff:ffff,BY
+2001:67c:226c::,2001:67c:226c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2270::,2001:67c:2270:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2274::,2001:67c:2274:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2278::,2001:67c:2278:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:227c::,2001:67c:227c:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2280::,2001:67c:2280:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2284::,2001:67c:2284:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2288::,2001:67c:2288:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:228c::,2001:67c:228c:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2290::,2001:67c:2290:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2294::,2001:67c:2294:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:2298::,2001:67c:2298:ffff:ffff:ffff:ffff:ffff,US
+2001:67c:229c::,2001:67c:229c:ffff:ffff:ffff:ffff:ffff,GR
+2001:67c:22a0::,2001:67c:22a0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:22a4::,2001:67c:22a4:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:22a8::,2001:67c:22a8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:22ac::,2001:67c:22ac:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:22b0::,2001:67c:22b0:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:22b4::,2001:67c:22b4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:22b8::,2001:67c:22b8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:22bc::,2001:67c:22bc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:22c0::,2001:67c:22c0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:22c4::,2001:67c:22c4:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:22c8::,2001:67c:22c8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:22cc::,2001:67c:22cc:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:22d0::,2001:67c:22d0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:22d4::,2001:67c:22d4:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:22d8::,2001:67c:22d8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:22dc::,2001:67c:22dc:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:22e0::,2001:67c:22e0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:22e4::,2001:67c:22e4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:22e8::,2001:67c:22e8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:22ec::,2001:67c:22ec:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:22f0::,2001:67c:22f0:ffff:ffff:ffff:ffff:ffff,RS
+2001:67c:22f8::,2001:67c:22f8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:22fc::,2001:67c:22fc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2300::,2001:67c:2300:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2304::,2001:67c:2304:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2308::,2001:67c:2308:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:230c::,2001:67c:230c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2310::,2001:67c:2310:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2314::,2001:67c:2314:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2318::,2001:67c:2318:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:231c::,2001:67c:231c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2320::,2001:67c:2320:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2324::,2001:67c:2324:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2328::,2001:67c:2328:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:232c::,2001:67c:232c:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c:2330::,2001:67c:2330:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2334::,2001:67c:2334:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2338::,2001:67c:2338:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:233c::,2001:67c:233c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2340::,2001:67c:2340:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2344::,2001:67c:2344:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2348::,2001:67c:2348:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:234c::,2001:67c:234c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2350::,2001:67c:2350:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2354::,2001:67c:2354:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2358::,2001:67c:2358:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:235c::,2001:67c:235c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2360::,2001:67c:2360:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2364::,2001:67c:2364:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2368::,2001:67c:2368:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:236c::,2001:67c:236c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2370::,2001:67c:2370:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2374::,2001:67c:2374:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2378::,2001:67c:2378:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:237c::,2001:67c:237c:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2380::,2001:67c:2380:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2384::,2001:67c:2384:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2388::,2001:67c:2388:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:238c::,2001:67c:238c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2394::,2001:67c:2394:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2398::,2001:67c:2398:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:239c::,2001:67c:239c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:23a0::,2001:67c:23a0:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:23a4::,2001:67c:23a4:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:23a8::,2001:67c:23a8:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:23b0::,2001:67c:23b0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:23b4::,2001:67c:23b4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:23b8::,2001:67c:23b8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:23bc::,2001:67c:23bc:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:23c0::,2001:67c:23c0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:23c4::,2001:67c:23c4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:23c8::,2001:67c:23c8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:23cc::,2001:67c:23cc:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:23d0::,2001:67c:23d0:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:23d4::,2001:67c:23d4:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:23d8::,2001:67c:23d9:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:23e4::,2001:67c:23e4:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:23e8::,2001:67c:23e8:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:23ec::,2001:67c:23ec:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:23f0::,2001:67c:23f0:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:23f4::,2001:67c:23f4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:23f8::,2001:67c:23f8:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:23fc::,2001:67c:23fc:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:2400::,2001:67c:2400:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2404::,2001:67c:2404:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2408::,2001:67c:2408:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:240c::,2001:67c:240c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2410::,2001:67c:2410:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:2414::,2001:67c:2414:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2418::,2001:67c:2418:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2420::,2001:67c:2420:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2424::,2001:67c:2424:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2428::,2001:67c:2428:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:242c::,2001:67c:242c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2430::,2001:67c:2433:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2440::,2001:67c:2440:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2444::,2001:67c:2444:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2448::,2001:67c:2448:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:244c::,2001:67c:244c:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2450::,2001:67c:2450:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:2454::,2001:67c:2454:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2458::,2001:67c:2458:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:245c::,2001:67c:245c:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2460::,2001:67c:2460:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2464::,2001:67c:2464:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2468::,2001:67c:2468:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:246c::,2001:67c:246c:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2470::,2001:67c:2470:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2474::,2001:67c:2474:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2478::,2001:67c:2478:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:247c::,2001:67c:247c:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2480::,2001:67c:2480:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2484::,2001:67c:2484:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2488::,2001:67c:2488:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:248c::,2001:67c:248c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2490::,2001:67c:2490:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2494::,2001:67c:2494:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2498::,2001:67c:2498:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:249c::,2001:67c:249c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:24a0::,2001:67c:24a0:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:24a4::,2001:67c:24a4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:24a8::,2001:67c:24a8:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:24ac::,2001:67c:24ac:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:24b0::,2001:67c:24b0:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:24b4::,2001:67c:24b4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:24b8::,2001:67c:24b8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:24bc::,2001:67c:24bc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:24c0::,2001:67c:24c0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:24c4::,2001:67c:24c4:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:24c8::,2001:67c:24c8:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:24cc::,2001:67c:24cc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:24d0::,2001:67c:24d0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:24d4::,2001:67c:24d4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:24d8::,2001:67c:24d8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:24dc::,2001:67c:24dc:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:24e0::,2001:67c:24e0:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:24e4::,2001:67c:24e4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:24e8::,2001:67c:24e9:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:24f0::,2001:67c:24f0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:24f4::,2001:67c:24f4:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:24f8::,2001:67c:24f8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:24fc::,2001:67c:24fc:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2500::,2001:67c:2507:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2520::,2001:67c:2520:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2524::,2001:67c:2524:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2528::,2001:67c:2528:ffff:ffff:ffff:ffff:ffff,LV
+2001:67c:252c::,2001:67c:252c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2530::,2001:67c:2530:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2534::,2001:67c:2534:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:2538::,2001:67c:2538:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:253c::,2001:67c:253c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2540::,2001:67c:2540:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2544::,2001:67c:2544:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2548::,2001:67c:2548:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:254c::,2001:67c:254c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2550::,2001:67c:2550:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2554::,2001:67c:2554:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2558::,2001:67c:2558:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:255c::,2001:67c:255c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2560::,2001:67c:2560:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2564::,2001:67c:2564:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:256c::,2001:67c:256c:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2570::,2001:67c:2570:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:2574::,2001:67c:2574:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2578::,2001:67c:2578:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:257c::,2001:67c:257c:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2580::,2001:67c:2580:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2584::,2001:67c:2584:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2588::,2001:67c:2588:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:258c::,2001:67c:258c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2590::,2001:67c:2590:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2594::,2001:67c:2594:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2598::,2001:67c:2598:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:259c::,2001:67c:259c:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:25a0::,2001:67c:25a0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:25a4::,2001:67c:25a4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:25a8::,2001:67c:25a8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:25ac::,2001:67c:25ac:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:25b0::,2001:67c:25b0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:25b4::,2001:67c:25b4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:25b8::,2001:67c:25b8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:25bc::,2001:67c:25bc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:25c0::,2001:67c:25c0:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:25c4::,2001:67c:25c4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:25cc::,2001:67c:25cc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:25d0::,2001:67c:25d0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:25d4::,2001:67c:25d4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:25d8::,2001:67c:25d8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:25dc::,2001:67c:25dc:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:25e4::,2001:67c:25e4:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:25e8::,2001:67c:25e9:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:25f0::,2001:67c:25f0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:25f4::,2001:67c:25f4:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:25f8::,2001:67c:25f8:ffff:ffff:ffff:ffff:ffff,EU
+2001:67c:25fc::,2001:67c:25fc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2600::,2001:67c:2600:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2604::,2001:67c:2604:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:260c::,2001:67c:260c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2610::,2001:67c:2610:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2614::,2001:67c:2614:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2618::,2001:67c:2618:ffff:ffff:ffff:ffff:ffff,EE
+2001:67c:261c::,2001:67c:261c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2620::,2001:67c:2620:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2624::,2001:67c:2624:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:262c::,2001:67c:262c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2630::,2001:67c:2630:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2634::,2001:67c:2634:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2638::,2001:67c:2638:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:263c::,2001:67c:263c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2640::,2001:67c:2640:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2644::,2001:67c:2644:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2648::,2001:67c:2648:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:264c::,2001:67c:264c:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2650::,2001:67c:2650:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2654::,2001:67c:2654:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2658::,2001:67c:2658:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:265c::,2001:67c:265c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2660::,2001:67c:2660:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2664::,2001:67c:2664:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2668::,2001:67c:2668:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:266c::,2001:67c:266c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2670::,2001:67c:2670:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:2674::,2001:67c:2674:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2678::,2001:67c:2678:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:267c::,2001:67c:267c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2680::,2001:67c:2680:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:2684::,2001:67c:2684:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2688::,2001:67c:2688:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:268c::,2001:67c:268c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2690::,2001:67c:2690:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:2694::,2001:67c:2694:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2698::,2001:67c:2698:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:269c::,2001:67c:269c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:26a0::,2001:67c:26a0:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:26a4::,2001:67c:26a4:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:26a8::,2001:67c:26a8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:26ac::,2001:67c:26ac:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:26b0::,2001:67c:26b0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:26b4::,2001:67c:26b4:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:26b8::,2001:67c:26b8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:26bc::,2001:67c:26bc:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:26c0::,2001:67c:26c3:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:26d0::,2001:67c:26d0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:26d4::,2001:67c:26d4:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:26d8::,2001:67c:26d8:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:26dc::,2001:67c:26dc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:26e0::,2001:67c:26e0:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:26e4::,2001:67c:26e4:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:26e8::,2001:67c:26e8:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:26ec::,2001:67c:26ec:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:26f0::,2001:67c:26f0:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:26f4::,2001:67c:26f4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:26f8::,2001:67c:26f8:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:26fc::,2001:67c:26fc:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2700::,2001:67c:2700:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2704::,2001:67c:2704:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2708::,2001:67c:2708:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:270c::,2001:67c:270c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2710::,2001:67c:2710:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:2714::,2001:67c:2714:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2718::,2001:67c:2718:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:271c::,2001:67c:271c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2720::,2001:67c:2720:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2724::,2001:67c:2724:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2728::,2001:67c:2728:ffff:ffff:ffff:ffff:ffff,IR
+2001:67c:272c::,2001:67c:272c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2730::,2001:67c:2730:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2734::,2001:67c:2734:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2738::,2001:67c:2738:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:273c::,2001:67c:273c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2740::,2001:67c:2740:ffff:ffff:ffff:ffff:ffff,SK
+2001:67c:2744::,2001:67c:2744:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:2748::,2001:67c:2748:ffff:ffff:ffff:ffff:ffff,GR
+2001:67c:274c::,2001:67c:274c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2750::,2001:67c:2750:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2758::,2001:67c:2758:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:275c::,2001:67c:275c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2760::,2001:67c:2760:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2764::,2001:67c:2764:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2768::,2001:67c:2768:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:276c::,2001:67c:276c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2770::,2001:67c:2770:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2774::,2001:67c:2774:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:2778::,2001:67c:2778:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:277c::,2001:67c:277c:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2780::,2001:67c:2780:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2784::,2001:67c:2784:ffff:ffff:ffff:ffff:ffff,FI
+2001:67c:2788::,2001:67c:2788:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:278c::,2001:67c:278c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2790::,2001:67c:2790:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2794::,2001:67c:2794:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2798::,2001:67c:2798:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:279c::,2001:67c:279c:ffff:ffff:ffff:ffff:ffff,US
+2001:67c:27a0::,2001:67c:27a7:ffff:ffff:ffff:ffff:ffff,US
+2001:67c:27c0::,2001:67c:27c0:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:27c4::,2001:67c:27c4:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:27c8::,2001:67c:27c8:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:27cc::,2001:67c:27cc:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:27d0::,2001:67c:27d0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:27d4::,2001:67c:27d4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:27d8::,2001:67c:27d8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:27dc::,2001:67c:27dc:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:27e0::,2001:67c:27e0:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:27e4::,2001:67c:27e4:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:27e8::,2001:67c:27e8:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:27ec::,2001:67c:27ec:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:27f0::,2001:67c:27f0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:27f4::,2001:67c:27f4:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:27f8::,2001:67c:27f8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:27fc::,2001:67c:27fc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2800::,2001:67c:2800:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2804::,2001:67c:2804:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2808::,2001:67c:2808:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:280c::,2001:67c:280c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2810::,2001:67c:2810:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2814::,2001:67c:2814:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2818::,2001:67c:2818:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:281c::,2001:67c:281c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2820::,2001:67c:2820:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2824::,2001:67c:2824:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2828::,2001:67c:2828:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:282c::,2001:67c:282c:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:2830::,2001:67c:2830:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2834::,2001:67c:2834:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2838::,2001:67c:2838:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:283c::,2001:67c:283c:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:2840::,2001:67c:2840:ffff:ffff:ffff:ffff:ffff,IL
+2001:67c:2844::,2001:67c:2844:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2848::,2001:67c:2848:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:284c::,2001:67c:284c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2850::,2001:67c:2850:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2854::,2001:67c:2854:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2858::,2001:67c:2858:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:285c::,2001:67c:285c:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2860::,2001:67c:2860:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2864::,2001:67c:2864:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2868::,2001:67c:2868:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:286c::,2001:67c:286c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2870::,2001:67c:2870:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2874::,2001:67c:2874:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2878::,2001:67c:2878:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:287c::,2001:67c:287c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2880::,2001:67c:2880:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2884::,2001:67c:2884:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2888::,2001:67c:2889:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2890::,2001:67c:2890:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2894::,2001:67c:2894:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2898::,2001:67c:2898:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:289c::,2001:67c:289c:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:28a0::,2001:67c:28a0:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:28a4::,2001:67c:28a4:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:28a8::,2001:67c:28a8:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:28ac::,2001:67c:28ac:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:28b0::,2001:67c:28b0:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:28b4::,2001:67c:28b4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:28b8::,2001:67c:28b8:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:28bc::,2001:67c:28bc:ffff:ffff:ffff:ffff:ffff,HU
+2001:67c:28c0::,2001:67c:28c0:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:28c4::,2001:67c:28c4:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:28c8::,2001:67c:28c8:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:28cc::,2001:67c:28cc:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:28d0::,2001:67c:28d0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:28d4::,2001:67c:28d4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:28d8::,2001:67c:28d8:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:28e0::,2001:67c:28e0:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:28e4::,2001:67c:28e4:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:28e8::,2001:67c:28e8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:28f0::,2001:67c:28f0:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:28f4::,2001:67c:28f4:ffff:ffff:ffff:ffff:ffff,SI
+2001:67c:28f8::,2001:67c:28f8:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:28fc::,2001:67c:28fc:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2900::,2001:67c:291f:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2980::,2001:67c:2980:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2984::,2001:67c:2984:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2988::,2001:67c:2989:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:2994::,2001:67c:2994:ffff:ffff:ffff:ffff:ffff,SA
+2001:67c:2998::,2001:67c:2998:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:299c::,2001:67c:299c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:29a0::,2001:67c:29a0:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:29a4::,2001:67c:29a4:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:29a8::,2001:67c:29a8:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:29ac::,2001:67c:29ac:ffff:ffff:ffff:ffff:ffff,CY
+2001:67c:29b0::,2001:67c:29b1:ffff:ffff:ffff:ffff:ffff,CY
+2001:67c:29bc::,2001:67c:29bc:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:29c0::,2001:67c:29c1:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:29c8::,2001:67c:29c8:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:29cc::,2001:67c:29cc:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:29d0::,2001:67c:29d0:ffff:ffff:ffff:ffff:ffff,CZ
+2001:67c:29d4::,2001:67c:29d4:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:29d8::,2001:67c:29d8:ffff:ffff:ffff:ffff:ffff,AE
+2001:67c:29dc::,2001:67c:29dc:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:29e0::,2001:67c:29e0:ffff:ffff:ffff:ffff:ffff,UA
+2001:67c:29e4::,2001:67c:29e4:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:29e8::,2001:67c:29e8:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:29ec::,2001:67c:29ec:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:29f0::,2001:67c:29f0:ffff:ffff:ffff:ffff:ffff,BG
+2001:67c:29f4::,2001:67c:29f4:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:29f8::,2001:67c:29f8:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:29fc::,2001:67c:29fc:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2a00::,2001:67c:2a00:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2a04::,2001:67c:2a04:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2a08::,2001:67c:2a08:ffff:ffff:ffff:ffff:ffff,NO
+2001:67c:2a0c::,2001:67c:2a0c:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a14::,2001:67c:2a14:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a18::,2001:67c:2a18:ffff:ffff:ffff:ffff:ffff,SE
+2001:67c:2a1c::,2001:67c:2a1c:ffff:ffff:ffff:ffff:ffff,PL
+2001:67c:2a20::,2001:67c:2a20:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2a24::,2001:67c:2a24:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2a28::,2001:67c:2a28:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2a2c::,2001:67c:2a2c:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2a30::,2001:67c:2a30:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a34::,2001:67c:2a34:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a38::,2001:67c:2a38:ffff:ffff:ffff:ffff:ffff,AT
+2001:67c:2a3c::,2001:67c:2a3c:ffff:ffff:ffff:ffff:ffff,ES
+2001:67c:2a40::,2001:67c:2a40:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2a44::,2001:67c:2a44:ffff:ffff:ffff:ffff:ffff,RO
+2001:67c:2a48::,2001:67c:2a48:ffff:ffff:ffff:ffff:ffff,RU
+2001:67c:2a4c::,2001:67c:2a4c:ffff:ffff:ffff:ffff:ffff,GB
+2001:67c:2a50::,2001:67c:2a50:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2a54::,2001:67c:2a54:ffff:ffff:ffff:ffff:ffff,DE
+2001:67c:2a58::,2001:67c:2a58:ffff:ffff:ffff:ffff:ffff,BE
+2001:67c:2a5c::,2001:67c:2a5c:ffff:ffff:ffff:ffff:ffff,CH
+2001:67c:2a64::,2001:67c:2a64:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2a68::,2001:67c:2a68:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2a6c::,2001:67c:2a6c:ffff:ffff:ffff:ffff:ffff,TR
+2001:67c:2a70::,2001:67c:2a70:ffff:ffff:ffff:ffff:ffff,NL
+2001:67c:2a74::,2001:67c:2a74:ffff:ffff:ffff:ffff:ffff,FR
+2001:67c:2a78::,2001:67c:2a78:ffff:ffff:ffff:ffff:ffff,DK
+2001:67c:2a7c::,2001:67c:2a7c:ffff:ffff:ffff:ffff:ffff,DE
+2001:680::,2001:680:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:688::,2001:688:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:690::,2001:690:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:698::,2001:698:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:6a0::,2001:6a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:6a8::,2001:6a8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:6b0::,2001:6b0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:6b8::,2001:6b8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:6c0::,2001:6c0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:6c8::,2001:6cf:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:6d0::,2001:6d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:6d8::,2001:6df:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:6e0::,2001:6e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:6e8::,2001:6ef:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:6f0::,2001:6f0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:6f8::,2001:6f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:700::,2001:700:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:708::,2001:708:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:710::,2001:710:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:718::,2001:718:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:720::,2001:720:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:728::,2001:728:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:730::,2001:737:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:738::,2001:738:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2001:740::,2001:740:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:748::,2001:748:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:750::,2001:750:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:758::,2001:758:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:760::,2001:760:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:768::,2001:768:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:770::,2001:770:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:778::,2001:778:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2001:780::,2001:787:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:788::,2001:788:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:790::,2001:790:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:798::,2001:798:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:7a0::,2001:7a0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:7a8::,2001:7a8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:7b0::,2001:7b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:7b8::,2001:7b8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:7c0::,2001:7c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:7c8::,2001:7c8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:7d0::,2001:7d0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:7d8::,2001:7d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:7e0::,2001:7e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:7e8::,2001:7e8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:7f0::,2001:7f0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8::,2001:7f8:0:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:1::,2001:7f8:1:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:2::,2001:7f8:2:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:3::,2001:7f8:5:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:6::,2001:7f8:6:ffff:ffff:ffff:ffff:ffff,BG
+2001:7f8:7::,2001:7f8:7:ffff:ffff:ffff:ffff:ffff,FI
+2001:7f8:8::,2001:7f8:8:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:9::,2001:7f8:9:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:a::,2001:7f8:a:ffff:ffff:ffff:ffff:ffff,PT
+2001:7f8:b::,2001:7f8:b:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:c::,2001:7f8:c:ffff:ffff:ffff:ffff:ffff,CH
+2001:7f8:d::,2001:7f8:d:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:e::,2001:7f8:e:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:f::,2001:7f8:f:ffff:ffff:ffff:ffff:ffff,ES
+2001:7f8:10::,2001:7f8:10:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:11::,2001:7f8:11:ffff:ffff:ffff:ffff:ffff,LU
+2001:7f8:12::,2001:7f8:12:ffff:ffff:ffff:ffff:ffff,NO
+2001:7f8:13::,2001:7f8:13:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:14::,2001:7f8:14:ffff:ffff:ffff:ffff:ffff,CZ
+2001:7f8:15::,2001:7f8:15:ffff:ffff:ffff:ffff:ffff,EE
+2001:7f8:16::,2001:7f8:16:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:17::,2001:7f8:17:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:18::,2001:7f8:18:ffff:ffff:ffff:ffff:ffff,IE
+2001:7f8:19::,2001:7f8:19:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:1a::,2001:7f8:1a:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8:1b::,2001:7f8:1b:ffff:ffff:ffff:ffff:ffff,BE
+2001:7f8:1c::,2001:7f8:1c:ffff:ffff:ffff:ffff:ffff,CH
+2001:7f8:1d::,2001:7f8:1d:ffff:ffff:ffff:ffff:ffff,FI
+2001:7f8:1e::,2001:7f8:1e:ffff:ffff:ffff:ffff:ffff,RS
+2001:7f8:1f::,2001:7f8:1f:ffff:ffff:ffff:ffff:ffff,DK
+2001:7f8:20::,2001:7f8:20:ffff:ffff:ffff:ffff:ffff,RU
+2001:7f8:21::,2001:7f8:21:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:22::,2001:7f8:22:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:23::,2001:7f8:23:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:24::,2001:7f8:24:ffff:ffff:ffff:ffff:ffff,CH
+2001:7f8:25::,2001:7f8:25:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:26::,2001:7f8:26:ffff:ffff:ffff:ffff:ffff,BE
+2001:7f8:27::,2001:7f8:27:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:28::,2001:7f8:28:ffff:ffff:ffff:ffff:ffff,HR
+2001:7f8:29::,2001:7f8:29:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:2a::,2001:7f8:2a:ffff:ffff:ffff:ffff:ffff,ES
+2001:7f8:2b::,2001:7f8:2c:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8:2d::,2001:7f8:2d:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:2e::,2001:7f8:2e:ffff:ffff:ffff:ffff:ffff,PT
+2001:7f8:2f::,2001:7f8:2f:ffff:ffff:ffff:ffff:ffff,SK
+2001:7f8:30::,2001:7f8:30:ffff:ffff:ffff:ffff:ffff,AT
+2001:7f8:31::,2001:7f8:31:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:33::,2001:7f8:33:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:34::,2001:7f8:34:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:35::,2001:7f8:35:ffff:ffff:ffff:ffff:ffff,HU
+2001:7f8:37::,2001:7f8:38:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:39::,2001:7f8:39:ffff:ffff:ffff:ffff:ffff,EE
+2001:7f8:3a::,2001:7f8:3a:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:3b::,2001:7f8:3b:ffff:ffff:ffff:ffff:ffff,IL
+2001:7f8:3c::,2001:7f8:3c:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8:3d::,2001:7f8:3d:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:3e::,2001:7f8:3e:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:3f::,2001:7f8:3f:ffff:ffff:ffff:ffff:ffff,SK
+2001:7f8:41::,2001:7f8:41:ffff:ffff:ffff:ffff:ffff,NO
+2001:7f8:42::,2001:7f8:42:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:43::,2001:7f8:43:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:44::,2001:7f8:44:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:45::,2001:7f8:45:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:46::,2001:7f8:46:ffff:ffff:ffff:ffff:ffff,SI
+2001:7f8:47::,2001:7f8:47:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:48::,2001:7f8:48:ffff:ffff:ffff:ffff:ffff,IS
+2001:7f8:49::,2001:7f8:49:ffff:ffff:ffff:ffff:ffff,EU
+2001:7f8:4a::,2001:7f8:4a:ffff:ffff:ffff:ffff:ffff,AT
+2001:7f8:4b::,2001:7f8:4b:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:4c::,2001:7f8:4c:ffff:ffff:ffff:ffff:ffff,LU
+2001:7f8:4d::,2001:7f8:4d:ffff:ffff:ffff:ffff:ffff,IE
+2001:7f8:4e::,2001:7f8:4e:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:4f::,2001:7f8:4f:ffff:ffff:ffff:ffff:ffff,BH
+2001:7f8:50::,2001:7f8:50:ffff:ffff:ffff:ffff:ffff,EE
+2001:7f8:51::,2001:7f8:51:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:52::,2001:7f8:52:ffff:ffff:ffff:ffff:ffff,LB
+2001:7f8:53::,2001:7f8:53:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:54::,2001:7f8:54:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:55::,2001:7f8:55:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:56::,2001:7f8:56:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:58::,2001:7f8:58:ffff:ffff:ffff:ffff:ffff,BG
+2001:7f8:59::,2001:7f8:59:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:5a::,2001:7f8:5a:ffff:ffff:ffff:ffff:ffff,BY
+2001:7f8:5b::,2001:7f8:5b:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:5c::,2001:7f8:5c:ffff:ffff:ffff:ffff:ffff,SE
+2001:7f8:5d::,2001:7f8:5d:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:5e::,2001:7f8:5e:ffff:ffff:ffff:ffff:ffff,CZ
+2001:7f8:5f::,2001:7f8:5f:ffff:ffff:ffff:ffff:ffff,IT
+2001:7f8:60::,2001:7f8:60:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:61::,2001:7f8:61:ffff:ffff:ffff:ffff:ffff,NL
+2001:7f8:62::,2001:7f8:62:ffff:ffff:ffff:ffff:ffff,DE
+2001:7f8:63::,2001:7f8:63:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:64::,2001:7f8:64:ffff:ffff:ffff:ffff:ffff,RO
+2001:7f8:66::,2001:7f8:66:ffff:ffff:ffff:ffff:ffff,AT
+2001:7f8:67::,2001:7f8:67:ffff:ffff:ffff:ffff:ffff,GB
+2001:7f8:68::,2001:7f8:68:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:69::,2001:7f8:69:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:6a::,2001:7f8:6a:ffff:ffff:ffff:ffff:ffff,MD
+2001:7f8:6b::,2001:7f8:6b:ffff:ffff:ffff:ffff:ffff,PL
+2001:7f8:6c::,2001:7f8:6c:ffff:ffff:ffff:ffff:ffff,UA
+2001:7f8:6d::,2001:7f8:6d:ffff:ffff:ffff:ffff:ffff,FR
+2001:7f8:6e::,2001:7f8:6e:ffff:ffff:ffff:ffff:ffff,GR
+2001:7f8:6f::,2001:7f8:6f:ffff:ffff:ffff:ffff:ffff,RU
+2001:7fa:0:1::,2001:7fa:0:1:ffff:ffff:ffff:ffff,HK
+2001:7fa:0:2::,2001:7fa:0:2:ffff:ffff:ffff:ffff,KR
+2001:7fa:0:3::,2001:7fa:0:3:ffff:ffff:ffff:ffff,JP
+2001:7fa:1::,2001:7fa:1:ffff:ffff:ffff:ffff:ffff,TW
+2001:7fa:2::,2001:7fa:2:ffff:ffff:ffff:ffff:ffff,ID
+2001:7fa:3::,2001:7fa:4:ffff:ffff:ffff:ffff:ffff,NZ
+2001:7fa:5::,2001:7fa:5:ffff:ffff:ffff:ffff:ffff,CN
+2001:7fa:6::,2001:7fa:6:ffff:ffff:ffff:ffff:ffff,VN
+2001:7fa:7::,2001:7fa:7:ffff:ffff:ffff:ffff:ffff,JP
+2001:7fa:8::,2001:7fa:8:ffff:ffff:ffff:ffff:ffff,KR
+2001:7fa:9::,2001:7fa:e:ffff:ffff:ffff:ffff:ffff,AU
+2001:7fa:f::,2001:7fa:f:ffff:ffff:ffff:ffff:ffff,ID
+2001:7fa:10::,2001:7fa:10:ffff:ffff:ffff:ffff:ffff,CN
+2001:7fa:11::,2001:7fa:11:ffff:ffff:ffff:ffff:ffff,AU
+2001:7fb::,2001:7fb:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:7fd::,2001:7fd:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:7fe::,2001:7fe:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:808::,2001:808:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:810::,2001:810:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:818::,2001:818:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:820::,2001:820:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:828::,2001:828:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:830::,2001:830:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:838::,2001:83f:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:840::,2001:840:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:848::,2001:848:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:850::,2001:850:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:858::,2001:858:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:860::,2001:860:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:868::,2001:86f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:870::,2001:870:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:878::,2001:878:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:880::,2001:880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:888::,2001:88b:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:890::,2001:890:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:898::,2001:89f:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:8a0::,2001:8a0:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:8a8::,2001:8a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:8b0::,2001:8b0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:8b8::,2001:8bf:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:8c0::,2001:8c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:8c8::,2001:8c8:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2001:8d0::,2001:8d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:8d8::,2001:8d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:8e0::,2001:8e0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:8e8::,2001:8e8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:8f0::,2001:8f0:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2001:8f8::,2001:8f8:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2001:900::,2001:900:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:908::,2001:908:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:910::,2001:910:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:918::,2001:918:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:920::,2001:920:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:928::,2001:928:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:930::,2001:930:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2001:938::,2001:938:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:940::,2001:940:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:948::,2001:948:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:950::,2001:950:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2001:958::,2001:958:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:960::,2001:960:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:968::,2001:968:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:978::,2001:978:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:980::,2001:983:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:988::,2001:988:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:990::,2001:990:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:998::,2001:998:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:9a0::,2001:9a0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:9a8::,2001:9a8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:9b0::,2001:9b0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:9b8::,2001:9b8:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:9c0::,2001:9c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:9c8::,2001:9c8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:9d0::,2001:9d0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:9d8::,2001:9d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:9e0::,2001:9e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:9e8::,2001:9e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:9f0::,2001:9f0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:a00::,2001:a00:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:a08::,2001:a08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:a10::,2001:a10:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:a18::,2001:a18:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:a20::,2001:a20:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:a30::,2001:a30:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:a38::,2001:a38:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:a40::,2001:a40:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:a48::,2001:a48:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:a50::,2001:a50:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:a58::,2001:a58:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:a60::,2001:a60:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:a68::,2001:a68:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:a70::,2001:a70:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:a78::,2001:a78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:a80::,2001:a80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:a88::,2001:a88:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:a90::,2001:a90:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:a98::,2001:a98:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2001:aa0::,2001:aa0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:aa8::,2001:aa8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:ab0::,2001:ab0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:ab8::,2001:ab8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:ac0::,2001:ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:ac8::,2001:ac8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:ad0::,2001:ad0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:ad8::,2001:ae0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:ae8::,2001:ae8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:af0::,2001:af0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:af8::,2001:af8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:b00::,2001:b00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:b08::,2001:b08:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:b10::,2001:b10:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:b18::,2001:b18:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:b20::,2001:b20:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:b28::,2001:b28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:b30::,2001:b30:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2001:b38::,2001:b38:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:b40::,2001:b40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:b48::,2001:b48:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:b50::,2001:b50:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:b58::,2001:b58:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:b60::,2001:b67:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:b68::,2001:b68:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2001:b70::,2001:b70:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:b80::,2001:b80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:b88::,2001:b88:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:b90::,2001:b90:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:b98::,2001:b98:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:ba0::,2001:ba0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:ba8::,2001:ba8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:bb0::,2001:bb0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:bb8::,2001:bb8:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:bc0::,2001:bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:bc8::,2001:bc8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:bd0::,2001:bd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:be0::,2001:be0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:be8::,2001:be8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:bf0::,2001:bf0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:bf8::,2001:bf8:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2001:c00::,2001:c00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:c08::,2001:c08:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:c10::,2001:c10:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:c18::,2001:c18:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:c20::,2001:c20:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:c28::,2001:c28:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c30::,2001:c30:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c38::,2001:c39:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:c40::,2001:c40:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c48::,2001:c48:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:c50::,2001:c50:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:c58::,2001:c58:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:c60::,2001:c60:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2001:c68::,2001:c68:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:c70::,2001:c70:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c78::,2001:c79:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:c80::,2001:c80:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c88::,2001:c88:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c90::,2001:c90:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:c98::,2001:c98:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ca0::,2001:ca0:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:ca8::,2001:ca8:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:cb0::,2001:cb0:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:cb8::,2001:cb8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:cc0::,2001:cc0:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:cc8::,2001:cc9:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:cd0::,2001:cd0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:cd8::,2001:cd8:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:ce0::,2001:ce0:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:ce8::,2001:ce8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:cf0::,2001:cf0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:cf8::,2001:cf8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d00::,2001:d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d08::,2001:d08:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:d10::,2001:d10:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:d18::,2001:d18:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:d28::,2001:d28:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d30::,2001:d30:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d38::,2001:d38:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:d40::,2001:d40:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:d48::,2001:d48:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:d50::,2001:d50:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d58::,2001:d58:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:d68::,2001:d68:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:d70::,2001:d73:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d80::,2001:d80:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d88::,2001:d88:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d90::,2001:d90:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:d98::,2001:d98:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:da0::,2001:da0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:da8::,2001:daa:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:db0::,2001:db0:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:dc0::,2001:dc0:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:dc1::,2001:dc1:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:dc2::,2001:dc4:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:dc5::,2001:dc5:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:dc6::,2001:dc6:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:dc7::,2001:dc7:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:dc8::,2001:dc8:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2001:dc9::,2001:dc9:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:dca::,2001:dca:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:dcc::,2001:dcc:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:dcd::,2001:dcd:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:dce::,2001:dce:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:dd8::,2001:dd8:0:ffff:ffff:ffff:ffff:ffff,FJ
+2001:dd8:1::,2001:dd8:1:ffff:ffff:ffff:ffff:ffff,CN
+2001:dd8:2::,2001:dd8:2:ffff:ffff:ffff:ffff:ffff,MY
+2001:dd8:3::,2001:dd8:3:ffff:ffff:ffff:ffff:ffff,NZ
+2001:dd8:4::,2001:dd8:4:ffff:ffff:ffff:ffff:ffff,SG
+2001:dd8:5::,2001:dd8:5:ffff:ffff:ffff:ffff:ffff,CN
+2001:dd8:6::,2001:dd8:6:ffff:ffff:ffff:ffff:ffff,AU
+2001:dd8:7::,2001:dd8:7:ffff:ffff:ffff:ffff:ffff,NP
+2001:dd8:8::,2001:dd8:f:ffff:ffff:ffff:ffff:ffff,AU
+2001:dd8:10::,2001:dd8:11:ffff:ffff:ffff:ffff:ffff,NP
+2001:dd8:12::,2001:dd8:12:ffff:ffff:ffff:ffff:ffff,AU
+2001:dd8:13::,2001:dd8:13:ffff:ffff:ffff:ffff:ffff,NZ
+2001:dd8:14::,2001:dd8:14:ffff:ffff:ffff:ffff:ffff,AU
+2001:dd8:15::,2001:dd8:15:ffff:ffff:ffff:ffff:ffff,HK
+2001:dd8:16::,2001:dd8:16:ffff:ffff:ffff:ffff:ffff,SG
+2001:dd8:17::,2001:dd8:17:ffff:ffff:ffff:ffff:ffff,KR
+2001:dd8:18::,2001:dd8:18:ffff:ffff:ffff:ffff:ffff,TW
+2001:dd8:19::,2001:dd8:19:ffff:ffff:ffff:ffff:ffff,IN
+2001:dd8:1a::,2001:dd8:1a:ffff:ffff:ffff:ffff:ffff,CN
+2001:dd8:1b::,2001:dd8:1b:ffff:ffff:ffff:ffff:ffff,IN
+2001:dd8:1c::,2001:dd8:1c:ffff:ffff:ffff:ffff:ffff,PK
+2001:dd8:1d::,2001:dd8:1d:ffff:ffff:ffff:ffff:ffff,BD
+2001:dd8:1e::,2001:dd8:1e:ffff:ffff:ffff:ffff:ffff,KH
+2001:dd8:1f::,2001:dd8:1f:ffff:ffff:ffff:ffff:ffff,ID
+2001:dd8:20::,2001:dd8:21:ffff:ffff:ffff:ffff:ffff,IN
+2001:dd8:22::,2001:dd8:22:ffff:ffff:ffff:ffff:ffff,JP
+2001:dd8:24::,2001:dd8:25:ffff:ffff:ffff:ffff:ffff,NP
+2001:de1::,2001:de1:3f:ffff:ffff:ffff:ffff:ffff,JP
+2001:de8::,2001:de8:0:ffff:ffff:ffff:ffff:ffff,TH
+2001:de8:1::,2001:de8:1:ffff:ffff:ffff:ffff:ffff,IN
+2001:de8:2::,2001:de8:2:ffff:ffff:ffff:ffff:ffff,ID
+2001:de8:3::,2001:de8:3:ffff:ffff:ffff:ffff:ffff,VN
+2001:de8:4::,2001:de8:7:ffff:ffff:ffff:ffff:ffff,SG
+2001:de8:8::,2001:de8:8:ffff:ffff:ffff:ffff:ffff,JP
+2001:de8:9::,2001:de8:9:ffff:ffff:ffff:ffff:ffff,AU
+2001:de8:a::,2001:de8:a:ffff:ffff:ffff:ffff:ffff,VN
+2001:de8:b::,2001:de8:b:ffff:ffff:ffff:ffff:ffff,BD
+2001:de8:c::,2001:de8:c:ffff:ffff:ffff:ffff:ffff,JP
+2001:de8:d::,2001:de8:d:ffff:ffff:ffff:ffff:ffff,SG
+2001:de8:e::,2001:de8:e:ffff:ffff:ffff:ffff:ffff,TH
+2001:de8:f::,2001:de8:10:ffff:ffff:ffff:ffff:ffff,MY
+2001:de8:11::,2001:de8:11:ffff:ffff:ffff:ffff:ffff,ID
+2001:de8:12::,2001:de8:12:ffff:ffff:ffff:ffff:ffff,SG
+2001:de8:13::,2001:de8:13:ffff:ffff:ffff:ffff:ffff,MY
+2001:de8:14::,2001:de8:14:ffff:ffff:ffff:ffff:ffff,AU
+2001:de8:15::,2001:de8:15:ffff:ffff:ffff:ffff:ffff,ID
+2001:de8:16::,2001:de8:16:ffff:ffff:ffff:ffff:ffff,PF
+2001:de8:17::,2001:de8:17:ffff:ffff:ffff:ffff:ffff,AU
+2001:de8:19::,2001:de8:19:ffff:ffff:ffff:ffff:ffff,NZ
+2001:de8:1a::,2001:de8:1a:ffff:ffff:ffff:ffff:ffff,ID
+2001:de8:1b::,2001:de8:1b:ffff:ffff:ffff:ffff:ffff,MY
+2001:de8:1c::,2001:de8:1d:ffff:ffff:ffff:ffff:ffff,KH
+2001:df0::,2001:df0:1:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2::,2001:df0:2:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:3::,2001:df0:4:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:7::,2001:df0:7:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:8::,2001:df0:8:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:9::,2001:df0:a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:c::,2001:df0:13:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:14::,2001:df0:14:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:15::,2001:df0:15:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:17::,2001:df0:17:ffff:ffff:ffff:ffff:ffff,LK
+2001:df0:18::,2001:df0:18:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:19::,2001:df0:1d:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:1e::,2001:df0:1e:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:1f::,2001:df0:1f:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:20::,2001:df0:3f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:40::,2001:df0:40:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:41::,2001:df0:41:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:42::,2001:df0:42:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:43::,2001:df0:43:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:44::,2001:df0:44:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:45::,2001:df0:46:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:48::,2001:df0:48:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:49::,2001:df0:49:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:4a::,2001:df0:4a:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:4b::,2001:df0:4d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:4f::,2001:df0:60:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:62::,2001:df0:62:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:63::,2001:df0:63:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:65::,2001:df0:65:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:66::,2001:df0:66:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:67::,2001:df0:67:ffff:ffff:ffff:ffff:ffff,FJ
+2001:df0:68::,2001:df0:68:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:69::,2001:df0:69:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:6a::,2001:df0:6a:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:6b::,2001:df0:6b:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:6c::,2001:df0:6c:ffff:ffff:ffff:ffff:ffff,WS
+2001:df0:6e::,2001:df0:6f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:70::,2001:df0:70:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:71::,2001:df0:71:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:73::,2001:df0:74:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:75::,2001:df0:75:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:76::,2001:df0:76:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:77::,2001:df0:77:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:78::,2001:df0:78:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:79::,2001:df0:79:ffff:ffff:ffff:ffff:ffff,MN
+2001:df0:7b::,2001:df0:7c:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:7d::,2001:df0:7d:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:7e::,2001:df0:81:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:82::,2001:df0:82:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:83::,2001:df0:83:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:84::,2001:df0:84:ffff:ffff:ffff:ffff:ffff,PK
+2001:df0:85::,2001:df0:85:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:86::,2001:df0:87:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:89::,2001:df0:89:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:8a::,2001:df0:8a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:8b::,2001:df0:8b:ffff:ffff:ffff:ffff:ffff,NP
+2001:df0:8c::,2001:df0:8c:ffff:ffff:ffff:ffff:ffff,NU
+2001:df0:8d::,2001:df0:8d:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:8e::,2001:df0:90:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:91::,2001:df0:91:ffff:ffff:ffff:ffff:ffff,FJ
+2001:df0:92::,2001:df0:92:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:93::,2001:df0:93:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:94::,2001:df0:94:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:95::,2001:df0:95:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:96::,2001:df0:96:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:97::,2001:df0:97:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:98::,2001:df0:9a:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:9b::,2001:df0:9b:ffff:ffff:ffff:ffff:ffff,FJ
+2001:df0:9c::,2001:df0:9c:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:9d::,2001:df0:9d:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:9e::,2001:df0:9e:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:9f::,2001:df0:9f:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:a0::,2001:df0:a1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:a2::,2001:df0:a2:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:a3::,2001:df0:a3:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:a4::,2001:df0:a4:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:a5::,2001:df0:a6:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:a7::,2001:df0:ac:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:ad::,2001:df0:ad:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:ae::,2001:df0:ae:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:af::,2001:df0:b0:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:b1::,2001:df0:b8:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:b9::,2001:df0:b9:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:ba::,2001:df0:bd:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:be::,2001:df0:be:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:bf::,2001:df0:bf:ffff:ffff:ffff:ffff:ffff,LA
+2001:df0:c0::,2001:df0:c0:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:c1::,2001:df0:c2:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:c4::,2001:df0:c4:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:c5::,2001:df0:c5:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:c6::,2001:df0:c6:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:c7::,2001:df0:c8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:c9::,2001:df0:cc:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:cd::,2001:df0:cd:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:ce::,2001:df0:ce:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:cf::,2001:df0:cf:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:d1::,2001:df0:d1:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:d2::,2001:df0:d2:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:d3::,2001:df0:d3:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:d4::,2001:df0:d6:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:d7::,2001:df0:d7:ffff:ffff:ffff:ffff:ffff,KR
+2001:df0:d8::,2001:df0:d8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:d9::,2001:df0:d9:ffff:ffff:ffff:ffff:ffff,TW
+2001:df0:da::,2001:df0:da:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:db::,2001:df0:db:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:dc::,2001:df0:dc:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:dd::,2001:df0:dd:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:de::,2001:df0:df:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:e0::,2001:df0:e1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:e2::,2001:df0:e2:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:e3::,2001:df0:e3:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:e4::,2001:df0:e5:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:e6::,2001:df0:e6:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:e7::,2001:df0:e8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:e9::,2001:df0:e9:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:ea::,2001:df0:ea:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:eb::,2001:df0:eb:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:ed::,2001:df0:ed:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:ee::,2001:df0:ee:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:ef::,2001:df0:f0:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:f1::,2001:df0:f1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:f2::,2001:df0:f2:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:f3::,2001:df0:f3:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:f4::,2001:df0:f4:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:f5::,2001:df0:f5:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:f6::,2001:df0:f6:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:f7::,2001:df0:f7:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:f8::,2001:df0:fa:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:fb::,2001:df0:fb:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:fc::,2001:df0:fc:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:fd::,2001:df0:fe:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:100::,2001:df0:1ff:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:200::,2001:df0:200:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:201::,2001:df0:201:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:202::,2001:df0:202:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:203::,2001:df0:203:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:204::,2001:df0:204:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:205::,2001:df0:205:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:206::,2001:df0:206:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:207::,2001:df0:207:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:208::,2001:df0:208:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:209::,2001:df0:209:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:20a::,2001:df0:20a:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:20b::,2001:df0:20b:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:20c::,2001:df0:20c:ffff:ffff:ffff:ffff:ffff,NF
+2001:df0:20d::,2001:df0:20d:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:20e::,2001:df0:20f:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:210::,2001:df0:210:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:211::,2001:df0:211:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:212::,2001:df0:212:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:213::,2001:df0:213:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:214::,2001:df0:214:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:215::,2001:df0:215:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:216::,2001:df0:217:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:218::,2001:df0:219:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:21a::,2001:df0:21a:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:21b::,2001:df0:21b:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:21c::,2001:df0:21c:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:21d::,2001:df0:21d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:21e::,2001:df0:21e:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:21f::,2001:df0:220:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:221::,2001:df0:221:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:222::,2001:df0:222:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:224::,2001:df0:224:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:225::,2001:df0:225:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:226::,2001:df0:228:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:229::,2001:df0:229:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:22a::,2001:df0:22a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:22b::,2001:df0:22b:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:22c::,2001:df0:22d:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:22e::,2001:df0:22f:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:230::,2001:df0:230:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:231::,2001:df0:231:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:232::,2001:df0:232:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:233::,2001:df0:234:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:235::,2001:df0:235:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:237::,2001:df0:237:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:238::,2001:df0:238:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:239::,2001:df0:239:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:23a::,2001:df0:23a:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:23b::,2001:df0:23b:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:23c::,2001:df0:23d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:23e::,2001:df0:23e:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:23f::,2001:df0:23f:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:240::,2001:df0:241:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:242::,2001:df0:242:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:243::,2001:df0:243:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:245::,2001:df0:246:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:247::,2001:df0:247:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:248::,2001:df0:248:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:249::,2001:df0:24a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:24b::,2001:df0:24b:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:24c::,2001:df0:24c:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:24d::,2001:df0:24d:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:24e::,2001:df0:24e:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:24f::,2001:df0:24f:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:250::,2001:df0:250:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:251::,2001:df0:252:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:253::,2001:df0:253:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:254::,2001:df0:254:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:255::,2001:df0:255:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:256::,2001:df0:256:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:257::,2001:df0:257:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:258::,2001:df0:258:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:259::,2001:df0:259:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:25a::,2001:df0:25a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:25b::,2001:df0:25b:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:25c::,2001:df0:25d:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:25e::,2001:df0:25e:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:25f::,2001:df0:25f:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:260::,2001:df0:260:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:261::,2001:df0:261:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:262::,2001:df0:262:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:263::,2001:df0:263:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:264::,2001:df0:264:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:265::,2001:df0:265:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:266::,2001:df0:266:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:267::,2001:df0:267:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:268::,2001:df0:269:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:26a::,2001:df0:26b:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:26c::,2001:df0:26c:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:26d::,2001:df0:26f:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:270::,2001:df0:270:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:271::,2001:df0:271:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:272::,2001:df0:272:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:273::,2001:df0:273:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:274::,2001:df0:277:ffff:ffff:ffff:ffff:ffff,NP
+2001:df0:278::,2001:df0:278:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:279::,2001:df0:279:ffff:ffff:ffff:ffff:ffff,PK
+2001:df0:27a::,2001:df0:27a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:27b::,2001:df0:27b:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:27c::,2001:df0:27c:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:27d::,2001:df0:27d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:27e::,2001:df0:27e:ffff:ffff:ffff:ffff:ffff,CN
+2001:df0:27f::,2001:df0:27f:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:280::,2001:df0:28f:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:290::,2001:df0:290:ffff:ffff:ffff:ffff:ffff,KR
+2001:df0:291::,2001:df0:291:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:292::,2001:df0:292:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:293::,2001:df0:293:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:294::,2001:df0:294:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:295::,2001:df0:296:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:298::,2001:df0:298:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:299::,2001:df0:299:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:29a::,2001:df0:29a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:29b::,2001:df0:29b:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:29c::,2001:df0:29c:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:29d::,2001:df0:29d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:29f::,2001:df0:29f:ffff:ffff:ffff:ffff:ffff,BD
+2001:df0:2a0::,2001:df0:2a0:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:2a1::,2001:df0:2a1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2a2::,2001:df0:2a2:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:2a3::,2001:df0:2a3:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2a4::,2001:df0:2a4:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2a5::,2001:df0:2a5:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:2a6::,2001:df0:2a6:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2a7::,2001:df0:2a7:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2a8::,2001:df0:2a8:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:2a9::,2001:df0:2aa:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2ab::,2001:df0:2ab:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2ac::,2001:df0:2ac:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:2ad::,2001:df0:2ad:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2ae::,2001:df0:2ae:ffff:ffff:ffff:ffff:ffff,WS
+2001:df0:2af::,2001:df0:2af:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:2b0::,2001:df0:2b1:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2b2::,2001:df0:2b2:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2b3::,2001:df0:2b3:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2b4::,2001:df0:2b4:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2b5::,2001:df0:2b5:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2b6::,2001:df0:2b6:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2b7::,2001:df0:2b7:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2b8::,2001:df0:2b8:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:2b9::,2001:df0:2b9:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2ba::,2001:df0:2ba:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:2bb::,2001:df0:2bb:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2bc::,2001:df0:2bc:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2bd::,2001:df0:2bd:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2be::,2001:df0:2be:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2bf::,2001:df0:2bf:ffff:ffff:ffff:ffff:ffff,GB
+2001:df0:2c0::,2001:df0:2c0:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:2c1::,2001:df0:2c1:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2c2::,2001:df0:2c2:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2c3::,2001:df0:2c3:ffff:ffff:ffff:ffff:ffff,BD
+2001:df0:2c4::,2001:df0:2c4:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2c5::,2001:df0:2c5:ffff:ffff:ffff:ffff:ffff,BD
+2001:df0:2c6::,2001:df0:2c8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2c9::,2001:df0:2c9:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2ca::,2001:df0:2ca:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2cb::,2001:df0:2cb:ffff:ffff:ffff:ffff:ffff,PK
+2001:df0:2cc::,2001:df0:2cc:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2cd::,2001:df0:2cd:ffff:ffff:ffff:ffff:ffff,MY
+2001:df0:2ce::,2001:df0:2e0:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2e1::,2001:df0:2e1:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2e2::,2001:df0:2e2:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2e3::,2001:df0:2e3:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2e4::,2001:df0:2e4:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2e5::,2001:df0:2e5:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2e6::,2001:df0:2e7:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2e8::,2001:df0:2e8:ffff:ffff:ffff:ffff:ffff,VN
+2001:df0:2e9::,2001:df0:2e9:ffff:ffff:ffff:ffff:ffff,CN
+2001:df0:2ea::,2001:df0:2ea:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:2eb::,2001:df0:2eb:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2ec::,2001:df0:2ec:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2ed::,2001:df0:2ee:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2ef::,2001:df0:2ef:ffff:ffff:ffff:ffff:ffff,PH
+2001:df0:2f0::,2001:df0:2f3:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2f4::,2001:df0:2f4:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2f5::,2001:df0:2f5:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:2f6::,2001:df0:2f6:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2f7::,2001:df0:2f7:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:2f8::,2001:df0:2f8:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2f9::,2001:df0:2f9:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2fa::,2001:df0:2fa:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:2fb::,2001:df0:2fb:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:2fc::,2001:df0:2fc:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:2fd::,2001:df0:2fd:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:2fe::,2001:df0:2ff:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:300::,2001:df0:30f:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:400::,2001:df0:400:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:401::,2001:df0:401:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:402::,2001:df0:403:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:404::,2001:df0:404:ffff:ffff:ffff:ffff:ffff,SG
+2001:df0:405::,2001:df0:405:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:406::,2001:df0:406:ffff:ffff:ffff:ffff:ffff,TH
+2001:df0:407::,2001:df0:407:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:408::,2001:df0:408:ffff:ffff:ffff:ffff:ffff,NZ
+2001:df0:409::,2001:df0:409:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:40a::,2001:df0:40a:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:40c::,2001:df0:40c:ffff:ffff:ffff:ffff:ffff,JP
+2001:df0:40d::,2001:df0:40d:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:40e::,2001:df0:40f:ffff:ffff:ffff:ffff:ffff,ID
+2001:df0:410::,2001:df0:410:ffff:ffff:ffff:ffff:ffff,VU
+2001:df0:411::,2001:df0:411:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:412::,2001:df0:412:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:413::,2001:df0:413:ffff:ffff:ffff:ffff:ffff,IN
+2001:df0:415::,2001:df0:415:ffff:ffff:ffff:ffff:ffff,AU
+2001:df0:416::,2001:df0:416:ffff:ffff:ffff:ffff:ffff,HK
+2001:df0:500::,2001:df0:5ff:ffff:ffff:ffff:ffff:ffff,AU
+2001:df8::,2001:df9:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:dfa::,2001:dfa:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e00::,2001:e01:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:e08::,2001:e08:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:e10::,2001:e10:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:e18::,2001:e18:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:e20::,2001:e20:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:e28::,2001:e28:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:e30::,2001:e30:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:e38::,2001:e38:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e40::,2001:e47:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e48::,2001:e48:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:e50::,2001:e50:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e58::,2001:e58:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e60::,2001:e60:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:e68::,2001:e68:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:e70::,2001:e70:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:e78::,2001:e78:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:e80::,2001:e80:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:e88::,2001:e88:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:e90::,2001:e90:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:e98::,2001:e98:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ea0::,2001:ea0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ea8::,2001:ea8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:eb0::,2001:eb0:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:eb8::,2001:eb8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ec0::,2001:ec0:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:ec8::,2001:ec8:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:ed0::,2001:ed0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ed8::,2001:ed8:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:ee0::,2001:ee0:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2001:ee8::,2001:ee8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ef0::,2001:ef0:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:ef8::,2001:ef8:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:f00::,2001:f00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:f08::,2001:f08:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:f10::,2001:f10:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:f18::,2001:f18:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:f20::,2001:f20:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:f28::,2001:f28:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:f30::,2001:f30:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:f38::,2001:f38:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:f40::,2001:f40:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:f48::,2001:f48:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:f50::,2001:f50:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:f58::,2001:f58:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:f60::,2001:f6f:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:f80::,2001:f80:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:f88::,2001:f88:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:f90::,2001:f90:ffff:ffff:ffff:ffff:ffff:ffff,MO
+2001:f98::,2001:f98:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fa0::,2001:fa0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fa8::,2001:fa8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fb0::,2001:fb1:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:fb8::,2001:fb8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fc0::,2001:fc0:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2001:fc8::,2001:fc8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:fd0::,2001:fd0:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:fd8::,2001:fd8:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:fe0::,2001:fe0:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:fe8::,2001:fe8:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2001:ff0::,2001:ff0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:ff8::,2001:ff8:ffff:ffff:ffff:ffff:ffff:ffff,MO
+2001:1200::,2001:1200:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1208::,2001:1208:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1210::,2001:1210:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1218::,2001:1218:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1220::,2001:1220:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1228::,2001:1228:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:122c::,2001:122c:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1230::,2001:1230:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1238::,2001:1238:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1240::,2001:1240:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1248::,2001:1248:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1250::,2001:1250:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1258::,2001:1258:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1260::,2001:1260:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1270::,2001:1270:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1278::,2001:1278:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:1280::,2001:12ff:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2001:1300::,2001:1300:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2001:1308::,2001:1308:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2001:1310::,2001:1310:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2001:1318::,2001:1318:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2001:1320::,2001:1320:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2001:1328::,2001:1328:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2001:1330::,2001:1337:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2001:1338::,2001:1338:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2001:1340::,2001:1340:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2001:1348::,2001:1348:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2001:1350::,2001:1350:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2001:1358::,2001:1358:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2001:1360::,2001:1360:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2001:1368::,2001:1368:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2001:1370::,2001:1370:ffff:ffff:ffff:ffff:ffff:ffff,HT
+2001:1378::,2001:1378:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2001:1380::,2001:1380:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2001:1388::,2001:1388:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2001:1398::,2001:1398:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2001:13a0::,2001:13a0:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2001:13a8::,2001:13a8:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2001:13b0::,2001:13b7:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2001:13c7:6000::,2001:13c7:6000:ffff:ffff:ffff:ffff:ffff,CO
+2001:13c7:6001::,2001:13c7:6001:ffff:ffff:ffff:ffff:ffff,AR
+2001:13c7:6002::,2001:13c7:6002:ffff:ffff:ffff:ffff:ffff,CW
+2001:13c7:6003::,2001:13c7:6003:ffff:ffff:ffff:ffff:ffff,HT
+2001:13c7:6004::,2001:13c7:6005:ffff:ffff:ffff:ffff:ffff,CW
+2001:13c7:6006::,2001:13c7:6006:ffff:ffff:ffff:ffff:ffff,EC
+2001:13c7:6007::,2001:13c7:600e:ffff:ffff:ffff:ffff:ffff,AR
+2001:13c7:6010::,2001:13c7:601f:ffff:ffff:ffff:ffff:ffff,AR
+2001:13c7:6f00::,2001:13c7:6fff:ffff:ffff:ffff:ffff:ffff,EC
+2001:13c7:7000::,2001:13c7:7000:ffff:ffff:ffff:ffff:ffff,MX
+2001:13c7:7001::,2001:13c7:7003:ffff:ffff:ffff:ffff:ffff,UY
+2001:13c7:7004::,2001:13c7:7004:ffff:ffff:ffff:ffff:ffff,CR
+2001:13c7:7005::,2001:13c7:7009:ffff:ffff:ffff:ffff:ffff,UY
+2001:13c7:7010::,2001:13c7:7013:ffff:ffff:ffff:ffff:ffff,UY
+2001:13c7:7014::,2001:13c7:7014:ffff:ffff:ffff:ffff:ffff,MX
+2001:13c8::,2001:13c8:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2001:13d0::,2001:13d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2001:13d8::,2001:13d8:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2001:13e0::,2001:13e0:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2001:13e8::,2001:13e8:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2001:13f0::,2001:13f0:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2001:13f8::,2001:13f8:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2001:1400::,2001:1400:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1408::,2001:1408:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:1410::,2001:1410:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1418::,2001:1418:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1420::,2001:1420:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1428::,2001:1428:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:1430::,2001:1430:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:1438::,2001:1438:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1440::,2001:1440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1448::,2001:1448:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:1450::,2001:1450:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1458::,2001:1459:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1460::,2001:1460:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1468::,2001:1468:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1470::,2001:1477:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2001:1478::,2001:1478:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1488::,2001:1488:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1490::,2001:1490:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2001:1498::,2001:1498:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:14a0::,2001:14a0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:14a8::,2001:14a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:14b0::,2001:14b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14b8::,2001:14b8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:14c0::,2001:14c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14c8::,2001:14c8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:14d0::,2001:14d0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:14d8::,2001:14d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14e0::,2001:14e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14e8::,2001:14e8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:14f0::,2001:14f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:14f8::,2001:14f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1500::,2001:1500:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:1508::,2001:1508:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1510::,2001:1510:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1520::,2001:1520:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1528::,2001:1528:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1530::,2001:1530:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:1538::,2001:1538:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1540::,2001:1540:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1548::,2001:1548:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2001:1558::,2001:1558:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1560::,2001:1560:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1568::,2001:1568:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1570::,2001:1570:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1578::,2001:1578:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1580::,2001:1580:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:1588::,2001:1588:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:1590::,2001:1590:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2001:1598::,2001:1598:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:15a0::,2001:15a0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:15a8::,2001:15a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:15b0::,2001:15b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:15b8::,2001:15b8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:15c0::,2001:15c0:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2001:15c8::,2001:15c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:15d0::,2001:15d0:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2001:15d8::,2001:15d8:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:15e0::,2001:15e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:15e8::,2001:15e8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:15f0::,2001:15f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:15f8::,2001:15f8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2001:1600::,2001:1600:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1608::,2001:1608:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1610::,2001:1610:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:1618::,2001:1618:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:1620::,2001:1620:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1628::,2001:1628:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1630::,2001:1630:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1638::,2001:1638:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1640::,2001:1640:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1650::,2001:1650:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1658::,2001:1658:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:1660::,2001:1660:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1668::,2001:1668:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1670::,2001:1670:ffff:ffff:ffff:ffff:ffff:ffff,OM
+2001:1678::,2001:1678:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1680::,2001:1687:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1688::,2001:1688:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2001:1690::,2001:1690:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1698::,2001:1698:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2001:16a0::,2001:16a7:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2001:16a8::,2001:16a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:16b0::,2001:16b0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:16b8::,2001:16b8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:16c0::,2001:16c0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:16c8::,2001:16c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:16d0::,2001:16d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:16d8::,2001:16d8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:16e0::,2001:16e7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:16e8::,2001:16e8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:16f0::,2001:16f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:16f8::,2001:16f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1700::,2001:171f:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1800::,2001:1800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1808::,2001:1808:ffff:ffff:ffff:ffff:ffff:ffff,GD
+2001:1810::,2001:1810:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1818::,2001:1818:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1820::,2001:1820:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1828::,2001:1828:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1830::,2001:1830:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1838::,2001:1838:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1840::,2001:1840:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1848::,2001:1848:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1850::,2001:1850:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1858::,2001:1858:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1860::,2001:1860:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1868::,2001:1868:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1878::,2001:1878:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1880::,2001:1880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1888::,2001:1888:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1890::,2001:1898:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18a0::,2001:18a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18a8::,2001:18a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18b0::,2001:18b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18b8::,2001:18b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18c0::,2001:18c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:18c8::,2001:18c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18d8::,2001:18d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18e0::,2001:18e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18e8::,2001:18e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:18f0::,2001:18f0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:18f8::,2001:18f8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:1900::,2001:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1908::,2001:1908:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1910::,2001:1910:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1920::,2001:1920:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:1928::,2001:1928:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:1930::,2001:1930:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1938::,2001:1938:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1940::,2001:1940:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1948::,2001:1948:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1950::,2001:1950:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1958::,2001:1958:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1960::,2001:1960:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1968::,2001:1968:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1970::,2001:1970:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:1978::,2001:1978:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1980::,2001:1980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1988::,2001:1988:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1990::,2001:1990:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1998::,2001:1998:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19a0::,2001:19a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19a8::,2001:19a8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:19b0::,2001:19b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19b8::,2001:19b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19c0::,2001:19c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:19c8::,2001:19c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19d0::,2001:19d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19d8::,2001:19d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19e0::,2001:19e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19e8::,2001:19e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19f0::,2001:19f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:19f8::,2001:19f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:1a00::,2001:1a00:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:1a08::,2001:1a08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1a10::,2001:1a10:ffff:ffff:ffff:ffff:ffff:ffff,QA
+2001:1a18::,2001:1a18:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2001:1a20::,2001:1a20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1a28::,2001:1a28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a30::,2001:1a30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a38::,2001:1a38:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1a40::,2001:1a40:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2001:1a48::,2001:1a48:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1a50::,2001:1a50:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a58::,2001:1a58:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:1a60::,2001:1a60:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1a68::,2001:1a68:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:1a70::,2001:1a70:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2001:1a78::,2001:1a78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a80::,2001:1a80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1a88::,2001:1a88:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1a90::,2001:1a90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1a98::,2001:1a98:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2001:1aa0::,2001:1aa0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2001:1aa8::,2001:1aa8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1ab0::,2001:1ab0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1ab8::,2001:1ab8:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2001:1ac0::,2001:1ac0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1ac8::,2001:1ac8:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2001:1ad0::,2001:1ad0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:1ad8::,2001:1ad8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:1ae0::,2001:1ae0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2001:1ae8::,2001:1aef:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:1af0::,2001:1af0:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2001:1af8::,2001:1af8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1b00::,2001:1b00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:1b08::,2001:1b08:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b10::,2001:1b10:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b18::,2001:1b18:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b20::,2001:1b20:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b28::,2001:1b28:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:1b30::,2001:1b30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b38::,2001:1b38:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b40::,2001:1b40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1b48::,2001:1b48:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b50::,2001:1b50:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:1b58::,2001:1b58:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b60::,2001:1b60:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1b68::,2001:1b68:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2001:1b70::,2001:1b70:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1b78::,2001:1b78:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:1b80::,2001:1b80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:1b88::,2001:1b88:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1b90::,2001:1b90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1b98::,2001:1b98:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:1ba0::,2001:1ba0:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2001:1ba8::,2001:1ba8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:1bb0::,2001:1bb0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:1bb8::,2001:1bb8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:1bc0::,2001:1bc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:1bc8::,2001:1bc8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:1bd0::,2001:1bd0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:1bd8::,2001:1bd8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:1be0::,2001:1be0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:1be8::,2001:1be8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:1bf0::,2001:1bf0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2001:1bf8::,2001:1bf8:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2001:1c00::,2001:1dff:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:2000::,2001:2fff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:4000::,2001:4000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4010::,2001:4010:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4018::,2001:4018:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4020::,2001:4020:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4028::,2001:4028:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4030::,2001:4030:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4038::,2001:4038:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4040::,2001:4040:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:4048::,2001:4048:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2001:4050::,2001:4050:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4058::,2001:4058:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:4060::,2001:4060:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4068::,2001:4068:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4070::,2001:4070:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4078::,2001:4078:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:4080::,2001:4080:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4088::,2001:4088:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4090::,2001:4090:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4098::,2001:4098:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2001:40a0::,2001:40a0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:40a8::,2001:40a8:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2001:40b0::,2001:40b0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:40b8::,2001:40b8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:40c0::,2001:40c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:40c8::,2001:40c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:40d0::,2001:40d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:40d8::,2001:40d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:40e0::,2001:40e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:40e8::,2001:40e8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2001:40f0::,2001:40f0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:40f8::,2001:40f8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4100::,2001:4100:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4108::,2001:4108:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4118::,2001:4118:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2001:4120::,2001:4120:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4128::,2001:4128:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4130::,2001:4130:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2001:4138::,2001:4138:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4140::,2001:4140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4150::,2001:4150:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4158::,2001:4158:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:4160::,2001:4160:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4168::,2001:4168:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4170::,2001:4170:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2001:4178::,2001:4178:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4180::,2001:4180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4188::,2001:4188:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:4190::,2001:4190:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4198::,2001:4198:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:41a0::,2001:41a0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:41a8::,2001:41a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:41b0::,2001:41b0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:41b8::,2001:41b8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:41c0::,2001:41c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:41d0::,2001:41d0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:41d8::,2001:41d8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:41e0::,2001:41e0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:41e8::,2001:41e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:41f0::,2001:41f0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:41f8::,2001:41f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4200::,2001:4200:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4208::,2001:4208:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4210::,2001:4210:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4218::,2001:4218:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4220::,2001:4220:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:4228::,2001:4228:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2001:4230::,2001:4230:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:4238::,2001:4238:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:4240::,2001:4240:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2001:4248::,2001:4248:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2001:4250::,2001:4250:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2001:4258::,2001:4258:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2001:4260::,2001:4260:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4268::,2001:4268:ffff:ffff:ffff:ffff:ffff:ffff,CM
+2001:4270::,2001:4270:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2001:4278::,2001:4278:ffff:ffff:ffff:ffff:ffff:ffff,SN
+2001:4288::,2001:4288:ffff:ffff:ffff:ffff:ffff:ffff,MA
+2001:4290::,2001:4290:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2001:4298::,2001:4298:ffff:ffff:ffff:ffff:ffff:ffff,DJ
+2001:42a0::,2001:42a0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:42a8::,2001:42a8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:42b0::,2001:42b0:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2001:42b8::,2001:42b8:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:42c0::,2001:42c0:ffff:ffff:ffff:ffff:ffff:ffff,ML
+2001:42c8::,2001:42c8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:42d0::,2001:42d0:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2001:42d8::,2001:42d8:ffff:ffff:ffff:ffff:ffff:ffff,CI
+2001:42e0::,2001:42e0:ffff:ffff:ffff:ffff:ffff:ffff,SC
+2001:42f0::,2001:42f0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:42f8::,2001:42f8:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2001:4300::,2001:4300:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:4308::,2001:4308:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4310::,2001:4310:ffff:ffff:ffff:ffff:ffff:ffff,MA
+2001:4318::,2001:4318:ffff:ffff:ffff:ffff:ffff:ffff,CI
+2001:4320::,2001:4320:ffff:ffff:ffff:ffff:ffff:ffff,BJ
+2001:4328::,2001:4328:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2001:4330::,2001:4330:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:4338::,2001:4338:ffff:ffff:ffff:ffff:ffff:ffff,SZ
+2001:4340::,2001:4340:ffff:ffff:ffff:ffff:ffff:ffff,DZ
+2001:4350::,2001:4350:ffff:ffff:ffff:ffff:ffff:ffff,TN
+2001:4358::,2001:4358:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:4368::,2001:4368:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:4370::,2001:4370:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:4378::,2001:4378:ffff:ffff:ffff:ffff:ffff:ffff,MZ
+2001:4388::,2001:4388:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:4398::,2001:4398:ffff:ffff:ffff:ffff:ffff:ffff,MG
+2001:43a0::,2001:43a0:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43a8::,2001:43a8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43b0::,2001:43b0:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2001:43b8::,2001:43b8:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2001:43c0::,2001:43c0:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2001:43c8::,2001:43c8:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2001:43d0::,2001:43d0:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2001:43d8::,2001:43d8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43e0::,2001:43e0:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2001:43e8::,2001:43e8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f0::,2001:43f0:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2001:43f8::,2001:43f8:0:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:10::,2001:43f8:10:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:20::,2001:43f8:20:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:30::,2001:43f8:30:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:50::,2001:43f8:50:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:60::,2001:43f8:60:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:70::,2001:43f8:77:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:80::,2001:43f8:80:ffff:ffff:ffff:ffff:ffff,NA
+2001:43f8:90::,2001:43f8:90:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:a0::,2001:43f8:a0:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:b0::,2001:43f8:b0:ffff:ffff:ffff:ffff:ffff,SL
+2001:43f8:c0::,2001:43f8:c0:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:d0::,2001:43f8:d0:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:e0::,2001:43f8:e0:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:100::,2001:43f8:100:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:110::,2001:43f8:110:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:120::,2001:43f8:120:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:130::,2001:43f8:130:ffff:ffff:ffff:ffff:ffff,UG
+2001:43f8:140::,2001:43f8:140:ffff:ffff:ffff:ffff:ffff,ZM
+2001:43f8:150::,2001:43f8:150:ffff:ffff:ffff:ffff:ffff,RW
+2001:43f8:160::,2001:43f8:160:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:170::,2001:43f8:170:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:180::,2001:43f8:180:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:1a0::,2001:43f8:1a0:ffff:ffff:ffff:ffff:ffff,GH
+2001:43f8:1c0::,2001:43f8:1c0:ffff:ffff:ffff:ffff:ffff,DZ
+2001:43f8:1d0::,2001:43f8:1d0:ffff:ffff:ffff:ffff:ffff,GH
+2001:43f8:1e0::,2001:43f8:1e0:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:1f0::,2001:43f8:1f2:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:200::,2001:43f8:200:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:210::,2001:43f8:210:ffff:ffff:ffff:ffff:ffff,LS
+2001:43f8:220::,2001:43f8:220:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:230::,2001:43f8:230:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:240::,2001:43f8:241:ffff:ffff:ffff:ffff:ffff,GH
+2001:43f8:250::,2001:43f8:250:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:260::,2001:43f8:260:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:270::,2001:43f8:270:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:290::,2001:43f8:290:ffff:ffff:ffff:ffff:ffff,MG
+2001:43f8:2a0::,2001:43f8:2a0:ffff:ffff:ffff:ffff:ffff,BW
+2001:43f8:2b0::,2001:43f8:2b0:ffff:ffff:ffff:ffff:ffff,BW
+2001:43f8:2c0::,2001:43f8:2c0:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:2e0::,2001:43f8:2e0:ffff:ffff:ffff:ffff:ffff,EG
+2001:43f8:2f0::,2001:43f8:2f0:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:300::,2001:43f8:300:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:310::,2001:43f8:310:ffff:ffff:ffff:ffff:ffff,ZW
+2001:43f8:320::,2001:43f8:320:ffff:ffff:ffff:ffff:ffff,TN
+2001:43f8:330::,2001:43f8:330:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:340::,2001:43f8:340:ffff:ffff:ffff:ffff:ffff,KE
+2001:43f8:360::,2001:43f8:360:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:370::,2001:43f8:370:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:380::,2001:43f8:380:ffff:ffff:ffff:ffff:ffff,MW
+2001:43f8:390::,2001:43f8:390:ffff:ffff:ffff:ffff:ffff,AO
+2001:43f8:3a0::,2001:43f8:3a0:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:3b0::,2001:43f8:3b0:ffff:ffff:ffff:ffff:ffff,NA
+2001:43f8:3c0::,2001:43f8:3c0:ffff:ffff:ffff:ffff:ffff,CD
+2001:43f8:400::,2001:43f8:4ff:ffff:ffff:ffff:ffff:ffff,AO
+2001:43f8:600::,2001:43f8:60f:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:610::,2001:43f8:610:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:620::,2001:43f8:620:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:630::,2001:43f8:630:ffff:ffff:ffff:ffff:ffff,MW
+2001:43f8:640::,2001:43f8:640:ffff:ffff:ffff:ffff:ffff,MZ
+2001:43f8:650::,2001:43f8:650:ffff:ffff:ffff:ffff:ffff,MA
+2001:43f8:660::,2001:43f8:660:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:670::,2001:43f8:670:ffff:ffff:ffff:ffff:ffff,AO
+2001:43f8:680::,2001:43f8:680:ffff:ffff:ffff:ffff:ffff,TZ
+2001:43f8:690::,2001:43f8:690:ffff:ffff:ffff:ffff:ffff,MU
+2001:43f8:6a0::,2001:43f8:6a0:ffff:ffff:ffff:ffff:ffff,CG
+2001:43f8:6b0::,2001:43f8:6b3:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:6c0::,2001:43f8:6c0:ffff:ffff:ffff:ffff:ffff,NG
+2001:43f8:6d0::,2001:43f8:6d3:ffff:ffff:ffff:ffff:ffff,ZA
+2001:43f8:6e0::,2001:43f8:6e0:ffff:ffff:ffff:ffff:ffff,KE
+2001:4400::,2001:4403:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:4408::,2001:4408:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:4410::,2001:4410:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:4418::,2001:4418:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:4420::,2001:4420:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4428::,2001:4428:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:4430::,2001:4430:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:4438::,2001:4438:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:4450::,2001:4450:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2001:4458::,2001:4458:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:4460::,2001:4460:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:4470::,2001:4470:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:4478::,2001:447b:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:4480::,2001:4480:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2001:4488::,2001:448b:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2001:4490::,2001:4493:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:4498::,2001:4498:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2001:44a0::,2001:44a0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:44a8::,2001:44a8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:44b0::,2001:44b0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:44b8::,2001:44b8:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:44c0::,2001:44c0:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:44c8::,2001:44c8:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2001:44d0::,2001:44df:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2001:44f0::,2001:44f0:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4500::,2001:4500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4508::,2001:4508:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4510::,2001:4517:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2001:4520::,2001:4520:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:4528::,2001:452b:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2001:4530::,2001:4530:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2001:4538::,2001:4538:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2001:4540::,2001:455f:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4580::,2001:45bf:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2001:4600::,2001:46ff:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4800::,2001:4808:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4810::,2001:4810:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4818::,2001:4818:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4828::,2001:4828:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4830::,2001:4830:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4838::,2001:4838:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4840::,2001:4840:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4848::,2001:4848:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4850::,2001:4850:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4858::,2001:4858:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4860::,2001:4860:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4868::,2001:4868:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4870::,2001:4871:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4878::,2001:4878:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4880::,2001:4880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4888::,2001:4888:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4890::,2001:4890:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4898::,2001:489a:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48a0::,2001:48a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48a8::,2001:48a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48b0::,2001:48b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48b8::,2001:48b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48c0::,2001:48c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48c8::,2001:48c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48d0::,2001:48d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48d8::,2001:48d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48e0::,2001:48e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48e8::,2001:48e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48f0::,2001:48f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:48f8::,2001:48f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4900::,2001:4900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4908::,2001:4908:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4910::,2001:4910:ffff:ffff:ffff:ffff:ffff:ffff,BM
+2001:4918::,2001:4918:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4920::,2001:4920:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4928::,2001:4928:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4930::,2001:4930:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4938::,2001:4938:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4940::,2001:4940:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4948::,2001:4948:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4950::,2001:4950:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4958::,2001:4958:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2001:4960::,2001:4960:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4968::,2001:4968:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4970::,2001:4970:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4978::,2001:4978:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4980::,2001:4980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4988::,2001:4988:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4990::,2001:4990:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4998::,2001:4998:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49a0::,2001:49a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49a8::,2001:49a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49b0::,2001:49b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49b8::,2001:49b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49c0::,2001:49c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49c8::,2001:49c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49d0::,2001:49d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49d8::,2001:49d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49e0::,2001:49e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49e8::,2001:49e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49f0::,2001:49f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:49f8::,2001:49f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2001:4a00::,2001:4a1f:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4b00::,2001:4b00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4b08::,2001:4b08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4b10::,2001:4b10:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4b18::,2001:4b18:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4b20::,2001:4b20:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4b28::,2001:4b28:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4b30::,2001:4b30:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4b38::,2001:4b38:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4b40::,2001:4b40:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4b48::,2001:4b48:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4b50::,2001:4b50:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:4b58::,2001:4b58:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2001:4b60::,2001:4b60:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4b68::,2001:4b68:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4b70::,2001:4b70:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4b78::,2001:4b78:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4b80::,2001:4b80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4b88::,2001:4b88:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4b90::,2001:4b90:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4b98::,2001:4b98:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2001:4ba0::,2001:4ba0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ba8::,2001:4ba8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:4bb0::,2001:4bb0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4bb8::,2001:4bb8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4bc0::,2001:4bc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4bc8::,2001:4bc8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2001:4bd0::,2001:4bd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4bd8::,2001:4bd8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4be0::,2001:4be0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2001:4be8::,2001:4be8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4bf0::,2001:4bf0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4bf8::,2001:4bf8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4c00::,2001:4c00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4c08::,2001:4c08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4c10::,2001:4c10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4c20::,2001:4c20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4c28::,2001:4c28:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4c30::,2001:4c30:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4c38::,2001:4c38:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4c40::,2001:4c40:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2001:4c48::,2001:4c4f:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2001:4c50::,2001:4c57:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4c58::,2001:4c58:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4c60::,2001:4c60:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4c68::,2001:4c68:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4c70::,2001:4c70:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2001:4c78::,2001:4c78:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4c80::,2001:4c80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4c88::,2001:4c88:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2001:4c90::,2001:4c90:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4c98::,2001:4c98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ca0::,2001:4ca0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ca8::,2001:4ca8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4cb0::,2001:4cb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4cb8::,2001:4cb8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4cc0::,2001:4cc0:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2001:4cc8::,2001:4cc8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:4cd0::,2001:4cd0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2001:4cd8::,2001:4cd8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ce0::,2001:4ce0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4ce8::,2001:4cf0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4cf8::,2001:4cf8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d00::,2001:4d00:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2001:4d08::,2001:4d08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d10::,2001:4d10:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4d18::,2001:4d18:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2001:4d20::,2001:4d20:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d28::,2001:4d28:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4d30::,2001:4d30:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4d38::,2001:4d38:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2001:4d40::,2001:4d40:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:4d48::,2001:4d48:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4d50::,2001:4d50:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d58::,2001:4d58:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4d60::,2001:4d60:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4d68::,2001:4d68:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2001:4d70::,2001:4d70:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2001:4d78::,2001:4d78:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4d80::,2001:4d80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2001:4d88::,2001:4d88:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4d90::,2001:4d90:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2001:4d98::,2001:4d98:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4da0::,2001:4da7:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2001:4da8::,2001:4da8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4db0::,2001:4db0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4db8::,2001:4db8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2001:4dc0::,2001:4dc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2001:4dc8::,2001:4dc8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4dd0::,2001:4dd7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2001:4dd8::,2001:4dd8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2001:4de0::,2001:4de0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2001:4de8::,2001:4de8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2001:4df0::,2001:4df0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2001:5000::,2001:57ff:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2001:8000::,2001:8fff:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2001:a000::,2001:a7ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2001:b000::,2001:b7ff:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2003::,2003:1fff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2400::,2400:fff:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:1000::,2400:1000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:1100::,2400:1100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:1200::,2400:1200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:1300::,2400:1300:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2400:1400::,2400:1400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:1500::,2400:1500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2400:1600::,2400:1600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:1700::,2400:1700:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:1800::,2400:1800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:1900::,2400:1900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:1a00::,2400:1a00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:1b00::,2400:1b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:1c00::,2400:1c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:1d00::,2400:1d00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:1e00::,2400:1e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:1f00::,2400:1f00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:2000::,2400:3000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:3100::,2400:3100:ffff:ffff:ffff:ffff:ffff:ffff,VU
+2400:3200::,2400:3200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:3300::,2400:3300:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:3400::,2400:3400:ffff:ffff:ffff:ffff:ffff:ffff,VU
+2400:3500::,2400:3500:ffff:ffff:ffff:ffff:ffff:ffff,TV
+2400:3600::,2400:3600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:3700::,2400:3700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:3800::,2400:3800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:3900::,2400:3900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:3a00::,2400:3a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:3b00::,2400:3b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:3c00::,2400:3c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:3d00::,2400:3d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:3e00::,2400:3e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:3f00::,2400:3f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:4000::,2400:43ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:4400::,2400:4400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:4500::,2400:4500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2400:4600::,2400:4600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:4700::,2400:4700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:4800::,2400:4800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:4900::,2400:4900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:4a00::,2400:4a00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:4b00::,2400:4b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:4c00::,2400:4c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:4d00::,2400:4d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:4e00::,2400:4e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:4f00::,2400:4f00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2400:5000::,2400:5000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:5100::,2400:5100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:5200::,2400:5200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:5300::,2400:5300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:5400::,2400:5400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:5500::,2400:5500:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:5600::,2400:5600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:5700::,2400:5700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:5800::,2400:5800:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2400:5900::,2400:5900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:5a00::,2400:5a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:5b00::,2400:5b00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:5c00::,2400:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:5d00::,2400:5d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:5e00::,2400:5e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:5f00::,2400:5f00:ffff:ffff:ffff:ffff:ffff:ffff,PF
+2400:6000::,2400:6000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6100::,2400:6100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:6200::,2400:6200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6300::,2400:6300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:6400::,2400:6400:ffff:ffff:ffff:ffff:ffff:ffff,TO
+2400:6500::,2400:6500:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:6600::,2400:6600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6700::,2400:6700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:6800::,2400:6800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:6900::,2400:6900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:6a00::,2400:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6b00::,2400:6b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:6c00::,2400:6c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:6d00::,2400:6d00:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2400:6e00::,2400:6e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:6f00::,2400:6f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:7000::,2400:7000:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2400:7100::,2400:7100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:7200::,2400:7200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:7300::,2400:7300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:7400::,2400:7400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:7500::,2400:7500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:7600::,2400:7600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:7700::,2400:7700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:7800::,2400:7800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:7900::,2400:7900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:7a00::,2400:7a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:7b00::,2400:7b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:7c00::,2400:7c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:7d00::,2400:7d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:7e00::,2400:7e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:7f00::,2400:7f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:8000::,2400:8000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:8100::,2400:8100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:8200::,2400:8200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:8300::,2400:8300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:8400::,2400:8400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:8500::,2400:8500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:8600::,2400:8600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:8700::,2400:8700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:8800::,2400:8800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:8900::,2400:8900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:8a00::,2400:8a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:8b00::,2400:8b00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:8c00::,2400:8c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:8d00::,2400:8d00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:8e00::,2400:8e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:8f00::,2400:8f00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:9000::,2400:9000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:9100::,2400:9100:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2400:9200::,2400:9200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:9300::,2400:9300:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2400:9400::,2400:9400:ffff:ffff:ffff:ffff:ffff:ffff,BN
+2400:9500::,2400:9500:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:9600::,2400:9600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:9700::,2400:9700:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:9800::,2400:9800:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:9900::,2400:9900:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:9a00::,2400:9a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:9b00::,2400:9b00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:9c00::,2400:9c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:9d00::,2400:9d00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:9e00::,2400:9e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:a000::,2400:a000:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:a100::,2400:a100:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:a300::,2400:a300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:a400::,2400:a400:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2400:a500::,2400:a500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:a600::,2400:a600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:a700::,2400:a700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:a800::,2400:a800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:a900::,2400:a900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:aa00::,2400:aa00:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2400:ab00::,2400:ab00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:ac00::,2400:ac00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:ad00::,2400:ad00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:ae00::,2400:ae00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:af00::,2400:af00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:b000::,2400:b000:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:b100::,2400:b100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:b200::,2400:b200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:b300::,2400:b300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:b400::,2400:b400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:b500::,2400:b500:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:b600::,2400:b600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:b700::,2400:b700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:b800::,2400:b800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:b900::,2400:b900:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:ba00::,2400:ba00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:bb00::,2400:bb00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:bc00::,2400:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:bd00::,2400:bd00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:be00::,2400:be00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:bf00::,2400:bf00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:c000::,2400:c000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:c100::,2400:c100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:c200::,2400:c200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:c300::,2400:c300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:c400::,2400:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:c500::,2400:c500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:c600::,2400:c600:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2400:c700::,2400:c700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:c800::,2400:c800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:c900::,2400:c900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:ca00::,2400:ca00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2400:cb00::,2400:cb00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:cc00::,2400:cc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:cd00::,2400:cd00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2400:ce00::,2400:ce00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:cf00::,2400:cf00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2400:d000::,2400:d000:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:d100::,2400:d100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:d200::,2400:d200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:d300::,2400:d300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:d400::,2400:d400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:d500::,2400:d500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:d600::,2400:d600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:d700::,2400:d700:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:d800::,2400:d803:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:d900::,2400:d900:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2400:da00::,2400:da00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:db00::,2400:db00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:dc00::,2400:dc00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:dd00::,2400:dd0f:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:de00::,2400:de00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:df00::,2400:df00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:e000::,2400:e000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:e100::,2400:e100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:e200::,2400:e200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:e300::,2400:e300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:e400::,2400:e400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:e500::,2400:e500:ffff:ffff:ffff:ffff:ffff:ffff,AF
+2400:e700::,2400:e700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2400:e800::,2400:e800:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2400:e900::,2400:e900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:ea00::,2400:ea00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2400:eb00::,2400:eb00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:ec00::,2400:ec00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:ed00::,2400:ed00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2400:ee00::,2400:ee00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:ef00::,2400:ef00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f000::,2400:f000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f100::,2400:f100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f200::,2400:f200:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:f300::,2400:f300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2400:f400::,2400:f400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2400:f600::,2400:f600:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2400:f700::,2400:f700:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f800::,2400:f800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2400:f900::,2400:f900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:fa00::,2400:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2400:fb00::,2400:fb00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2400:fc00::,2400:fc00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2400:fd00::,2400:fd00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2400:fe00::,2400:fe00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2400:ff00::,2400:ff00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2401::,2401:0:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:100::,2401:100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:200::,2401:200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:300::,2401:300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:400::,2401:400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:500::,2401:500:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:600::,2401:600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:700::,2401:700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:800::,2401:800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:900::,2401:900:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:a00::,2401:a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:b00::,2401:b00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:c00::,2401:c00:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2401:d00::,2401:d00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:e00::,2401:e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:f00::,2401:f00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:1000::,2401:1000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:1100::,2401:1100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:1200::,2401:1200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:1300::,2401:1300:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:1400::,2401:1400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:1500::,2401:1500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:1600::,2401:1600:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:1700::,2401:1700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:1800::,2401:1800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:1900::,2401:1900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:1a00::,2401:1a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:1b00::,2401:1b00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:1c00::,2401:1c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:1d00::,2401:1d00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:1e00::,2401:1e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:1f00::,2401:1f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:2000::,2401:2000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:2001::,2401:2001:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:2100::,2401:2100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:2200::,2401:2200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:2300::,2401:2300:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:2400::,2401:2400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:2500::,2401:2500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:2600::,2401:2600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:2700::,2401:2700:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:2800::,2401:2800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:2900::,2401:2900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:2a00::,2401:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:2b00::,2401:2b00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:2c00::,2401:2c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:2d00::,2401:2d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:2e00::,2401:2e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:2f00::,2401:2f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:3000::,2401:3000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:3100::,2401:3100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:3200::,2401:3200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:3300::,2401:3300:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:3400::,2401:3400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:3500::,2401:3500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:3600::,2401:3600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:3700::,2401:3700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:3800::,2401:3800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:3900::,2401:3900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:3a00::,2401:3a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:3b00::,2401:3b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:3c00::,2401:3c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:3d00::,2401:3d0f:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:3e00::,2401:3e00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2401:3f00::,2401:3f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:4000::,2401:4000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:4100::,2401:4100:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:4200::,2401:4200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:4300::,2401:4300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:4400::,2401:4400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:4500::,2401:4500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:4600::,2401:4600:ffff:ffff:ffff:ffff:ffff:ffff,AP
+2401:4700::,2401:4700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:4800::,2401:4800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:4900::,2401:4900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:4a00::,2401:4a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:4b00::,2401:4b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:4c00::,2401:4c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:4d00::,2401:4d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:4e00::,2401:4e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:4f00::,2401:4f00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:5000::,2401:5000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:5100::,2401:5100:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2401:5200::,2401:5200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:5300::,2401:5300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:5400::,2401:5400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:5500::,2401:5500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:5700::,2401:5700:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:5800::,2401:5800:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:5900::,2401:5900:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:5a00::,2401:5a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:5b00::,2401:5b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:5c00::,2401:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:5d00::,2401:5d00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:5e00::,2401:5e00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:5f00::,2401:5f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:6000::,2401:6fff:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7000::,2401:7000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:7100::,2401:7100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7200::,2401:7200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7300::,2401:7300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7400::,2401:7401:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:7500::,2401:7500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:7600::,2401:7600:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:7700::,2401:7700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:7800::,2401:7800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:7900::,2401:7900:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2401:7a00::,2401:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:7b00::,2401:7b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:7c00::,2401:7c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:7d00::,2401:7d00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:7e00::,2401:7e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:7f00::,2401:7f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:8000::,2401:803f:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:8100::,2401:8100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:8200::,2401:8200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:8300::,2401:8300:ffff:ffff:ffff:ffff:ffff:ffff,MV
+2401:8400::,2401:8400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:8500::,2401:8500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:8600::,2401:8600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:8700::,2401:8700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:8800::,2401:8800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:8900::,2401:8900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:8a00::,2401:8a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:8b00::,2401:8b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:8c00::,2401:8c01:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:8d00::,2401:8d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:8e00::,2401:8e00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:8f00::,2401:8f00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:9000::,2401:9000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:9100::,2401:9100:ffff:ffff:ffff:ffff:ffff:ffff,MO
+2401:9200::,2401:9200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:9300::,2401:9300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:9400::,2401:9400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:9500::,2401:9500:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:9600::,2401:9600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:9700::,2401:9700:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2401:9800::,2401:9800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:9900::,2401:9900:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2401:9a00::,2401:9a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:9b00::,2401:9b00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:9c00::,2401:9c00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:9d00::,2401:9d00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:9e00::,2401:9e00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:9f00::,2401:9f00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:a000::,2401:a000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:a100::,2401:a100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:a200::,2401:a200:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:a300::,2401:a300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:a400::,2401:a400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:a500::,2401:a500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:a600::,2401:a600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:a700::,2401:a700:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2401:a800::,2401:a800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:a900::,2401:a900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:aa00::,2401:aa00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:ab00::,2401:ab00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2401:ac00::,2401:ac00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:ad00::,2401:ad00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:ae00::,2401:ae00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:af00::,2401:af00:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2401:b000::,2401:b000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:b100::,2401:b100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:b200::,2401:b200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:b300::,2401:b300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:b400::,2401:b400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:b500::,2401:b500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:b600::,2401:b600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:b700::,2401:b700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:b800::,2401:b800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2401:b900::,2401:b900:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:ba00::,2401:ba00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:bb00::,2401:bb00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:bc00::,2401:bc00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2401:bd00::,2401:bd00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:be00::,2401:be00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:bf00::,2401:bf00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:c000::,2401:c000:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:c100::,2401:c100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:c200::,2401:c200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:c300::,2401:c300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:c400::,2401:c400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:c500::,2401:c500:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:c600::,2401:c600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:c700::,2401:c700:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:c800::,2401:c800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:c900::,2401:c900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:ca00::,2401:ca00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:cb00::,2401:cb00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2401:cc00::,2401:cc00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:cd00::,2401:cd00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:ce00::,2401:ce00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:cf00::,2401:cf00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:d000::,2401:d000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:d100::,2401:d100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:d200::,2401:d200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:d300::,2401:d300:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:d400::,2401:d400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:d500::,2401:d500:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:d600::,2401:d600:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2401:d700::,2401:d700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:d800::,2401:d800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2401:d900::,2401:d900:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:da00::,2401:da00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:db00::,2401:db00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:dc00::,2401:dc00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:dd00::,2401:dd00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2401:de00::,2401:de00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:df00::,2401:df01:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:e000::,2401:e000:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2401:e100::,2401:e100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:e200::,2401:e200:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2401:e300::,2401:e300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:e400::,2401:e400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:e500::,2401:e500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:e600::,2401:e600:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2401:e700::,2401:e700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:e800::,2401:e800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2401:e900::,2401:e900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2401:ea00::,2401:ea00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2401:eb00::,2401:eb00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:ec00::,2401:ec00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:ed00::,2401:ed00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:ee00::,2401:ee00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2401:ef00::,2401:ef00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:f000::,2401:f000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:f100::,2401:f100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:f200::,2401:f200:ffff:ffff:ffff:ffff:ffff:ffff,MM
+2401:f300::,2401:f300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2401:f400::,2401:f400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2401:f500::,2401:f500:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2401:f600::,2401:f600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:f700::,2401:f700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:f800::,2401:f800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2401:f900::,2401:f900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2401:fa00::,2401:fa00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:fb00::,2401:fb00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2401:fc00::,2401:fc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:fd00::,2401:fd00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2401:fe00::,2401:fe00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2401:ff00::,2401:ff00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402::,2402:3ff:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:400::,2402:400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:500::,2402:500:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:600::,2402:600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:700::,2402:700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:800::,2402:800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2402:900::,2402:900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:a00::,2402:a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:b00::,2402:b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:c00::,2402:c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:d00::,2402:d00:ffff:ffff:ffff:ffff:ffff:ffff,AF
+2402:e00::,2402:e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:f00::,2402:f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1000::,2402:1000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:1100::,2402:1100:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:1200::,2402:1200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:1300::,2402:1300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1400::,2402:1400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:1500::,2402:1500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:1600::,2402:1600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:1700::,2402:1700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1800::,2402:1800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1900::,2402:1900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1a00::,2402:1a00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:1b00::,2402:1b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:1c00::,2402:1c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:1d00::,2402:1d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:1e00::,2402:1e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:1f00::,2402:1f00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:2000::,2402:2000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:2100::,2402:2100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:2200::,2402:2200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:2300::,2402:2300:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2402:2400::,2402:2400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:2500::,2402:2500:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:2600::,2402:2600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:2700::,2402:2700:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2402:2800::,2402:2800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:2900::,2402:2900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:2a00::,2402:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:2b00::,2402:2b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:2c00::,2402:2c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:2d00::,2402:2d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:2e00::,2402:2e00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2402:2f00::,2402:2f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3000::,2402:3000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:3100::,2402:3100:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:3200::,2402:3200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3300::,2402:3300:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:3400::,2402:3400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3500::,2402:3500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3600::,2402:3600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3700::,2402:3700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:3800::,2402:3800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:3900::,2402:3900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3a00::,2402:3a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:3b00::,2402:3b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:3c00::,2402:3c00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:3d00::,2402:3d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:3e00::,2402:3e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:3f00::,2402:3f00:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2402:4000::,2402:4000:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2402:4100::,2402:4100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:4200::,2402:4200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:4300::,2402:4300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:4400::,2402:4400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:4500::,2402:4500:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:4600::,2402:4600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:4700::,2402:4700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:4800::,2402:4800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:4900::,2402:4900:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2402:4a00::,2402:4a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:4b00::,2402:4b00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:4c00::,2402:4c01:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:4d00::,2402:4d00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:4e00::,2402:4e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:4f00::,2402:4f00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:5100::,2402:5100:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2402:5200::,2402:5200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:5300::,2402:5300:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2402:5400::,2402:5400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:5500::,2402:5500:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2402:5600::,2402:5600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:5700::,2402:5700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:5800::,2402:5800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:5900::,2402:5900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:5a00::,2402:5a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:5b00::,2402:5b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:5c00::,2402:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:5d00::,2402:5d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:5e00::,2402:5e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:5f00::,2402:5f00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:6000::,2402:6000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:6100::,2402:6100:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:6200::,2402:6200:ffff:ffff:ffff:ffff:ffff:ffff,GU
+2402:6300::,2402:6300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6400::,2402:6400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6500::,2402:6500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6600::,2402:6600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6700::,2402:6700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:6800::,2402:6800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:6900::,2402:6900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:6a00::,2402:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:6b00::,2402:6b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:6c00::,2402:6c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:6d00::,2402:6d00:ffff:ffff:ffff:ffff:ffff:ffff,PF
+2402:6e00::,2402:6e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:6f00::,2402:6f00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:7000::,2402:7000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:7100::,2402:7100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:7200::,2402:7200:ffff:ffff:ffff:ffff:ffff:ffff,TK
+2402:7300::,2402:7300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2402:7400::,2402:7400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:7500::,2402:7500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2402:7600::,2402:7600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:7700::,2402:7700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:7800::,2402:7800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:7900::,2402:7900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:7a00::,2402:7a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:7b00::,2402:7b00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:7c00::,2402:7c00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2402:7d00::,2402:7d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:7e00::,2402:7e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:7f00::,2402:7f00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8000::,2402:8000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:8100::,2402:8100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8200::,2402:8200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:8300::,2402:8300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:8400::,2402:8400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8500::,2402:8500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:8600::,2402:8600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:8700::,2402:8700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:8800::,2402:8800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:8900::,2402:8900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:8a00::,2402:8a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8b00::,2402:8b00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:8c00::,2402:8c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8d00::,2402:8d03:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:8e00::,2402:8e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:8f00::,2402:8f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:9100::,2402:9100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9200::,2402:9200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9300::,2402:9300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:9400::,2402:9400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9500::,2402:9500:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:9700::,2402:9700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9800::,2402:9800:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:9900::,2402:9900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:9a00::,2402:9a00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:9b00::,2402:9b00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2402:9c00::,2402:9c00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2402:9d00::,2402:9d00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2402:9e00::,2402:9e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:9f00::,2402:9f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:a000::,2402:a000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:a100::,2402:a100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:a200::,2402:a200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:a300::,2402:a300:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2402:a400::,2402:a400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:a500::,2402:a500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:a600::,2402:a600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:a700::,2402:a700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:a800::,2402:a800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:a900::,2402:a900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:aa00::,2402:aa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ab00::,2402:ab00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:ac00::,2402:ac00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:ad00::,2402:ad00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ae00::,2402:ae00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:af00::,2402:af00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:b000::,2402:b000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:b100::,2402:b100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:b200::,2402:b200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:b300::,2402:b300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:b400::,2402:b400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:b500::,2402:b500:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2402:b600::,2402:b600:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2402:b700::,2402:b700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:b800::,2402:b801:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:b900::,2402:b900:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2402:ba00::,2402:ba00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2402:bb00::,2402:bb00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:bc00::,2402:bc07:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:bd00::,2402:bd00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:be00::,2402:be00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:bf00::,2402:bf00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2402:c000::,2402:c000:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2402:c100::,2402:c100:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2402:c200::,2402:c200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:c300::,2402:c300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:c400::,2402:c400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:c500::,2402:c500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:c600::,2402:c600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:c700::,2402:c700:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2402:c800::,2402:c800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:c900::,2402:c900:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2402:ca00::,2402:ca00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:cb00::,2402:cb00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2402:cc00::,2402:cc00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:cd00::,2402:cd00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:ce00::,2402:ce00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:cf00::,2402:cf00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:d000::,2402:d000:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2402:d100::,2402:d100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:d200::,2402:d200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:d300::,2402:d300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:d400::,2402:d400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:d500::,2402:d500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:d600::,2402:d600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:d700::,2402:d700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:d800::,2402:d800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:d900::,2402:d900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:da00::,2402:da00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:db00::,2402:db00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:dc00::,2402:dc00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:dd00::,2402:dd00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:de00::,2402:de00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:df00::,2402:df00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:e000::,2402:e000:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2402:e100::,2402:e100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:e200::,2402:e200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:e300::,2402:e300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:e400::,2402:e400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:e500::,2402:e500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:e600::,2402:e600:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2402:e800::,2402:e800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:e900::,2402:e900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ea00::,2402:ea00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:eb00::,2402:eb00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ec00::,2402:ec00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ed00::,2402:ed00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2402:ee00::,2402:ee00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:ef00::,2402:ef3f:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:f000::,2402:f000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2402:f100::,2402:f100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:f200::,2402:f200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2402:f300::,2402:f300:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:f400::,2402:f400:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2402:f500::,2402:f500:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2402:f600::,2402:f600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:f700::,2402:f700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:f800::,2402:f800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2402:f900::,2402:f900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2402:fa00::,2402:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2402:fb00::,2402:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2402:fc00::,2402:fc00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2402:fd00::,2402:fd00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2402:fe00::,2402:fe00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2402:ff00::,2402:ff00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403::,2403:1:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:100::,2403:100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:200::,2403:200:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2403:300::,2403:300:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:400::,2403:400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:500::,2403:500:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2403:600::,2403:600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:700::,2403:700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:800::,2403:801:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:900::,2403:900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:a00::,2403:a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:b00::,2403:b00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:c00::,2403:c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:d00::,2403:d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:e00::,2403:e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:f00::,2403:f00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:1000::,2403:1000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:1100::,2403:1100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:1300::,2403:1300:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:1400::,2403:1400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:1500::,2403:1500:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:1600::,2403:1600:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2403:1700::,2403:1700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:1800::,2403:1800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:1900::,2403:1900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:1a00::,2403:1a00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:1b00::,2403:1b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:1c00::,2403:1c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:1d00::,2403:1d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:1e00::,2403:1e00:ffff:ffff:ffff:ffff:ffff:ffff,AS
+2403:1f00::,2403:1f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:2000::,2403:2000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:2100::,2403:2100:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:2200::,2403:2200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:2300::,2403:2300:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:2400::,2403:2400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:2500::,2403:2500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:2600::,2403:2600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:2700::,2403:2700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:2800::,2403:2801:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:2900::,2403:2900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:2a00::,2403:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:2b00::,2403:2b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:2c00::,2403:2c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:2d00::,2403:2d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:2e00::,2403:2e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:2f00::,2403:2f00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:3100::,2403:3100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:3200::,2403:3200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:3300::,2403:3300:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2403:3400::,2403:3400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3500::,2403:3500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3600::,2403:3600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3700::,2403:3700:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2403:3800::,2403:3800:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2403:3900::,2403:3900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:3a00::,2403:3a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:3b00::,2403:3b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3c00::,2403:3c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:3d00::,2403:3d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:3e00::,2403:3e00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2403:3f00::,2403:3f00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:4000::,2403:4000:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:4100::,2403:4100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:4200::,2403:4200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:4300::,2403:4300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:4400::,2403:4400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:4500::,2403:4500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:4600::,2403:4600:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2403:4700::,2403:4700:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:4800::,2403:4800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:4900::,2403:4900:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:4a00::,2403:4a00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:4b00::,2403:4b00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:4c00::,2403:4c00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:4d00::,2403:4d00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:4e00::,2403:4e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:4f00::,2403:4f00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:5000::,2403:5000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:5100::,2403:5100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:5200::,2403:5200:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2403:5300::,2403:5300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:5400::,2403:5400:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:5500::,2403:5500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:5600::,2403:5600:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:5700::,2403:5700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:5800::,2403:5800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:5900::,2403:5900:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:5a00::,2403:5a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:5b00::,2403:5b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:5c00::,2403:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:5d00::,2403:5d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:5e00::,2403:5e00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2403:5f00::,2403:5f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:6000::,2403:6000:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2403:6100::,2403:6100:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:6200::,2403:6200:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:6300::,2403:6300:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2403:6400::,2403:6400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:6500::,2403:6500:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2403:6600::,2403:6600:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2403:6700::,2403:6700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:6800::,2403:6800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:6900::,2403:6900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:6a00::,2403:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:6b00::,2403:6b00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:6c00::,2403:6c00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:6d00::,2403:6d00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:6e00::,2403:6e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:6f00::,2403:6f00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:7000::,2403:7000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:7100::,2403:7100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:7200::,2403:7200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:7300::,2403:7300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7400::,2403:7400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7500::,2403:7500:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2403:7600::,2403:7600:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:7700::,2403:7700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:7800::,2403:7800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7900::,2403:7900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:7a00::,2403:7a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7b00::,2403:7b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:7c00::,2403:7c00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:7d00::,2403:7d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:7e00::,2403:7e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:7f00::,2403:7f00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:8000::,2403:8000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:8100::,2403:8100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:8200::,2403:8200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:8300::,2403:8300:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2403:8400::,2403:8400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:8500::,2403:8500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:8600::,2403:8600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:8700::,2403:8700:ffff:ffff:ffff:ffff:ffff:ffff,BT
+2403:8800::,2403:8800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:8900::,2403:8900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:8a00::,2403:8a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:8b00::,2403:8b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:8c00::,2403:8c00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:8d00::,2403:8d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:8e00::,2403:8e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:8f00::,2403:8f00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9000::,2403:9000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:9100::,2403:9100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:9200::,2403:9200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9300::,2403:9300:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:9400::,2403:9400:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9500::,2403:9500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:9600::,2403:9600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9700::,2403:9700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:9800::,2403:9800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:9900::,2403:9a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9b00::,2403:9b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:9c00::,2403:9c00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:9d00::,2403:9d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:9e00::,2403:9e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:9f00::,2403:9f00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2403:a000::,2403:a000:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2403:a100::,2403:a100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:a200::,2403:a200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:a300::,2403:a300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:a400::,2403:a400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:a500::,2403:a500:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2403:a600::,2403:a600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:a700::,2403:a700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:a800::,2403:a800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:a900::,2403:a900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:aa00::,2403:aa00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:ab00::,2403:ab00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:ac00::,2403:ac00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:ad00::,2403:ad00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:ae00::,2403:ae00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:af00::,2403:af00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:b000::,2403:b000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:b100::,2403:b100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:b200::,2403:b200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:b300::,2403:b300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:b400::,2403:b400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:b500::,2403:b500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:b600::,2403:b600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:b700::,2403:b700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:b800::,2403:b800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:b900::,2403:b900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:ba00::,2403:ba00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:bb00::,2403:bb00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:bc00::,2403:bc00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2403:bd00::,2403:bd00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:be00::,2403:be00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:bf00::,2403:bf00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:c000::,2403:c000:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2403:c100::,2403:c100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:c200::,2403:c200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:c300::,2403:c300:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2403:c400::,2403:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:c500::,2403:c500:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:c600::,2403:c600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:c700::,2403:c700:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2403:c800::,2403:c800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:c900::,2403:c900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:ca00::,2403:ca00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:cb00::,2403:cb00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:cc00::,2403:cc00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:cd00::,2403:cd00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2403:ce00::,2403:ce00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:cf00::,2403:cf00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:d000::,2403:d000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:d100::,2403:d100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:d200::,2403:d200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:d300::,2403:d300:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:d400::,2403:d400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:d500::,2403:d500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:d600::,2403:d600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:d700::,2403:d700:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2403:d800::,2403:d800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:d900::,2403:d900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:da00::,2403:da00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:db00::,2403:db00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:dc00::,2403:dc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:dd00::,2403:dd00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:de00::,2403:de00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:df00::,2403:df00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:e000::,2403:e000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:e100::,2403:e100:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:e200::,2403:e200:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2403:e300::,2403:e300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:e400::,2403:e400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:e500::,2403:e500:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:e600::,2403:e600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2403:e700::,2403:e700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:e800::,2403:e800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:e900::,2403:e900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2403:ea00::,2403:ea00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:eb00::,2403:eb00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:ec00::,2403:ec00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:ed00::,2403:ed00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:ee00::,2403:ee00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2403:f000::,2403:f000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:f100::,2403:f100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:f200::,2403:f200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2403:f300::,2403:f300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:f400::,2403:f400:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2403:f500::,2403:f500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:f600::,2403:f600:ffff:ffff:ffff:ffff:ffff:ffff,NR
+2403:f700::,2403:f700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2403:f800::,2403:f800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:f900::,2403:f900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:fa00::,2403:fa00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2403:fb00::,2403:fb00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2403:fc00::,2403:fc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:fd00::,2403:fd00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2403:fe00::,2403:fe00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2403:ff00::,2403:ff00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404::,2404:3f:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:80::,2404:8f:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:a0::,2404:a0:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:a8::,2404:a8:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:b0::,2404:b0:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:b8::,2404:b8:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:c0::,2404:c0:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:c8::,2404:c8:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:d0::,2404:d0:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:d8::,2404:d8:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:e0::,2404:ef:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:100::,2404:100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:130::,2404:130:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:138::,2404:139:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:140::,2404:140:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:148::,2404:148:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:150::,2404:150:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:158::,2404:158:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:160::,2404:160:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:168::,2404:168:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:170::,2404:170:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:178::,2404:178:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:180::,2404:18f:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2404:1a0::,2404:1a3:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:1a8::,2404:1a8:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1b0::,2404:1b0:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:1b8::,2404:1b8:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:200::,2404:200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:300::,2404:300:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2404:400::,2404:400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:500::,2404:500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:600::,2404:600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:700::,2404:700:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2404:800::,2404:800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2404:900::,2404:900:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:a00::,2404:a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:b00::,2404:b00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:c00::,2404:c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:d00::,2404:d00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:e00::,2404:e00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:f00::,2404:f00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:1000::,2404:1000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1100::,2404:1100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:1200::,2404:1200:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:1300::,2404:1300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1400::,2404:1400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:1500::,2404:1500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:1600::,2404:1600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:1700::,2404:1700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1800::,2404:1800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:1900::,2404:1900:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1a00::,2404:1a00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:1b00::,2404:1b00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:1c00::,2404:1c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:1d00::,2404:1d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:1e00::,2404:1e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:1f00::,2404:1f00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:2000::,2404:2000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:2100::,2404:2100:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:2200::,2404:2200:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2404:2300::,2404:2300:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2404:2400::,2404:2400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:2500::,2404:2500:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:2600::,2404:2600:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:2700::,2404:2700:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2404:2800::,2404:2800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:2900::,2404:2900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:2a00::,2404:2a00:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2404:2b00::,2404:2b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:2c00::,2404:2c00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2404:2d00::,2404:2d00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:2e00::,2404:2e00:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2404:2f00::,2404:2f00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:3100::,2404:3100:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:3200::,2404:3200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:3300::,2404:3300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:3400::,2404:3400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:3500::,2404:3500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:3600::,2404:3601:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:3700::,2404:3700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:3800::,2404:3800:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:3900::,2404:3900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:3a00::,2404:3a00:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2404:3b00::,2404:3b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:3c00::,2404:3c00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:3d00::,2404:3d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:3e00::,2404:3e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:3f00::,2404:3f00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:4100::,2404:4100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:4200::,2404:4200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:4300::,2404:4300:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:4400::,2404:440f:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:4500::,2404:4500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:4600::,2404:4600:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2404:4700::,2404:4700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:4800::,2404:4800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:4900::,2404:4900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:4a00::,2404:4a00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:4b00::,2404:4b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:4c00::,2404:4c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:4d00::,2404:4d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:4e00::,2404:4e00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:4f00::,2404:4f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5000::,2404:5000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5100::,2404:5100:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:5200::,2404:5200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:5300::,2404:5300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5400::,2404:5400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5500::,2404:5500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5600::,2404:5600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:5700::,2404:5700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:5800::,2404:5800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:5900::,2404:5900:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:5a00::,2404:5a00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:5b00::,2404:5b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:5c00::,2404:5c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5d00::,2404:5d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:5e00::,2404:5e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:5f00::,2404:5f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:6000::,2404:6000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:6100::,2404:6100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:6200::,2404:6200:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:6300::,2404:6300:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:6400::,2404:6400:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2404:6500::,2404:6500:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:6600::,2404:6600:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:6700::,2404:6700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:6800::,2404:6800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:6900::,2404:6900:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:6a00::,2404:6a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:6b00::,2404:6b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:6c00::,2404:6c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:6d00::,2404:6d00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:6e00::,2404:6e00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:6f00::,2404:6f00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:7000::,2404:7000:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:7100::,2404:7100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:7200::,2404:7200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:7300::,2404:7300:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:7400::,2404:7400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:7500::,2404:7500:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:7600::,2404:7600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:7700::,2404:7700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:7800::,2404:7800:ffff:ffff:ffff:ffff:ffff:ffff,PW
+2404:7900::,2404:7900:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:7a00::,2404:7a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:7b00::,2404:7b00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:7c00::,2404:7c00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2404:7d00::,2404:7d00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:7e00::,2404:7e00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:7f00::,2404:7f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:8000::,2404:8000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:8100::,2404:8100:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:8200::,2404:8200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:8300::,2404:8300:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:8500::,2404:8500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:8600::,2404:8600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:8700::,2404:8700:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:8800::,2404:8800:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:8900::,2404:8900:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:8a00::,2404:8a00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2404:8b00::,2404:8b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:8c00::,2404:8c00:ffff:ffff:ffff:ffff:ffff:ffff,GU
+2404:8d00::,2404:8d00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:8e00::,2404:8e01:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:8f00::,2404:8f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9000::,2404:9000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:9100::,2404:9100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:9200::,2404:9200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:9300::,2404:9300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9400::,2404:9400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9500::,2404:9500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:9600::,2404:9600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9700::,2404:9700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9800::,2404:9800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:9900::,2404:9900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:9a00::,2404:9a00:ffff:ffff:ffff:ffff:ffff:ffff,GU
+2404:9b00::,2404:9b00:ffff:ffff:ffff:ffff:ffff:ffff,AF
+2404:9c00::,2404:9c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:9d00::,2404:9d00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:9e00::,2404:9e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:9f00::,2404:9f00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:a000::,2404:a000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:a100::,2404:a100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:a200::,2404:a200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:a300::,2404:a300:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2404:a400::,2404:a400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:a500::,2404:a500:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:a600::,2404:a600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:a700::,2404:a700:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:a800::,2404:a800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:aa00::,2404:aa00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:ab00::,2404:ab00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:ac00::,2404:ac00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:ad00::,2404:ad00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:ae00::,2404:ae00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:af00::,2404:af00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:b000::,2404:b000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:b100::,2404:b100:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:b200::,2404:b200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:b300::,2404:b300:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2404:b400::,2404:b400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:b500::,2404:b500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:b600::,2404:b600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:b700::,2404:b700:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:b800::,2404:b800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:b900::,2404:b900:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:ba00::,2404:ba00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:bb00::,2404:bb00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:bc00::,2404:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:bd00::,2404:bd00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:be00::,2404:be00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2404:bf00::,2404:bf00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:c000::,2404:c000:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:c100::,2404:c100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:c200::,2404:c200:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2404:c300::,2404:c300:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:c400::,2404:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:c500::,2404:c500:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:c600::,2404:c600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:c700::,2404:c700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:c800::,2404:c800:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:c900::,2404:c900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:ca00::,2404:ca00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:cb00::,2404:cb00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:cc00::,2404:cc00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2404:cd00::,2404:cd00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:ce00::,2404:ce00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:cf00::,2404:cf00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:d000::,2404:d000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:d100::,2404:d100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d200::,2404:d200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d300::,2404:d300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d400::,2404:d400:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:d500::,2404:d500:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d600::,2404:d600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d700::,2404:d700:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:d800::,2404:d800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:d900::,2404:d900:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2404:da00::,2404:da00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:db00::,2404:db00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2404:dc00::,2404:dc00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2404:dd00::,2404:dd00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:de00::,2404:de00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:df00::,2404:df00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2404:e000::,2404:e000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:e100::,2404:e100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:e200::,2404:e200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2404:e300::,2404:e300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:e400::,2404:e400:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2404:e500::,2404:e500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:e600::,2404:e600:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:e700::,2404:e700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:e800::,2404:e801:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2404:e900::,2404:e900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:ea00::,2404:ea00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:eb00::,2404:eb00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:ec00::,2404:ec00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:ed00::,2404:ed00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:ee00::,2404:ee00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:ef00::,2404:ef00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f000::,2404:f000:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2404:f100::,2404:f100:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2404:f200::,2404:f200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:f300::,2404:f300:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f400::,2404:f400:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2404:f500::,2404:f500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f600::,2404:f600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f700::,2404:f700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:f800::,2404:f800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2404:f900::,2404:f900:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:fa00::,2404:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:fb00::,2404:fb00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:fc00::,2404:fc00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2404:fd00::,2404:fd00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2404:fe00::,2404:fe00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2404:ff00::,2404:ff00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405::,2405:0:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:100::,2405:100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:200::,2405:207:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:400::,2405:400:ffff:ffff:ffff:ffff:ffff:ffff,MH
+2405:500::,2405:500:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:600::,2405:600:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2405:700::,2405:700:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:800::,2405:800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:900::,2405:900:ffff:ffff:ffff:ffff:ffff:ffff,LA
+2405:a00::,2405:a00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:b00::,2405:b00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:c00::,2405:c00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2405:d00::,2405:d00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:e00::,2405:e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:f00::,2405:f00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:1000::,2405:1000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:1100::,2405:1100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:1200::,2405:1200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:1300::,2405:1300:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:1400::,2405:1400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:1500::,2405:1500:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:1600::,2405:1600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:1700::,2405:1700:ffff:ffff:ffff:ffff:ffff:ffff,BN
+2405:1800::,2405:1800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:1900::,2405:1900:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:1a00::,2405:1a00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:1b00::,2405:1b00:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2405:1c00::,2405:1c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:1d00::,2405:1d00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:1e00::,2405:1e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:1f00::,2405:1f00:ffff:ffff:ffff:ffff:ffff:ffff,TL
+2405:2000::,2405:2000:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:2100::,2405:2100:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2200::,2405:2200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:2300::,2405:2300:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:2400::,2405:2400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:2500::,2405:2500:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2405:2600::,2405:2600:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:2700::,2405:2700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:2800::,2405:2800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:2900::,2405:2900:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:2a00::,2405:2a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:2b00::,2405:2b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2c00::,2405:2c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2d00::,2405:2d00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2e00::,2405:2e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:2f00::,2405:2f00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:3000::,2405:3001:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:3100::,2405:3100:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:3200::,2405:3200:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:3300::,2405:3300:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:3400::,2405:3400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:3500::,2405:3500:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:3600::,2405:3600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:3700::,2405:3700:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:3800::,2405:3800:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:3900::,2405:3900:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:3a00::,2405:3a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:3b00::,2405:3b00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:3c00::,2405:3c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:3d00::,2405:3d00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:3e00::,2405:3e00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:3f00::,2405:3f00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:4000::,2405:4000:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2405:4100::,2405:4100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:4200::,2405:4200:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:4300::,2405:4300:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:4400::,2405:4400:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2405:4500::,2405:4500:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:4600::,2405:4600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:4700::,2405:4700:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:4800::,2405:4800:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2405:4900::,2405:4900:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:4a00::,2405:4a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:4b00::,2405:4b00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:4c00::,2405:4c00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:4d00::,2405:4d00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:4e00::,2405:4e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:4f00::,2405:4f00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:5000::,2405:5000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:5100::,2405:5100:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:5200::,2405:5200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:5300::,2405:5300:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:5400::,2405:5400:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2405:5600::,2405:5600:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:5800::,2405:5800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:5a00::,2405:5a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:5c00::,2405:5c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:5e00::,2405:5e00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:6000::,2405:6000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:6200::,2405:6200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:6400::,2405:6400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:6600::,2405:6600:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2405:6800::,2405:6800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:6a00::,2405:6a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:6c00::,2405:6c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:6e00::,2405:6e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:7000::,2405:7000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:7200::,2405:7200:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:7400::,2405:7400:ffff:ffff:ffff:ffff:ffff:ffff,GU
+2405:7600::,2405:7600:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:7800::,2405:7800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:7a00::,2405:7a00:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:7c00::,2405:7c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2405:7e00::,2405:7e00:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:8000::,2405:8000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:8200::,2405:8200:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:8400::,2405:8400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:8600::,2405:8600:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:8800::,2405:8800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:8a00::,2405:8a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:8c00::,2405:8c00:ffff:ffff:ffff:ffff:ffff:ffff,WS
+2405:8e00::,2405:8e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2405:9000::,2405:9000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:9200::,2405:9200:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:9400::,2405:9400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:9600::,2405:9600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:9800::,2405:9800:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2405:9a00::,2405:9a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:9c00::,2405:9c00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:9e00::,2405:9e00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:a000::,2405:a000:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2405:a200::,2405:a200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:a400::,2405:a400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:a600::,2405:a600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:aa00::,2405:aa00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:ac00::,2405:ac00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:ae00::,2405:ae00:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2405:b000::,2405:b000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:b200::,2405:b200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2405:b400::,2405:b400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:b600::,2405:b600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:b800::,2405:b800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:ba00::,2405:ba00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:bc00::,2405:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:be00::,2405:be00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:c000::,2405:c000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2405:c200::,2405:c200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:c400::,2405:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:c600::,2405:c600:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2405:c800::,2405:c800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:ca00::,2405:ca00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2405:cc00::,2405:cc00:ffff:ffff:ffff:ffff:ffff:ffff,PF
+2405:ce00::,2405:ce00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:d000::,2405:d000:ffff:ffff:ffff:ffff:ffff:ffff,BT
+2405:d200::,2405:d200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:d400::,2405:d400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:d600::,2405:d600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:d800::,2405:d800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:da00::,2405:da00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:dc00::,2405:dc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:e000::,2405:e000:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:e200::,2405:e200:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:e400::,2405:e400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:e600::,2405:e600:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2405:e800::,2405:e800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:ea00::,2405:ea00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:ec00::,2405:ec00:ffff:ffff:ffff:ffff:ffff:ffff,BT
+2405:ee00::,2405:ee00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2405:f000::,2405:f000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:f200::,2405:f200:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2405:f400::,2405:f400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2405:f600::,2405:f600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2405:f800::,2405:f800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2405:fa00::,2405:fa00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2405:fc00::,2405:fc00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2405:fe00::,2405:fe00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2406::,2406:0:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:200::,2406:200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:400::,2406:400:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2406:600::,2406:600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:800::,2406:800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:a00::,2406:a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:c00::,2406:c00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2406:e00::,2406:e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:1000::,2406:1000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:1200::,2406:1200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:1400::,2406:1400:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2406:1600::,2406:1600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:1a00::,2406:1a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:1c00::,2406:1c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:1e00::,2406:1e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:2000::,2406:2000:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2406:2200::,2406:2200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:2400::,2406:2400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:2600::,2406:2600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:2800::,2406:2800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:2a00::,2406:2a00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2406:2c00::,2406:2c00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:2e00::,2406:2e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:3000::,2406:3003:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:3200::,2406:3200:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2406:3400::,2406:3400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3600::,2406:3600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3800::,2406:3800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3a00::,2406:3a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3c00::,2406:3c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:3e00::,2406:3e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:4000::,2406:4000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:4200::,2406:4200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:4400::,2406:4400:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2406:4600::,2406:4600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:4800::,2406:4800:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:4a00::,2406:4a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:4c00::,2406:4c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:4e00::,2406:4e00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:5000::,2406:5000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:5200::,2406:5200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:5400::,2406:5400:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:5600::,2406:5600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:5800::,2406:5800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:5a00::,2406:5a00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:5c00::,2406:5c00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:5e00::,2406:5e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:6000::,2406:6000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2406:6200::,2406:6200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:6400::,2406:6400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:6600::,2406:6600:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:6800::,2406:6800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:6a00::,2406:6a00:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:6c00::,2406:6c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:6e00::,2406:6e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:7000::,2406:7000:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2406:7200::,2406:7200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:7400::,2406:7400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:7600::,2406:7600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:7800::,2406:7801:ffff:ffff:ffff:ffff:ffff:ffff,BN
+2406:7a00::,2406:7a00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:7c00::,2406:7c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:7e00::,2406:7e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:8000::,2406:8000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:8200::,2406:8200:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:8400::,2406:8400:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2406:8600::,2406:8600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:8800::,2406:8800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:8a00::,2406:8a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:8c00::,2406:8c00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:8e00::,2406:8e00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:9000::,2406:9000:ffff:ffff:ffff:ffff:ffff:ffff,VN
+2406:9200::,2406:9200:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2406:9400::,2406:9400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:9600::,2406:9600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:9800::,2406:9800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:9a00::,2406:9a01:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:9c00::,2406:9c00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:9e00::,2406:9e00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:a000::,2406:a000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:a200::,2406:a200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:a400::,2406:a400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:a600::,2406:a600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:a800::,2406:a800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:aa00::,2406:aa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:ac00::,2406:ac00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2406:ae00::,2406:ae00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:b000::,2406:b000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:b200::,2406:b200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2406:b400::,2406:b400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:b600::,2406:b600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:b800::,2406:b800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:ba00::,2406:ba00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:bc00::,2406:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:be00::,2406:be00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c000::,2406:c000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c200::,2406:c200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c400::,2406:c400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c600::,2406:c600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:c800::,2406:c800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:ca00::,2406:ca00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:cc00::,2406:cc00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:ce00::,2406:ce07:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:d000::,2406:d000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2406:d200::,2406:d200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:d400::,2406:d400:ffff:ffff:ffff:ffff:ffff:ffff,TW
+2406:d600::,2406:d600:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:d800::,2406:d800:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:da00::,2406:da00:ffff:ffff:ffff:ffff:ffff:ffff,AP
+2406:dc00::,2406:dc00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2406:de00::,2406:de00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:e000::,2406:e000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:e200::,2406:e200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2406:e400::,2406:e400:ffff:ffff:ffff:ffff:ffff:ffff,MV
+2406:e600::,2406:e600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:e800::,2406:e800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:ea00::,2406:ea00:ffff:ffff:ffff:ffff:ffff:ffff,MM
+2406:ec00::,2406:ec00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:ee00::,2406:ee00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2406:f000::,2406:f000:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:f200::,2406:f200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2406:f400::,2406:f400:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:f600::,2406:f600:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2406:f800::,2406:f800:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2406:fa00::,2406:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2406:fc00::,2406:fc00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2406:fe00::,2406:fe00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407::,2407:0:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:200::,2407:200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:400::,2407:400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:600::,2407:600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:800::,2407:800:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2407:a00::,2407:a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:c00::,2407:c00:ffff:ffff:ffff:ffff:ffff:ffff,LK
+2407:e00::,2407:e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:1000::,2407:1000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:1200::,2407:1200:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:1400::,2407:1400:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2407:1600::,2407:1600:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:1800::,2407:1800:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2407:1a00::,2407:1a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:1c00::,2407:1c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:1e00::,2407:1e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:2000::,2407:2000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2407:2200::,2407:2200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:2400::,2407:2400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:2600::,2407:2600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:2800::,2407:2800:ffff:ffff:ffff:ffff:ffff:ffff,WS
+2407:2a00::,2407:2a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:2c00::,2407:2c00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2407:2e00::,2407:2e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:3000::,2407:3000:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:3400::,2407:3400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:3600::,2407:3600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:3800::,2407:3800:ffff:ffff:ffff:ffff:ffff:ffff,SB
+2407:3a00::,2407:3a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:3c00::,2407:3c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:3e00::,2407:3e00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:4000::,2407:4000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:4200::,2407:4200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:4400::,2407:4400:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:4600::,2407:4600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:4800::,2407:4800:ffff:ffff:ffff:ffff:ffff:ffff,FM
+2407:4a00::,2407:4a00:ffff:ffff:ffff:ffff:ffff:ffff,NC
+2407:4c00::,2407:4c00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:4e00::,2407:4e00:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:5000::,2407:5000:ffff:ffff:ffff:ffff:ffff:ffff,BD
+2407:5200::,2407:5200:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2407:5400::,2407:5400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:5600::,2407:5600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:5800::,2407:5800:ffff:ffff:ffff:ffff:ffff:ffff,CK
+2407:5a00::,2407:5a00:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2407:5c00::,2407:5c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:5e00::,2407:5e00:ffff:ffff:ffff:ffff:ffff:ffff,KH
+2407:6000::,2407:6000:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:6200::,2407:6200:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2407:6400::,2407:6400:ffff:ffff:ffff:ffff:ffff:ffff,MN
+2407:6600::,2407:6600:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2407:6800::,2407:6800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:6a00::,2407:6a00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:6c00::,2407:6c00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:6e00::,2407:6e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:7000::,2407:7000:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:7200::,2407:7200:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:7400::,2407:7400:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:7600::,2407:7600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:7800::,2407:7800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:7a00::,2407:7a00:ffff:ffff:ffff:ffff:ffff:ffff,TH
+2407:7c00::,2407:7c00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:7e00::,2407:7e00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:8000::,2407:8000:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:8200::,2407:8200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:8400::,2407:8400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:8600::,2407:8600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:8800::,2407:8800:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:8a00::,2407:8a00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:8c00::,2407:8c00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:8e00::,2407:8e00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:9000::,2407:9000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:9200::,2407:9200:ffff:ffff:ffff:ffff:ffff:ffff,PG
+2407:9400::,2407:9400:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:9600::,2407:9600:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:9800::,2407:9800:ffff:ffff:ffff:ffff:ffff:ffff,PH
+2407:9a00::,2407:9a00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:9c00::,2407:9c00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2407:9e00::,2407:9e00:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2407:a000::,2407:a000:ffff:ffff:ffff:ffff:ffff:ffff,FJ
+2407:a200::,2407:a200:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:a600::,2407:a600:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:a800::,2407:a800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:aa00::,2407:aa00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:ac00::,2407:ac00:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:ae00::,2407:ae00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:b000::,2407:b000:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:b200::,2407:b200:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2407:b400::,2407:b400:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:b600::,2407:b600:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:b800::,2407:b800:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2407:ba00::,2407:ba00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2407:bc00::,2407:bc00:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2407:be00::,2407:be00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:c000::,2407:c000:ffff:ffff:ffff:ffff:ffff:ffff,KR
+2407:c200::,2407:c200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:c400::,2407:c400:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2407:c600::,2407:c600:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:c800::,2407:c800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:ca00::,2407:ca00:ffff:ffff:ffff:ffff:ffff:ffff,NZ
+2407:cc00::,2407:cc00:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:ce00::,2407:ce00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:d000::,2407:d000:ffff:ffff:ffff:ffff:ffff:ffff,PK
+2407:d200::,2407:d200:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:d400::,2407:d400:ffff:ffff:ffff:ffff:ffff:ffff,NP
+2407:d600::,2407:d600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:d800::,2407:d800:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:da00::,2407:da00:ffff:ffff:ffff:ffff:ffff:ffff,IN
+2407:dc00::,2407:dc00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:de00::,2407:de00:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:e000::,2407:e000:ffff:ffff:ffff:ffff:ffff:ffff,SG
+2407:e200::,2407:e200:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:e400::,2407:e400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:e600::,2407:e600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:e800::,2407:e800:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2407:ea00::,2407:ea00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:ec00::,2407:ec00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:ee00::,2407:ee00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:f000::,2407:f000:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:f200::,2407:f200:ffff:ffff:ffff:ffff:ffff:ffff,ID
+2407:f400::,2407:f400:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2407:f600::,2407:f600:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2407:f800::,2407:f800:ffff:ffff:ffff:ffff:ffff:ffff,MY
+2407:fa00::,2407:fa00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:fc00::,2407:fc00:ffff:ffff:ffff:ffff:ffff:ffff,HK
+2407:fe00::,2407:fe00:ffff:ffff:ffff:ffff:ffff:ffff,AU
+2408::,2408:3ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2408:8000::,2408:8fff:ffff:ffff:ffff:ffff:ffff:ffff,CN
+2409::,2409:3ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2409:8000::,2409:8fff:ffff:ffff:ffff:ffff:ffff:ffff,CN
+240a::,240a:7f:ffff:ffff:ffff:ffff:ffff:ffff,JP
+240b::,240b:3ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+240c::,240c:f:ffff:ffff:ffff:ffff:ffff:ffff,CN
+240d::,240d:1f:ffff:ffff:ffff:ffff:ffff:ffff,JP
+240e::,240e:fff:ffff:ffff:ffff:ffff:ffff:ffff,CN
+240f::,240f:ff:ffff:ffff:ffff:ffff:ffff:ffff,JP
+2600::,2600:7:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:100::,2600:10f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:200::,2600:20f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:300::,2600:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:800::,2600:81f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:900::,2600:90f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:a00::,2600:a01:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:b00::,2600:b0f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:c00::,2600:c14:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:d00::,2600:d0f:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2600:f00::,2600:1017:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1100::,2600:110f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1200::,2600:130f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1400::,2600:141f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1800::,2600:180f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:1c00::,2600:1c0f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:2000::,2600:200f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:2400::,2600:2407:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:2800::,2600:2803:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:2c00::,2600:2c03:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:3000::,2600:3007:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:3400::,2600:340f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:3800::,2600:380f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:3c00::,2600:3c03:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:4000::,2600:40ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:4400::,2600:4407:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:4800::,2600:480f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:4c00::,2600:4c01:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:5000::,2600:500f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:5400::,2600:541f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:5800::,2600:5801:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:5c00::,2600:5c01:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:6000::,2600:6001:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:6400::,2600:640f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:6800::,2600:68ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:6c00::,2600:6cff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:7000::,2600:70ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:8000::,2600:80ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2600:e000::,2600:e00f:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2601::,2601:f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2602::,2602:10f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2602:200::,2602:200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2602:210::,2602:210:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2602:220::,2602:220:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2602:230::,2602:230:ffff:ffff:ffff:ffff:ffff:ffff,US
+2602:240::,2602:24f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2602:300::,2602:3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604::,2604:0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:10::,2604:10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:100::,2604:100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:180::,2604:180:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:200::,2604:200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:280::,2604:280:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:300::,2604:300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:380::,2604:380:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:400::,2604:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:480::,2604:480:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:500::,2604:500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:580::,2604:580:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:600::,2604:600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:680::,2604:680:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:700::,2604:700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:780::,2604:780:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:800::,2604:800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:880::,2604:880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:900::,2604:900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:980::,2604:980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a00::,2604:a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a80::,2604:a80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b00::,2604:b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b80::,2604:b80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c00::,2604:c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c80::,2604:c80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d00::,2604:d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d80::,2604:d80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e00::,2604:e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e80::,2604:e80:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:f00::,2604:f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f80::,2604:f80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1000::,2604:1000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1080::,2604:1080:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1100::,2604:1100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1180::,2604:1180:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1200::,2604:1200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1280::,2604:1280:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1300::,2604:1300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1380::,2604:1380:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1400::,2604:1400:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2604:1480::,2604:1480:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1500::,2604:1500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1580::,2604:1580:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1600::,2604:1600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1680::,2604:1680:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1700::,2604:1700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1780::,2604:1780:ffff:ffff:ffff:ffff:ffff:ffff,KY
+2604:1800::,2604:1800:ffff:ffff:ffff:ffff:ffff:ffff,GP
+2604:1880::,2604:1880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1900::,2604:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1980::,2604:1980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1a00::,2604:1a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1a80::,2604:1a80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1b00::,2604:1b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1b80::,2604:1b80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1c00::,2604:1c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1c80::,2604:1c80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1d00::,2604:1d00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1d80::,2604:1d80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1e00::,2604:1e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1e80::,2604:1e80:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:1f00::,2604:1f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:1f80::,2604:1f80:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:2000::,2604:2000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2080::,2604:2080:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2100::,2604:2100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2200::,2604:2200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2300::,2604:2300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2400::,2604:2400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2500::,2604:2500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2600::,2604:2600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2700::,2604:2700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2800::,2604:2800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2900::,2604:2900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2a00::,2604:2a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2b00::,2604:2b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2c00::,2604:2c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2d00::,2604:2d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2e00::,2604:2e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:2f00::,2604:2f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3000::,2604:3000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3100::,2604:3100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3200::,2604:3200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3300::,2604:3300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3400::,2604:3400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3500::,2604:3500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3600::,2604:3600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3700::,2604:3700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3800::,2604:3800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3900::,2604:3900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3a00::,2604:3a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3b00::,2604:3b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:3c00::,2604:3c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3d00::,2604:3d00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:3e00::,2604:3e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:3f00::,2604:3f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4000::,2604:4000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:4100::,2604:4100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4200::,2604:4200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4300::,2604:4300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4400::,2604:4400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4500::,2604:4500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4600::,2604:4600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4700::,2604:4700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4800::,2604:4800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4900::,2604:4900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4a00::,2604:4a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4b00::,2604:4b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4c00::,2604:4c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:4d00::,2604:4d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4e00::,2604:4e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:4f00::,2604:4f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5000::,2604:5000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5100::,2604:5100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5200::,2604:5200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5300::,2604:5300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5400::,2604:5400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5500::,2604:5500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5600::,2604:5600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5700::,2604:5700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5800::,2604:5800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5900::,2604:5900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5a00::,2604:5a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5b00::,2604:5b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5c00::,2604:5c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5d00::,2604:5d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5e00::,2604:5e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:5f00::,2604:5f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6000::,2604:6000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6100::,2604:6100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6200::,2604:6200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6300::,2604:6300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6400::,2604:6400:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:6500::,2604:6500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:6600::,2604:6600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6700::,2604:6700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6800::,2604:6800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6900::,2604:6900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6a00::,2604:6a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6b00::,2604:6b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6c00::,2604:6c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6d00::,2604:6d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6e00::,2604:6e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:6f00::,2604:6f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7000::,2604:7000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7100::,2604:7100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7200::,2604:7200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7300::,2604:7300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7400::,2604:7400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7500::,2604:7500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7600::,2604:7600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7700::,2604:7700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7800::,2604:7800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7900::,2604:7900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7a00::,2604:7a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7b00::,2604:7b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7c00::,2604:7c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7d00::,2604:7d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7e00::,2604:7e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:7f00::,2604:7f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:8000::,2604:8000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8100::,2604:8100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8200::,2604:8200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8300::,2604:8300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8400::,2604:8400:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:8500::,2604:8500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8600::,2604:8600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:8700::,2604:8700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8800::,2604:8800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8900::,2604:8900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8a00::,2604:8a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8b00::,2604:8b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8c00::,2604:8c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8d00::,2604:8d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8e00::,2604:8e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:8f00::,2604:8f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9000::,2604:9000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9100::,2604:9100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9200::,2604:9200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9300::,2604:9300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9400::,2604:9400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9500::,2604:9500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9600::,2604:9600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9700::,2604:9700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9800::,2604:9800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9900::,2604:9900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9a00::,2604:9a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9b00::,2604:9b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9c00::,2604:9c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9d00::,2604:9d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9e00::,2604:9e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:9f00::,2604:9f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a000::,2604:a000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a100::,2604:a100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a200::,2604:a200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a300::,2604:a300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a400::,2604:a400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a500::,2604:a500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a600::,2604:a600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a700::,2604:a700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a800::,2604:a800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:a900::,2604:a900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:aa00::,2604:aa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ab00::,2604:ab00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ac00::,2604:ac00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ad00::,2604:ad00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ae00::,2604:ae00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:af00::,2604:af00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b000::,2604:b000:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2604:b100::,2604:b100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b200::,2604:b200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b300::,2604:b300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b400::,2604:b400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b500::,2604:b500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b600::,2604:b600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b700::,2604:b700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b800::,2604:b800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:b900::,2604:b900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ba00::,2604:ba00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:bb00::,2604:bb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:bc00::,2604:bc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:bd00::,2604:bd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:be00::,2604:be00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:bf00::,2604:bf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c000::,2604:c000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c100::,2604:c100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c200::,2604:c200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c300::,2604:c300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c400::,2604:c400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c500::,2604:c500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c600::,2604:c600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c700::,2604:c700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c800::,2604:c800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:c900::,2604:c900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ca00::,2604:ca00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:cb00::,2604:cb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:cc00::,2604:cc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:cd00::,2604:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ce00::,2604:ce00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:cf00::,2604:cf00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:d000::,2604:d000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d100::,2604:d100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d200::,2604:d200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d300::,2604:d300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d400::,2604:d400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d500::,2604:d500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d600::,2604:d600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d700::,2604:d700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d800::,2604:d801:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:d900::,2604:d900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:da00::,2604:da00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:db00::,2604:db00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:dc00::,2604:dc00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:dd00::,2604:dd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:de00::,2604:de00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:df00::,2604:df00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e000::,2604:e000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e100::,2604:e100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:e200::,2604:e200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e300::,2604:e300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e400::,2604:e400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e500::,2604:e500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e600::,2604:e600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e700::,2604:e700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e800::,2604:e800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:e900::,2604:e900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ea00::,2604:ea00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:eb00::,2604:eb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ec00::,2604:ec00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:ed00::,2604:ed00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ee00::,2604:ee00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ef00::,2604:ef00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:f000::,2604:f000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:f100::,2604:f100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f200::,2604:f200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f300::,2604:f300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f400::,2604:f400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f500::,2604:f500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f600::,2604:f600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f700::,2604:f700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:f800::,2604:f800:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2604:f900::,2604:f900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fa00::,2604:fa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fb00::,2604:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fc00::,2604:fc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fd00::,2604:fd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:fe00::,2604:fe00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2604:ff00::,2604:ff00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605::,2605:0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:100::,2605:100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:200::,2605:200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:300::,2605:300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:400::,2605:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:500::,2605:500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:600::,2605:600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:700::,2605:700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:800::,2605:800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:900::,2605:900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a00::,2605:a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b00::,2605:b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c00::,2605:c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:d00::,2605:d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e00::,2605:e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f00::,2605:f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1000::,2605:1000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1100::,2605:1100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1200::,2605:1200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1300::,2605:1300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1400::,2605:1400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1500::,2605:1500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1600::,2605:1600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1700::,2605:1700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1800::,2605:1800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1900::,2605:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1a00::,2605:1a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1b00::,2605:1b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:1c00::,2605:1c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1d00::,2605:1d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1e00::,2605:1e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:1f00::,2605:1f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2000::,2605:2000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2100::,2605:2100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2200::,2605:2200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2300::,2605:2300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2400::,2605:2400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2500::,2605:2500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2600::,2605:2600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2700::,2605:2700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2800::,2605:2800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2900::,2605:2900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2a00::,2605:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2b00::,2605:2b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2c00::,2605:2c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2d00::,2605:2d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:2e00::,2605:2e00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:2f00::,2605:2f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3000::,2605:3000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3100::,2605:3100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3200::,2605:3200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3300::,2605:3300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3400::,2605:3400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3500::,2605:3500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3600::,2605:3600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3700::,2605:3700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3800::,2605:3800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3900::,2605:3900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3a00::,2605:3a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3b00::,2605:3b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3c00::,2605:3c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3d00::,2605:3d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3e00::,2605:3e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:3f00::,2605:3f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:4000::,2605:4000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4100::,2605:4100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4200::,2605:4200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4300::,2605:4300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4400::,2605:4400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4500::,2605:4500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4600::,2605:4600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4700::,2605:4700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4800::,2605:4800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4900::,2605:4900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4a00::,2605:4a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4b00::,2605:4b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4c00::,2605:4c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4d00::,2605:4d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4e00::,2605:4e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:4f00::,2605:4f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:5000::,2605:5000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5100::,2605:5100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5200::,2605:5200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5300::,2605:5300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5400::,2605:5400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5500::,2605:5500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5600::,2605:5600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5700::,2605:5700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5800::,2605:5800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5900::,2605:5900:ffff:ffff:ffff:ffff:ffff:ffff,JM
+2605:5a00::,2605:5a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5b00::,2605:5b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5c00::,2605:5c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5d00::,2605:5d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5e00::,2605:5e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:5f00::,2605:5f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6000::,2605:6000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6100::,2605:6100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6200::,2605:6200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6300::,2605:6300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6400::,2605:6400:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:6500::,2605:6500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6600::,2605:6600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6700::,2605:6700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6800::,2605:6800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6900::,2605:6900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6a00::,2605:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:6b00::,2605:6b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:6c00::,2605:6c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6d00::,2605:6d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6e00::,2605:6e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:6f00::,2605:6f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:7000::,2605:7000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7100::,2605:7100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7200::,2605:7200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:7300::,2605:7300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7400::,2605:7400:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:7500::,2605:7500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7600::,2605:7600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7700::,2605:7700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7800::,2605:7801:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7900::,2605:7900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7a00::,2605:7a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7b00::,2605:7b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7c00::,2605:7c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:7d00::,2605:7d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7e00::,2605:7e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:7f00::,2605:7f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8000::,2605:8000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8100::,2605:8100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:8200::,2605:8200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8300::,2605:8300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8400::,2605:8400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8500::,2605:8500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8600::,2605:8600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8700::,2605:8700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8800::,2605:8800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8900::,2605:8900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8a00::,2605:8a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8b00::,2605:8b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8c00::,2605:8c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8d00::,2605:8d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8e00::,2605:8e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:8f00::,2605:8f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9000::,2605:9000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:9100::,2605:9100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9200::,2605:9200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9300::,2605:9300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:9400::,2605:9400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9500::,2605:9500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9600::,2605:9600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9700::,2605:9700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9800::,2605:9800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9900::,2605:9900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9a00::,2605:9a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9b00::,2605:9b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9c00::,2605:9c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9d00::,2605:9d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9e00::,2605:9e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:9f00::,2605:9f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a000::,2605:a000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a100::,2605:a100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a200::,2605:a200:ffff:ffff:ffff:ffff:ffff:ffff,JM
+2605:a300::,2605:a300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a400::,2605:a407:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a500::,2605:a500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a600::,2605:a601:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a700::,2605:a700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:a800::,2605:a800:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:a900::,2605:a900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:aa00::,2605:aa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ab00::,2605:ab00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:ac00::,2605:ac00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:ad00::,2605:ad00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ae00::,2605:ae00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:af00::,2605:af00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b000::,2605:b000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:b100::,2605:b100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:b200::,2605:b200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b300::,2605:b300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b400::,2605:b400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b500::,2605:b500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b600::,2605:b600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:b700::,2605:b700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:b800::,2605:b800:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2605:b900::,2605:b900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:ba00::,2605:ba00:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2605:bb00::,2605:bb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:bc00::,2605:bc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:bd00::,2605:bd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:be00::,2605:be00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:bf00::,2605:bf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c000::,2605:c000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c100::,2605:c100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c200::,2605:c200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c300::,2605:c300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c400::,2605:c400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c500::,2605:c500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:c600::,2605:c600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c700::,2605:c700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:c800::,2605:c800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:c900::,2605:c900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ca00::,2605:ca00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:cb00::,2605:cb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:cc00::,2605:cc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:cd00::,2605:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ce00::,2605:ce00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:cf00::,2605:cf00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:d000::,2605:d000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d100::,2605:d100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d200::,2605:d200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d300::,2605:d300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d400::,2605:d400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d500::,2605:d500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:d600::,2605:d600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d700::,2605:d700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d800::,2605:d800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:d900::,2605:d900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:da00::,2605:da00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:db00::,2605:db00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:dc00::,2605:dc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:dd00::,2605:dd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:de00::,2605:de00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:df00::,2605:df00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e000::,2605:e000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e100::,2605:e100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e200::,2605:e200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:e300::,2605:e300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e400::,2605:e400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e500::,2605:e500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e600::,2605:e600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e700::,2605:e700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e800::,2605:e800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:e900::,2605:e900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ea00::,2605:ea00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:eb00::,2605:eb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ec00::,2605:ec00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ed00::,2605:ed00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ee00::,2605:ee00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ef00::,2605:ef00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f000::,2605:f000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f100::,2605:f100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f200::,2605:f200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f300::,2605:f300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f400::,2605:f400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f500::,2605:f500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f600::,2605:f600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f700::,2605:f700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f800::,2605:f800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:f900::,2605:f900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:fa00::,2605:fa00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:fb00::,2605:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:fc00::,2605:fc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:fd00::,2605:fd00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2605:fe00::,2605:fe00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2605:ff00::,2605:ff00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606::,2606:0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:100::,2606:100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:200::,2606:200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:300::,2606:300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:400::,2606:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:500::,2606:500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:600::,2606:600:ffff:ffff:ffff:ffff:ffff:ffff,KY
+2606:700::,2606:700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:800::,2606:800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:900::,2606:900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a00::,2606:a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b00::,2606:b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c00::,2606:c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d00::,2606:d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e00::,2606:e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f00::,2606:f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1000::,2606:1000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1100::,2606:1100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1200::,2606:1200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1300::,2606:1300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1400::,2606:1400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1500::,2606:1500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1600::,2606:1600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1700::,2606:1700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1800::,2606:1800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1900::,2606:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1b00::,2606:1b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1c00::,2606:1c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1d00::,2606:1d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1e00::,2606:1e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:1f00::,2606:1f00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:2000::,2606:2000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2100::,2606:2100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2200::,2606:2200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2300::,2606:2300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2400::,2606:2400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2500::,2606:2500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2600::,2606:2600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2700::,2606:2700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:2800::,2606:2800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2900::,2606:2900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2a00::,2606:2a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2b00::,2606:2b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2c00::,2606:2c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2d00::,2606:2d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2e00::,2606:2e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:2f00::,2606:2f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3000::,2606:3000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:3100::,2606:3100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:3200::,2606:3200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3300::,2606:3300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3400::,2606:3400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3500::,2606:3500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3600::,2606:3600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3700::,2606:3700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3800::,2606:3800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3900::,2606:3900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3a00::,2606:3a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3b00::,2606:3b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3c00::,2606:3c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:3d00::,2606:3d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3e00::,2606:3e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:3f00::,2606:3f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4000::,2606:4000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4100::,2606:4100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4200::,2606:4200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4300::,2606:4300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4400::,2606:4400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4500::,2606:4500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4600::,2606:4600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4700::,2606:4700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4800::,2606:4800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4900::,2606:4900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4a00::,2606:4a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4b00::,2606:4b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4c00::,2606:4c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4d00::,2606:4d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4e00::,2606:4e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:4f00::,2606:4f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5000::,2606:5000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5100::,2606:5100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5200::,2606:5200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5300::,2606:5300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:5400::,2606:5400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5500::,2606:5500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5600::,2606:5600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5700::,2606:5700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5800::,2606:5800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5900::,2606:5900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5a00::,2606:5a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5b00::,2606:5b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5c00::,2606:5c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5d00::,2606:5d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:5e00::,2606:5e00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:5f00::,2606:5f00:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2606:6000::,2606:6000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6100::,2606:6100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6200::,2606:6200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:6300::,2606:6300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:6400::,2606:6400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6500::,2606:6500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6600::,2606:6600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6700::,2606:6700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6900::,2606:6900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6a00::,2606:6a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:6b00::,2606:6b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6c00::,2606:6c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6d00::,2606:6d00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:6e00::,2606:6e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:6f00::,2606:6f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7000::,2606:7000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7100::,2606:7100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7200::,2606:7200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7300::,2606:7300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7400::,2606:7400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7500::,2606:7500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7600::,2606:7600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7700::,2606:7700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7800::,2606:7800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7900::,2606:7900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7a00::,2606:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:7b00::,2606:7b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7c00::,2606:7c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7d00::,2606:7d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7e00::,2606:7e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:7f00::,2606:7f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8000::,2606:8000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8100::,2606:8100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8200::,2606:8200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8300::,2606:8300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:8400::,2606:8400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8500::,2606:8500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8600::,2606:8600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8700::,2606:8700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8800::,2606:8800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8a00::,2606:8a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8b00::,2606:8b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8c00::,2606:8c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:8d00::,2606:8d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8e00::,2606:8e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:8f00::,2606:8f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9100::,2606:9100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9200::,2606:9200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9300::,2606:9300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9400::,2606:9400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9500::,2606:9500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9600::,2606:9600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9700::,2606:9700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9800::,2606:9800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9900::,2606:9900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9a00::,2606:9a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9b00::,2606:9b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9c00::,2606:9c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9d00::,2606:9d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:9e00::,2606:9e00:ffff:ffff:ffff:ffff:ffff:ffff,BM
+2606:9f00::,2606:9f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a000::,2606:a000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a100::,2606:a100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a200::,2606:a200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a300::,2606:a300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a400::,2606:a400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a500::,2606:a500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a600::,2606:a600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a700::,2606:a700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a800::,2606:a800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:a900::,2606:a900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:aa00::,2606:aa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ab00::,2606:ab00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ac00::,2606:ac00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ad00::,2606:ad00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ae00::,2606:ae00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:af00::,2606:af00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:b000::,2606:b000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b100::,2606:b100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b200::,2606:b200:ffff:ffff:ffff:ffff:ffff:ffff,KY
+2606:b300::,2606:b300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b400::,2606:b400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b500::,2606:b500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b600::,2606:b600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b700::,2606:b700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:b800::,2606:b800:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:b900::,2606:b900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ba00::,2606:ba00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:bb00::,2606:bb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:bc00::,2606:bc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:bd00::,2606:bd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:be00::,2606:be00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:bf00::,2606:bf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c000::,2606:c000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c100::,2606:c100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c200::,2606:c200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c300::,2606:c300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c400::,2606:c400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c500::,2606:c500:ffff:ffff:ffff:ffff:ffff:ffff,JM
+2606:c600::,2606:c600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:c700::,2606:c700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c800::,2606:c800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:c900::,2606:c900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ca00::,2606:ca00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:cb00::,2606:cb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:cc00::,2606:cc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:cd00::,2606:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ce00::,2606:ce00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:cf00::,2606:cf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d000::,2606:d000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d100::,2606:d100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d200::,2606:d200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d300::,2606:d300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d400::,2606:d400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d500::,2606:d500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d600::,2606:d600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d700::,2606:d700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d800::,2606:d800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:d900::,2606:d900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:da00::,2606:da00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:db00::,2606:db00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:dc00::,2606:dc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:dd00::,2606:dd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:de00::,2606:de00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:df00::,2606:df00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e000::,2606:e000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:e100::,2606:e100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e200::,2606:e200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e300::,2606:e300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e400::,2606:e400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e500::,2606:e500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e600::,2606:e600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e700::,2606:e700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e800::,2606:e800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:e900::,2606:e900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ea00::,2606:ea00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:eb00::,2606:eb00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:ec00::,2606:ec00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ed00::,2606:ed00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ee00::,2606:ee00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:ef00::,2606:ef00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f000::,2606:f000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f100::,2606:f100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f200::,2606:f200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f300::,2606:f300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f400::,2606:f40f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f500::,2606:f500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f600::,2606:f600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f700::,2606:f700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:f800::,2606:f800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:f900::,2606:f900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:fa00::,2606:fa00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2606:fb00::,2606:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:fc00::,2606:fc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:fd00::,2606:fd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:fe00::,2606:fe00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2606:ff00::,2606:ff00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607::,2607:0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:100::,2607:100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:200::,2607:200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:300::,2607:300:ffff:ffff:ffff:ffff:ffff:ffff,BS
+2607:400::,2607:400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:500::,2607:500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:600::,2607:600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:700::,2607:700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:800::,2607:800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:900::,2607:900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a00::,2607:a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:b00::,2607:b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c00::,2607:c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d00::,2607:d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e00::,2607:e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f00::,2607:f00:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2607:1000::,2607:1000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1100::,2607:1100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1200::,2607:1200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1300::,2607:1300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1400::,2607:1400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1500::,2607:1500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1600::,2607:1600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1700::,2607:1700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1800::,2607:1800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1900::,2607:1900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1a00::,2607:1a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1b00::,2607:1b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1c00::,2607:1c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1d00::,2607:1d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1e00::,2607:1e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:1f00::,2607:1f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2000::,2607:2000:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2607:2100::,2607:2100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2200::,2607:2200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2300::,2607:2300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2400::,2607:2400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2500::,2607:2500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2600::,2607:2600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2700::,2607:2700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2800::,2607:2800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2900::,2607:2900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2a00::,2607:2a00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2b00::,2607:2b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2c00::,2607:2c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2d00::,2607:2d00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:2e00::,2607:2e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:2f00::,2607:2f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3000::,2607:3000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3100::,2607:3100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3200::,2607:3200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3300::,2607:3300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3400::,2607:3400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3500::,2607:3500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3600::,2607:3600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3700::,2607:3700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3800::,2607:3800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3900::,2607:3900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3a00::,2607:3a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3b00::,2607:3b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3c00::,2607:3c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3d00::,2607:3d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3e00::,2607:3e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:3f00::,2607:3f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4000::,2607:4000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4100::,2607:4100:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:4200::,2607:4200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4300::,2607:4300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:4400::,2607:4400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4500::,2607:4500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4600::,2607:4600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4700::,2607:4700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4800::,2607:4800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4900::,2607:4900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4a00::,2607:4a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4b00::,2607:4b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4c00::,2607:4c00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:4d00::,2607:4d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4e00::,2607:4e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:4f00::,2607:4f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5000::,2607:5006:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5100::,2607:5100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5200::,2607:5200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5300::,2607:5300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:5400::,2607:5400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5500::,2607:5500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5600::,2607:5600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5700::,2607:5700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5800::,2607:5800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5900::,2607:5900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:5a00::,2607:5a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5b00::,2607:5b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5c00::,2607:5c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5d00::,2607:5d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:5e00::,2607:5e00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:5f00::,2607:5f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6000::,2607:6000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6100::,2607:6100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6200::,2607:6200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6300::,2607:6300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6400::,2607:6400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6500::,2607:6500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:6600::,2607:6600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6700::,2607:6700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6800::,2607:6800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6900::,2607:6900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6a00::,2607:6a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6b00::,2607:6b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6c00::,2607:6c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6d00::,2607:6d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6e00::,2607:6e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:6f00::,2607:6f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7000::,2607:7000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7100::,2607:7100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7200::,2607:7200:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:7300::,2607:7300:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:7400::,2607:7400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7500::,2607:7500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7600::,2607:7600:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:7700::,2607:7700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7800::,2607:7800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7900::,2607:7900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7a00::,2607:7a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7b00::,2607:7b00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:7c00::,2607:7c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7d00::,2607:7d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:7e00::,2607:7e00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:8000::,2607:8000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8100::,2607:8100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8200::,2607:8200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8300::,2607:8300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8400::,2607:8400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8500::,2607:8500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8600::,2607:8600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8700::,2607:8700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8800::,2607:8800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8900::,2607:8900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8a00::,2607:8a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8b00::,2607:8b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8c00::,2607:8c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8d00::,2607:8d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8e00::,2607:8e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:8f00::,2607:8f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9000::,2607:9000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9100::,2607:9100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9200::,2607:9200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9300::,2607:9300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9400::,2607:9400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9500::,2607:9500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:9600::,2607:9600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9700::,2607:9700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9800::,2607:9800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9900::,2607:9900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:9a00::,2607:9a00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9b00::,2607:9b00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9c00::,2607:9c00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9d00::,2607:9d00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9e00::,2607:9e00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:9f00::,2607:9f00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a000::,2607:a000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:a100::,2607:a10f:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a200::,2607:a200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a300::,2607:a300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a400::,2607:a400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a500::,2607:a500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a600::,2607:a600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a700::,2607:a700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a800::,2607:a800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:a900::,2607:a900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:aa00::,2607:aa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ab00::,2607:ab00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ac00::,2607:ac00:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2607:ad00::,2607:ad00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ae00::,2607:ae00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:af00::,2607:af00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b000::,2607:b000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b100::,2607:b100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b200::,2607:b200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b300::,2607:b300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b400::,2607:b400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b500::,2607:b500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b600::,2607:b600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b700::,2607:b700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b800::,2607:b800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:b900::,2607:b900:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ba00::,2607:ba00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:bb00::,2607:bb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:bc00::,2607:bc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:bd00::,2607:bd00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:be00::,2607:be00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:bf00::,2607:bf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c000::,2607:c000:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:c100::,2607:c100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c200::,2607:c200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c300::,2607:c300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c400::,2607:c400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c500::,2607:c500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c600::,2607:c600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c700::,2607:c700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c800::,2607:c800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:c900::,2607:c900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ca00::,2607:ca00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:cb00::,2607:cb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:cc00::,2607:cc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:cd00::,2607:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ce00::,2607:ce00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:cf00::,2607:cf00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d000::,2607:d000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d200::,2607:d200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d300::,2607:d300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d400::,2607:d400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d500::,2607:d500:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:d600::,2607:d600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d700::,2607:d700:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:d800::,2607:d800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:d900::,2607:d900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:da00::,2607:da00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:db00::,2607:db00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:dc00::,2607:dc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:dd00::,2607:dd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:de00::,2607:de00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:df00::,2607:df00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e000::,2607:e000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e100::,2607:e100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e200::,2607:e200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e300::,2607:e300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e400::,2607:e400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e500::,2607:e500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e600::,2607:e600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e700::,2607:e700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e800::,2607:e800:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:e900::,2607:e900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ea00::,2607:ea00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:eb00::,2607:eb00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ec00::,2607:ec00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ed00::,2607:ed00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ee00::,2607:ee00:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ef00::,2607:ef00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f000::,2607:f000:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f008::,2607:f008:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f010::,2607:f010:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f018::,2607:f018:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f020::,2607:f020:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f028::,2607:f028:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f030::,2607:f030:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f038::,2607:f038:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f040::,2607:f040:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f048::,2607:f048:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f050::,2607:f050:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f058::,2607:f058:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f060::,2607:f060:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f068::,2607:f068:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f070::,2607:f070:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f078::,2607:f078:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f080::,2607:f080:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f088::,2607:f088:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f090::,2607:f090:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f098::,2607:f098:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0a0::,2607:f0a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0a8::,2607:f0a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0b0::,2607:f0b0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f0c0::,2607:f0c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0c8::,2607:f0c8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f0d0::,2607:f0d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0d8::,2607:f0e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0e8::,2607:f0e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f0f8::,2607:f0f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f100::,2607:f100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f108::,2607:f108:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f110::,2607:f110:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f118::,2607:f118:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f128::,2607:f128:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f130::,2607:f130:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f138::,2607:f138:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f140::,2607:f140:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f148::,2607:f148:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f150::,2607:f150:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f158::,2607:f158:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f160::,2607:f160:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f168::,2607:f168:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f170::,2607:f170:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f178::,2607:f178:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f180::,2607:f180:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f188::,2607:f188:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f190::,2607:f190:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f198::,2607:f198:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1a0::,2607:f1a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1a8::,2607:f1a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1b0::,2607:f1b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1b8::,2607:f1b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1c0::,2607:f1c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1c8::,2607:f1c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1d0::,2607:f1d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1d8::,2607:f1d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1e0::,2607:f1e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1e8::,2607:f1e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f1f0::,2607:f1f0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f1f8::,2607:f1f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f200::,2607:f200:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f208::,2607:f208:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f210::,2607:f210:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f218::,2607:f218:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f220::,2607:f220:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f228::,2607:f228:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f230::,2607:f230:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f238::,2607:f238:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f240::,2607:f240:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f248::,2607:f248:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f250::,2607:f250:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f258::,2607:f258:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f260::,2607:f260:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f270::,2607:f270:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f278::,2607:f278:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f280::,2607:f281:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f288::,2607:f288:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f290::,2607:f290:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f298::,2607:f298:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2a8::,2607:f2a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2b0::,2607:f2b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2c0::,2607:f2c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f2c8::,2607:f2c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2d0::,2607:f2d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2d8::,2607:f2d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2e0::,2607:f2e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2e8::,2607:f2e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2f0::,2607:f2f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f2f8::,2607:f2f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f300::,2607:f300:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f308::,2607:f308:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f310::,2607:f310:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f318::,2607:f318:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f330::,2607:f330:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f338::,2607:f338:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f340::,2607:f340:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f348::,2607:f348:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f350::,2607:f350:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f358::,2607:f358:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f360::,2607:f360:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f368::,2607:f368:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f370::,2607:f370:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f378::,2607:f378:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f380::,2607:f380:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f388::,2607:f388:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f390::,2607:f390:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f398::,2607:f398:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3a0::,2607:f3a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3b0::,2607:f3b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3b8::,2607:f3b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3c0::,2607:f3c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3c8::,2607:f3c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3d0::,2607:f3d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3d8::,2607:f3d8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f3e0::,2607:f3e0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f3e8::,2607:f3e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3f0::,2607:f3f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f3f8::,2607:f3f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f400::,2607:f400:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f408::,2607:f408:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f410::,2607:f410:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f418::,2607:f418:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f420::,2607:f420:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f428::,2607:f428:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f430::,2607:f430:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f438::,2607:f438:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f440::,2607:f440:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f448::,2607:f448:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f450::,2607:f450:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f458::,2607:f458:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f460::,2607:f460:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f468::,2607:f468:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f470::,2607:f470:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f478::,2607:f478:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f480::,2607:f480:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f488::,2607:f488:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f490::,2607:f490:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f498::,2607:f498:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4a0::,2607:f4a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4a8::,2607:f4a8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f4b0::,2607:f4b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4b8::,2607:f4b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4c0::,2607:f4c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4c8::,2607:f4c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4d0::,2607:f4d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4d8::,2607:f4d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4e0::,2607:f4e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4e8::,2607:f4e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4f0::,2607:f4f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f4f8::,2607:f4f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f500::,2607:f500:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f508::,2607:f508:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f510::,2607:f510:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f518::,2607:f518:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f520::,2607:f520:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f528::,2607:f528:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f530::,2607:f530:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f538::,2607:f538:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f540::,2607:f540:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f548::,2607:f548:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f550::,2607:f550:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f558::,2607:f558:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f560::,2607:f560:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f568::,2607:f568:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f570::,2607:f570:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f578::,2607:f578:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f580::,2607:f580:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f588::,2607:f588:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f590::,2607:f590:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f598::,2607:f598:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5a0::,2607:f5a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5a8::,2607:f5a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5b0::,2607:f5b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5b8::,2607:f5b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5c0::,2607:f5c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5c8::,2607:f5c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5d0::,2607:f5d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5d8::,2607:f5d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5e0::,2607:f5e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5e8::,2607:f5e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5f0::,2607:f5f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f5f8::,2607:f5f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f600::,2607:f600:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f608::,2607:f608:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f610::,2607:f610:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f618::,2607:f618:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f620::,2607:f620:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f628::,2607:f628:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f630::,2607:f630:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f638::,2607:f638:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f640::,2607:f640:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f648::,2607:f648:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f650::,2607:f650:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f658::,2607:f658:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f660::,2607:f660:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f668::,2607:f668:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f670::,2607:f670:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f678::,2607:f678:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f680::,2607:f680:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f688::,2607:f688:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f690::,2607:f690:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f698::,2607:f698:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f6a0::,2607:f6a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6a8::,2607:f6a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6b0::,2607:f6b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6b8::,2607:f6b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6c0::,2607:f6c0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f6c8::,2607:f6c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6d0::,2607:f6d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6d8::,2607:f6d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6e0::,2607:f6e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6e8::,2607:f6e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6f0::,2607:f6f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f6f8::,2607:f6f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f700::,2607:f700:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f708::,2607:f708:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f710::,2607:f710:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f718::,2607:f718:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f720::,2607:f720:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f728::,2607:f728:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f730::,2607:f730:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f738::,2607:f738:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f740::,2607:f740:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f748::,2607:f748:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f750::,2607:f750:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f758::,2607:f758:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f760::,2607:f760:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f768::,2607:f768:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f770::,2607:f770:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f778::,2607:f778:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f788::,2607:f788:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f790::,2607:f790:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f798::,2607:f798:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f7a0::,2607:f7a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7a8::,2607:f7a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7b0::,2607:f7b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7b8::,2607:f7b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7c0::,2607:f7c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7c8::,2607:f7c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7d0::,2607:f7d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7d8::,2607:f7d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7e0::,2607:f7e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7e8::,2607:f7e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7f0::,2607:f7f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f7f8::,2607:f7f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f800::,2607:f800:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f808::,2607:f808:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f810::,2607:f810:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f818::,2607:f818:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f820::,2607:f820:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f828::,2607:f828:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f830::,2607:f830:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f838::,2607:f838:ffff:ffff:ffff:ffff:ffff:ffff,VI
+2607:f848::,2607:f848:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f850::,2607:f850:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f858::,2607:f858:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f860::,2607:f860:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f868::,2607:f868:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f870::,2607:f870:ffff:ffff:ffff:ffff:ffff:ffff,PR
+2607:f878::,2607:f878:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f880::,2607:f880:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f888::,2607:f888:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f890::,2607:f890:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f898::,2607:f898:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8a0::,2607:f8a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8a8::,2607:f8a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8b0::,2607:f8b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8b8::,2607:f8b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8c0::,2607:f8c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8c8::,2607:f8c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8d0::,2607:f8d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8d8::,2607:f8d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8e0::,2607:f8e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8e8::,2607:f8e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f8f0::,2607:f8f0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f8f8::,2607:f8f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f900::,2607:f900:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f908::,2607:f908:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f910::,2607:f910:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f920::,2607:f920:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f928::,2607:f928:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f930::,2607:f930:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f938::,2607:f938:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f940::,2607:f940:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f948::,2607:f948:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f950::,2607:f950:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f958::,2607:f958:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f960::,2607:f960:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f968::,2607:f968:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f978::,2607:f978:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f980::,2607:f980:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f990::,2607:f990:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:f998::,2607:f998:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9a0::,2607:f9a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9a8::,2607:f9a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9b0::,2607:f9b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9b8::,2607:f9b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9c0::,2607:f9c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9c8::,2607:f9c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9d0::,2607:f9d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9d8::,2607:f9d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9e0::,2607:f9e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9f0::,2607:f9f1:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:f9f8::,2607:f9f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa00::,2607:fa00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa08::,2607:fa08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa10::,2607:fa10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa18::,2607:fa18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa20::,2607:fa20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa28::,2607:fa28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa38::,2607:fa38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa40::,2607:fa40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa48::,2607:fa48:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fa58::,2607:fa58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa60::,2607:fa60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa68::,2607:fa68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa70::,2607:fa70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa78::,2607:fa78:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa80::,2607:fa80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa88::,2607:fa88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa90::,2607:fa90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fa98::,2607:fa98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:faa0::,2607:faa0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:faa8::,2607:faa8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fab0::,2607:fab0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fab8::,2607:fab8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fac0::,2607:fac0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fac8::,2607:fac8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fad0::,2607:fad0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fad8::,2607:fad8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fae0::,2607:fae0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fae8::,2607:fae8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:faf0::,2607:faf0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:faf8::,2607:faf8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb00::,2607:fb00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb08::,2607:fb08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb10::,2607:fb10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb18::,2607:fb18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb20::,2607:fb20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb28::,2607:fb28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb30::,2607:fb30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb38::,2607:fb38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb40::,2607:fb40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb48::,2607:fb48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb50::,2607:fb50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb58::,2607:fb58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb60::,2607:fb60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb68::,2607:fb68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb70::,2607:fb70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb78::,2607:fb78:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb80::,2607:fb80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb88::,2607:fb88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb90::,2607:fb90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fb98::,2607:fb98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fba0::,2607:fba0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fba8::,2607:fba8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbb0::,2607:fbb0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbb8::,2607:fbb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbc0::,2607:fbc0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbc8::,2607:fbc8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbd0::,2607:fbd0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbd8::,2607:fbd8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fbe0::,2607:fbe0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbe8::,2607:fbe8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbf0::,2607:fbf0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fbf8::,2607:fbf8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc00::,2607:fc00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc08::,2607:fc08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc10::,2607:fc10:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fc18::,2607:fc18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc20::,2607:fc20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc28::,2607:fc28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc30::,2607:fc30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc38::,2607:fc38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc40::,2607:fc40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc48::,2607:fc48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc50::,2607:fc50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc58::,2607:fc58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc60::,2607:fc60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc68::,2607:fc68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc70::,2607:fc70:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fc78::,2607:fc78:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fc80::,2607:fc80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc88::,2607:fc88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc90::,2607:fc90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fc98::,2607:fc98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fca0::,2607:fca0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fca8::,2607:fca8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcb8::,2607:fcb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcc0::,2607:fcc0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fcc8::,2607:fcc8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcd0::,2607:fcd0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcd8::,2607:fcd8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fce0::,2607:fce0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fce8::,2607:fce8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcf0::,2607:fcf0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fcf8::,2607:fcf8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fd00::,2607:fd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd08::,2607:fd08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd10::,2607:fd10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd18::,2607:fd18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd20::,2607:fd20:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fd28::,2607:fd28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd30::,2607:fd30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd38::,2607:fd38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd40::,2607:fd40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd48::,2607:fd48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd50::,2607:fd50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd60::,2607:fd60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd68::,2607:fd68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd70::,2607:fd70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd78::,2607:fd78:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fd80::,2607:fd80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd88::,2607:fd88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd90::,2607:fd90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fd98::,2607:fd98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fda0::,2607:fda0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fda8::,2607:fda8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdb0::,2607:fdb0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdb8::,2607:fdb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdc0::,2607:fdc0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdc8::,2607:fdc8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdd0::,2607:fdd0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdd8::,2607:fdd8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fde0::,2607:fde0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fde8::,2607:fde8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdf0::,2607:fdf0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fdf8::,2607:fdf8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe00::,2607:fe00:ffff:ffff:ffff:ffff:ffff:ffff,JM
+2607:fe08::,2607:fe08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe10::,2607:fe10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe18::,2607:fe18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe20::,2607:fe20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe28::,2607:fe28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe30::,2607:fe30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe38::,2607:fe38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe40::,2607:fe40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe48::,2607:fe48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe50::,2607:fe50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe58::,2607:fe58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe60::,2607:fe60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe68::,2607:fe68:ffff:ffff:ffff:ffff:ffff:ffff,BS
+2607:fe70::,2607:fe70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe78::,2607:fe78:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe80::,2607:fe80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe88::,2607:fe88:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fe90::,2607:fe90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fe98::,2607:fe98:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fea0::,2607:fea0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fea8::,2607:fea8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:feb0::,2607:feb0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:feb8::,2607:feb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fec0::,2607:fec0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fec8::,2607:fec8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:fed0::,2607:fed0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fed8::,2607:fed8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fee0::,2607:fee0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fee8::,2607:fee8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fef8::,2607:fef8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff00::,2607:ff00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff08::,2607:ff08:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff10::,2607:ff10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff18::,2607:ff18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff28::,2607:ff28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff30::,2607:ff30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff38::,2607:ff38:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff40::,2607:ff40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff48::,2607:ff48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff50::,2607:ff50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff58::,2607:ff58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff60::,2607:ff60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff68::,2607:ff68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff70::,2607:ff70:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff78::,2607:ff78:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ff80::,2607:ff80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ff90::,2607:ff90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffa0::,2607:ffa0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffa8::,2607:ffa8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffb0::,2607:ffb0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ffb8::,2607:ffb8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffc0::,2607:ffc0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ffc8::,2607:ffc8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffd0::,2607:ffd0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffd8::,2607:ffd8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:ffe0::,2607:ffe0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2607:ffe8::,2607:ffe8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fff0::,2607:fff0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2607:fff8::,2607:fff8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2608::,2608:3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2608:4000::,2608:43ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2608:8000::,2608:83ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2608:c000::,2608:c3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609::,2609:3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:4000::,2609:43ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:8000::,2609:83ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:a000::,2609:a3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:c000::,2609:c3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2609:e000::,2609:e3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+260c:d000::,260c:d3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+260c:f000::,260c:f3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+260f:d000::,260f:d3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+260f:f000::,260f:f3ff:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610::,2610:0:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:8::,2610:8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:10::,2610:10:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:18::,2610:18:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:20::,2610:20:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:28::,2610:28:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:30::,2610:30:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:38::,2610:38:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:40::,2610:40:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:48::,2610:48:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:50::,2610:50:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:58::,2610:58:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:60::,2610:60:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:68::,2610:68:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:78::,2610:78:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:80::,2610:88:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:90::,2610:90:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:98::,2610:98:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:a0::,2610:a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:b0::,2610:b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:b8::,2610:b8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:c0::,2610:c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:c8::,2610:c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:d0::,2610:d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:d8::,2610:d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:e0::,2610:e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:e8::,2610:e8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:f0::,2610:f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:f8::,2610:f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:100::,2610:100:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:108::,2610:108:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:110::,2610:110:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:120::,2610:120:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:128::,2610:128:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:130::,2610:130:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:140::,2610:140:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:148::,2610:148:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:150::,2610:150:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:158::,2610:158:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:160::,2610:160:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:168::,2610:168:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:170::,2610:170:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:178::,2610:178:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:180::,2610:180:ffff:ffff:ffff:ffff:ffff:ffff,BS
+2610:188::,2610:188:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:190::,2610:190:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:198::,2610:198:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1a0::,2610:1a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1a8::,2610:1a8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1b0::,2610:1b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1c0::,2610:1c2:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1c8::,2610:1c8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1d0::,2610:1d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1d8::,2610:1d8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1e0::,2610:1e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1e8::,2610:1e8:ffff:ffff:ffff:ffff:ffff:ffff,CA
+2610:1f0::,2610:1f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2610:1f8::,2610:1f8:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620::,2620::ffff:ffff:ffff:ffff:ffff,US
+2620:0:10::,2620:0:10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:20::,2620:0:20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:30::,2620:0:37:ffff:ffff:ffff:ffff:ffff,US
+2620:0:40::,2620:0:40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:60::,2620:0:60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:70::,2620:0:70:ffff:ffff:ffff:ffff:ffff,US
+2620:0:80::,2620:0:80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:90::,2620:0:90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:a0::,2620:0:a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b0::,2620:0:b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c0::,2620:0:c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:f0::,2620:0:f0:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:100::,2620:0:100:ffff:ffff:ffff:ffff:ffff,US
+2620:0:110::,2620:0:110:ffff:ffff:ffff:ffff:ffff,US
+2620:0:120::,2620:0:120:ffff:ffff:ffff:ffff:ffff,US
+2620:0:140::,2620:0:140:ffff:ffff:ffff:ffff:ffff,US
+2620:0:150::,2620:0:150:ffff:ffff:ffff:ffff:ffff,US
+2620:0:160::,2620:0:160:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:170::,2620:0:170:ffff:ffff:ffff:ffff:ffff,US
+2620:0:180::,2620:0:180:ffff:ffff:ffff:ffff:ffff,US
+2620:0:190::,2620:0:190:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a0::,2620:0:1a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1b0::,2620:0:1b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1c0::,2620:0:1c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1d0::,2620:0:1d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1f0::,2620:0:1f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:200::,2620:0:200:ffff:ffff:ffff:ffff:ffff,US
+2620:0:210::,2620:0:210:ffff:ffff:ffff:ffff:ffff,US
+2620:0:220::,2620:0:220:ffff:ffff:ffff:ffff:ffff,US
+2620:0:230::,2620:0:230:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:240::,2620:0:240:ffff:ffff:ffff:ffff:ffff,US
+2620:0:250::,2620:0:250:ffff:ffff:ffff:ffff:ffff,US
+2620:0:260::,2620:0:260:ffff:ffff:ffff:ffff:ffff,US
+2620:0:270::,2620:0:270:ffff:ffff:ffff:ffff:ffff,US
+2620:0:280::,2620:0:280:ffff:ffff:ffff:ffff:ffff,US
+2620:0:290::,2620:0:290:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b0::,2620:0:2b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2c0::,2620:0:2c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2d0::,2620:0:2d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2f0::,2620:0:2f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:300::,2620:0:300:ffff:ffff:ffff:ffff:ffff,US
+2620:0:310::,2620:0:310:ffff:ffff:ffff:ffff:ffff,US
+2620:0:320::,2620:0:320:ffff:ffff:ffff:ffff:ffff,US
+2620:0:340::,2620:0:340:ffff:ffff:ffff:ffff:ffff,US
+2620:0:350::,2620:0:353:ffff:ffff:ffff:ffff:ffff,US
+2620:0:360::,2620:0:361:ffff:ffff:ffff:ffff:ffff,US
+2620:0:370::,2620:0:370:ffff:ffff:ffff:ffff:ffff,US
+2620:0:380::,2620:0:380:ffff:ffff:ffff:ffff:ffff,US
+2620:0:390::,2620:0:390:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3a0::,2620:0:3a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3b0::,2620:0:3b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3c0::,2620:0:3c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3d0::,2620:0:3d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3e0::,2620:0:3e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3f0::,2620:0:3f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:400::,2620:0:57f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:600::,2620:0:600:ffff:ffff:ffff:ffff:ffff,US
+2620:0:610::,2620:0:610:ffff:ffff:ffff:ffff:ffff,US
+2620:0:630::,2620:0:630:ffff:ffff:ffff:ffff:ffff,US
+2620:0:640::,2620:0:640:ffff:ffff:ffff:ffff:ffff,US
+2620:0:650::,2620:0:650:ffff:ffff:ffff:ffff:ffff,US
+2620:0:660::,2620:0:660:ffff:ffff:ffff:ffff:ffff,US
+2620:0:670::,2620:0:671:ffff:ffff:ffff:ffff:ffff,US
+2620:0:680::,2620:0:680:ffff:ffff:ffff:ffff:ffff,US
+2620:0:690::,2620:0:691:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6a0::,2620:0:6a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6b0::,2620:0:6b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6c0::,2620:0:6c7:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6d0::,2620:0:6d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6e0::,2620:0:6e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:6f0::,2620:0:6f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:700::,2620:0:77f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:800::,2620:0:802:ffff:ffff:ffff:ffff:ffff,US
+2620:0:810::,2620:0:810:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:820::,2620:0:820:ffff:ffff:ffff:ffff:ffff,US
+2620:0:840::,2620:0:840:ffff:ffff:ffff:ffff:ffff,US
+2620:0:850::,2620:0:850:ffff:ffff:ffff:ffff:ffff,US
+2620:0:860::,2620:0:863:ffff:ffff:ffff:ffff:ffff,US
+2620:0:870::,2620:0:877:ffff:ffff:ffff:ffff:ffff,US
+2620:0:880::,2620:0:880:ffff:ffff:ffff:ffff:ffff,US
+2620:0:890::,2620:0:890:ffff:ffff:ffff:ffff:ffff,US
+2620:0:8a0::,2620:0:8a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:8d0::,2620:0:8d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:8e0::,2620:0:8e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:8f0::,2620:0:8f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:900::,2620:0:900:ffff:ffff:ffff:ffff:ffff,US
+2620:0:910::,2620:0:910:ffff:ffff:ffff:ffff:ffff,US
+2620:0:920::,2620:0:920:ffff:ffff:ffff:ffff:ffff,US
+2620:0:930::,2620:0:930:ffff:ffff:ffff:ffff:ffff,US
+2620:0:940::,2620:0:940:ffff:ffff:ffff:ffff:ffff,US
+2620:0:950::,2620:0:950:ffff:ffff:ffff:ffff:ffff,US
+2620:0:960::,2620:0:960:ffff:ffff:ffff:ffff:ffff,US
+2620:0:970::,2620:0:970:ffff:ffff:ffff:ffff:ffff,US
+2620:0:980::,2620:0:980:ffff:ffff:ffff:ffff:ffff,US
+2620:0:990::,2620:0:990:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9a0::,2620:0:9a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9b0::,2620:0:9b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9c0::,2620:0:9c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9e0::,2620:0:9e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:9f0::,2620:0:9f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:a00::,2620:0:a1f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b00::,2620:0:b00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b10::,2620:0:b13:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b20::,2620:0:b20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b30::,2620:0:b30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b40::,2620:0:b40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b50::,2620:0:b50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b60::,2620:0:b61:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b80::,2620:0:b80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:b90::,2620:0:b90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ba0::,2620:0:ba0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:bb0::,2620:0:bb0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:bc0::,2620:0:bc0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:bd0::,2620:0:bd0:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:be0::,2620:0:be0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:bf0::,2620:0:bf0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c10::,2620:0:c10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c20::,2620:0:c20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c30::,2620:0:c30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c40::,2620:0:c40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c60::,2620:0:c60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c70::,2620:0:c70:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c80::,2620:0:c80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:c90::,2620:0:c90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ca0::,2620:0:ca0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:cb0::,2620:0:cb0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:cc0::,2620:0:ccf:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ce0::,2620:0:ce0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:cf0::,2620:0:cf0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d00::,2620:0:d00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d20::,2620:0:d20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d30::,2620:0:d30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d50::,2620:0:d50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d60::,2620:0:d63:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d70::,2620:0:d77:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d80::,2620:0:d80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:d90::,2620:0:d90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:dc0::,2620:0:dc0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:dd0::,2620:0:dd0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:de0::,2620:0:de0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:df0::,2620:0:df0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e00::,2620:0:e00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e10::,2620:0:e10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e20::,2620:0:e23:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e30::,2620:0:e30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e40::,2620:0:e40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e50::,2620:0:e50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e60::,2620:0:e60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e80::,2620:0:e80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:e90::,2620:0:e90:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ea0::,2620:0:eb0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ed0::,2620:0:ed0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ee0::,2620:0:ee0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:ef0::,2620:0:ef0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:f00::,2620:0:f7f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1000::,2620:0:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1400::,2620:0:143f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1500::,2620:0:157f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1600::,2620:0:167f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1700::,2620:0:170f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1800::,2620:0:181f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a00::,2620:0:1a00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a10::,2620:0:1a10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a20::,2620:0:1a20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a30::,2620:0:1a30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a40::,2620:0:1a40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a50::,2620:0:1a50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a60::,2620:0:1a60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a70::,2620:0:1a70:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1a80::,2620:0:1a80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1aa0::,2620:0:1aa0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1ab0::,2620:0:1ab0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1ac0::,2620:0:1ac0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1ad0::,2620:0:1ad7:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1ae0::,2620:0:1ae0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1af0::,2620:0:1af0:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:1b00::,2620:0:1b07:ffff:ffff:ffff:ffff:ffff,US
+2620:0:1c00::,2620:0:1cff:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2000::,2620:0:203f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2100::,2620:0:213f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2210::,2620:0:2210:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2220::,2620:0:2220:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:2240::,2620:0:2240:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2250::,2620:0:2250:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2260::,2620:0:2260:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2270::,2620:0:2270:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2280::,2620:0:2280:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2290::,2620:0:2290:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22a0::,2620:0:22a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22b0::,2620:0:22b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22c0::,2620:0:22c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22d0::,2620:0:22d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:22e0::,2620:0:22e0:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:22f0::,2620:0:22f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2300::,2620:0:230f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2400::,2620:0:24ff:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2800::,2620:0:2800:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2810::,2620:0:2810:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2820::,2620:0:2820:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2830::,2620:0:2830:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2840::,2620:0:2840:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2850::,2620:0:2850:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2860::,2620:0:2860:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2870::,2620:0:2870:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2880::,2620:0:2880:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28a0::,2620:0:28a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28b0::,2620:0:28b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28c0::,2620:0:28c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28d0::,2620:0:28d0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:28f0::,2620:0:28f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2900::,2620:0:290f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2a00::,2620:0:2a1f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b00::,2620:0:2b00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b10::,2620:0:2b10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b20::,2620:0:2b20:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b30::,2620:0:2b30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b40::,2620:0:2b40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b50::,2620:0:2b50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b60::,2620:0:2b60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b70::,2620:0:2b70:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2b80::,2620:0:2b8f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2bc0::,2620:0:2bc3:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2bd0::,2620:0:2bd0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2be0::,2620:0:2be0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2bf0::,2620:0:2bf0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2d00::,2620:0:2d7f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e00::,2620:0:2e00:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e10::,2620:0:2e10:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e30::,2620:0:2e30:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e40::,2620:0:2e40:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e50::,2620:0:2e50:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e60::,2620:0:2e60:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2e70::,2620:0:2e80:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2ea0::,2620:0:2ea0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2eb0::,2620:0:2eb0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2ed0::,2620:0:2ed0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2ee0::,2620:0:2ee0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:2f00::,2620:0:2f7f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:3000::,2620:0:31ff:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5000::,2620:0:5000:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5010::,2620:0:5010:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5030::,2620:0:5030:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5040::,2620:0:5040:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5050::,2620:0:5050:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5060::,2620:0:5060:ffff:ffff:ffff:ffff:ffff,CA
+2620:0:5070::,2620:0:5070:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5080::,2620:0:5080:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5090::,2620:0:5090:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50a0::,2620:0:50a0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50b0::,2620:0:50b0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50c0::,2620:0:50c0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50d0::,2620:0:50d1:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50e0::,2620:0:50e0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:50f0::,2620:0:50f0:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5100::,2620:0:510f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5200::,2620:0:5200:ffff:ffff:ffff:ffff:ffff,US
+2620:0:5300::,2620:0:530f:ffff:ffff:ffff:ffff:ffff,US
+2620:0:aa00::,2620:0:aa00:ffff:ffff:ffff:ffff:ffff,US
+2620:1::,2620:1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1:4000::,2620:1:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:1:8000::,2620:1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1:c000::,2620:1:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:2::,2620:2:0:ffff:ffff:ffff:ffff:ffff,US
+2620:2:4000::,2620:2:4000:ffff:ffff:ffff:ffff:ffff,CA
+2620:2:8000::,2620:2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2:c000::,2620:2:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:3::,2620:3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3:4000::,2620:3:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:3:8000::,2620:3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3:c000::,2620:3:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:4::,2620:4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4:4000::,2620:4:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:4:8000::,2620:4:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4:c000::,2620:4:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:5::,2620:5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5:4000::,2620:5:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:5:8000::,2620:5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5:c000::,2620:5:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:6::,2620:6:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:6:4000::,2620:6:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:6:8000::,2620:6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6:c000::,2620:6:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:7::,2620:7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:7:4000::,2620:7:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:7:8000::,2620:7:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7:c000::,2620:7:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:8::,2620:8:7f:ffff:ffff:ffff:ffff:ffff,CA
+2620:8:8200::,2620:8:8200:ffff:ffff:ffff:ffff:ffff,US
+2620:9::,2620:9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9:4000::,2620:9:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:9:8000::,2620:9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9:c000::,2620:9:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:a::,2620:a:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:a:4000::,2620:a:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:a:8000::,2620:a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a:c000::,2620:a:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:b::,2620:b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b:4000::,2620:b:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:b:8000::,2620:b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b:c000::,2620:b:c000:ffff:ffff:ffff:ffff:ffff,US
+2620:c::,2620:c:3:ffff:ffff:ffff:ffff:ffff,US
+2620:c:8000::,2620:c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d:8000::,2620:d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e::,2620:e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e:8000::,2620:e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f::,2620:f:3:ffff:ffff:ffff:ffff:ffff,US
+2620:f:8000::,2620:f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:10::,2620:10:0:ffff:ffff:ffff:ffff:ffff,US
+2620:10:8000::,2620:10:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:11::,2620:11:0:ffff:ffff:ffff:ffff:ffff,US
+2620:11:8000::,2620:11:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:12::,2620:12:0:ffff:ffff:ffff:ffff:ffff,US
+2620:12:8000::,2620:12:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:13::,2620:13:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:13:8000::,2620:13:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:14::,2620:14:0:ffff:ffff:ffff:ffff:ffff,US
+2620:14:8000::,2620:14:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:15::,2620:15:0:ffff:ffff:ffff:ffff:ffff,US
+2620:15:8000::,2620:15:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:16::,2620:16:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:16:8000::,2620:16:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:17::,2620:17:0:ffff:ffff:ffff:ffff:ffff,US
+2620:17:8000::,2620:17:8001:ffff:ffff:ffff:ffff:ffff,US
+2620:18::,2620:18:0:ffff:ffff:ffff:ffff:ffff,US
+2620:18:8000::,2620:18:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:19::,2620:19:0:ffff:ffff:ffff:ffff:ffff,US
+2620:19:8000::,2620:19:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1a::,2620:1a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1a:8000::,2620:1a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1b::,2620:1b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1b:8000::,2620:1b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1c::,2620:1c:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1c:8000::,2620:1c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1d::,2620:1d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1d:8000::,2620:1d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1e::,2620:1e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1e:8000::,2620:1e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:1f::,2620:1f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:1f:8000::,2620:1f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:20::,2620:20:0:ffff:ffff:ffff:ffff:ffff,US
+2620:20:8000::,2620:20:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:21::,2620:21:0:ffff:ffff:ffff:ffff:ffff,US
+2620:21:8000::,2620:21:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:22::,2620:22:0:ffff:ffff:ffff:ffff:ffff,US
+2620:22:8000::,2620:22:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:23::,2620:23:0:ffff:ffff:ffff:ffff:ffff,US
+2620:23:8000::,2620:23:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:24::,2620:24:1f:ffff:ffff:ffff:ffff:ffff,US
+2620:24:8080::,2620:24:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:25::,2620:25:0:ffff:ffff:ffff:ffff:ffff,US
+2620:25:8000::,2620:25:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:26::,2620:26:0:ffff:ffff:ffff:ffff:ffff,US
+2620:26:8000::,2620:26:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:27::,2620:27:f:ffff:ffff:ffff:ffff:ffff,US
+2620:27:8080::,2620:27:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:28::,2620:28:0:ffff:ffff:ffff:ffff:ffff,US
+2620:28:8000::,2620:28:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:29::,2620:29:0:ffff:ffff:ffff:ffff:ffff,US
+2620:29:8000::,2620:29:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2a::,2620:2a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:2a:8000::,2620:2a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2b::,2620:2b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:2b:8000::,2620:2b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2c::,2620:2c:f:ffff:ffff:ffff:ffff:ffff,US
+2620:2c:8080::,2620:2c:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:2d::,2620:2d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:2d:8000::,2620:2d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:2e::,2620:2e:3f:ffff:ffff:ffff:ffff:ffff,US
+2620:2e:8080::,2620:2e:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:2f::,2620:2f:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:2f:8000::,2620:2f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:30::,2620:30:0:ffff:ffff:ffff:ffff:ffff,US
+2620:30:8000::,2620:30:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:31::,2620:31:0:ffff:ffff:ffff:ffff:ffff,US
+2620:31:8000::,2620:31:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:32::,2620:32:0:ffff:ffff:ffff:ffff:ffff,US
+2620:32:8000::,2620:32:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:33::,2620:33:0:ffff:ffff:ffff:ffff:ffff,US
+2620:33:8000::,2620:33:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:34::,2620:34:0:ffff:ffff:ffff:ffff:ffff,US
+2620:34:8000::,2620:34:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:35::,2620:35:0:ffff:ffff:ffff:ffff:ffff,US
+2620:35:8000::,2620:35:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:36::,2620:36:0:ffff:ffff:ffff:ffff:ffff,US
+2620:36:8000::,2620:36:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:37::,2620:37:0:ffff:ffff:ffff:ffff:ffff,US
+2620:37:8000::,2620:37:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:38::,2620:38:0:ffff:ffff:ffff:ffff:ffff,US
+2620:38:8000::,2620:38:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:39::,2620:39:0:ffff:ffff:ffff:ffff:ffff,US
+2620:39:8000::,2620:39:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3a::,2620:3a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3a:8000::,2620:3a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3b::,2620:3b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3b:8000::,2620:3b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3c::,2620:3c:3f:ffff:ffff:ffff:ffff:ffff,US
+2620:3c:8080::,2620:3c:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:3d::,2620:3d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3d:8000::,2620:3d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3e::,2620:3e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3e:8000::,2620:3e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:3f::,2620:3f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:3f:8000::,2620:3f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:40::,2620:40:0:ffff:ffff:ffff:ffff:ffff,US
+2620:40:8000::,2620:40:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:41::,2620:41:0:ffff:ffff:ffff:ffff:ffff,US
+2620:41:8000::,2620:41:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:42::,2620:42:0:ffff:ffff:ffff:ffff:ffff,US
+2620:42:8000::,2620:42:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:43::,2620:43:0:ffff:ffff:ffff:ffff:ffff,US
+2620:43:8000::,2620:43:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:44::,2620:44:1:ffff:ffff:ffff:ffff:ffff,US
+2620:44:8000::,2620:44:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:45::,2620:45:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:45:8000::,2620:45:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:46::,2620:46:0:ffff:ffff:ffff:ffff:ffff,US
+2620:46:8000::,2620:46:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:47::,2620:47:0:ffff:ffff:ffff:ffff:ffff,US
+2620:47:8000::,2620:47:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:48::,2620:48:0:ffff:ffff:ffff:ffff:ffff,US
+2620:48:8000::,2620:48:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:49::,2620:49:f:ffff:ffff:ffff:ffff:ffff,CA
+2620:49:8080::,2620:49:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:4a::,2620:4a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4a:8000::,2620:4a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4b::,2620:4b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4b:8000::,2620:4b:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:4c::,2620:4c:1:ffff:ffff:ffff:ffff:ffff,US
+2620:4c:8000::,2620:4c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4d::,2620:4d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4d:8000::,2620:4d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4e::,2620:4e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4e:8000::,2620:4e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:4f::,2620:4f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:4f:8000::,2620:4f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:50::,2620:50:f:ffff:ffff:ffff:ffff:ffff,US
+2620:50:8080::,2620:50:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:51::,2620:51:0:ffff:ffff:ffff:ffff:ffff,US
+2620:51:8000::,2620:51:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:52::,2620:52:3:ffff:ffff:ffff:ffff:ffff,US
+2620:52:8000::,2620:52:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:53::,2620:53:0:ffff:ffff:ffff:ffff:ffff,US
+2620:53:8000::,2620:53:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:54::,2620:54:0:ffff:ffff:ffff:ffff:ffff,US
+2620:54:8000::,2620:54:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:55::,2620:55:0:ffff:ffff:ffff:ffff:ffff,US
+2620:55:8000::,2620:55:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:56::,2620:56:0:ffff:ffff:ffff:ffff:ffff,US
+2620:56:8000::,2620:56:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:57::,2620:57:0:ffff:ffff:ffff:ffff:ffff,US
+2620:57:8000::,2620:57:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:58::,2620:58:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:59::,2620:59:0:ffff:ffff:ffff:ffff:ffff,US
+2620:59:8000::,2620:59:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5a::,2620:5a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5a:8000::,2620:5a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5b::,2620:5b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5b:8000::,2620:5b:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:5c::,2620:5c:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5c:8000::,2620:5c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5d::,2620:5d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5d:8000::,2620:5d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5e::,2620:5e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5e:8000::,2620:5e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:5f::,2620:5f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:5f:8000::,2620:5f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:60::,2620:60:0:ffff:ffff:ffff:ffff:ffff,US
+2620:60:8000::,2620:60:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:61::,2620:61:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:61:8000::,2620:61:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:62::,2620:62:0:ffff:ffff:ffff:ffff:ffff,US
+2620:62:8000::,2620:62:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:63::,2620:63:0:ffff:ffff:ffff:ffff:ffff,US
+2620:63:8000::,2620:63:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:64::,2620:64:0:ffff:ffff:ffff:ffff:ffff,US
+2620:64:8000::,2620:64:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:65::,2620:65:0:ffff:ffff:ffff:ffff:ffff,US
+2620:65:8000::,2620:65:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:66::,2620:66:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:66:8000::,2620:66:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:67::,2620:67:0:ffff:ffff:ffff:ffff:ffff,US
+2620:68::,2620:68:0:ffff:ffff:ffff:ffff:ffff,US
+2620:68:8000::,2620:68:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:69::,2620:69:0:ffff:ffff:ffff:ffff:ffff,US
+2620:69:8000::,2620:69:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6a::,2620:6a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6a:8000::,2620:6a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6b::,2620:6b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6b:8000::,2620:6b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6c::,2620:6c:3f:ffff:ffff:ffff:ffff:ffff,US
+2620:6c:8080::,2620:6c:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:6d::,2620:6d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6d:8000::,2620:6d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6e::,2620:6e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6e:8000::,2620:6e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:6f::,2620:6f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:6f:8000::,2620:6f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:70::,2620:70:0:ffff:ffff:ffff:ffff:ffff,US
+2620:70:8000::,2620:70:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:71::,2620:71:0:ffff:ffff:ffff:ffff:ffff,US
+2620:71:8000::,2620:71:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:72::,2620:72:0:ffff:ffff:ffff:ffff:ffff,US
+2620:72:8000::,2620:72:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:73::,2620:73:0:ffff:ffff:ffff:ffff:ffff,US
+2620:73:8000::,2620:73:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:74::,2620:74:1f:ffff:ffff:ffff:ffff:ffff,US
+2620:74:8080::,2620:74:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:75::,2620:75:0:ffff:ffff:ffff:ffff:ffff,US
+2620:75:8000::,2620:75:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:76::,2620:76:0:ffff:ffff:ffff:ffff:ffff,US
+2620:76:8000::,2620:76:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:77::,2620:77:0:ffff:ffff:ffff:ffff:ffff,US
+2620:77:8000::,2620:77:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:78::,2620:78:0:ffff:ffff:ffff:ffff:ffff,US
+2620:78:8000::,2620:78:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:79::,2620:79:0:ffff:ffff:ffff:ffff:ffff,US
+2620:79:8000::,2620:79:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7a::,2620:7a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:7a:8000::,2620:7a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7b::,2620:7b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:7b:8000::,2620:7b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7b:e000::,2620:7b:e000:ffff:ffff:ffff:ffff:ffff,US
+2620:7c:4000::,2620:7c:4000:ffff:ffff:ffff:ffff:ffff,US
+2620:7c:a000::,2620:7c:a000:ffff:ffff:ffff:ffff:ffff,US
+2620:7d::,2620:7d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:7d:8000::,2620:7d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:7e::,2620:7e:f:ffff:ffff:ffff:ffff:ffff,US
+2620:7e:60c0::,2620:7e:60c0:ffff:ffff:ffff:ffff:ffff,US
+2620:7e:c080::,2620:7e:c080:ffff:ffff:ffff:ffff:ffff,US
+2620:7f:2040::,2620:7f:2040:ffff:ffff:ffff:ffff:ffff,US
+2620:7f:8000::,2620:7f:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:80::,2620:80:0:ffff:ffff:ffff:ffff:ffff,US
+2620:80:8000::,2620:80:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:81::,2620:81:0:ffff:ffff:ffff:ffff:ffff,US
+2620:81:8000::,2620:81:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:82::,2620:82:0:ffff:ffff:ffff:ffff:ffff,US
+2620:82:8000::,2620:82:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:83::,2620:83:0:ffff:ffff:ffff:ffff:ffff,US
+2620:83:8000::,2620:83:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:84::,2620:84:1:ffff:ffff:ffff:ffff:ffff,US
+2620:84:8000::,2620:84:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:85::,2620:85:0:ffff:ffff:ffff:ffff:ffff,US
+2620:85:8000::,2620:85:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:86::,2620:86:0:ffff:ffff:ffff:ffff:ffff,US
+2620:86:8000::,2620:86:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:87::,2620:87:0:ffff:ffff:ffff:ffff:ffff,US
+2620:87:8000::,2620:87:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:88::,2620:88:0:ffff:ffff:ffff:ffff:ffff,US
+2620:88:8000::,2620:88:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:89::,2620:89:0:ffff:ffff:ffff:ffff:ffff,US
+2620:89:8000::,2620:89:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8a::,2620:8a:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8a:8000::,2620:8a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8b::,2620:8b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8b:8000::,2620:8b:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:8c::,2620:8c:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8c:8000::,2620:8c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8d::,2620:8d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8d:8000::,2620:8d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8e::,2620:8e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8e:8000::,2620:8e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:8f::,2620:8f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:8f:8000::,2620:8f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:90::,2620:90:0:ffff:ffff:ffff:ffff:ffff,US
+2620:90:8000::,2620:90:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:91::,2620:91:0:ffff:ffff:ffff:ffff:ffff,US
+2620:91:8000::,2620:91:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:92::,2620:92:0:ffff:ffff:ffff:ffff:ffff,US
+2620:92:8000::,2620:92:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:93::,2620:93:0:ffff:ffff:ffff:ffff:ffff,US
+2620:93:8000::,2620:93:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:94::,2620:94:0:ffff:ffff:ffff:ffff:ffff,US
+2620:94:8000::,2620:94:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:95::,2620:95:0:ffff:ffff:ffff:ffff:ffff,US
+2620:95:8000::,2620:95:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:96::,2620:96:0:ffff:ffff:ffff:ffff:ffff,US
+2620:96:8000::,2620:96:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:97::,2620:97:0:ffff:ffff:ffff:ffff:ffff,US
+2620:97:8000::,2620:97:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:98::,2620:98:0:ffff:ffff:ffff:ffff:ffff,US
+2620:98:8000::,2620:98:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:99::,2620:99:0:ffff:ffff:ffff:ffff:ffff,US
+2620:99:8000::,2620:99:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9a::,2620:9a:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:9a:8000::,2620:9a:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9b::,2620:9b:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9b:8000::,2620:9b:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9c::,2620:9c:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9c:8000::,2620:9c:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9d::,2620:9d:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9d:8000::,2620:9d:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9e::,2620:9e:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9e:8000::,2620:9e:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:9f::,2620:9f:0:ffff:ffff:ffff:ffff:ffff,US
+2620:9f:8000::,2620:9f:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a0::,2620:a0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a0:8000::,2620:a0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a1::,2620:a1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a1:8000::,2620:a1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a2::,2620:a2:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a2:8000::,2620:a2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a3::,2620:a3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a3:8000::,2620:a3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a4::,2620:a4:f:ffff:ffff:ffff:ffff:ffff,US
+2620:a4:8080::,2620:a4:8080:ffff:ffff:ffff:ffff:ffff,US
+2620:a5::,2620:a5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a5:8000::,2620:a5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a6::,2620:a6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a6:8000::,2620:a6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a7::,2620:a7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a7:8000::,2620:a7:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a8::,2620:a8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a8:8000::,2620:a8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:a9::,2620:a9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:a9:8000::,2620:a9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:aa::,2620:aa:0:ffff:ffff:ffff:ffff:ffff,US
+2620:aa:8000::,2620:aa:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ab::,2620:ab:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ab:8000::,2620:ab:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ac::,2620:ac:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ac:8000::,2620:ac:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ad::,2620:ad:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ad:8000::,2620:ad:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ae::,2620:ae:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:ae:8000::,2620:ae:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:af::,2620:af:0:ffff:ffff:ffff:ffff:ffff,US
+2620:af:8000::,2620:af:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b0::,2620:b0:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:b0:8000::,2620:b0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b1::,2620:b1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b1:8000::,2620:b1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b2:8000::,2620:b2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b3::,2620:b3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b3:8000::,2620:b3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b4::,2620:b4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b4:8000::,2620:b4:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:b5::,2620:b5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b5:8000::,2620:b5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b6::,2620:b6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b6:8000::,2620:b6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b7::,2620:b7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b7:8000::,2620:b7:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:b8::,2620:b8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b8:8000::,2620:b8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:b9::,2620:b9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:b9:8000::,2620:b9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ba::,2620:ba:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ba:8000::,2620:ba:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:bb::,2620:bb:0:ffff:ffff:ffff:ffff:ffff,US
+2620:bb:8000::,2620:bb:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:bc::,2620:bc:0:ffff:ffff:ffff:ffff:ffff,US
+2620:bc:8000::,2620:bc:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:bd::,2620:bd:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:bd:8000::,2620:bd:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:be::,2620:be:0:ffff:ffff:ffff:ffff:ffff,US
+2620:be:8000::,2620:be:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:bf::,2620:bf:0:ffff:ffff:ffff:ffff:ffff,US
+2620:bf:8000::,2620:bf:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c0::,2620:c0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c0:8000::,2620:c0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c1::,2620:c1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c1:8000::,2620:c1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c2::,2620:c2:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:c2:8000::,2620:c2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c3::,2620:c3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c3:8000::,2620:c3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c4::,2620:c4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c4:8000::,2620:c4:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c5::,2620:c5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c5:8000::,2620:c5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c6::,2620:c6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c6:8000::,2620:c6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c7::,2620:c7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c7:8000::,2620:c7:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c8::,2620:c8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c8:8000::,2620:c8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:c9::,2620:c9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:c9:8000::,2620:c9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ca::,2620:ca:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ca:8000::,2620:ca:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:cb::,2620:cb:0:ffff:ffff:ffff:ffff:ffff,US
+2620:cb:8000::,2620:cb:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:cc::,2620:cc:0:ffff:ffff:ffff:ffff:ffff,US
+2620:cc:8000::,2620:cc:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:cd::,2620:cd:0:ffff:ffff:ffff:ffff:ffff,US
+2620:cd:8000::,2620:cd:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ce::,2620:ce:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ce:8000::,2620:ce:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:cf::,2620:cf:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d0::,2620:d0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d0:8000::,2620:d0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d1::,2620:d1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d1:8000::,2620:d1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d2::,2620:d2:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d2:8000::,2620:d2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d3::,2620:d3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d3:8000::,2620:d3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d4::,2620:d4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d5::,2620:d5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d5:8000::,2620:d5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d6::,2620:d6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d6:8000::,2620:d6:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:d7::,2620:d7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d8::,2620:d8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:d8:8000::,2620:d8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:d9::,2620:d9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:da::,2620:da:0:ffff:ffff:ffff:ffff:ffff,US
+2620:db::,2620:db:0:ffff:ffff:ffff:ffff:ffff,US
+2620:db:8000::,2620:db:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:dc::,2620:dc:0:ffff:ffff:ffff:ffff:ffff,US
+2620:dc:8::,2620:dc:8:ffff:ffff:ffff:ffff:ffff,US
+2620:dc:8000::,2620:dc:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:dd::,2620:dd:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:dd:8000::,2620:dd:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:de::,2620:de:0:ffff:ffff:ffff:ffff:ffff,US
+2620:de:8000::,2620:de:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:df::,2620:df:0:ffff:ffff:ffff:ffff:ffff,US
+2620:df:8000::,2620:df:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e0::,2620:e0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e0:8000::,2620:e0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e1::,2620:e1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e1:8000::,2620:e1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e2::,2620:e2:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e2:8000::,2620:e2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e3::,2620:e3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e3:8000::,2620:e3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e4::,2620:e4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e4:8000::,2620:e4:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e5::,2620:e5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e5:8000::,2620:e5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e6::,2620:e6:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e6:8000::,2620:e6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e7::,2620:e7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e7:8000::,2620:e7:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:e8::,2620:e8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e8:8000::,2620:e8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:e9::,2620:e9:0:ffff:ffff:ffff:ffff:ffff,US
+2620:e9:8000::,2620:e9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ea::,2620:ea:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ea:8000::,2620:ea:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:eb::,2620:eb:0:ffff:ffff:ffff:ffff:ffff,US
+2620:eb:8000::,2620:eb:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ec::,2620:ec:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ec:8000::,2620:ec:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ed::,2620:ed:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ed:8000::,2620:ed:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ee::,2620:ee:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ee:8000::,2620:ee:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ef::,2620:ef:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ef:8000::,2620:ef:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f0::,2620:f0:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f0:8000::,2620:f0:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f1::,2620:f1:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f1:8000::,2620:f1:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f2::,2620:f2:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:f2:8000::,2620:f2:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f3::,2620:f3:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f3:8000::,2620:f3:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f4::,2620:f4:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f4:8000::,2620:f4:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:f5::,2620:f5:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f5:8000::,2620:f5:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f6::,2620:f6:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:f6:8000::,2620:f6:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f7::,2620:f7:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f7:8000::,2620:f7:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f8::,2620:f8:0:ffff:ffff:ffff:ffff:ffff,US
+2620:f8:8000::,2620:f8:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:f9::,2620:f9:f:ffff:ffff:ffff:ffff:ffff,US
+2620:f9:8000::,2620:f9:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:fa::,2620:fa:0:ffff:ffff:ffff:ffff:ffff,US
+2620:fa:8000::,2620:fa:8000:ffff:ffff:ffff:ffff:ffff,CA
+2620:fb::,2620:fb:0:ffff:ffff:ffff:ffff:ffff,US
+2620:fb:8000::,2620:fb:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:fc::,2620:fc:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:fc:8000::,2620:fc:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:fd::,2620:fd:0:ffff:ffff:ffff:ffff:ffff,CA
+2620:fd:8000::,2620:fd:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:fe::,2620:fe:0:ffff:ffff:ffff:ffff:ffff,US
+2620:fe:8000::,2620:fe:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:ff::,2620:ff:0:ffff:ffff:ffff:ffff:ffff,US
+2620:ff:8000::,2620:ff:8000:ffff:ffff:ffff:ffff:ffff,US
+2620:100::,2620:100:f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:1000::,2620:100:1001:ffff:ffff:ffff:ffff:ffff,US
+2620:100:3000::,2620:100:3007:ffff:ffff:ffff:ffff:ffff,US
+2620:100:4000::,2620:100:403f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:5000::,2620:100:5007:ffff:ffff:ffff:ffff:ffff,US
+2620:100:6000::,2620:100:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:7000::,2620:100:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:8000::,2620:100:8003:ffff:ffff:ffff:ffff:ffff,US
+2620:100:9000::,2620:100:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:a000::,2620:100:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:c000::,2620:100:c03f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:d000::,2620:100:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:e000::,2620:100:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:100:f000::,2620:100:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:101::,2620:101:3:ffff:ffff:ffff:ffff:ffff,US
+2620:101:1000::,2620:101:103f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:2000::,2620:101:201f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:3000::,2620:101:303f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:4000::,2620:101:403f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:5000::,2620:101:503f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:6000::,2620:101:6001:ffff:ffff:ffff:ffff:ffff,US
+2620:101:7000::,2620:101:7001:ffff:ffff:ffff:ffff:ffff,US
+2620:101:8000::,2620:101:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:9000::,2620:101:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:a000::,2620:101:a001:ffff:ffff:ffff:ffff:ffff,US
+2620:101:b000::,2620:101:b07f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:c000::,2620:101:c00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:101:d000::,2620:101:d007:ffff:ffff:ffff:ffff:ffff,US
+2620:101:e000::,2620:101:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:101:f000::,2620:101:f001:ffff:ffff:ffff:ffff:ffff,CA
+2620:102::,2620:102:f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:1000::,2620:102:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:2000::,2620:102:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:3000::,2620:102:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:4000::,2620:102:403f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:5000::,2620:102:501f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:6000::,2620:102:6003:ffff:ffff:ffff:ffff:ffff,US
+2620:102:7000::,2620:102:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:8000::,2620:102:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:9000::,2620:102:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:102:a000::,2620:102:a01f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:b000::,2620:102:b001:ffff:ffff:ffff:ffff:ffff,US
+2620:102:c000::,2620:102:c007:ffff:ffff:ffff:ffff:ffff,US
+2620:102:d000::,2620:102:d07f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:e000::,2620:102:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:102:f000::,2620:102:f003:ffff:ffff:ffff:ffff:ffff,US
+2620:103::,2620:103:7:ffff:ffff:ffff:ffff:ffff,US
+2620:103:1000::,2620:103:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:2000::,2620:103:200f:ffff:ffff:ffff:ffff:ffff,CA
+2620:103:3000::,2620:103:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:103:4000::,2620:103:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:5000::,2620:103:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:6000::,2620:103:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:7000::,2620:103:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:8000::,2620:103:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:103:9000::,2620:103:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:103:a000::,2620:103:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:b000::,2620:103:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:c000::,2620:103:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:d000::,2620:103:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:103:e000::,2620:103:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:103:f000::,2620:103:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:104::,2620:104:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:1000::,2620:104:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:2000::,2620:104:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:3000::,2620:104:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:4000::,2620:104:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:5000::,2620:104:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:6000::,2620:104:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:7000::,2620:104:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:8000::,2620:104:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:9000::,2620:104:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:a000::,2620:104:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:b000::,2620:104:b01f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:c000::,2620:104:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:104:d000::,2620:104:d0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:e000::,2620:104:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:104:f000::,2620:104:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:105::,2620:105:f:ffff:ffff:ffff:ffff:ffff,CA
+2620:105:1000::,2620:105:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:2000::,2620:105:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:3000::,2620:105:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:4000::,2620:105:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:5000::,2620:105:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:6000::,2620:105:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:7000::,2620:105:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:8000::,2620:105:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:9000::,2620:105:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:a000::,2620:105:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:b000::,2620:105:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:c000::,2620:105:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:105:d000::,2620:105:d0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:e000::,2620:105:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:105:f000::,2620:105:f0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106::,2620:106:f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:1000::,2620:106:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:2000::,2620:106:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:3000::,2620:106:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:4000::,2620:106:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:5000::,2620:106:50ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:6000::,2620:106:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:7000::,2620:106:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:8000::,2620:106:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:9000::,2620:106:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:a000::,2620:106:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:b000::,2620:106:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:c000::,2620:106:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:d000::,2620:106:d0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:106:e000::,2620:106:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:106:f000::,2620:106:f00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:107::,2620:107:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:1000::,2620:107:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:2000::,2620:107:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:3000::,2620:107:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:4000::,2620:107:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:5000::,2620:107:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:6000::,2620:107:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:7000::,2620:107:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:8000::,2620:107:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:9000::,2620:107:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:a000::,2620:107:a0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:b000::,2620:107:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:c000::,2620:107:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:d000::,2620:107:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:107:e000::,2620:107:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:107:f000::,2620:107:f0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108::,2620:108:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:1000::,2620:108:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:2000::,2620:108:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:3000::,2620:108:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:4000::,2620:108:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:5000::,2620:108:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:6000::,2620:108:60ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:7000::,2620:108:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:8000::,2620:108:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:9000::,2620:108:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:a000::,2620:108:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:b000::,2620:108:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:c000::,2620:108:c0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:108:d000::,2620:108:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:e000::,2620:108:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:108:f000::,2620:108:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109::,2620:109:ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:1000::,2620:109:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:2000::,2620:109:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:3000::,2620:109:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:4000::,2620:109:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:5000::,2620:109:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:6000::,2620:109:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:7000::,2620:109:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:8000::,2620:109:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:9000::,2620:109:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:a000::,2620:109:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:b000::,2620:109:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:c000::,2620:109:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:d000::,2620:109:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:109:e000::,2620:109:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:109:f000::,2620:109:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a::,2620:10a:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:1000::,2620:10a:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:2000::,2620:10a:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:3000::,2620:10a:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:4000::,2620:10a:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:5000::,2620:10a:50ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:6000::,2620:10a:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:7000::,2620:10a:700f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10a:8000::,2620:10a:800f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10a:9000::,2620:10a:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:a000::,2620:10a:a0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:b000::,2620:10a:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:c000::,2620:10a:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:d000::,2620:10a:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:e000::,2620:10a:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10a:f000::,2620:10a:f0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b::,2620:10b:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:1000::,2620:10b:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:2000::,2620:10b:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:3000::,2620:10b:30ff:ffff:ffff:ffff:ffff:ffff,CA
+2620:10b:4000::,2620:10b:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:5000::,2620:10b:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:6000::,2620:10b:60ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:7000::,2620:10b:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:8000::,2620:10b:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:9000::,2620:10b:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:a000::,2620:10b:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:b000::,2620:10b:b00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10b:c000::,2620:10b:c0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:d000::,2620:10b:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:e000::,2620:10b:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10b:f000::,2620:10b:f0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c::,2620:10c:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:1000::,2620:10c:10ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:2000::,2620:10c:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:3000::,2620:10c:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:4000::,2620:10c:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:5000::,2620:10c:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:6000::,2620:10c:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:7000::,2620:10c:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:8000::,2620:10c:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:9000::,2620:10c:90ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:a000::,2620:10c:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:b000::,2620:10c:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:c000::,2620:10c:c0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:d000::,2620:10c:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:e000::,2620:10c:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10c:f000::,2620:10c:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d::,2620:10d:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:1000::,2620:10d:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:2000::,2620:10d:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:3000::,2620:10d:300f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:4000::,2620:10d:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:5000::,2620:10d:50ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:6000::,2620:10d:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:7000::,2620:10d:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:8000::,2620:10d:800f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:9000::,2620:10d:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:a000::,2620:10d:a0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:b000::,2620:10d:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:c000::,2620:10d:c0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10d:d000::,2620:10d:d00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10d:e000::,2620:10d:e00f:ffff:ffff:ffff:ffff:ffff,CA
+2620:10d:f000::,2620:10d:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e::,2620:10e:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:1000::,2620:10e:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:2000::,2620:10e:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:3000::,2620:10e:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:4000::,2620:10e:40ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:5000::,2620:10e:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:6000::,2620:10e:60ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:7000::,2620:10e:70ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:8000::,2620:10e:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:9000::,2620:10e:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:a000::,2620:10e:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:b000::,2620:10e:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:c000::,2620:10e:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:d000::,2620:10e:d00f:ffff:ffff:ffff:ffff:ffff,BL
+2620:10e:e000::,2620:10e:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10e:f000::,2620:10e:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f::,2620:10f:f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:1000::,2620:10f:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:2000::,2620:10f:200f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:3000::,2620:10f:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:4000::,2620:10f:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:5000::,2620:10f:50ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:6000::,2620:10f:60ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:7000::,2620:10f:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:8000::,2620:10f:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:9000::,2620:10f:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:a000::,2620:10f:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:b000::,2620:10f:b0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:c000::,2620:10f:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:d000::,2620:10f:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:e000::,2620:10f:e0ff:ffff:ffff:ffff:ffff:ffff,US
+2620:10f:f000::,2620:10f:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110::,2620:110:f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:1000::,2620:110:100f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:2000::,2620:110:20ff:ffff:ffff:ffff:ffff:ffff,US
+2620:110:3000::,2620:110:30ff:ffff:ffff:ffff:ffff:ffff,US
+2620:110:4000::,2620:110:400f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:5000::,2620:110:500f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:6000::,2620:110:600f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:7000::,2620:110:700f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:8000::,2620:110:80ff:ffff:ffff:ffff:ffff:ffff,US
+2620:110:9000::,2620:110:900f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:a000::,2620:110:a00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:b000::,2620:110:b00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:c000::,2620:110:c00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:d000::,2620:110:d00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:e000::,2620:110:e00f:ffff:ffff:ffff:ffff:ffff,US
+2620:110:f000::,2620:110:f00f:ffff:ffff:ffff:ffff:ffff,US
+2620:140::,2620:140:3ff:ffff:ffff:ffff:ffff:ffff,US
+2620:141::,2620:141:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:143::,2620:143:7ff:ffff:ffff:ffff:ffff:ffff,US
+2620:144::,2620:145:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:146::,2620:146:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:147::,2620:147:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:148::,2620:148:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:149::,2620:149:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14a::,2620:14a:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14b::,2620:14b:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14c::,2620:14c:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14d::,2620:14d:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14e::,2620:14e:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:14f::,2620:14f:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:150::,2620:150:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:151::,2620:151:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:152::,2620:152:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:153::,2620:153:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:154::,2620:154:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:155::,2620:155:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:156::,2620:156:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:157::,2620:157:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:158::,2620:158:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:159::,2620:159:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15a::,2620:15a:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15b::,2620:15b:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15c::,2620:15c:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15d::,2620:15e:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:15f::,2620:15f:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:160::,2620:160:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:162::,2620:162:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:163::,2620:163:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:164::,2620:164:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:165::,2620:165:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:166::,2620:166:fff:ffff:ffff:ffff:ffff:ffff,US
+2620:180::,2620:180:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:190::,2620:190:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1a0::,2620:1a0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1b0::,2620:1b0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1c0::,2620:1c0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1d0::,2620:1d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1e0::,2620:1e0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2620:1f0::,2620:1f0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2800:8::,2800:8:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:10::,2800:10:ffff:ffff:ffff:ffff:ffff:ffff,NI
+2800:18::,2800:18:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:20::,2800:2f:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:30::,2800:30:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:38::,2800:38:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:40::,2800:40:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:48::,2800:48:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:60::,2800:60:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:68::,2800:68:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:70::,2800:70:ffff:ffff:ffff:ffff:ffff:ffff,TT
+2800:78::,2800:78:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:80::,2800:80:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:88::,2800:88:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2800:90::,2800:90:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2800:98::,2800:98:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2800:a0::,2800:af:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2800:e0::,2800:ef:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:f0::,2800:f0:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:100::,2800:100:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:110::,2800:110:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:120::,2800:120:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:130::,2800:130:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:140::,2800:140:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:150::,2800:150:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:160::,2800:160:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:170::,2800:170:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2800:180::,2800:180:ffff:ffff:ffff:ffff:ffff:ffff,TT
+2800:190::,2800:190:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:1a0::,2800:1a0:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2800:1b0::,2800:1b0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:1c0::,2800:1c0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:1d0::,2800:1d0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:1e0::,2800:1e0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:1f0::,2800:1f0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:200::,2800:200:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:220::,2800:220:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:230::,2800:230:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2800:240::,2800:240:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:250::,2800:250:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2800:260::,2800:26f:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:270::,2800:270:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:280::,2800:280:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:290::,2800:290:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:2a0::,2800:2a0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:2b0::,2800:2b0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:2c0::,2800:2c0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:2d0::,2800:2d0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:2e0::,2800:2e0:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:2f0::,2800:2f0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:300::,2800:300:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:310::,2800:310:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:320::,2800:320:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2800:330::,2800:330:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:340::,2800:340:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:350::,2800:350:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:360::,2800:360:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2800:370::,2800:370:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:380::,2800:380:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:390::,2800:390:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2800:3a0::,2800:3a0:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2800:3b0::,2800:3b0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:3c0::,2800:3c0:ffff:ffff:ffff:ffff:ffff:ffff,GY
+2800:3d0::,2800:3d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:3e0::,2800:3e0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:3f0::,2800:3f0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:400::,2800:400:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:410::,2800:410:ffff:ffff:ffff:ffff:ffff:ffff,BZ
+2800:420::,2800:423:ffff:ffff:ffff:ffff:ffff:ffff,TT
+2800:430::,2800:430:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:440::,2800:440:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:450::,2800:450:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:460::,2800:460:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:470::,2800:470:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:480::,2800:480:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:490::,2800:490:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:4a0::,2800:4a0:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:4b0::,2800:4b0:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:4c0::,2800:4c0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:4d0::,2800:4d0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:4e0::,2800:4e0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:4f0::,2800:4f0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:500::,2800:500:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:510::,2800:510:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:520::,2800:520:ffff:ffff:ffff:ffff:ffff:ffff,TT
+2800:530::,2800:530:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:540::,2800:540:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:550::,2800:550:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:560::,2800:560:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:570::,2800:570:ffff:ffff:ffff:ffff:ffff:ffff,HT
+2800:580::,2800:580:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:590::,2800:590:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:5a0::,2800:5a0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:5b0::,2800:5b0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:5c0::,2800:5c0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:5d0::,2800:5d0:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:5e0::,2800:5e0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:5f0::,2800:5f0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:600::,2800:600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:610::,2800:610:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:620::,2800:620:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:630::,2800:630:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:640::,2800:640:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:650::,2800:650:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:660::,2800:660:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:670::,2800:670:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:680::,2800:680:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:690::,2800:690:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:6a0::,2800:6a0:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2800:6b0::,2800:6b0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:6c0::,2800:6c0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:6d0::,2800:6d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:6e0::,2800:6e0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:6f0::,2800:6f0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:700::,2800:700:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2800:800::,2800:800:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:810::,2800:810:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:820::,2800:820:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:830::,2800:831:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:840::,2800:840:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2800:850::,2800:850:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:860::,2800:860:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:870::,2800:870:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:880::,2800:883:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2800:890::,2800:890:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2800:8a0::,2800:8a0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:8b0::,2800:8b0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:8c0::,2800:8c0:ffff:ffff:ffff:ffff:ffff:ffff,NI
+2800:8d0::,2800:8d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:8e0::,2800:8e0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:8f0::,2800:8f0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:900::,2800:900:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:910::,2800:910:ffff:ffff:ffff:ffff:ffff:ffff,CU
+2800:920::,2800:920:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:930::,2800:930:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:940::,2800:940:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:950::,2800:950:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:960::,2800:960:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2800:970::,2800:970:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:980::,2800:980:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:990::,2800:990:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:9a0::,2800:9a7:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:9b0::,2800:9b0:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:9c0::,2800:9c0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:9d0::,2800:9d0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:9e0::,2800:9e0:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:9f0::,2800:9f0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:a00::,2800:a00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a10::,2800:a10:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a20::,2800:a20:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:a30::,2800:a30:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a40::,2800:a40:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a50::,2800:a50:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a60::,2800:a60:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:a70::,2800:a70:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:a80::,2800:a80:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a90::,2800:a90:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:aa0::,2800:aa0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:ab0::,2800:ab0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:ac0::,2800:ac0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:ad0::,2800:ad0:ffff:ffff:ffff:ffff:ffff:ffff,AW
+2800:ae0::,2800:ae0:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:af0::,2800:af0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:b00::,2800:b00:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2800:b10::,2800:b10:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2800:b20::,2800:b23:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2800:b30::,2800:b31:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:b40::,2800:b40:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:b50::,2800:b50:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:b60::,2800:b60:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:b70::,2800:b70:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2800:b80::,2800:b80:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:b90::,2800:b90:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:ba0::,2800:ba0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:bb0::,2800:bb0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:bc0::,2800:bc0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2800:bd0::,2800:bd0:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:be0::,2800:be0:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:bf0::,2800:bf0:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:c00::,2800:c00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:c10::,2800:c10:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:c20::,2800:c20:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2800:c30::,2800:c30:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:c40::,2800:c40:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2800:c50::,2800:c50:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:c60::,2800:c60:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2800:c70::,2800:c70:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2800:c80::,2800:c80:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:c90::,2800:c90:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2800:ca0::,2800:ca0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:cb0::,2800:cb0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:cc0::,2800:cc0:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2800:cd0::,2800:cd0:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2800:ce0::,2800:ce0:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2800:cf0::,2800:cf0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:d00::,2800:d00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:d10::,2800:d10:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:d20::,2800:d20:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2800:1000::,2800:10ff:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:2000::,2800:2fff:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:a000::,2800:a000:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a008::,2800:a008:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a010::,2800:a010:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a018::,2800:a018:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a020::,2800:a020:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a028::,2800:a028:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a030::,2800:a030:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:a038::,2800:a038:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2800:b000::,2800:b000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2800:d300::,2800:d307:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2801::,2801::ffff:ffff:ffff:ffff:ffff,UY
+2801:0:10::,2801:0:10:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:20::,2801:0:20:ffff:ffff:ffff:ffff:ffff,EC
+2801:0:30::,2801:0:30:ffff:ffff:ffff:ffff:ffff,HN
+2801:0:40::,2801:0:40:ffff:ffff:ffff:ffff:ffff,TT
+2801:0:50::,2801:0:50:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:60::,2801:0:63:ffff:ffff:ffff:ffff:ffff,EC
+2801:0:70::,2801:0:70:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:80::,2801:0:80:ffff:ffff:ffff:ffff:ffff,DO
+2801:0:90::,2801:0:90:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:a0::,2801:0:a0:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:b0::,2801:0:b7:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:c0::,2801:0:df:ffff:ffff:ffff:ffff:ffff,CR
+2801:0:100::,2801:0:100:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:110::,2801:0:110:ffff:ffff:ffff:ffff:ffff,GT
+2801:0:120::,2801:0:120:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:130::,2801:0:130:ffff:ffff:ffff:ffff:ffff,PY
+2801:0:140::,2801:0:140:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:150::,2801:0:150:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:160::,2801:0:160:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:170::,2801:0:170:ffff:ffff:ffff:ffff:ffff,BO
+2801:0:180::,2801:0:180:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:190::,2801:0:190:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:1a0::,2801:0:1a0:ffff:ffff:ffff:ffff:ffff,HN
+2801:0:1b0::,2801:0:1b0:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:1c0::,2801:0:1c7:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:1d0::,2801:0:1d7:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:1e0::,2801:0:1e0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:1f0::,2801:0:1f0:ffff:ffff:ffff:ffff:ffff,PY
+2801:0:200::,2801:0:200:ffff:ffff:ffff:ffff:ffff,VE
+2801:0:210::,2801:0:210:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:220::,2801:0:22f:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:240::,2801:0:240:ffff:ffff:ffff:ffff:ffff,PA
+2801:0:250::,2801:0:250:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:260::,2801:0:260:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:270::,2801:0:270:ffff:ffff:ffff:ffff:ffff,EC
+2801:0:280::,2801:0:280:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:290::,2801:0:290:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:2a0::,2801:0:2a0:ffff:ffff:ffff:ffff:ffff,CR
+2801:0:2b0::,2801:0:2b0:ffff:ffff:ffff:ffff:ffff,PA
+2801:0:2c0::,2801:0:2c0:ffff:ffff:ffff:ffff:ffff,HN
+2801:0:2d0::,2801:0:2d0:ffff:ffff:ffff:ffff:ffff,PA
+2801:0:2e0::,2801:0:2e0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:2f0::,2801:0:2f0:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:300::,2801:0:300:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:310::,2801:0:310:ffff:ffff:ffff:ffff:ffff,CW
+2801:0:320::,2801:0:320:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:330::,2801:0:330:ffff:ffff:ffff:ffff:ffff,HT
+2801:0:340::,2801:0:340:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:350::,2801:0:350:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:380::,2801:0:380:ffff:ffff:ffff:ffff:ffff,CL
+2801:0:390::,2801:0:390:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3a0::,2801:0:3a0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3b0::,2801:0:3b0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3c0::,2801:0:3c0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3d0::,2801:0:3d0:ffff:ffff:ffff:ffff:ffff,CO
+2801:0:3e0::,2801:0:3e0:ffff:ffff:ffff:ffff:ffff,AR
+2801:0:2000::,2801:0:2fff:ffff:ffff:ffff:ffff:ffff,UY
+2801:1::,2801:1:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2801:2::,2801:2:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2801:10::,2801:10:7:ffff:ffff:ffff:ffff:ffff,AR
+2801:18::,2801:18:0:ffff:ffff:ffff:ffff:ffff,CR
+2801:80::,2801:bf:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2801:c0::,2801:c0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4::,2801:c4:0:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:10::,2801:c4:10:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:20::,2801:c4:20:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:30::,2801:c4:30:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:40::,2801:c4:40:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:50::,2801:c4:50:ffff:ffff:ffff:ffff:ffff,MX
+2801:c4:60::,2801:c4:60:ffff:ffff:ffff:ffff:ffff,MX
+2801:d0::,2801:d0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2801:f0::,2801:f0:0:ffff:ffff:ffff:ffff:ffff,MX
+2801:f0:16::,2801:f0:16:ffff:ffff:ffff:ffff:ffff,MX
+2801:f0:20::,2801:f0:20:ffff:ffff:ffff:ffff:ffff,MX
+2801:f0:28::,2801:f0:28:ffff:ffff:ffff:ffff:ffff,MX
+2801:100::,2801:100:ff:ffff:ffff:ffff:ffff:ffff,AR
+2802::,2802:3:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803::,2803:0:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:100::,2803:100:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:200::,2803:200:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:400::,2803:400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:600::,2803:600:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:800::,2803:800:ffff:ffff:ffff:ffff:ffff:ffff,NI
+2803:a00::,2803:a00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:c00::,2803:c00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:e00::,2803:e00:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:1000::,2803:1000:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2803:1200::,2803:1200:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:1400::,2803:1400:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2803:1600::,2803:1600:ffff:ffff:ffff:ffff:ffff:ffff,BQ
+2803:1800::,2803:1800:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:1a00::,2803:1a00:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:1c00::,2803:1c00:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:1e00::,2803:1e00:ffff:ffff:ffff:ffff:ffff:ffff,NI
+2803:2000::,2803:2000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:2200::,2803:2200:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:2400::,2803:2400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:2600::,2803:2600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:2800::,2803:2800:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:2a00::,2803:2a00:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2803:2c00::,2803:2c00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:2e00::,2803:2e00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:3000::,2803:3000:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:3200::,2803:3200:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:3400::,2803:3400:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:3600::,2803:3600:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:3800::,2803:3800:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:3a00::,2803:3a00:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2803:3c00::,2803:3c00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:3e00::,2803:3e00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:4000::,2803:4000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:4100::,2803:4100:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:4200::,2803:4200:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:4400::,2803:4400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:4600::,2803:4600:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:4800::,2803:4800:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2803:4a00::,2803:4a00:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:4c00::,2803:4c00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:4e00::,2803:4e00:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2803:5000::,2803:5000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:5200::,2803:5200:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:5400::,2803:5400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:5600::,2803:5600:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:5800::,2803:5800:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2803:5a00::,2803:5a00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:5c00::,2803:5c00:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2803:5e00::,2803:5e00:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2803:6000::,2803:6000:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:6200::,2803:6200:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:6400::,2803:6400:ffff:ffff:ffff:ffff:ffff:ffff,DO
+2803:6600::,2803:6600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:6800::,2803:6800:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:6a00::,2803:6a00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:6c00::,2803:6c00:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:6e00::,2803:6e00:ffff:ffff:ffff:ffff:ffff:ffff,SR
+2803:7000::,2803:7000:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2803:7200::,2803:7200:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:7400::,2803:7400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:7600::,2803:7600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:7800::,2803:7800:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2803:7a00::,2803:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:7c00::,2803:7c00:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:7e00::,2803:7e00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:8000::,2803:8000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:8100::,2803:8100:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2803:8200::,2803:8200:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:8400::,2803:8400:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:8600::,2803:8600:ffff:ffff:ffff:ffff:ffff:ffff,HT
+2803:8800::,2803:8800:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:8a00::,2803:8a00:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:8c00::,2803:8c00:ffff:ffff:ffff:ffff:ffff:ffff,BZ
+2803:8e00::,2803:8e00:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:9000::,2803:9000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:9200::,2803:9200:ffff:ffff:ffff:ffff:ffff:ffff,SV
+2803:9400::,2803:9400:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2803:9600::,2803:9600:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2803:9800::,2803:9800:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:9a00::,2803:9a00:ffff:ffff:ffff:ffff:ffff:ffff,BZ
+2803:9c00::,2803:9c00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:9e00::,2803:9e00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:a000::,2803:a000:ffff:ffff:ffff:ffff:ffff:ffff,CW
+2803:a200::,2803:a200:ffff:ffff:ffff:ffff:ffff:ffff,SR
+2803:a400::,2803:a400:ffff:ffff:ffff:ffff:ffff:ffff,EC
+2803:a600::,2803:a600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:a800::,2803:a800:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:aa00::,2803:aa00:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:ac00::,2803:ac00:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:ae00::,2803:ae00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:b000::,2803:b000:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:b200::,2803:b200:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2803:b400::,2803:b400:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2803:b600::,2803:b600:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:b800::,2803:b800:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:ba00::,2803:ba00:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2803:bc00::,2803:bc00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:be00::,2803:be00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:c000::,2803:c000:ffff:ffff:ffff:ffff:ffff:ffff,VE
+2803:c200::,2803:c200:ffff:ffff:ffff:ffff:ffff:ffff,PE
+2803:c400::,2803:c400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:c600::,2803:c600:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:c800::,2803:c800:ffff:ffff:ffff:ffff:ffff:ffff,GT
+2803:ca00::,2803:ca00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:cc00::,2803:cc00:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:ce00::,2803:ce00:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:d000::,2803:d000:ffff:ffff:ffff:ffff:ffff:ffff,BZ
+2803:d200::,2803:d200:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:d400::,2803:d400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:d600::,2803:d600:ffff:ffff:ffff:ffff:ffff:ffff,UY
+2803:d800::,2803:d800:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:da00::,2803:da00:ffff:ffff:ffff:ffff:ffff:ffff,GY
+2803:dc00::,2803:dc00:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:de00::,2803:de00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:e000::,2803:e000:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2803:e200::,2803:e200:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:e400::,2803:e400:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:e600::,2803:e600:ffff:ffff:ffff:ffff:ffff:ffff,PA
+2803:e800::,2803:e800:ffff:ffff:ffff:ffff:ffff:ffff,CL
+2803:ea00::,2803:ea00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:ec00::,2803:ec00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:ee00::,2803:ee00:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:f000::,2803:f000:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:f200::,2803:f200:ffff:ffff:ffff:ffff:ffff:ffff,AR
+2803:f400::,2803:f400:ffff:ffff:ffff:ffff:ffff:ffff,HN
+2803:f600::,2803:f600:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:f800::,2803:f800:ffff:ffff:ffff:ffff:ffff:ffff,CR
+2803:fa00::,2803:fa00:ffff:ffff:ffff:ffff:ffff:ffff,BO
+2803:fc00::,2803:fc00:ffff:ffff:ffff:ffff:ffff:ffff,PY
+2803:fe00::,2803:fe00:ffff:ffff:ffff:ffff:ffff:ffff,CO
+2804::,2804:ffff:ffff:ffff:ffff:ffff:ffff:ffff,BR
+2806::,2806:f:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:200::,2806:200:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:220::,2806:220:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:230::,2806:230:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:240::,2806:240:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:250::,2806:250:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:260::,2806:260:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:270::,2806:270:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:290::,2806:290:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:2a0::,2806:2a0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:2b0::,2806:2b0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:2d0::,2806:2d0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:2e0::,2806:2e0:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2806:1000::,2806:10ff:ffff:ffff:ffff:ffff:ffff:ffff,MX
+2a00::,2a00:3ff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:800::,2a00:87f:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:c00::,2a00:c00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:c08::,2a00:c08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c10::,2a00:c10:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:c18::,2a00:c18:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c20::,2a00:c20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c28::,2a00:c28:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c30::,2a00:c37:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:c38::,2a00:c38:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:c40::,2a00:c40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:c50::,2a00:c50:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c58::,2a00:c58:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c60::,2a00:c60:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c68::,2a00:c68:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:c70::,2a00:c70:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c78::,2a00:c78:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:c80::,2a00:c80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:c88::,2a00:c88:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:c90::,2a00:c90:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:c98::,2a00:c98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ca0::,2a00:ca0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:ca8::,2a00:ca8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:cb0::,2a00:cb0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cb8::,2a00:cb8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:cc0::,2a00:cc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cc8::,2a00:cc8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:cd0::,2a00:cd0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cd8::,2a00:cd8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:ce0::,2a00:ce0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ce8::,2a00:ce8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:cf0::,2a00:cf0:ffff:ffff:ffff:ffff:ffff:ffff,MC
+2a00:cf8::,2a00:cf8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:d00::,2a00:d00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d08::,2a00:d08:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d10::,2a00:d10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d18::,2a00:d18:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:d20::,2a00:d20:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:d28::,2a00:d28:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d30::,2a00:d30:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a00:d38::,2a00:d38:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:d40::,2a00:d40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:d50::,2a00:d50:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d58::,2a00:d58:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d60::,2a00:d60:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:d68::,2a00:d68:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d70::,2a00:d70:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d78::,2a00:d78:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d80::,2a00:d80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:d88::,2a00:d88:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:d90::,2a00:d90:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:d98::,2a00:d98:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:da0::,2a00:da0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:da8::,2a00:da9:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:db0::,2a00:db0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:db8::,2a00:db8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:dc0::,2a00:dc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:dc8::,2a00:dc8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:dd0::,2a00:dd0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:dd8::,2a00:dd8:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:de8::,2a00:de8:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:df0::,2a00:df0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:df8::,2a00:df8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:e00::,2a00:e00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e08::,2a00:e08:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:e10::,2a00:e10:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e18::,2a00:e18:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:e20::,2a00:e20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e28::,2a00:e28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e30::,2a00:e30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e38::,2a00:e38:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:e40::,2a00:e40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:e48::,2a00:e48:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:e50::,2a00:e50:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e58::,2a00:e58:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e60::,2a00:e60:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e68::,2a00:e68:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e70::,2a00:e70:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:e78::,2a00:e78:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e80::,2a00:e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e88::,2a00:e88:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e90::,2a00:e90:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:e98::,2a00:e98:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:ea0::,2a00:ea0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:ea8::,2a00:ea8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:eb0::,2a00:eb0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:eb8::,2a00:eb8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:ec0::,2a00:ec0:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a00:ec8::,2a00:ec8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:ed0::,2a00:ed0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ed8::,2a00:ed8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:ee0::,2a00:ee0:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:ee8::,2a00:ee8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ef0::,2a00:ef0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:ef8::,2a00:ef8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:f00::,2a00:f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f08::,2a00:f08:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f10::,2a00:f10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:f18::,2a00:f18:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f20::,2a00:f20:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:f28::,2a00:f28:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a00:f30::,2a00:f30:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f38::,2a00:f38:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a00:f40::,2a00:f40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:f48::,2a00:f48:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f50::,2a00:f50:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:f58::,2a00:f58:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:f60::,2a00:f60:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:f68::,2a00:f68:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f70::,2a00:f70:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f78::,2a00:f78:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:f80::,2a00:f80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:f88::,2a00:f88:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f90::,2a00:f90:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:f98::,2a00:f98:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:fa0::,2a00:fa0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:fa8::,2a00:fa8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fb8::,2a00:fb8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fc0::,2a00:fc0:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:fc8::,2a00:fc8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:fd0::,2a00:fd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:fd8::,2a00:fd8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:fe0::,2a00:fe0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fe8::,2a00:fe8:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:ff0::,2a00:ff0:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:ff8::,2a00:ff8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1000::,2a00:1000:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1008::,2a00:1008:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1010::,2a00:1010:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1018::,2a00:1018:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1020::,2a00:1020:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1028::,2a00:1028:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1030::,2a00:1030:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1038::,2a00:1038:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1040::,2a00:1040:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1048::,2a00:1048:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1050::,2a00:1050:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1058::,2a00:1058:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1060::,2a00:1060:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a00:1068::,2a00:1068:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1070::,2a00:1070:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1078::,2a00:1078:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1080::,2a00:1080:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1088::,2a00:1088:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1090::,2a00:1090:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1098::,2a00:1098:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:10a0::,2a00:10a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:10a8::,2a00:10a8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:10b0::,2a00:10b7:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:10b8::,2a00:10b8:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:10c0::,2a00:10c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:10c8::,2a00:10c8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:10d0::,2a00:10d0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:10d8::,2a00:10d8:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:10e0::,2a00:10e0:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:10e8::,2a00:10f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:10f8::,2a00:10f8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:1100::,2a00:1100:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1108::,2a00:1108:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:1110::,2a00:1110:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1118::,2a00:1118:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:1120::,2a00:1120:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1128::,2a00:1128:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1130::,2a00:1130:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1138::,2a00:1138:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1140::,2a00:1140:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1148::,2a00:1148:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1150::,2a00:1150:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a00:1158::,2a00:1158:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1160::,2a00:1160:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1168::,2a00:1168:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1170::,2a00:1170:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:1178::,2a00:1178:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1180::,2a00:1180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1188::,2a00:1188:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1190::,2a00:1190:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1198::,2a00:1198:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:11a8::,2a00:11a8:ffff:ffff:ffff:ffff:ffff:ffff,OM
+2a00:11b0::,2a00:11b0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:11b8::,2a00:11b8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:11c0::,2a00:11c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:11c8::,2a00:11c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:11d0::,2a00:11d0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:11d8::,2a00:11d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:11e0::,2a00:11e0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:11e8::,2a00:11e8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:11f0::,2a00:11f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:11f8::,2a00:11f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1200::,2a00:1200:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1208::,2a00:1208:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1210::,2a00:1210:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1218::,2a00:1218:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a00:1220::,2a00:1220:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1228::,2a00:1228:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1230::,2a00:1237:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1238::,2a00:1238:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1240::,2a00:1240:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1248::,2a00:1248:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1250::,2a00:1250:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1258::,2a00:1258:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1260::,2a00:1260:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1268::,2a00:1268:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1270::,2a00:1270:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a00:1278::,2a00:1278:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1280::,2a00:1280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1288::,2a00:1288:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1290::,2a00:1290:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1298::,2a00:1298:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:12a0::,2a00:12a0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:12a8::,2a00:12a8:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:12b0::,2a00:12b0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:12b8::,2a00:12b8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:12c0::,2a00:12c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:12c8::,2a00:12c8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:12d0::,2a00:12d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:12d8::,2a00:12d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:12e0::,2a00:12e0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:12e8::,2a00:12e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:12f0::,2a00:12f0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:12f8::,2a00:12f8:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a00:1300::,2a00:1300:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1308::,2a00:1308:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1310::,2a00:1310:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:1318::,2a00:1318:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1320::,2a00:1320:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1328::,2a00:1328:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1330::,2a00:1330:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1338::,2a00:1338:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1340::,2a00:1340:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1348::,2a00:1348:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1350::,2a00:1350:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1358::,2a00:1358:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a00:1360::,2a00:1360:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1368::,2a00:1368:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1370::,2a00:1370:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1378::,2a00:1378:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1380::,2a00:1380:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1388::,2a00:1388:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1390::,2a00:1390:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1398::,2a00:1398:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:13a0::,2a00:13a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:13a8::,2a00:13a8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:13b0::,2a00:13b0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:13b8::,2a00:13b8:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:13c0::,2a00:13c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:13c8::,2a00:13c8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:13d0::,2a00:13d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:13d8::,2a00:13d8:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:13e0::,2a00:13e0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:13e8::,2a00:13e8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:13f0::,2a00:13f0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:13f8::,2a00:13f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1400::,2a00:1400:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1408::,2a00:1408:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1410::,2a00:1410:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1418::,2a00:1418:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1420::,2a00:1420:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1428::,2a00:1428:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:1430::,2a00:1430:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1438::,2a00:1438:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1440::,2a00:1440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1448::,2a00:1448:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1450::,2a00:1457:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:1458::,2a00:1458:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1460::,2a00:1460:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1468::,2a00:1468:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1470::,2a00:1470:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1478::,2a00:1478:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1480::,2a00:1480:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:1488::,2a00:1488:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1490::,2a00:1490:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1498::,2a00:1498:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:14a0::,2a00:14a0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:14a8::,2a00:14a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:14b0::,2a00:14b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:14b8::,2a00:14b8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:14c0::,2a00:14c0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:14c8::,2a00:14c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:14d0::,2a00:14d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:14d8::,2a00:14d8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:14e0::,2a00:14e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:14e8::,2a00:14e8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:14f0::,2a00:14f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:14f8::,2a00:14f8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1500::,2a00:1500:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a00:1508::,2a00:1508:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1510::,2a00:1510:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1518::,2a00:1518:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1520::,2a00:1520:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1528::,2a00:1528:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1530::,2a00:1530:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1538::,2a00:1538:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1540::,2a00:1540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1548::,2a00:1548:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1550::,2a00:1550:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1558::,2a00:1558:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1560::,2a00:1560:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1568::,2a00:1568:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1570::,2a00:1570:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1578::,2a00:1578:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1580::,2a00:1580:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:1588::,2a00:1588:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1590::,2a00:1590:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:1598::,2a00:1598:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:15a0::,2a00:15a0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:15a8::,2a00:15a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:15b0::,2a00:15b0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:15b8::,2a00:15b8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:15c0::,2a00:15c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:15c8::,2a00:15c8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:15d0::,2a00:15d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:15d8::,2a00:15d8:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:15e0::,2a00:15e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:15e8::,2a00:15e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:15f0::,2a00:15f0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:15f8::,2a00:15f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1600::,2a00:1600:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1608::,2a00:1608:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:1610::,2a00:1610:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1618::,2a00:1618:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1620::,2a00:1620:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1628::,2a00:1628:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1630::,2a00:1630:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1638::,2a00:1638:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1640::,2a00:1640:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1648::,2a00:1648:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1650::,2a00:1650:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:1660::,2a00:1660:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1668::,2a00:1668:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1670::,2a00:1670:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1678::,2a00:1678:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1680::,2a00:1680:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1688::,2a00:1688:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1690::,2a00:1690:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1698::,2a00:1698:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:16a0::,2a00:16a0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:16a8::,2a00:16a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:16b0::,2a00:16b0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:16c8::,2a00:16c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:16d0::,2a00:16d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:16d8::,2a00:16d8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:16e0::,2a00:16e0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:16e8::,2a00:16e8:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:16f0::,2a00:16f0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:16f8::,2a00:16f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1700::,2a00:1700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1708::,2a00:1708:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1710::,2a00:1710:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:1718::,2a00:1718:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1720::,2a00:1720:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1728::,2a00:1728:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:1730::,2a00:1730:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1748::,2a00:1748:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1750::,2a00:1750:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1758::,2a00:1758:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1760::,2a00:1760:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a00:1768::,2a00:1768:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1778::,2a00:1778:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1780::,2a00:1780:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:1788::,2a00:1788:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1790::,2a00:1790:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1798::,2a00:1798:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:17a0::,2a00:17a0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:17a8::,2a00:17a8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:17b0::,2a00:17b0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:17b8::,2a00:17b8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:17c0::,2a00:17c0:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:17c8::,2a00:17c8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:17d0::,2a00:17d0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:17d8::,2a00:17d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:17e0::,2a00:17e0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:17e8::,2a00:17e8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:17f0::,2a00:17f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:17f8::,2a00:17f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1800::,2a00:1800:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1808::,2a00:1808:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1810::,2a00:1810:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:1818::,2a00:1818:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1828::,2a00:1828:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1830::,2a00:1830:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1838::,2a00:1838:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1840::,2a00:1840:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:1848::,2a00:1848:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1850::,2a00:1850:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a00:1858::,2a00:1858:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:1860::,2a00:1860:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1868::,2a00:1868:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1870::,2a00:1870:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1878::,2a00:1878:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1880::,2a00:1880:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:1888::,2a00:1888:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1890::,2a00:1890:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1898::,2a00:1898:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:18a0::,2a00:18a0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:18a8::,2a00:18a8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:18b0::,2a00:18b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:18b8::,2a00:18b8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:18c0::,2a00:18c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:18c8::,2a00:18c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:18d0::,2a00:18d0:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a00:18d8::,2a00:18d8:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a00:18e0::,2a00:18e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:18e8::,2a00:18e8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:18f0::,2a00:18f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:18f8::,2a00:18f8:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1900::,2a00:1900:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1908::,2a00:1908:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1910::,2a00:1910:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1918::,2a00:1918:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1920::,2a00:1920:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1928::,2a00:1928:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1930::,2a00:1930:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1938::,2a00:1938:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1940::,2a00:1940:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1948::,2a00:1948:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1950::,2a00:1950:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1958::,2a00:1958:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1960::,2a00:1960:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1968::,2a00:1968:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1970::,2a00:1970:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1978::,2a00:1978:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1980::,2a00:1980:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1988::,2a00:1988:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1990::,2a00:1990:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1998::,2a00:1998:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:19a0::,2a00:19a0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:19a8::,2a00:19a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:19b0::,2a00:19b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:19b8::,2a00:19b8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:19c0::,2a00:19c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:19c8::,2a00:19c8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:19d0::,2a00:19d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:19d8::,2a00:19d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:19e0::,2a00:19e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:19e8::,2a00:19e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:19f0::,2a00:19f0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:19f8::,2a00:19f8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1a00::,2a00:1a00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1a08::,2a00:1a08:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a00:1a10::,2a00:1a10:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a18::,2a00:1a18:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1a20::,2a00:1a20:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1a28::,2a00:1a28:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1a30::,2a00:1a30:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a38::,2a00:1a38:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1a40::,2a00:1a40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1a48::,2a00:1a48:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a50::,2a00:1a50:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1a58::,2a00:1a58:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1a60::,2a00:1a60:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1a68::,2a00:1a68:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1a70::,2a00:1a70:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1a78::,2a00:1a78:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1a80::,2a00:1a80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a88::,2a00:1a88:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1a90::,2a00:1a90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1a98::,2a00:1a98:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:1aa0::,2a00:1aa0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1aa8::,2a00:1aa8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1ab0::,2a00:1ab0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1ab8::,2a00:1ab8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1ac0::,2a00:1ac0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1ac8::,2a00:1ac8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1ad0::,2a00:1ad0:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a00:1ad8::,2a00:1ad8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1ae0::,2a00:1ae0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1ae8::,2a00:1ae8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1af0::,2a00:1af0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1af8::,2a00:1af8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b00::,2a00:1b00:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a00:1b08::,2a00:1b08:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b10::,2a00:1b10:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1b18::,2a00:1b18:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1b20::,2a00:1b20:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1b28::,2a00:1b28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1b30::,2a00:1b30:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b38::,2a00:1b38:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1b40::,2a00:1b40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1b48::,2a00:1b48:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b50::,2a00:1b50:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1b58::,2a00:1b58:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1b60::,2a00:1b60:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1b68::,2a00:1b68:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b70::,2a00:1b70:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1b78::,2a00:1b78:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1b80::,2a00:1b80:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:1b88::,2a00:1b88:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1b90::,2a00:1b90:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1b98::,2a00:1b98:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1ba0::,2a00:1ba0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1ba8::,2a00:1ba8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1bb0::,2a00:1bb0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1bb8::,2a00:1bb8:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:1bc0::,2a00:1bc0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1bc8::,2a00:1bc8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1bd0::,2a00:1bd0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1bd8::,2a00:1bd8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1be0::,2a00:1be0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1be8::,2a00:1be8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1bf0::,2a00:1bf0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1bf8::,2a00:1bf8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1c00::,2a00:1c00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1c08::,2a00:1c08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1c10::,2a00:1c10:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1c18::,2a00:1c18:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1c20::,2a00:1c20:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1c28::,2a00:1c28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c30::,2a00:1c30:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1c38::,2a00:1c3f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1c40::,2a00:1c40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1c48::,2a00:1c48:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c50::,2a00:1c50:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1c58::,2a00:1c58:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1c60::,2a00:1c60:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:1c68::,2a00:1c68:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1c70::,2a00:1c70:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c78::,2a00:1c78:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c80::,2a00:1c80:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1c88::,2a00:1c88:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1c90::,2a00:1c90:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1c98::,2a00:1c98:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1ca0::,2a00:1ca0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1ca8::,2a00:1ca8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1cb0::,2a00:1cb0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1cb8::,2a00:1cb8:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a00:1cc0::,2a00:1cc0:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a00:1cc8::,2a00:1cc8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1cd0::,2a00:1cd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1cd8::,2a00:1cd8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1ce0::,2a00:1ce0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1ce8::,2a00:1ce8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1cf0::,2a00:1cf0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1cf8::,2a00:1cf8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:1d00::,2a00:1d00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1d08::,2a00:1d08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1d10::,2a00:1d10:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:1d18::,2a00:1d18:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1d20::,2a00:1d20:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1d28::,2a00:1d28:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1d30::,2a00:1d30:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:1d38::,2a00:1d38:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1d40::,2a00:1d40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1d48::,2a00:1d48:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1d50::,2a00:1d50:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1d58::,2a00:1d58:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:1d60::,2a00:1d60:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1d68::,2a00:1d68:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1d70::,2a00:1d70:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:1d78::,2a00:1d78:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1d80::,2a00:1d80:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1d88::,2a00:1d88:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1d90::,2a00:1d90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1da0::,2a00:1da0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1da8::,2a00:1da8:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:1db0::,2a00:1db0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1db8::,2a00:1db8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1dc0::,2a00:1dc0:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:1dc8::,2a00:1dc8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1dd0::,2a00:1dd0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1dd8::,2a00:1ddf:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:1de0::,2a00:1de0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1de8::,2a00:1de8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1df0::,2a00:1df0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1df8::,2a00:1df8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1e00::,2a00:1e00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e08::,2a00:1e08:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1e10::,2a00:1e10:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e18::,2a00:1e18:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1e20::,2a00:1e20:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1e28::,2a00:1e28:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1e30::,2a00:1e30:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1e38::,2a00:1e38:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1e40::,2a00:1e40:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:1e48::,2a00:1e48:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e50::,2a00:1e50:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1e58::,2a00:1e58:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1e60::,2a00:1e60:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1e68::,2a00:1e68:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e70::,2a00:1e70:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1e78::,2a00:1e78:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1e80::,2a00:1e80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1e88::,2a00:1e88:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1e90::,2a00:1e90:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1e98::,2a00:1e98:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:1ea0::,2a00:1ea0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1ea8::,2a00:1ea8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1eb0::,2a00:1eb0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:1eb8::,2a00:1eb8:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:1ec0::,2a00:1ec0:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a00:1ec8::,2a00:1ec8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1ed0::,2a00:1ed0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:1ed8::,2a00:1ed8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:1ee0::,2a00:1ee0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1ee8::,2a00:1ee8:ffff:ffff:ffff:ffff:ffff:ffff,SY
+2a00:1ef0::,2a00:1ef0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:1ef8::,2a00:1ef8:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1f00::,2a00:1f00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1f08::,2a00:1f08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1f10::,2a00:1f10:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1f18::,2a00:1f18:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:1f20::,2a00:1f20:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:1f28::,2a00:1f28:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a00:1f30::,2a00:1f30:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1f38::,2a00:1f38:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1f40::,2a00:1f40:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:1f48::,2a00:1f48:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:1f50::,2a00:1f50:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1f58::,2a00:1f58:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1f60::,2a00:1f60:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1f68::,2a00:1f68:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a00:1f70::,2a00:1f70:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1f78::,2a00:1f78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1f80::,2a00:1f80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:1f88::,2a00:1f88:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:1f90::,2a00:1f90:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:1f98::,2a00:1f98:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:1fa0::,2a00:1fa0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1fa8::,2a00:1fa8:ffff:ffff:ffff:ffff:ffff:ffff,GL
+2a00:1fb0::,2a00:1fb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1fb8::,2a00:1fb8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:1fc0::,2a00:1fc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:1fc8::,2a00:1fc8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:1fd0::,2a00:1fd0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:1fd8::,2a00:1fd8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1fe0::,2a00:1fe0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:1fe8::,2a00:1fe8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:1ff0::,2a00:1ff0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:1ff8::,2a00:1ff8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:2000::,2a00:23ff:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4000::,2a00:4000:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:4040::,2a00:4040:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4080::,2a00:4080:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:40c0::,2a00:40c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:4100::,2a00:4100:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4140::,2a00:4140:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:4180::,2a00:4180:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:41c0::,2a00:41c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:4200::,2a00:4200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4240::,2a00:4240:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4280::,2a00:4280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:42c0::,2a00:42c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4300::,2a00:4300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4340::,2a00:4340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4380::,2a00:4380:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:43c0::,2a00:43c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:4400::,2a00:4400:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:4440::,2a00:4440:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:4480::,2a00:4480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:44c0::,2a00:44c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4500::,2a00:4500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4540::,2a00:4540:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:4580::,2a00:4580:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:45c0::,2a00:45c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:4600::,2a00:4600:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:4640::,2a00:4640:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4680::,2a00:4680:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:46c0::,2a00:46c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:4700::,2a00:4700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4740::,2a00:4740:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:4780::,2a00:4780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:47c0::,2a00:47c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4800::,2a00:4800:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:4840::,2a00:4840:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4880::,2a00:4880:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:48c0::,2a00:48c0:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a00:4900::,2a00:4900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4940::,2a00:4940:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a00:4980::,2a00:4987:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:49c0::,2a00:49c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:4a00::,2a00:4a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4a40::,2a00:4a40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:4a80::,2a00:4a80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4ac0::,2a00:4ac0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4b00::,2a00:4b00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4b40::,2a00:4b40:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:4b80::,2a00:4b80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:4bc0::,2a00:4bc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:4c00::,2a00:4c00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4c40::,2a00:4c40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4c80::,2a00:4c80:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:4cc0::,2a00:4cc0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:4d00::,2a00:4d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:4d40::,2a00:4d40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:4d80::,2a00:4d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4dc0::,2a00:4dc0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:4e00::,2a00:4e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:4e40::,2a00:4e40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:4e80::,2a00:4e80:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a00:4ec0::,2a00:4ec0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:4f00::,2a00:4f00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:4f40::,2a00:4f40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:4f80::,2a00:4f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:4fc0::,2a00:4fc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:5000::,2a00:5000:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:5040::,2a00:5040:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:5080::,2a00:5080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:50c0::,2a00:50c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5100::,2a00:5100:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:5140::,2a00:5140:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:5180::,2a00:5180:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:51c0::,2a00:51c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:5200::,2a00:5200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5240::,2a00:5240:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:5280::,2a00:5280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:52c0::,2a00:52c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:5300::,2a00:5300:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5340::,2a00:5340:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:5380::,2a00:5380:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:53c0::,2a00:53c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5400::,2a00:5400:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:5440::,2a00:5440:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a00:5480::,2a00:5480:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:54c0::,2a00:54c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:5500::,2a00:5500:ffff:ffff:ffff:ffff:ffff:ffff,AX
+2a00:5540::,2a00:5540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5580::,2a00:5580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:55c0::,2a00:55c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5600::,2a00:5600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5640::,2a00:5640:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5680::,2a00:5680:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:56c0::,2a00:56c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5700::,2a00:5700:ffff:ffff:ffff:ffff:ffff:ffff,KG
+2a00:5740::,2a00:5740:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:5780::,2a00:5780:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:57c0::,2a00:57c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:5800::,2a00:5800:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:5840::,2a00:5840:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5880::,2a00:5880:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:58c0::,2a00:58c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5900::,2a00:5900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5940::,2a00:5940:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:5980::,2a00:5980:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:59c0::,2a00:59c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5a00::,2a00:5a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5a40::,2a00:5a40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:5a80::,2a00:5a80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5ac0::,2a00:5ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:5b00::,2a00:5b00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:5b40::,2a00:5b40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:5b80::,2a00:5b80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:5bc0::,2a00:5bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5c00::,2a00:5c00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:5c40::,2a00:5c40:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a00:5c80::,2a00:5c80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5cc0::,2a00:5cc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5d00::,2a00:5d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:5d40::,2a00:5d40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:5d80::,2a00:5d80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5dc0::,2a00:5dc0:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:5e00::,2a00:5e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5e40::,2a00:5e40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:5e80::,2a00:5e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:5ec0::,2a00:5ec0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:5f00::,2a00:5f00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:5f40::,2a00:5f40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:5fc0::,2a00:5fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6000::,2a00:6000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6040::,2a00:6040:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:6080::,2a00:6080:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:60c0::,2a00:60c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:6100::,2a00:6100:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:6140::,2a00:6140:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6180::,2a00:6180:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:61c0::,2a00:61c0:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:6200::,2a00:6200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6240::,2a00:6240:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6280::,2a00:6280:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:62c0::,2a00:62c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6300::,2a00:6300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:6340::,2a00:6340:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:6380::,2a00:6380:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:63c0::,2a00:63c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:6400::,2a00:6400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6440::,2a00:6440:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a00:6480::,2a00:6480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:64c0::,2a00:64c0:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:6500::,2a00:6500:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:6540::,2a00:6540:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6580::,2a00:6580:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:65c0::,2a00:65c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:6600::,2a00:6600:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a00:6640::,2a00:6640:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:6680::,2a00:6680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:6740::,2a00:6740:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:6780::,2a00:6780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:67c0::,2a00:67c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:6800::,2a00:6800:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6840::,2a00:6840:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:68c0::,2a00:68c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6900::,2a00:6900:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6940::,2a00:6940:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:6980::,2a00:6980:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:69c0::,2a00:69c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6a00::,2a00:6a00:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:6a40::,2a00:6a40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6a80::,2a00:6a80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:6ac0::,2a00:6ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:6b00::,2a00:6b00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:6b40::,2a00:6b40:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:6b80::,2a00:6b80:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a00:6bc0::,2a00:6bc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:6c00::,2a00:6c00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6c40::,2a00:6c40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:6c80::,2a00:6c80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6d40::,2a00:6d40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:6d80::,2a00:6d80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:6dc0::,2a00:6dc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:6e00::,2a00:6e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:6e40::,2a00:6e40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:6e80::,2a00:6e80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:6ec0::,2a00:6ec0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:6f00::,2a00:6f00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:6f40::,2a00:6f40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:6f80::,2a00:6f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:6fc0::,2a00:6fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7000::,2a00:7000:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:7040::,2a00:7040:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:7080::,2a00:7080:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:70c0::,2a00:70c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7100::,2a00:7100:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7140::,2a00:7140:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7180::,2a00:7180:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:71c0::,2a00:71c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7200::,2a00:7200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7240::,2a00:7240:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:7280::,2a00:7280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:72c0::,2a00:72c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7300::,2a00:7300:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:7340::,2a00:7340:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:7380::,2a00:7380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:73c0::,2a00:73c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7400::,2a00:7400:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:7440::,2a00:7440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7480::,2a00:7480:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:74c0::,2a00:74c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7500::,2a00:7500:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7540::,2a00:7540:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7580::,2a00:7580:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:75c0::,2a00:75c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7600::,2a00:7600:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:7640::,2a00:7640:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7680::,2a00:7680:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:76c0::,2a00:76c0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:7700::,2a00:7700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7740::,2a00:7740:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7780::,2a00:7780:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:77c0::,2a00:77c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:7800::,2a00:7800:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:7840::,2a00:7840:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:7880::,2a00:7880:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:78c0::,2a00:78c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7900::,2a00:7900:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7940::,2a00:7940:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7980::,2a00:7980:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:79c0::,2a00:79c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7a00::,2a00:7a00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:7a40::,2a00:7a40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7a80::,2a00:7a80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:7ac0::,2a00:7ac0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7b00::,2a00:7b00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7b40::,2a00:7b40:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:7b80::,2a00:7b80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7bc0::,2a00:7bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7c00::,2a00:7c00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7c40::,2a00:7c40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:7c80::,2a00:7c80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7cc0::,2a00:7cc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:7d00::,2a00:7d00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:7d40::,2a00:7d40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:7d80::,2a00:7d80:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:7dc0::,2a00:7dc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:7e00::,2a00:7e00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:7e40::,2a00:7e40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7e80::,2a00:7e80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:7ec0::,2a00:7ec0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7f00::,2a00:7f00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:7f40::,2a00:7f40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:7f80::,2a00:7f80:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:7fc0::,2a00:7fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8040::,2a00:8040:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8080::,2a00:8080:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:80c0::,2a00:80c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:8100::,2a00:8100:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:8140::,2a00:8140:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8180::,2a00:8180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:81c0::,2a00:81c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8200::,2a00:8200:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:8240::,2a00:8240:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8280::,2a00:8280:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:82c0::,2a00:82c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:8300::,2a00:8300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8340::,2a00:8340:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:8380::,2a00:8380:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:83c0::,2a00:83c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8400::,2a00:8400:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:8440::,2a00:8440:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8480::,2a00:8480:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:84c0::,2a00:84c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8500::,2a00:8500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8540::,2a00:8540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8580::,2a00:8580:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:85c0::,2a00:85c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8600::,2a00:8600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8640::,2a00:8640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8680::,2a00:8680:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:86c0::,2a00:86c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8700::,2a00:8700:ffff:ffff:ffff:ffff:ffff:ffff,ME
+2a00:8740::,2a00:8740:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8780::,2a00:8780:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:87c0::,2a00:87c0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:8800::,2a00:8800:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8840::,2a00:8840:ffff:ffff:ffff:ffff:ffff:ffff,UZ
+2a00:8880::,2a00:8880:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:88c0::,2a00:88c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8900::,2a00:8900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8940::,2a00:8940:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8980::,2a00:8980:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:89c0::,2a00:89c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:8a00::,2a00:8a00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:8a40::,2a00:8a40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:8a80::,2a00:8a80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:8ac0::,2a00:8ac0:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a00:8b00::,2a00:8b00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:8b80::,2a00:8b80:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:8bc0::,2a00:8bc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8c00::,2a00:8c00:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:8c40::,2a00:8c40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:8c80::,2a00:8c80:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:8cc0::,2a00:8cc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:8d00::,2a00:8d00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:8d40::,2a00:8d40:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a00:8d80::,2a00:8d80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:8dc0::,2a00:8dc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:8e00::,2a00:8e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8e40::,2a00:8e40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8ec0::,2a00:8ec0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:8f00::,2a00:8f00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:8f40::,2a00:8f40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:8fc0::,2a00:8fc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9000::,2a00:9000:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a00:9040::,2a00:9040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9080::,2a00:9080:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:90c0::,2a00:90c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:9100::,2a00:9100:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a00:9140::,2a00:9140:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:9180::,2a00:9180:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:91c0::,2a00:91c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9200::,2a00:9200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9240::,2a00:9240:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a00:9280::,2a00:9280:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:92c0::,2a00:92c0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:9300::,2a00:9300:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:9340::,2a00:9340:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:9380::,2a00:9380:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:93c0::,2a00:93c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:9400::,2a00:9400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9440::,2a00:9440:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:9480::,2a00:9480:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:94c0::,2a00:94c0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:9500::,2a00:9500:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:9540::,2a00:9540:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:9580::,2a00:9580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:95c0::,2a00:95c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9600::,2a00:9600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9640::,2a00:9640:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:9680::,2a00:9680:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:96c0::,2a00:96c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:9700::,2a00:9700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9740::,2a00:9740:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:9780::,2a00:9780:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:97c0::,2a00:97c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:9800::,2a00:9800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9840::,2a00:9840:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:9880::,2a00:9880:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:98c0::,2a00:98c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:9900::,2a00:9900:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:9940::,2a00:9940:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:9980::,2a00:9980:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:99c0::,2a00:99c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:9a00::,2a00:9a00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9a40::,2a00:9a40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:9a80::,2a00:9a80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9ac0::,2a00:9ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:9b00::,2a00:9b00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:9b40::,2a00:9b40:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a00:9b80::,2a00:9b80:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:9bc0::,2a00:9bc0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:9c00::,2a00:9c00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:9c40::,2a00:9c40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9c80::,2a00:9c80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:9cc0::,2a00:9cc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:9d00::,2a00:9d00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9d40::,2a00:9d40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:9d80::,2a00:9d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:9dc0::,2a00:9dc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:9e00::,2a00:9e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:9e40::,2a00:9e40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:9e80::,2a00:9e80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:9ec0::,2a00:9ec0:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:9f00::,2a00:9f00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:9f40::,2a00:9f40:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a00:9f80::,2a00:9f80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:9fc0::,2a00:9fc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:a000::,2a00:a000:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a040::,2a00:a040:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a00:a080::,2a00:a080:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:a0c0::,2a00:a0c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a100::,2a00:a100:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:a140::,2a00:a140:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:a180::,2a00:a180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:a1c0::,2a00:a1c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:a200::,2a00:a200:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:a240::,2a00:a240:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:a280::,2a00:a280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a2c0::,2a00:a2c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a300::,2a00:a300:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:a340::,2a00:a340:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:a380::,2a00:a380:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:a3c0::,2a00:a3c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a400::,2a00:a400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a440::,2a00:a440:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:a480::,2a00:a480:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:a4c0::,2a00:a4c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:a500::,2a00:a500:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:a540::,2a00:a540:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:a580::,2a00:a580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:a5c0::,2a00:a5c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a600::,2a00:a600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a640::,2a00:a640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a680::,2a00:a680:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:a6c0::,2a00:a6c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:a700::,2a00:a700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:a740::,2a00:a740:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:a780::,2a00:a780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:a7c0::,2a00:a7c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a800::,2a00:a800:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:a840::,2a00:a840:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:a880::,2a00:a880:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a00:a900::,2a00:a900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:a980::,2a00:a980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:a9c0::,2a00:a9c0:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a00:aa00::,2a00:aa00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:aa40::,2a00:aa40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:aa80::,2a00:aa80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a00:aac0::,2a00:aac0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:ab00::,2a00:ab00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:ab40::,2a00:ab40:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a00:ab80::,2a00:ab80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ac00::,2a00:ac00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:ac40::,2a00:ac40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ac80::,2a00:ac80:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:acc0::,2a00:acc0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:ad00::,2a00:ad00:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:ad40::,2a00:ad40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ad80::,2a00:ad87:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:adc0::,2a00:adc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:ae00::,2a00:ae00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:ae40::,2a00:ae40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:ae80::,2a00:ae80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:aec0::,2a00:aec0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:af00::,2a00:af00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:af40::,2a00:af40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:af80::,2a00:af80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:afc0::,2a00:afc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:b000::,2a00:b000:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:b040::,2a00:b040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b080::,2a00:b080:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:b0c0::,2a00:b0c0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:b100::,2a00:b100:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b140::,2a00:b140:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:b180::,2a00:b180:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:b1c0::,2a00:b1c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b200::,2a00:b200:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:b240::,2a00:b240:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:b280::,2a00:b280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:b2c0::,2a00:b2c0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a00:b300::,2a00:b300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b340::,2a00:b340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b380::,2a00:b380:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:b3c0::,2a00:b3c0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a00:b400::,2a00:b400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:b440::,2a00:b440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b480::,2a00:b480:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:b4c0::,2a00:b4c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b500::,2a00:b500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b540::,2a00:b540:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:b580::,2a00:b580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:b5c0::,2a00:b5c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:b600::,2a00:b607:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b640::,2a00:b640:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:b680::,2a00:b680:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:b6c0::,2a00:b6c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:b700::,2a00:b700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b740::,2a00:b740:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:b780::,2a00:b780:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:b7c0::,2a00:b7c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:b800::,2a00:b800:ffff:ffff:ffff:ffff:ffff:ffff,SY
+2a00:b840::,2a00:b840:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b880::,2a00:b880:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:b8c0::,2a00:b8c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:b900::,2a00:b900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b980::,2a00:b981:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:b9c0::,2a00:b9c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ba00::,2a00:ba00:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:ba40::,2a00:ba40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ba80::,2a00:ba80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bac0::,2a00:bac0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:bb00::,2a00:bb00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:bb40::,2a00:bb40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:bb80::,2a00:bb80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:bbc0::,2a00:bbc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bc00::,2a00:bc00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:bc40::,2a00:bc40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:bc80::,2a00:bc80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bcc0::,2a00:bcc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:bd00::,2a00:bd00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:bd40::,2a00:bd40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:bd80::,2a00:bd80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:bdc0::,2a00:bdc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:be00::,2a00:be00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:be40::,2a00:be40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:be80::,2a00:be80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bec0::,2a00:bec7:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:bf00::,2a00:bf00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:bf40::,2a00:bf40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:bf80::,2a00:bf80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:bfc0::,2a00:bfc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c000::,2a00:c000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c040::,2a00:c040:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c080::,2a00:c080:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c0c0::,2a00:c0c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c100::,2a00:c100:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:c140::,2a00:c140:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:c180::,2a00:c180:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:c1c0::,2a00:c1c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:c200::,2a00:c200:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:c240::,2a00:c240:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a00:c280::,2a00:c280:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a00:c2c0::,2a00:c2c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c300::,2a00:c300:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c340::,2a00:c340:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c380::,2a00:c380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:c3c0::,2a00:c3c0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:c400::,2a00:c400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c440::,2a00:c440:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:c480::,2a00:c480:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c4c0::,2a00:c4c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c500::,2a00:c500:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:c540::,2a00:c540:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:c580::,2a00:c580:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:c5c0::,2a00:c5c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c600::,2a00:c600:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c640::,2a00:c640:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:c680::,2a00:c680:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c6c0::,2a00:c6c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c700::,2a00:c700:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:c740::,2a00:c740:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:c780::,2a00:c780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:c7c0::,2a00:c7c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:c800::,2a00:c800:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:c840::,2a00:c840:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:c880::,2a00:c880:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:c8c0::,2a00:c8c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c900::,2a00:c900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:c940::,2a00:c940:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:c980::,2a00:c980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:c9c0::,2a00:c9c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:ca00::,2a00:ca00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ca40::,2a00:ca40:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:ca80::,2a00:ca80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:cac0::,2a00:cac0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:cb00::,2a00:cb00:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:cb40::,2a00:cb40:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:cb80::,2a00:cb80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:cbc0::,2a00:cbc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:cc00::,2a00:cc00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:cc40::,2a00:cc40:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a00:cc80::,2a00:cc80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ccc0::,2a00:ccc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cd00::,2a00:cd00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:cd40::,2a00:cd40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:cd80::,2a00:cd80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:cdc0::,2a00:cdc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ce00::,2a00:ce00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:ce40::,2a00:ce40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ce80::,2a00:ce80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:cec0::,2a00:cec0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:cf00::,2a00:cf00:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:cf40::,2a00:cf40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:cf80::,2a00:cf80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:cfc0::,2a00:cfc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:d000::,2a00:d000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d040::,2a00:d040:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:d080::,2a00:d080:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:d0c0::,2a00:d0c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d100::,2a00:d100:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:d140::,2a00:d140:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a00:d180::,2a00:d180:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:d1c0::,2a00:d1c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d200::,2a00:d200:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d240::,2a00:d240:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:d280::,2a00:d280:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:d2c0::,2a00:d2c0:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a00:d300::,2a00:d300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d340::,2a00:d340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d380::,2a00:d380:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d400::,2a00:d400:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:d440::,2a00:d447:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:d480::,2a00:d480:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:d4c0::,2a00:d4c0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:d500::,2a00:d500:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:d540::,2a00:d540:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d580::,2a00:d580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d5c0::,2a00:d5c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:d600::,2a00:d600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d640::,2a00:d640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d680::,2a00:d680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d6c0::,2a00:d6c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d700::,2a00:d700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:d740::,2a00:d747:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:d780::,2a00:d780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:d7c0::,2a00:d7c0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:d800::,2a00:d800:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:d840::,2a00:d840:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:d880::,2a00:d880:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:d8c0::,2a00:d8c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:d900::,2a00:d900:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:d940::,2a00:d940:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:d980::,2a00:d980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:d9c0::,2a00:d9c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:da00::,2a00:da00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:da40::,2a00:da40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:da80::,2a00:da80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:dac0::,2a00:dac0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:db00::,2a00:db00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:db40::,2a00:db40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:db80::,2a00:db80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:dbc0::,2a00:dbc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:dc00::,2a00:dc00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:dc40::,2a00:dc40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:dc80::,2a00:dc80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:dcc0::,2a00:dcc7:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:dd00::,2a00:dd00:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a00:dd40::,2a00:dd40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:dd80::,2a00:dd80:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a00:ddc0::,2a00:ddc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:de00::,2a00:de00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:de40::,2a00:de40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:de80::,2a00:de80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:dec0::,2a00:dec0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:df00::,2a00:df00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:df40::,2a00:df40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:df80::,2a00:df80:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:dfc0::,2a00:dfc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e000::,2a00:e000:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a00:e040::,2a00:e040:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a00:e080::,2a00:e080:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e0c0::,2a00:e0c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e100::,2a00:e100:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e140::,2a00:e140:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:e180::,2a00:e180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e1c0::,2a00:e1c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e200::,2a00:e200:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:e240::,2a00:e240:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e280::,2a00:e280:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:e2c0::,2a00:e2c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:e300::,2a00:e300:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a00:e340::,2a00:e340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e380::,2a00:e380:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:e3c0::,2a00:e3c0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:e400::,2a00:e400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e440::,2a00:e440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e480::,2a00:e480:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:e4c0::,2a00:e4c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:e500::,2a00:e500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:e540::,2a00:e540:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:e580::,2a00:e580:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:e5c0::,2a00:e5c0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:e600::,2a00:e600:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:e640::,2a00:e640:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:e680::,2a00:e680:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:e6c0::,2a00:e6c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:e700::,2a00:e700:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e740::,2a00:e740:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:e780::,2a00:e780:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:e7c0::,2a00:e7c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:e800::,2a00:e807:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:e840::,2a00:e840:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e880::,2a00:e880:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:e8c0::,2a00:e8c0:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a00:e900::,2a00:e900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:e940::,2a00:e940:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:e980::,2a00:e980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:e9c0::,2a00:e9c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:ea00::,2a00:ea00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:ea40::,2a00:ea40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ea80::,2a00:ea80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:eac0::,2a00:eac0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:eb00::,2a00:eb00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:eb40::,2a00:eb40:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:eb80::,2a00:eb80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ebc0::,2a00:ebc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a00:ec00::,2a00:ec00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:ec40::,2a00:ec47:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ec80::,2a00:ec80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:ecc0::,2a00:ecc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ed00::,2a00:ed00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ed40::,2a00:ed40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ed80::,2a00:ed80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:ee00::,2a00:ee00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:ee40::,2a00:ee40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:ee80::,2a00:ee80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:eec0::,2a00:eec0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:ef00::,2a00:ef00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:ef40::,2a00:ef40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:ef80::,2a00:ef80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:efc0::,2a00:efc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f000::,2a00:f000:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a00:f040::,2a00:f040:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f080::,2a00:f080:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:f0c0::,2a00:f0c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f100::,2a00:f100:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a00:f140::,2a00:f140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f180::,2a00:f180:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f1c0::,2a00:f1c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f200::,2a00:f200:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:f240::,2a00:f240:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:f280::,2a00:f280:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f2c0::,2a00:f2c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:f300::,2a00:f300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f340::,2a00:f340:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:f380::,2a00:f380:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:f3c0::,2a00:f3c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f400::,2a00:f400:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a00:f440::,2a00:f440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f480::,2a00:f480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f4c0::,2a00:f4c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f500::,2a00:f500:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a00:f540::,2a00:f540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f580::,2a00:f580:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a00:f5c0::,2a00:f5c0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a00:f600::,2a00:f600:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f640::,2a00:f640:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:f680::,2a00:f680:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:f6c0::,2a00:f6c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:f700::,2a00:f700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:f740::,2a00:f740:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a00:f780::,2a00:f780:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:f7c0::,2a00:f7c7:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a00:f800::,2a00:f800:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:f840::,2a00:f840:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:f880::,2a00:f880:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:f8c0::,2a00:f8c0:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a00:f900::,2a00:f900:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a00:f940::,2a00:f940:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a00:f980::,2a00:f980:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a00:f9c0::,2a00:f9c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:fa00::,2a00:fa00:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a00:fa40::,2a00:fa40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fa80::,2a00:fa80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a00:fac0::,2a00:fac0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fb00::,2a00:fb00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:fb40::,2a00:fb40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a00:fb80::,2a00:fb80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fbc0::,2a00:fbc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a00:fc00::,2a00:fc00:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a00:fc40::,2a00:fc40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a00:fc80::,2a00:fc80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:fcc0::,2a00:fcc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fd00::,2a00:fd00:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a00:fd40::,2a00:fd40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a00:fd80::,2a00:fd80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a00:fdc0::,2a00:fdc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:fe00::,2a00:fe00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a00:fe40::,2a00:fe40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a00:fe80::,2a00:fe80:ffff:ffff:ffff:ffff:ffff:ffff,ME
+2a00:fec0::,2a00:fec0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a00:ff00::,2a00:ff00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a00:ff40::,2a00:ff40:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a00:ff80::,2a00:ff80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a00:ffc0::,2a00:ffc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01::,2a01:0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:8::,2a01:8:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a01:10::,2a01:10:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a01:18::,2a01:18:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:20::,2a01:20:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:28::,2a01:28:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:30::,2a01:30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:38::,2a01:38:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:40::,2a01:40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:48::,2a01:48:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:50::,2a01:50:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:58::,2a01:58:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:68::,2a01:68:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:70::,2a01:70:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:78::,2a01:78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:80::,2a01:80:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a01:88::,2a01:88:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:90::,2a01:90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:98::,2a01:98:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a0::,2a01:a0:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a01:a8::,2a01:a8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:b0::,2a01:b1:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:b8::,2a01:b8:ffff:ffff:ffff:ffff:ffff:ffff,VA
+2a01:c0::,2a01:c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:c8::,2a01:c8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:d0::,2a01:d0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:d8::,2a01:d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:e0::,2a01:e0:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:e8::,2a01:e8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:f0::,2a01:f0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:f8::,2a01:f8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:100::,2a01:100:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:108::,2a01:108:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:110::,2a01:111:ffff:ffff:ffff:ffff:ffff:ffff,DZ
+2a01:120::,2a01:120:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:128::,2a01:128:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:130::,2a01:130:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:138::,2a01:138:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:140::,2a01:140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:148::,2a01:148:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:150::,2a01:150:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:158::,2a01:158:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a01:160::,2a01:160:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:168::,2a01:168:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:170::,2a01:170:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:178::,2a01:178:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:180::,2a01:180:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a01:188::,2a01:188:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:190::,2a01:190:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:198::,2a01:198:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:1a0::,2a01:1a0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:1a8::,2a01:1a8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:1b0::,2a01:1b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:1b8::,2a01:1b8:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a01:1c0::,2a01:1c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:1c8::,2a01:1c8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:1d0::,2a01:1d0:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a01:1d8::,2a01:1d8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:1e0::,2a01:1e0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:1e8::,2a01:1e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:1f0::,2a01:1f0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:1f8::,2a01:1f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:200::,2a01:200:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:208::,2a01:208:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:210::,2a01:210:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:220::,2a01:220:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:228::,2a01:228:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:230::,2a01:230:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:238::,2a01:238:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:240::,2a01:240:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:248::,2a01:248:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:250::,2a01:250:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:258::,2a01:258:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:260::,2a01:260:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a01:268::,2a01:268:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:270::,2a01:270:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:278::,2a01:278:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:280::,2a01:280:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:288::,2a01:288:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:290::,2a01:290:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:298::,2a01:298:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:2a0::,2a01:2a0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:2a8::,2a01:2a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:2b0::,2a01:2b7:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:2b8::,2a01:2b8:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a01:2c0::,2a01:2c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:2c8::,2a01:2c8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:2d0::,2a01:2d0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:2d8::,2a01:2d8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:2e0::,2a01:2ef:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:300::,2a01:307:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a01:308::,2a01:308:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:310::,2a01:310:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:320::,2a01:320:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a01:328::,2a01:328:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:330::,2a01:330:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:338::,2a01:338:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:340::,2a01:340:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:348::,2a01:348:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:350::,2a01:350:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:358::,2a01:358:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:360::,2a01:360:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:368::,2a01:36f:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:378::,2a01:378:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:380::,2a01:380:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:388::,2a01:388:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:390::,2a01:390:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:398::,2a01:398:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:3a0::,2a01:3a0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:3a8::,2a01:3a8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:3b0::,2a01:3b0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a01:3b8::,2a01:3b8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:3c0::,2a01:3c0:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a01:3c8::,2a01:3c8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:3d8::,2a01:3d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:3e0::,2a01:3e0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a01:3e8::,2a01:3e8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:3f0::,2a01:3f0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:3f8::,2a01:3f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:400::,2a01:400:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:408::,2a01:408:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:410::,2a01:410:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:418::,2a01:418:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:420::,2a01:420:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:428::,2a01:428:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:430::,2a01:430:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:438::,2a01:438:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:440::,2a01:440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:448::,2a01:448:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:450::,2a01:450:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:458::,2a01:458:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:460::,2a01:460:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:468::,2a01:468:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:470::,2a01:470:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:478::,2a01:47f:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a01:480::,2a01:480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:488::,2a01:488:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:490::,2a01:490:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:498::,2a01:498:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:4a0::,2a01:4a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4a8::,2a01:4a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4b0::,2a01:4b0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:4c0::,2a01:4c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:4c8::,2a01:4cf:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4d0::,2a01:4d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4d8::,2a01:4d8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:4e0::,2a01:4e0:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a01:4e8::,2a01:4e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4f0::,2a01:4f0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:4f8::,2a01:4ff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:500::,2a01:500:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:508::,2a01:508:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:510::,2a01:510:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:518::,2a01:518:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:520::,2a01:520:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:528::,2a01:528:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:530::,2a01:530:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:538::,2a01:538:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:540::,2a01:540:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:548::,2a01:548:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:550::,2a01:550:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:558::,2a01:558:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:560::,2a01:560:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:568::,2a01:568:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:570::,2a01:570:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:578::,2a01:578:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:580::,2a01:580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:590::,2a01:590:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:598::,2a01:59f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5a0::,2a01:5a0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5a8::,2a01:5a8:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:5b0::,2a01:5b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5b8::,2a01:5b8:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a01:5c0::,2a01:5c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5c8::,2a01:5c8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5d0::,2a01:5d0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:5d8::,2a01:5d8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:5e0::,2a01:5e0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:5e8::,2a01:5e8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:5f0::,2a01:5f0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:5f8::,2a01:5f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:600::,2a01:600:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:608::,2a01:608:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a01:610::,2a01:610:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:618::,2a01:618:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:620::,2a01:620:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:628::,2a01:628:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:630::,2a01:630:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:638::,2a01:638:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a01:640::,2a01:647:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:648::,2a01:648:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:650::,2a01:650:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:658::,2a01:658:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:660::,2a01:667:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:668::,2a01:668:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:670::,2a01:670:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:678::,2a01:678:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:680::,2a01:680:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:688::,2a01:688:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:690::,2a01:690:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:698::,2a01:698:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6a0::,2a01:6a0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:6a8::,2a01:6a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:6b0::,2a01:6b0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:6b8::,2a01:6b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6c0::,2a01:6c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6c8::,2a01:6c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6d0::,2a01:6d0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:6d8::,2a01:6d8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6e0::,2a01:6e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6e8::,2a01:6e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6f0::,2a01:6f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6f8::,2a01:6f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:700::,2a01:700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:710::,2a01:710:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:718::,2a01:718:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:720::,2a01:720:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:728::,2a01:72f:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:730::,2a01:730:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:738::,2a01:738:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:740::,2a01:740:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:748::,2a01:748:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:750::,2a01:750:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:758::,2a01:758:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:760::,2a01:760:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:768::,2a01:768:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:770::,2a01:770:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:778::,2a01:778:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:780::,2a01:780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:788::,2a01:788:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:790::,2a01:790:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:798::,2a01:79f:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:7a0::,2a01:7a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7a8::,2a01:7a8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7b0::,2a01:7b0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:7b8::,2a01:7b8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7c0::,2a01:7c0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:7c8::,2a01:7c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:7d0::,2a01:7d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7d8::,2a01:7d8:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a01:7e0::,2a01:7e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7e8::,2a01:7e8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:7f0::,2a01:7f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7f8::,2a01:7f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:800::,2a01:8ff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:c00::,2a01:c3f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:e00::,2a01:e3f:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:1000::,2a01:17ff:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:2000::,2a01:2fff:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4000::,2a01:4000:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a01:4040::,2a01:4040:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:4080::,2a01:4080:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:40c0::,2a01:40c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:41c0::,2a01:41c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4200::,2a01:4200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4240::,2a01:4240:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:4280::,2a01:4280:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a01:42c0::,2a01:42c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:4300::,2a01:4300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4340::,2a01:4340:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:4380::,2a01:4380:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:43c0::,2a01:43c0:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a01:4400::,2a01:4400:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:4440::,2a01:4440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4480::,2a01:4480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:44c0::,2a01:44c0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:4500::,2a01:4500:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a01:4540::,2a01:4540:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4580::,2a01:4580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:45c0::,2a01:45c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:4600::,2a01:4600:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a01:4640::,2a01:4640:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4680::,2a01:4680:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a01:46c0::,2a01:46c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:4700::,2a01:4700:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4740::,2a01:4740:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a01:4780::,2a01:4780:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a01:47c0::,2a01:47c0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:4800::,2a01:4800:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4840::,2a01:4840:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4880::,2a01:4880:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:48c0::,2a01:48c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4900::,2a01:4900:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a01:4940::,2a01:4940:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4980::,2a01:4980:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:49c0::,2a01:49c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4a00::,2a01:4a00:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a01:4a40::,2a01:4a40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:4a80::,2a01:4a80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:4ac0::,2a01:4ac0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:4b00::,2a01:4b00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4b40::,2a01:4b40:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:4b80::,2a01:4b80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:4bc0::,2a01:4bc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4c00::,2a01:4c00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:4c40::,2a01:4c40:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:4c80::,2a01:4c80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4cc0::,2a01:4cc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:4d00::,2a01:4d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4d40::,2a01:4d40:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:4d80::,2a01:4d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4dc0::,2a01:4dc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4e00::,2a01:4e00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:4e40::,2a01:4e40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:4e80::,2a01:4e80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4ec0::,2a01:4ec0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:4f00::,2a01:4f00:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a01:4f40::,2a01:4f40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:4f80::,2a01:4f80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:4fc0::,2a01:4fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5000::,2a01:5000:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5040::,2a01:5047:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:5080::,2a01:5080:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:50c0::,2a01:50c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5100::,2a01:5100:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:5140::,2a01:5140:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:5180::,2a01:5180:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:51c0::,2a01:51c0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:5200::,2a01:5200:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:5240::,2a01:5240:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5280::,2a01:5280:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:52c0::,2a01:52c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5300::,2a01:5300:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:5340::,2a01:5340:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5380::,2a01:5380:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:53c0::,2a01:53c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5400::,2a01:5400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5440::,2a01:5440:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:5480::,2a01:5480:ffff:ffff:ffff:ffff:ffff:ffff,GG
+2a01:54c0::,2a01:54c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:5500::,2a01:5500:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:5540::,2a01:5540:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:5580::,2a01:5580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:55c0::,2a01:55c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5600::,2a01:5600:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:5640::,2a01:5640:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5680::,2a01:5680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:56c0::,2a01:56c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5700::,2a01:5700:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:5740::,2a01:5740:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:5780::,2a01:5780:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:57c0::,2a01:57c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5800::,2a01:5800:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:5840::,2a01:5840:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:5900::,2a01:5900:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:5940::,2a01:5940:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:5980::,2a01:5980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:59c0::,2a01:59c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5a00::,2a01:5a00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:5a40::,2a01:5a40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5a80::,2a01:5a80:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a01:5ac0::,2a01:5ac0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5b00::,2a01:5b00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5b40::,2a01:5b40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:5b80::,2a01:5b80:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:5bc0::,2a01:5bc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:5c00::,2a01:5c00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:5c40::,2a01:5c40:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:5c80::,2a01:5c80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5cc0::,2a01:5cc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:5d00::,2a01:5d00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5d40::,2a01:5d40:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:5d80::,2a01:5d80:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a01:5dc0::,2a01:5dc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:5e00::,2a01:5e00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:5e40::,2a01:5e40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:5e80::,2a01:5e80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:5ec0::,2a01:5ec0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:5f00::,2a01:5f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5f40::,2a01:5f40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:5f80::,2a01:5f80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:5fc0::,2a01:5fc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6000::,2a01:6000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6040::,2a01:6040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6080::,2a01:6080:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:60c0::,2a01:60c0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:6100::,2a01:6100:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6140::,2a01:6140:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:6180::,2a01:6180:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:61c0::,2a01:61c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6200::,2a01:6200:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:6240::,2a01:6240:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6280::,2a01:6280:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:62c0::,2a01:62c0:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a01:6300::,2a01:6300:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:6340::,2a01:6340:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:6380::,2a01:6380:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:63c0::,2a01:63c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:6400::,2a01:6400:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:6440::,2a01:6440:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a01:6480::,2a01:6480:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a01:64c0::,2a01:64c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6500::,2a01:6500:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a01:6540::,2a01:6540:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6580::,2a01:6580:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:65c0::,2a01:65c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:6600::,2a01:6600:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6640::,2a01:6640:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:6680::,2a01:6680:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:66c0::,2a01:66c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6700::,2a01:6700:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a01:6740::,2a01:6740:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6780::,2a01:6780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:67c0::,2a01:67c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:6800::,2a01:6800:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6840::,2a01:6840:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:6880::,2a01:6880:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:68c0::,2a01:68c0:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:6900::,2a01:6900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:6940::,2a01:6940:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6980::,2a01:6980:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:69c0::,2a01:69c0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:6a00::,2a01:6a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:6a40::,2a01:6a40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:6a80::,2a01:6a80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:6ac0::,2a01:6ac0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6b00::,2a01:6b00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:6b40::,2a01:6b40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:6b80::,2a01:6b80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:6bc0::,2a01:6bc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6c00::,2a01:6c00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6c40::,2a01:6c40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:6c80::,2a01:6c80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:6cc0::,2a01:6cc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6d00::,2a01:6d00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:6d40::,2a01:6d40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:6d80::,2a01:6d80:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:6dc0::,2a01:6dc0:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a01:6e00::,2a01:6e00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:6e40::,2a01:6e40:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a01:6e80::,2a01:6e80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:6ec0::,2a01:6ec0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:6f00::,2a01:6f00:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:6f40::,2a01:6f40:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:6f80::,2a01:6f80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:6fc0::,2a01:6fc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:7000::,2a01:7000:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7040::,2a01:7040:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:7080::,2a01:7080:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:70c0::,2a01:70c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7100::,2a01:7100:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7140::,2a01:7140:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7180::,2a01:7180:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:71c0::,2a01:71c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:7200::,2a01:7200:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:7240::,2a01:7240:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:7280::,2a01:7280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7300::,2a01:7300:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:7340::,2a01:7340:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:7380::,2a01:7380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:73c0::,2a01:73c0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a01:7400::,2a01:7400:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:7440::,2a01:7440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7480::,2a01:7480:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:74c0::,2a01:74c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7500::,2a01:7500:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:7540::,2a01:7540:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7580::,2a01:7580:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:75c0::,2a01:75c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7600::,2a01:7600:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:7640::,2a01:7640:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:7680::,2a01:7680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:76c0::,2a01:76c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7700::,2a01:7700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7740::,2a01:7740:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7780::,2a01:7780:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a01:77c0::,2a01:77c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:7800::,2a01:7800:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7840::,2a01:7840:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7880::,2a01:7880:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:78c0::,2a01:78c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7900::,2a01:7900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:7940::,2a01:7940:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7980::,2a01:7980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:79c0::,2a01:79c0:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a01:7a00::,2a01:7a00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:7a40::,2a01:7a40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7a80::,2a01:7a80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:7ac0::,2a01:7ac0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7b00::,2a01:7b00:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a01:7b40::,2a01:7b40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7b80::,2a01:7b80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:7bc0::,2a01:7bc0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:7c00::,2a01:7c00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:7c40::,2a01:7c40:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a01:7c80::,2a01:7c80:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a01:7cc0::,2a01:7cc0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:7d00::,2a01:7d00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:7d40::,2a01:7d40:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:7d80::,2a01:7d80:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:7e00::,2a01:7e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:7e40::,2a01:7e40:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a01:7e80::,2a01:7e80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:7ec0::,2a01:7ec0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:7f00::,2a01:7f00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:7f40::,2a01:7f40:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a01:7f80::,2a01:7f80:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a01:7fc0::,2a01:7fc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8000::,2a01:8000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8040::,2a01:8040:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8080::,2a01:8080:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a01:80c0::,2a01:80c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:8100::,2a01:8100:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:8140::,2a01:8140:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:8180::,2a01:8180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:81c0::,2a01:81c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8200::,2a01:8200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:8240::,2a01:8240:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8280::,2a01:8280:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:82c0::,2a01:82c0:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a01:8300::,2a01:8300:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:8340::,2a01:8340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8380::,2a01:8380:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:83c0::,2a01:83c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:8400::,2a01:8400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8440::,2a01:8440:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:8480::,2a01:8480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:84c0::,2a01:84c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8500::,2a01:8500:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:8540::,2a01:8540:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:8580::,2a01:8580:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:85c0::,2a01:85c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8600::,2a01:8600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8640::,2a01:8640:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8680::,2a01:8680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:86c0::,2a01:86c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:8700::,2a01:8700:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a01:8740::,2a01:8740:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:8780::,2a01:8780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:87c0::,2a01:87c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8800::,2a01:8800:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:8840::,2a01:8840:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:8880::,2a01:8880:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:88c0::,2a01:88c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8900::,2a01:8900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8940::,2a01:8940:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8980::,2a01:8980:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:89c0::,2a01:89c0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:8a00::,2a01:8a00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:8a40::,2a01:8a40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8a80::,2a01:8a80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:8ac0::,2a01:8ac0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:8b00::,2a01:8b00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:8b40::,2a01:8b40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:8b80::,2a01:8b80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:8bc0::,2a01:8bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:8c00::,2a01:8c00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:8c40::,2a01:8c40:ffff:ffff:ffff:ffff:ffff:ffff,GI
+2a01:8c80::,2a01:8c80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:8cc0::,2a01:8cc0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:8d00::,2a01:8d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:8d40::,2a01:8d47:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:8d80::,2a01:8d80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:8dc0::,2a01:8dc0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:8e00::,2a01:8e00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:8e40::,2a01:8e40:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a01:8e80::,2a01:8e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:8ec0::,2a01:8ec0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a01:8f00::,2a01:8f00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:8f40::,2a01:8f40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:8f80::,2a01:8f80:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:8fc0::,2a01:8fc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:9000::,2a01:9000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9040::,2a01:9040:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a01:9080::,2a01:9080:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:90c0::,2a01:90c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9100::,2a01:9100:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:9140::,2a01:9140:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:9180::,2a01:9180:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:91c0::,2a01:91c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:9240::,2a01:9240:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a01:9280::,2a01:9280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:92c0::,2a01:92c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9300::,2a01:9300:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9340::,2a01:9340:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:9380::,2a01:9380:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:93c0::,2a01:93c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9400::,2a01:9400:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:9440::,2a01:9440:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:9480::,2a01:9480:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:94c0::,2a01:94c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9500::,2a01:9500:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9540::,2a01:9540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9580::,2a01:9580:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:95c0::,2a01:95c0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:9600::,2a01:9600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9640::,2a01:9640:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:9680::,2a01:9680:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:96c0::,2a01:96c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9700::,2a01:9700:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a01:9740::,2a01:9740:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9780::,2a01:9780:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:97c0::,2a01:97c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:9800::,2a01:9800:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:9840::,2a01:9840:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9880::,2a01:9880:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:98c0::,2a01:98c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9900::,2a01:9900:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:9940::,2a01:9940:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9980::,2a01:9980:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:9a00::,2a01:9a00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9a40::,2a01:9a40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9a80::,2a01:9a80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9ac0::,2a01:9ac0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9b00::,2a01:9b00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:9b40::,2a01:9b40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:9b80::,2a01:9b80:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:9bc0::,2a01:9bc0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:9c00::,2a01:9c00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:9c40::,2a01:9c41:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9c80::,2a01:9c80:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a01:9cc0::,2a01:9cc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9d00::,2a01:9d00:ffff:ffff:ffff:ffff:ffff:ffff,KG
+2a01:9d40::,2a01:9d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:9d80::,2a01:9d80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:9dc0::,2a01:9dc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:9e00::,2a01:9e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9e40::,2a01:9e40:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:9e80::,2a01:9e80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:9ec0::,2a01:9ec0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:9f00::,2a01:9f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:9f40::,2a01:9f40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:9f80::,2a01:9f80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:9fc0::,2a01:9fc0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:a000::,2a01:a000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a040::,2a01:a040:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:a080::,2a01:a080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a0c0::,2a01:a0c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a100::,2a01:a100:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:a140::,2a01:a140:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a180::,2a01:a180:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a01:a1c0::,2a01:a1c0:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a01:a200::,2a01:a200:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a240::,2a01:a240:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:a280::,2a01:a280:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:a2c0::,2a01:a2c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a300::,2a01:a300:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:a340::,2a01:a340:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:a380::,2a01:a380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a3c0::,2a01:a3c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a400::,2a01:a400:ffff:ffff:ffff:ffff:ffff:ffff,JE
+2a01:a440::,2a01:a440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:a480::,2a01:a480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a4c0::,2a01:a4c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:a500::,2a01:a500:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a540::,2a01:a540:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:a580::,2a01:a580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:a5c0::,2a01:a5c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:a600::,2a01:a600:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:a640::,2a01:a640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a680::,2a01:a680:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:a6c0::,2a01:a6c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:a700::,2a01:a700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a740::,2a01:a740:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a780::,2a01:a780:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a7c0::,2a01:a7c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:a800::,2a01:a800:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:a840::,2a01:a840:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:a880::,2a01:a880:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a01:a8c0::,2a01:a8c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:a900::,2a01:a900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:a940::,2a01:a940:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:a980::,2a01:a980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:a9c0::,2a01:a9c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:aa00::,2a01:aa00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a01:aa40::,2a01:aa40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:aa80::,2a01:aa80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:aac0::,2a01:aac0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:ab00::,2a01:ab00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:ab40::,2a01:ab40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:abc0::,2a01:abc0:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a01:ac00::,2a01:ac00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:ac40::,2a01:ac40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:ac80::,2a01:ac80:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a01:acc0::,2a01:acc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:ad00::,2a01:ad00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:ad40::,2a01:ad40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:ad80::,2a01:ad80:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a01:adc0::,2a01:adc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:ae00::,2a01:ae00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:ae40::,2a01:ae40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:ae80::,2a01:ae80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a01:aec0::,2a01:aec0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:af00::,2a01:af00:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:af40::,2a01:af40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:af80::,2a01:af80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a01:afc0::,2a01:afc0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:b000::,2a01:b000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b040::,2a01:b040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b080::,2a01:b080:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:b0c0::,2a01:b0c0:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a01:b100::,2a01:b100:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b140::,2a01:b140:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:b180::,2a01:b180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:b1c0::,2a01:b1c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:b200::,2a01:b200:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a01:b240::,2a01:b240:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b280::,2a01:b280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b2c0::,2a01:b2c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b300::,2a01:b307:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:b340::,2a01:b340:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:b380::,2a01:b380:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:b3c0::,2a01:b3c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b400::,2a01:b400:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b440::,2a01:b440:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a01:b480::,2a01:b480:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a01:b4c0::,2a01:b4c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a01:b500::,2a01:b500:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a01:b540::,2a01:b540:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b580::,2a01:b580:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:b5c0::,2a01:b5c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:b600::,2a01:b600:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:b640::,2a01:b640:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:b680::,2a01:b680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:b6c0::,2a01:b6c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:b700::,2a01:b700:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:b740::,2a01:b740:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:b780::,2a01:b780:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a01:b7c0::,2a01:b7c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:b800::,2a01:b800:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a01:b840::,2a01:b840:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b880::,2a01:b880:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a01:b8c0::,2a01:b8c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:b900::,2a01:b900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:b940::,2a01:b940:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a01:b980::,2a01:b980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:b9c0::,2a01:b9c0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a01:ba00::,2a01:ba00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a01:ba40::,2a01:ba40:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:ba80::,2a01:ba80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:bac0::,2a01:bac0:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:bb40::,2a01:bb40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:bb80::,2a01:bb80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a01:bbc0::,2a01:bbc0:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a01:bc00::,2a01:bc00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a01:bc40::,2a01:bc40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:bc80::,2a01:bc80:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a01:bcc0::,2a01:bcc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:bd00::,2a01:bd00:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a01:bd40::,2a01:bd40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:bd80::,2a01:bd80:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a01:bdc0::,2a01:bdc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a01:be00::,2a01:be00:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a01:be40::,2a01:be40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:be80::,2a01:be80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a01:bec0::,2a01:bec0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:bf00::,2a01:bf00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a01:bf40::,2a01:bf40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a01:bf80::,2a01:bf80:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a01:bfc0::,2a01:bfc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a01:c000::,2a01:dfff:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02::,2a02:0:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:8::,2a02:8:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:10::,2a02:10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:18::,2a02:18:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:20::,2a02:20:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:28::,2a02:28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:30::,2a02:30:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:38::,2a02:38:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:40::,2a02:40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:48::,2a02:48:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:50::,2a02:50:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:58::,2a02:58:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:60::,2a02:60:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:68::,2a02:68:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:70::,2a02:70:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:78::,2a02:78:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:80::,2a02:80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:88::,2a02:88:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:90::,2a02:90:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:98::,2a02:98:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:a0::,2a02:a0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:a8::,2a02:a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b0::,2a02:b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b8::,2a02:b8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:c0::,2a02:c0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:c8::,2a02:c8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:d0::,2a02:d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:d8::,2a02:d8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:e0::,2a02:e0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:e8::,2a02:e8:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:f0::,2a02:f0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:f8::,2a02:f8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:100::,2a02:100:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:108::,2a02:108:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:110::,2a02:110:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:118::,2a02:118:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:120::,2a02:120:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:128::,2a02:128:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:130::,2a02:130:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:138::,2a02:138:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:140::,2a02:140:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:148::,2a02:148:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:150::,2a02:150:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:158::,2a02:158:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:160::,2a02:160:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:168::,2a02:168:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:170::,2a02:170:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:178::,2a02:178:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:180::,2a02:180:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:188::,2a02:18f:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:190::,2a02:190:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:198::,2a02:198:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:1a0::,2a02:1a0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1a8::,2a02:1a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1b0::,2a02:1b0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:1b8::,2a02:1b8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:1c0::,2a02:1c0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:1c8::,2a02:1c8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1d0::,2a02:1d0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1d8::,2a02:1d8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1e0::,2a02:1e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1e8::,2a02:1e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1f0::,2a02:1f0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1f8::,2a02:1f8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:200::,2a02:200:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:208::,2a02:208:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:210::,2a02:210:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:218::,2a02:218:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:220::,2a02:220:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:228::,2a02:22f:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:230::,2a02:230:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:238::,2a02:238:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:240::,2a02:240:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:248::,2a02:248:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:250::,2a02:250:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:258::,2a02:258:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:260::,2a02:260:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:268::,2a02:268:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:270::,2a02:270:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:278::,2a02:278:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:280::,2a02:280:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:288::,2a02:288:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:290::,2a02:290:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:298::,2a02:298:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2a0::,2a02:2a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2a8::,2a02:2a8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2b0::,2a02:2b0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2b8::,2a02:2b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2c0::,2a02:2c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2c8::,2a02:2c8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2d0::,2a02:2d0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2d8::,2a02:2d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2e0::,2a02:2e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2e8::,2a02:2e8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2f0::,2a02:2f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2f8::,2a02:2f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:300::,2a02:300:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:308::,2a02:308:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:310::,2a02:310:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:318::,2a02:318:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:320::,2a02:320:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:328::,2a02:328:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:330::,2a02:330:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:338::,2a02:338:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:340::,2a02:340:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:348::,2a02:348:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:350::,2a02:350:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:358::,2a02:358:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:360::,2a02:360:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:368::,2a02:368:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:370::,2a02:370:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:380::,2a02:380:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a02:388::,2a02:388:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:390::,2a02:390:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:398::,2a02:398:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:3a0::,2a02:3a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:3a8::,2a02:3a8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:3b0::,2a02:3b0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:3b8::,2a02:3b8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:3c0::,2a02:3c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:3c8::,2a02:3c8:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:3d0::,2a02:3d0:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a02:3d8::,2a02:3d8:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:3e0::,2a02:3e0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:3e8::,2a02:3e8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:3f0::,2a02:3f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:3f8::,2a02:3f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:400::,2a02:400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:408::,2a02:408:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:410::,2a02:410:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:418::,2a02:418:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:420::,2a02:420:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:428::,2a02:428:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:430::,2a02:430:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:438::,2a02:438:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:440::,2a02:440:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:448::,2a02:448:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:450::,2a02:450:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:458::,2a02:458:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:460::,2a02:460:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:468::,2a02:468:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:470::,2a02:470:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:478::,2a02:478:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:480::,2a02:480:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:488::,2a02:488:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:490::,2a02:490:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:498::,2a02:498:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4a0::,2a02:4a0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:4a8::,2a02:4a8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:4b0::,2a02:4b0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:4b8::,2a02:4b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:4c0::,2a02:4c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:4c8::,2a02:4c8:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:4d0::,2a02:4d0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4d8::,2a02:4d8:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:4e0::,2a02:4e0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:4e8::,2a02:4e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4f0::,2a02:4f0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:4f8::,2a02:4f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:500::,2a02:500:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:508::,2a02:508:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:510::,2a02:510:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:518::,2a02:518:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:520::,2a02:520:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:530::,2a02:530:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:538::,2a02:538:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:540::,2a02:540:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:548::,2a02:548:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:550::,2a02:550:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:558::,2a02:558:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:560::,2a02:560:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:568::,2a02:568:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:570::,2a02:570:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:578::,2a02:578:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:580::,2a02:587:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:588::,2a02:588:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:590::,2a02:590:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:598::,2a02:598:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5a0::,2a02:5a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:5b0::,2a02:5b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:5b8::,2a02:5b8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5c0::,2a02:5c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:5c8::,2a02:5c8:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:5d0::,2a02:5d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:5d8::,2a02:5d8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:5e0::,2a02:5e0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:5f0::,2a02:5f0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:5f8::,2a02:5f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:600::,2a02:600:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:608::,2a02:608:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:610::,2a02:610:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:618::,2a02:618:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:620::,2a02:620:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:628::,2a02:628:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:630::,2a02:630:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:638::,2a02:638:ffff:ffff:ffff:ffff:ffff:ffff,GI
+2a02:640::,2a02:640:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:648::,2a02:648:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:650::,2a02:650:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:658::,2a02:658:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:660::,2a02:660:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a02:668::,2a02:668:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:670::,2a02:670:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:678::,2a02:678:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:680::,2a02:680:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:688::,2a02:688:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:690::,2a02:690:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:698::,2a02:698:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6a0::,2a02:6a0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:6a8::,2a02:6a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:6b0::,2a02:6b0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6b8::,2a02:6b8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6c0::,2a02:6c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:6c8::,2a02:6c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:6d0::,2a02:6d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6d8::,2a02:6d8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:6e0::,2a02:6e0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:6e8::,2a02:6e8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6f0::,2a02:6f0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6f8::,2a02:6f8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:700::,2a02:700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:708::,2a02:708:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:710::,2a02:710:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:718::,2a02:718:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:720::,2a02:720:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:728::,2a02:728:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:730::,2a02:730:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:738::,2a02:738:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:740::,2a02:740:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:748::,2a02:748:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:750::,2a02:750:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:758::,2a02:758:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:760::,2a02:760:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:768::,2a02:768:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:770::,2a02:770:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:778::,2a02:778:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:780::,2a02:780:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:788::,2a02:788:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:790::,2a02:790:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:798::,2a02:798:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:7a0::,2a02:7a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7a8::,2a02:7a8:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:7b0::,2a02:7b0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:7b8::,2a02:7b8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:7c0::,2a02:7c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7c8::,2a02:7c8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:7d0::,2a02:7d0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:7d8::,2a02:7d8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:7e0::,2a02:7e0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:7e8::,2a02:7e8:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:7f0::,2a02:7f0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:7f8::,2a02:7f8:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:800::,2a02:800:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:808::,2a02:808:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:810::,2a02:810:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:818::,2a02:818:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:820::,2a02:820:ffff:ffff:ffff:ffff:ffff:ffff,KG
+2a02:828::,2a02:828:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:830::,2a02:830:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:838::,2a02:838:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:840::,2a02:840:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:848::,2a02:848:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:850::,2a02:850:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:858::,2a02:858:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:860::,2a02:860:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:868::,2a02:868:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:870::,2a02:870:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:878::,2a02:878:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:880::,2a02:880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:888::,2a02:888:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:890::,2a02:890:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:898::,2a02:898:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:8a0::,2a02:8a0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8a8::,2a02:8a8:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:8b0::,2a02:8b0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:8b8::,2a02:8b8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8c0::,2a02:8c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8c8::,2a02:8c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:8d0::,2a02:8d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:8d8::,2a02:8d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:8e0::,2a02:8e0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:8e8::,2a02:8e8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:8f0::,2a02:8f0:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:8f8::,2a02:8f8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:900::,2a02:900:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:908::,2a02:908:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:910::,2a02:910:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:918::,2a02:918:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:920::,2a02:920:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:928::,2a02:928:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:930::,2a02:930:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:938::,2a02:938:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:940::,2a02:940:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:948::,2a02:948:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:950::,2a02:950:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:958::,2a02:958:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:960::,2a02:960:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:968::,2a02:968:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:970::,2a02:970:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:978::,2a02:978:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:980::,2a02:980:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:988::,2a02:988:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:990::,2a02:990:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:998::,2a02:998:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:9a0::,2a02:9a0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:9a8::,2a02:9a8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:9b0::,2a02:9b0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:9b8::,2a02:9b9:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:9c0::,2a02:9c0:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a02:9c8::,2a02:9c8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:9d0::,2a02:9d0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:9d8::,2a02:9d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:9e0::,2a02:9e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:9e8::,2a02:9e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:9f0::,2a02:9f0:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:9f8::,2a02:9f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:a00::,2a02:a00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:a08::,2a02:a08:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a10::,2a02:a10:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a18::,2a02:a18:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:a20::,2a02:a20:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:a28::,2a02:a28:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:a30::,2a02:a30:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a02:a38::,2a02:a38:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:a40::,2a02:a40:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:a48::,2a02:a48:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:a50::,2a02:a50:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:a58::,2a02:a58:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:a60::,2a02:a60:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:a68::,2a02:a68:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:a70::,2a02:a70:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a78::,2a02:a78:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:a80::,2a02:a80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:a88::,2a02:a88:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:a90::,2a02:a90:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:a98::,2a02:a98:ffff:ffff:ffff:ffff:ffff:ffff,UZ
+2a02:aa0::,2a02:aa0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:aa8::,2a02:aa9:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:ab0::,2a02:ab0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:ab8::,2a02:ab8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:ac0::,2a02:ac0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:ac8::,2a02:ac8:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a02:ad0::,2a02:ad0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ad8::,2a02:ad8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:ae0::,2a02:ae0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ae8::,2a02:ae8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:af0::,2a02:af0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:af8::,2a02:af8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b00::,2a02:b00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b08::,2a02:b08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b10::,2a02:b10:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b18::,2a02:b18:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:b20::,2a02:b20:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:b28::,2a02:b28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b30::,2a02:b30:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b38::,2a02:b38:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:b48::,2a02:b48:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:b50::,2a02:b50:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b58::,2a02:b58:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a02:b60::,2a02:b60:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a02:b70::,2a02:b70:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:b78::,2a02:b78:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b80::,2a02:b87:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b88::,2a02:b88:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:b90::,2a02:b90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:b98::,2a02:b98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ba0::,2a02:ba0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:ba8::,2a02:ba8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:bb0::,2a02:bb0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:bb8::,2a02:bb8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:bc0::,2a02:bc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:bc8::,2a02:bc8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:bd0::,2a02:bd0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:bd8::,2a02:bd8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:be0::,2a02:be0:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:be8::,2a02:be8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:bf0::,2a02:bf0:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a02:bf8::,2a02:bf8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c00::,2a02:c00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c08::,2a02:c08:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a02:c10::,2a02:c10:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:c18::,2a02:c18:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:c20::,2a02:c20:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:c28::,2a02:c28:ffff:ffff:ffff:ffff:ffff:ffff,JE
+2a02:c30::,2a02:c30:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c38::,2a02:c38:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:c40::,2a02:c47:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:c48::,2a02:c48:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c50::,2a02:c50:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c58::,2a02:c58:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:c60::,2a02:c60:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:c68::,2a02:c68:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c70::,2a02:c70:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:c78::,2a02:c7f:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c80::,2a02:c80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:c88::,2a02:c88:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:c90::,2a02:c90:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c98::,2a02:c98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ca0::,2a02:ca0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:ca8::,2a02:ca8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:cb0::,2a02:cb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:cb8::,2a02:cb8:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:cc0::,2a02:cc0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:cc8::,2a02:cc8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:cd0::,2a02:cd0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:cd8::,2a02:cd8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:ce0::,2a02:ce0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:ce8::,2a02:ce8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:cf0::,2a02:cf0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:d00::,2a02:d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:d08::,2a02:d08:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:d10::,2a02:d10:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:d18::,2a02:d18:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a02:d20::,2a02:d20:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:d28::,2a02:d28:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:d30::,2a02:d30:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:d38::,2a02:d38:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:d40::,2a02:d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:d48::,2a02:d48:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:d50::,2a02:d50:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:d58::,2a02:d58:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:d60::,2a02:d60:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:d68::,2a02:d68:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:d70::,2a02:d70:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:d78::,2a02:d78:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:d80::,2a02:d80:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:d88::,2a02:d88:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:d90::,2a02:d90:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:d98::,2a02:d98:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:da8::,2a02:da8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:db0::,2a02:db0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:db8::,2a02:db8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:dc0::,2a02:dc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:dc8::,2a02:dc8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:dd0::,2a02:dd0:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a02:dd8::,2a02:dd8:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:de0::,2a02:de0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:de8::,2a02:de8:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:df0::,2a02:df0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:df8::,2a02:df8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:e00::,2a02:e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:e08::,2a02:e08:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:e10::,2a02:e10:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:e20::,2a02:e20:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:e28::,2a02:e28:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:e30::,2a02:e30:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:e38::,2a02:e38:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:e40::,2a02:e40:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a02:e48::,2a02:e48:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a02:e50::,2a02:e50:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:e58::,2a02:e58:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:e60::,2a02:e60:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:e68::,2a02:e68:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:e70::,2a02:e70:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:e78::,2a02:e78:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a02:e80::,2a02:e80:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:e88::,2a02:e88:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:e90::,2a02:e90:ffff:ffff:ffff:ffff:ffff:ffff,FO
+2a02:e98::,2a02:e98:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:ea0::,2a02:ea0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ea8::,2a02:ea8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:eb0::,2a02:eb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:eb8::,2a02:eb8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:ec0::,2a02:ec0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:ec8::,2a02:ec8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:ed0::,2a02:ed0:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:ed8::,2a02:ed8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:ee0::,2a02:ee0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:ee8::,2a02:ee8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:ef0::,2a02:ef0:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:ef8::,2a02:ef8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:f00::,2a02:f00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:f08::,2a02:f08:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:f10::,2a02:f10:ffff:ffff:ffff:ffff:ffff:ffff,UZ
+2a02:f18::,2a02:f18:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:f20::,2a02:f20:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:f28::,2a02:f28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:f30::,2a02:f30:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:f38::,2a02:f38:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:f40::,2a02:f40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:f48::,2a02:f48:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:f50::,2a02:f50:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:f58::,2a02:f58:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:f60::,2a02:f60:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:f68::,2a02:f68:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:f70::,2a02:f70:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:f78::,2a02:f78:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:f80::,2a02:f80:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:f88::,2a02:f88:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a02:f90::,2a02:f90:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:f98::,2a02:f98:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:fa0::,2a02:fa0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:fa8::,2a02:fa8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:fb0::,2a02:fb0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:fb8::,2a02:fb8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:fc0::,2a02:fc0:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:fc8::,2a02:fc8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:fd0::,2a02:fd0:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a02:fd8::,2a02:fd8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:fe0::,2a02:fe0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:fe8::,2a02:fe8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:ff0::,2a02:ff0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:ff8::,2a02:ff8:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:1000::,2a02:103f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1200::,2a02:121f:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:1300::,2a02:1300:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:1308::,2a02:1308:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1310::,2a02:1310:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1318::,2a02:1318:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1320::,2a02:1320:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:1328::,2a02:1328:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1330::,2a02:1330:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1338::,2a02:1338:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:1340::,2a02:1340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1348::,2a02:1348:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1350::,2a02:1350:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1358::,2a02:1358:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:1360::,2a02:1360:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1368::,2a02:1368:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:1370::,2a02:1370:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:1378::,2a02:1378:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1380::,2a02:1380:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1388::,2a02:1388:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:1390::,2a02:1390:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:1398::,2a02:1398:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:13a0::,2a02:13a0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:13a8::,2a02:13a8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:13b0::,2a02:13b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:13b8::,2a02:13b8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:13c0::,2a02:13c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:13c8::,2a02:13c8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:13d0::,2a02:13d0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:13d8::,2a02:13d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:13e0::,2a02:13e0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:13e8::,2a02:13e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:13f0::,2a02:13f0:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:13f8::,2a02:13f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1400::,2a02:143f:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1600::,2a02:1600:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:1608::,2a02:1608:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1610::,2a02:1610:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1618::,2a02:1618:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a02:1620::,2a02:1620:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1628::,2a02:1628:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1630::,2a02:1630:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:1638::,2a02:1638:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1640::,2a02:1640:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:1648::,2a02:1648:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1650::,2a02:1650:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:1658::,2a02:1658:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1660::,2a02:1660:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:1668::,2a02:1668:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1670::,2a02:1670:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1678::,2a02:1678:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:1680::,2a02:1680:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1688::,2a02:1688:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:1690::,2a02:1690:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1698::,2a02:1698:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:16a0::,2a02:16a0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:16a8::,2a02:16a8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:16b0::,2a02:16b0:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a02:16b8::,2a02:16b8:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:16c0::,2a02:16c0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:16c8::,2a02:16c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:16d0::,2a02:16d0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:16d8::,2a02:16d8:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:16e0::,2a02:16e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:16e8::,2a02:16e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:16f0::,2a02:16f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:16f8::,2a02:16f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1700::,2a02:1700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1708::,2a02:1708:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:1710::,2a02:1710:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1718::,2a02:1718:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a02:1720::,2a02:1720:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1730::,2a02:1730:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:1738::,2a02:1738:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:1740::,2a02:1740:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:1748::,2a02:1748:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:1750::,2a02:1750:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:1758::,2a02:1758:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:1760::,2a02:1760:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:1768::,2a02:1768:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:1770::,2a02:1770:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:1778::,2a02:1778:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:1780::,2a02:1780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:1788::,2a02:1788:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:1790::,2a02:1790:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:1798::,2a02:179f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:17a0::,2a02:17a0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:17a8::,2a02:17a8:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:17b0::,2a02:17b0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:17b8::,2a02:17b8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:17c0::,2a02:17c0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:17c8::,2a02:17c8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:17d0::,2a02:17d0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:17d8::,2a02:17d8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:17e0::,2a02:17e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:17e8::,2a02:17e8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:17f0::,2a02:17f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:17f8::,2a02:17f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:1800::,2a02:18ff:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2000::,2a02:2000:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2008::,2a02:2008:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2010::,2a02:2010:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:2018::,2a02:2018:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2020::,2a02:2020:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:2028::,2a02:2028:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2030::,2a02:2030:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:2038::,2a02:2038:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2040::,2a02:2040:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2048::,2a02:2048:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2050::,2a02:2050:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2058::,2a02:2058:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2060::,2a02:2060:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2068::,2a02:2068:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2070::,2a02:2070:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2078::,2a02:2078:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:2080::,2a02:2080:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2088::,2a02:2088:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2090::,2a02:2090:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2098::,2a02:2098:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:20a0::,2a02:20a0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:20a8::,2a02:20a8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:20b0::,2a02:20b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:20b8::,2a02:20b8:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a02:20c0::,2a02:20c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:20c8::,2a02:20c8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:20d0::,2a02:20d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:20d8::,2a02:20d8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:20e0::,2a02:20e0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:20e8::,2a02:20e8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:20f0::,2a02:20f0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:20f8::,2a02:20f8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2100::,2a02:2100:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2108::,2a02:2108:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2110::,2a02:2110:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2118::,2a02:211f:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2120::,2a02:2123:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2140::,2a02:2140:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2148::,2a02:214f:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:2150::,2a02:2150:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2158::,2a02:2158:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:2160::,2a02:2160:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:2168::,2a02:216f:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2170::,2a02:2170:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2178::,2a02:2178:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2180::,2a02:2180:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2188::,2a02:2188:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2190::,2a02:2190:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2198::,2a02:2198:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:21a0::,2a02:21a0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:21a8::,2a02:21a8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:21b0::,2a02:21b0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:21b8::,2a02:21b8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:21c0::,2a02:21c0:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:21c8::,2a02:21c8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:21d0::,2a02:21d0:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:21d8::,2a02:21d8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:21e0::,2a02:21e0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:21e8::,2a02:21e8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:21f0::,2a02:21f0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:21f8::,2a02:21f8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2200::,2a02:2200:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2208::,2a02:2208:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a02:2210::,2a02:2210:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2218::,2a02:2218:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2220::,2a02:2220:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2228::,2a02:2228:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2230::,2a02:2230:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:2238::,2a02:2238:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2240::,2a02:2240:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2248::,2a02:2248:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:2250::,2a02:2250:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2258::,2a02:2258:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2260::,2a02:2260:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2268::,2a02:2268:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2270::,2a02:2270:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2278::,2a02:2278:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2280::,2a02:2280:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2288::,2a02:2288:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2290::,2a02:2290:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:2298::,2a02:2298:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:22a0::,2a02:22a0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:22a8::,2a02:22a8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:22b0::,2a02:22b0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:22b8::,2a02:22b8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:22c0::,2a02:22c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:22c8::,2a02:22c8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:22d0::,2a02:22d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:22d8::,2a02:22d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:22e0::,2a02:22e0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:22e8::,2a02:22e8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:22f0::,2a02:22f0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:22f8::,2a02:22f8:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:2300::,2a02:2300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2308::,2a02:2308:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2310::,2a02:2310:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2318::,2a02:2318:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2320::,2a02:2320:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2328::,2a02:2328:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2330::,2a02:2330:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:2338::,2a02:2338:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2340::,2a02:2340:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2348::,2a02:2348:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2350::,2a02:2350:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2358::,2a02:2358:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2360::,2a02:2360:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2368::,2a02:2368:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2370::,2a02:2370:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:2378::,2a02:2378:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2380::,2a02:2380:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2388::,2a02:2388:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2390::,2a02:2390:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a02:2398::,2a02:2398:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:23a0::,2a02:23a0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:23a8::,2a02:23a8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:23b0::,2a02:23b0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:23b8::,2a02:23b8:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:23c0::,2a02:23c0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:23c8::,2a02:23c8:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:23d0::,2a02:23d0:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:23d8::,2a02:23d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:23e0::,2a02:23e0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:23e8::,2a02:23e8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:23f0::,2a02:23f0:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a02:23f8::,2a02:23f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2400::,2a02:2400:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2408::,2a02:2408:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2410::,2a02:2410:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2418::,2a02:2418:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2420::,2a02:2420:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2428::,2a02:2428:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2430::,2a02:2430:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2438::,2a02:2438:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2440::,2a02:2440:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2448::,2a02:2448:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2450::,2a02:2450:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2458::,2a02:2458:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2460::,2a02:2460:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:2468::,2a02:2468:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2470::,2a02:2470:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2478::,2a02:2478:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2480::,2a02:2480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2488::,2a02:2488:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2490::,2a02:2490:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2498::,2a02:2498:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:24a0::,2a02:24a0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:24a8::,2a02:24a8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:24b0::,2a02:24b0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:24b8::,2a02:24b8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:24c0::,2a02:24c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:24c8::,2a02:24c8:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a02:24d0::,2a02:24d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:24d8::,2a02:24d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:24e0::,2a02:24e0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:24e8::,2a02:24e8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:24f0::,2a02:24f0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:24f8::,2a02:24f8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2500::,2a02:2500:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2508::,2a02:2508:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2510::,2a02:2510:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2518::,2a02:2518:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2520::,2a02:2520:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2528::,2a02:2528:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2530::,2a02:2530:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2538::,2a02:2538:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2540::,2a02:2540:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2548::,2a02:2548:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2550::,2a02:2550:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2558::,2a02:2558:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a02:2560::,2a02:2560:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2568::,2a02:2568:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2570::,2a02:2570:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2578::,2a02:2578:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a02:2580::,2a02:2580:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2588::,2a02:2588:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2590::,2a02:2590:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:2598::,2a02:2598:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:25a0::,2a02:25a0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:25a8::,2a02:25a8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:25b0::,2a02:25b0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:25b8::,2a02:25b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:25c0::,2a02:25c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:25c8::,2a02:25c8:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:25d0::,2a02:25d0:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:25d8::,2a02:25d8:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a02:25e0::,2a02:25e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:25e8::,2a02:25e8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:25f0::,2a02:25f0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:25f8::,2a02:25f8:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:2600::,2a02:2600:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2608::,2a02:2608:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a02:2610::,2a02:2610:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2618::,2a02:2618:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2620::,2a02:2620:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2628::,2a02:2628:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:2630::,2a02:2630:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:2638::,2a02:2638:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2640::,2a02:2647:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2648::,2a02:2648:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2650::,2a02:2650:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2658::,2a02:2658:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2660::,2a02:2660:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:2668::,2a02:2668:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2670::,2a02:2670:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2678::,2a02:2678:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2680::,2a02:2680:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2688::,2a02:2688:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2690::,2a02:2690:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2698::,2a02:2698:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:26a0::,2a02:26a0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:26a8::,2a02:26a8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:26b0::,2a02:26b0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:26b8::,2a02:26b8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:26c0::,2a02:26c0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:26c8::,2a02:26c8:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:26d0::,2a02:26d0:ffff:ffff:ffff:ffff:ffff:ffff,PS
+2a02:26d8::,2a02:26d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:26e0::,2a02:26e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:26e8::,2a02:26e8:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:26f0::,2a02:26f0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:26f8::,2a02:26f8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2700::,2a02:2700:ffff:ffff:ffff:ffff:ffff:ffff,IQ
+2a02:2708::,2a02:2708:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2710::,2a02:2710:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2718::,2a02:2718:ffff:ffff:ffff:ffff:ffff:ffff,YE
+2a02:2720::,2a02:2720:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:2728::,2a02:2728:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2730::,2a02:2730:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2738::,2a02:2738:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2740::,2a02:2740:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2748::,2a02:2748:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2750::,2a02:2750:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2758::,2a02:2758:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2760::,2a02:2760:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2768::,2a02:2768:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2770::,2a02:2770:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2778::,2a02:2778:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2780::,2a02:2780:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2788::,2a02:2788:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2790::,2a02:2790:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2798::,2a02:2798:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:27a0::,2a02:27a0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:27a8::,2a02:27a8:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:27b0::,2a02:27b0:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:27b8::,2a02:27b8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:27c0::,2a02:27c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:27c8::,2a02:27c8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:27d0::,2a02:27d0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:27d8::,2a02:27d8:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:27e0::,2a02:27e0:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:27e8::,2a02:27e8:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:27f0::,2a02:27f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:27f8::,2a02:27f8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2800::,2a02:2800:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2808::,2a02:2808:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2810::,2a02:2810:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2818::,2a02:2818:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2820::,2a02:2820:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2828::,2a02:2828:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2830::,2a02:2830:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2838::,2a02:2838:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2840::,2a02:2840:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2848::,2a02:2848:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2850::,2a02:2850:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2858::,2a02:2858:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2860::,2a02:2860:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2868::,2a02:2868:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:2870::,2a02:2870:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2878::,2a02:2878:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2880::,2a02:2880:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:2888::,2a02:2888:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2890::,2a02:2890:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2898::,2a02:2898:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:28a0::,2a02:28a0:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:28a8::,2a02:28a8:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:28b0::,2a02:28b7:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:28b8::,2a02:28b8:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a02:28c0::,2a02:28c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:28c8::,2a02:28c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:28d0::,2a02:28d0:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:28d8::,2a02:28d8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:28e0::,2a02:28e0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:28e8::,2a02:28e8:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:28f0::,2a02:28f0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:28f8::,2a02:28f8:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2900::,2a02:2900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2908::,2a02:2908:ffff:ffff:ffff:ffff:ffff:ffff,OM
+2a02:2910::,2a02:2910:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2918::,2a02:2918:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2920::,2a02:2920:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2928::,2a02:2928:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2930::,2a02:2930:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2938::,2a02:2938:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2940::,2a02:2940:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2948::,2a02:2948:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2950::,2a02:2950:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:2958::,2a02:2958:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2960::,2a02:2960:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:2968::,2a02:2968:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2970::,2a02:2970:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2978::,2a02:2978:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2980::,2a02:2980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2988::,2a02:2988:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2990::,2a02:2990:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2998::,2a02:2998:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:29a0::,2a02:29a0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:29a8::,2a02:29a8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:29b0::,2a02:29b0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:29b8::,2a02:29b8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:29c0::,2a02:29c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:29c8::,2a02:29c8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:29d0::,2a02:29d0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:29d8::,2a02:29d8:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:29e0::,2a02:29e0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:29e8::,2a02:29e8:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:29f0::,2a02:29f0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:29f8::,2a02:29f8:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a02:2a00::,2a02:2a00:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:2a08::,2a02:2a08:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2a10::,2a02:2a10:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2a18::,2a02:2a18:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2a20::,2a02:2a20:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2a28::,2a02:2a28:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2a30::,2a02:2a30:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2a38::,2a02:2a38:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2a40::,2a02:2a40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2a48::,2a02:2a48:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2a50::,2a02:2a50:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a02:2a58::,2a02:2a58:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2a60::,2a02:2a60:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a02:2a68::,2a02:2a68:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2a70::,2a02:2a70:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:2a78::,2a02:2a78:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2a80::,2a02:2a80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2a88::,2a02:2a88:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:2a90::,2a02:2a90:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:2a98::,2a02:2a98:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:2aa0::,2a02:2aa0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2aa8::,2a02:2aa8:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2ab0::,2a02:2ab0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2ab8::,2a02:2ab8:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:2ac0::,2a02:2ac0:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2ac8::,2a02:2ac8:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2ad0::,2a02:2ad0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2ad8::,2a02:2ad8:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:2ae0::,2a02:2ae0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2ae8::,2a02:2ae8:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2af0::,2a02:2af0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:2af8::,2a02:2af8:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2b00::,2a02:2b00:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2b08::,2a02:2b08:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2b10::,2a02:2b10:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:2b18::,2a02:2b18:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2b20::,2a02:2b20:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:2b28::,2a02:2b28:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:2b30::,2a02:2b30:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:2b38::,2a02:2b38:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2b40::,2a02:2b40:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:2b48::,2a02:2b48:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2b50::,2a02:2b50:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:2b58::,2a02:2b58:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:2b80::,2a02:2b80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2b88::,2a02:2b88:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:2b90::,2a02:2b90:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2b98::,2a02:2b98:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:2ba0::,2a02:2ba0:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a02:2ba8::,2a02:2ba8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2bb0::,2a02:2bb0:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:2bb8::,2a02:2bb8:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2bc0::,2a02:2bc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:2c00::,2a02:2c00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:2c40::,2a02:2c40:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2c80::,2a02:2c80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:2cc0::,2a02:2cc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2d00::,2a02:2d00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:2d40::,2a02:2d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2d80::,2a02:2d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2dc0::,2a02:2dc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:2e00::,2a02:2e1f:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2f00::,2a02:2f0f:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:2f80::,2a02:2f80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:2fc0::,2a02:2fc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:3000::,2a02:31ff:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4000::,2a02:4000:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:4040::,2a02:4040:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4080::,2a02:4080:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:40c0::,2a02:40c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4100::,2a02:4100:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4140::,2a02:4140:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:4180::,2a02:4180:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:41c0::,2a02:41c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:4200::,2a02:4200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:4240::,2a02:4240:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4280::,2a02:4280:ffff:ffff:ffff:ffff:ffff:ffff,ME
+2a02:42c0::,2a02:42c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4300::,2a02:4300:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:4340::,2a02:4340:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4380::,2a02:4380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:43c0::,2a02:43c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4400::,2a02:4400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4440::,2a02:4440:ffff:ffff:ffff:ffff:ffff:ffff,QA
+2a02:4480::,2a02:4480:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:44c0::,2a02:44c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4500::,2a02:4500:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4540::,2a02:4540:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:4580::,2a02:4580:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:45c0::,2a02:45c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4600::,2a02:4600:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4640::,2a02:4640:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4680::,2a02:4680:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:46c0::,2a02:46c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:4700::,2a02:4700:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:4740::,2a02:4740:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4780::,2a02:4780:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:47c0::,2a02:47c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:4800::,2a02:4800:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:4840::,2a02:4840:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:4880::,2a02:4880:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:48c0::,2a02:48c0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:4900::,2a02:4900:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:4940::,2a02:4940:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:4980::,2a02:4980:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:49c0::,2a02:49c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4a00::,2a02:4a00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:4a40::,2a02:4a40:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:4ac0::,2a02:4ac0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:4b00::,2a02:4b00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:4b40::,2a02:4b40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4b80::,2a02:4b80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4bc0::,2a02:4bc0:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:4c00::,2a02:4c00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4c40::,2a02:4c40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:4c80::,2a02:4c80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:4cc0::,2a02:4cc0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4d00::,2a02:4d00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4d40::,2a02:4d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:4d80::,2a02:4d80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4dc0::,2a02:4dc0:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:4e40::,2a02:4e40:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:4ec0::,2a02:4ec0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:4f00::,2a02:4f00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:4f40::,2a02:4f40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:4f80::,2a02:4f80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:4fc0::,2a02:4fc0:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:5000::,2a02:5000:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:5040::,2a02:5040:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:5080::,2a02:5080:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:50c0::,2a02:50c0:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a02:5100::,2a02:5100:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5140::,2a02:5140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5180::,2a02:5180:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:51c0::,2a02:51c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5200::,2a02:5200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5240::,2a02:5240:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:5280::,2a02:5280:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:52c0::,2a02:52c0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:5300::,2a02:5300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5340::,2a02:5340:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:5380::,2a02:5380:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:53c0::,2a02:53c0:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5400::,2a02:5400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5440::,2a02:5440:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:5480::,2a02:5480:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:54c0::,2a02:54c0:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:5500::,2a02:5500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5540::,2a02:5540:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5580::,2a02:5580:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a02:55c0::,2a02:55c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5600::,2a02:5600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5640::,2a02:5640:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:5680::,2a02:5680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:56c0::,2a02:56c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5740::,2a02:5740:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:5780::,2a02:5780:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:57c0::,2a02:57c0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:5800::,2a02:5800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5840::,2a02:5840:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5880::,2a02:5880:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:58c0::,2a02:58c0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:5900::,2a02:5900:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:5940::,2a02:5940:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:5980::,2a02:5980:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:59c0::,2a02:59c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5a00::,2a02:5a00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5a40::,2a02:5a40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:5a80::,2a02:5a80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:5ac0::,2a02:5ac0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:5b00::,2a02:5b00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5b40::,2a02:5b40:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:5b80::,2a02:5b80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:5bc0::,2a02:5bc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5c40::,2a02:5c40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5c80::,2a02:5c80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:5cc0::,2a02:5cc0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:5d00::,2a02:5d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5d40::,2a02:5d40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5d80::,2a02:5d80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5dc0::,2a02:5dc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:5e00::,2a02:5e00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:5e40::,2a02:5e40:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:5e80::,2a02:5e80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:5ec0::,2a02:5ec0:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:5f00::,2a02:5f00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:5f40::,2a02:5f40:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a02:5f80::,2a02:5f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:5fc0::,2a02:5fc0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:6000::,2a02:6000:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:6040::,2a02:6040:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:60c0::,2a02:60c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6100::,2a02:6100:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6140::,2a02:6140:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6180::,2a02:6180:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:61c0::,2a02:61c0:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:6200::,2a02:6200:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:6240::,2a02:6240:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:6280::,2a02:6280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:62c0::,2a02:62c0:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:6300::,2a02:6300:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:6340::,2a02:6340:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:6380::,2a02:6380:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:63c0::,2a02:63c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6400::,2a02:6400:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:6440::,2a02:6440:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:6480::,2a02:6480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:64c0::,2a02:64c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6500::,2a02:6500:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:6540::,2a02:6540:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6580::,2a02:6580:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:65c0::,2a02:65c0:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:6600::,2a02:6600:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:6640::,2a02:6640:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:6680::,2a02:6680:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a02:66c0::,2a02:66c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6700::,2a02:6700:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:6740::,2a02:6740:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:6780::,2a02:6780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:67c0::,2a02:67c0:ffff:ffff:ffff:ffff:ffff:ffff,SY
+2a02:6800::,2a02:6800:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:6840::,2a02:6840:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6880::,2a02:6880:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:68c0::,2a02:68c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6900::,2a02:6900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:6940::,2a02:6940:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:6980::,2a02:6980:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:69c0::,2a02:69c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6a00::,2a02:6a00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:6a40::,2a02:6a40:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:6a80::,2a02:6a80:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:6ac0::,2a02:6ac0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6b00::,2a02:6b00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6b40::,2a02:6b40:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:6b80::,2a02:6b80:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a02:6bc0::,2a02:6bc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6c00::,2a02:6c00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6c40::,2a02:6c40:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6c80::,2a02:6c80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6cc0::,2a02:6cc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6d00::,2a02:6d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6d40::,2a02:6d40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:6d80::,2a02:6d80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:6dc0::,2a02:6dc0:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:6e00::,2a02:6e00:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:6e80::,2a02:6e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:6ec0::,2a02:6ec0:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:6f00::,2a02:6f00:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:6f40::,2a02:6f40:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:6f80::,2a02:6f80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:6fc0::,2a02:6fc0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7000::,2a02:7000:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a02:7040::,2a02:7040:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:7080::,2a02:7080:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:70c0::,2a02:70c0:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a02:7100::,2a02:7100:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:7140::,2a02:7140:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7180::,2a02:7180:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:71c0::,2a02:71c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7200::,2a02:7200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7240::,2a02:7240:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:7280::,2a02:7280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:72c0::,2a02:72c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:7300::,2a02:7300:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a02:7340::,2a02:7340:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:7380::,2a02:7380:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:73c0::,2a02:73c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7400::,2a02:7400:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:7440::,2a02:7440:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7480::,2a02:7480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:74c0::,2a02:74c0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:7500::,2a02:7500:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a02:7540::,2a02:7540:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:7580::,2a02:7580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:75c0::,2a02:75c0:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:7600::,2a02:7600:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:7640::,2a02:7640:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:7680::,2a02:7680:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:76c0::,2a02:76c0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7700::,2a02:7700:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7740::,2a02:7740:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a02:7780::,2a02:7780:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a02:77c0::,2a02:77c0:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7800::,2a02:7800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7840::,2a02:7840:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:7880::,2a02:7880:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:78c0::,2a02:78c0:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7900::,2a02:7900:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:7940::,2a02:7940:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7980::,2a02:7980:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a02:79c0::,2a02:79c0:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:7a00::,2a02:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:7a40::,2a02:7a40:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:7a80::,2a02:7a80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:7ac0::,2a02:7ac0:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:7b00::,2a02:7b00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7b40::,2a02:7b40:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:7b80::,2a02:7b80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:7bc0::,2a02:7bc0:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7c00::,2a02:7c00:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:7c40::,2a02:7c40:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:7c80::,2a02:7c80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:7cc0::,2a02:7cc0:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:7d00::,2a02:7d00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:7d40::,2a02:7d40:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:7d80::,2a02:7d80:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:7dc0::,2a02:7dc0:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:7e00::,2a02:7e00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:7e40::,2a02:7e40:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7e80::,2a02:7e80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:7f00::,2a02:7f00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:7f80::,2a02:7f80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:8010::,2a02:8017:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:8020::,2a02:8023:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8040::,2a02:8043:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:8060::,2a02:8061:ffff:ffff:ffff:ffff:ffff:ffff,AD
+2a02:8070::,2a02:8071:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8080::,2a02:8087:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a02:80c0::,2a02:80c3:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:80e0::,2a02:80e3:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a02:8100::,2a02:811f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8200::,2a02:821f:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:8300::,2a02:830f:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:8380::,2a02:838f:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a02:8400::,2a02:847f:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:8800::,2a02:88ff:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:9000::,2a02:91ff:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:a000::,2a02:a03f:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:a200::,2a02:a21f:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a300::,2a02:a31f:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:a400::,2a02:a47f:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:a800::,2a02:a83f:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:aa00::,2a02:aa1f:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:ab00::,2a02:ab07:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a02:ab40::,2a02:ab47:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:ab80::,2a02:ab8f:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:ac00::,2a02:ac07:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:ac40::,2a02:ac47:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:ac80::,2a02:ac87:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:acc0::,2a02:acc7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ad00::,2a02:ad07:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ad40::,2a02:ad47:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ad80::,2a02:ad87:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a02:adc0::,2a02:adc7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ae00::,2a02:ae07:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a02:ae40::,2a02:ae47:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a02:ae80::,2a02:ae87:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:aec0::,2a02:aec7:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:af00::,2a02:af07:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a02:af40::,2a02:af47:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:af80::,2a02:af87:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:afc0::,2a02:afc7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:b000::,2a02:b1ff:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c000::,2a02:c007:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c040::,2a02:c047:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:c080::,2a02:c087:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:c0c0::,2a02:c0c7:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c100::,2a02:c107:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c140::,2a02:c147:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c180::,2a02:c187:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:c1c0::,2a02:c1c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c200::,2a02:c207:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c240::,2a02:c247:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2a02:c280::,2a02:c287:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a02:c2c0::,2a02:c2c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c300::,2a02:c307:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c340::,2a02:c347:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a02:c380::,2a02:c381:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:c390::,2a02:c391:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:c3a0::,2a02:c3a3:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:c3c0::,2a02:c3c7:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a02:c400::,2a02:c407:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a02:c440::,2a02:c447:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a02:c480::,2a02:c487:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c4c0::,2a02:c4c7:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:c500::,2a02:c507:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a02:c540::,2a02:c547:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:c580::,2a02:c587:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a02:c5c0::,2a02:c5c7:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a02:c600::,2a02:c607:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a02:c640::,2a02:c647:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a02:c680::,2a02:c681:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c690::,2a02:c691:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a02:c6a0::,2a02:c6a3:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c6c0::,2a02:c6c7:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c700::,2a02:c707:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c740::,2a02:c747:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:c780::,2a02:c787:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a02:c7c0::,2a02:c7c7:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a02:c800::,2a02:c807:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c840::,2a02:c847:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a02:c880::,2a02:c887:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a02:c8c0::,2a02:c8c7:ffff:ffff:ffff:ffff:ffff:ffff,UZ
+2a02:c900::,2a02:c907:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a02:c940::,2a02:c947:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:c980::,2a02:c987:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:c9c0::,2a02:c9c7:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ca00::,2a02:ca07:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:ca40::,2a02:ca47:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a02:ca80::,2a02:ca87:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a02:cac0::,2a02:cac7:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a02:cb00::,2a02:cb07:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a02:cb40::,2a02:cb47:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a02:cb80::,2a02:cb87:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a03:80::,2a03:80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:100::,2a03:100:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a03:180::,2a03:180:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a03:200::,2a03:200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:280::,2a03:280:ffff:ffff:ffff:ffff:ffff:ffff,LT
+2a03:300::,2a03:300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:380::,2a03:380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:400::,2a03:400:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:480::,2a03:480:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:500::,2a03:500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:580::,2a03:580:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:600::,2a03:600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:680::,2a03:680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:700::,2a03:700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:780::,2a03:780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:800::,2a03:800:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:880::,2a03:880:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:900::,2a03:900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:980::,2a03:980:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a03:a00::,2a03:a00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:a80::,2a03:a80:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a03:b00::,2a03:b00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:b80::,2a03:b80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:c00::,2a03:c00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:c80::,2a03:c80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:d00::,2a03:d00:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:d80::,2a03:d80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:e00::,2a03:e00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:e80::,2a03:e80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:f00::,2a03:f00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:f80::,2a03:f87:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:1000::,2a03:1000:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:1080::,2a03:1080:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a03:1100::,2a03:1100:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:1180::,2a03:1180:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:1200::,2a03:1200:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:1280::,2a03:1280:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:1300::,2a03:1300:ffff:ffff:ffff:ffff:ffff:ffff,CY
+2a03:1380::,2a03:1380:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:1400::,2a03:1400:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:1480::,2a03:1480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:1500::,2a03:1500:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:1580::,2a03:1580:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:1600::,2a03:1600:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:1680::,2a03:1680:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:1700::,2a03:1707:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:1780::,2a03:1780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:1800::,2a03:1800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:1880::,2a03:1880:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:1900::,2a03:1900:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a03:1980::,2a03:1980:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:1a00::,2a03:1a00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:1a80::,2a03:1a80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:1b00::,2a03:1b00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:1b80::,2a03:1b80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:1c00::,2a03:1c00:ffff:ffff:ffff:ffff:ffff:ffff,BH
+2a03:1c80::,2a03:1c80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:1d00::,2a03:1d00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:1d80::,2a03:1d80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a03:1e00::,2a03:1e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:1e80::,2a03:1e80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:1f00::,2a03:1f00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:1f80::,2a03:1f80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:2000::,2a03:2000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2080::,2a03:2080:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:2100::,2a03:2100:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:2180::,2a03:2180:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:2200::,2a03:2200:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:2280::,2a03:2280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:2300::,2a03:2300:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a03:2380::,2a03:2380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2400::,2a03:2400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2480::,2a03:2480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:2500::,2a03:2500:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2580::,2a03:2580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2600::,2a03:2600:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:2680::,2a03:2680:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:2700::,2a03:2700:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:2780::,2a03:2780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:2800::,2a03:2800:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2880::,2a03:2880:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:2900::,2a03:2900:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2980::,2a03:2980:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:2a00::,2a03:2a00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2a80::,2a03:2a80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:2b00::,2a03:2b00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:2b80::,2a03:2b80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:2c00::,2a03:2c00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:2c80::,2a03:2c80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2d00::,2a03:2d00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:2d80::,2a03:2d80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:2e00::,2a03:2e00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:2f00::,2a03:2f00:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a03:2f80::,2a03:2f80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:3000::,2a03:3000:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a03:3100::,2a03:3100:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3180::,2a03:3180:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:3200::,2a03:3200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3280::,2a03:3280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:3300::,2a03:3300:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:3380::,2a03:3380:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:3400::,2a03:3400:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:3480::,2a03:3480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3500::,2a03:3500:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:3580::,2a03:3580:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a03:3600::,2a03:3600:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:3680::,2a03:3680:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:3700::,2a03:3700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3800::,2a03:3800:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:3880::,2a03:3880:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:3900::,2a03:3900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:3980::,2a03:3980:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a03:3a00::,2a03:3a00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:3a80::,2a03:3a80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:3b00::,2a03:3b00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:3b80::,2a03:3b80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:3c00::,2a03:3c00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:3c80::,2a03:3c80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:3d00::,2a03:3d00:ffff:ffff:ffff:ffff:ffff:ffff,AM
+2a03:3d80::,2a03:3d80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:3e00::,2a03:3e00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:3e80::,2a03:3e80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:3f00::,2a03:3f00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:3f80::,2a03:3f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4000::,2a03:4000:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:4080::,2a03:4080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:4100::,2a03:4100:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:4180::,2a03:4180:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:4200::,2a03:4200:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:4280::,2a03:4280:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a03:4300::,2a03:4300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:4380::,2a03:4380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:4400::,2a03:4400:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:4480::,2a03:4480:ffff:ffff:ffff:ffff:ffff:ffff,AZ
+2a03:4500::,2a03:4500:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:4580::,2a03:4580:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:4600::,2a03:4600:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:4680::,2a03:4680:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:4700::,2a03:4700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4780::,2a03:4780:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a03:4800::,2a03:4800:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:4880::,2a03:4880:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4900::,2a03:4900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4980::,2a03:4980:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:4a00::,2a03:4a00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4a80::,2a03:4a80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:4b00::,2a03:4b00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:4b80::,2a03:4b80:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a03:4c00::,2a03:4c00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:4c80::,2a03:4c80:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a03:4d00::,2a03:4d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:4d80::,2a03:4d80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:4e00::,2a03:4e00:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:4e80::,2a03:4e80:ffff:ffff:ffff:ffff:ffff:ffff,GE
+2a03:4f00::,2a03:4f00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:4f80::,2a03:4f80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5000::,2a03:5000:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:5080::,2a03:5080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:5100::,2a03:5100:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:5180::,2a03:5180:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:5200::,2a03:5200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5280::,2a03:5280:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:5300::,2a03:5300:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:5380::,2a03:5380:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5400::,2a03:5400:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:5480::,2a03:5480:ffff:ffff:ffff:ffff:ffff:ffff,LI
+2a03:5500::,2a03:5500:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5580::,2a03:5580:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:5600::,2a03:5600:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5680::,2a03:5680:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:5700::,2a03:5700:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5780::,2a03:5780:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a03:5800::,2a03:5800:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5880::,2a03:5880:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a03:5900::,2a03:5900:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a03:5980::,2a03:5980:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:5a00::,2a03:5a00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5a80::,2a03:5a80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5b00::,2a03:5b00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:5b80::,2a03:5b80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5c00::,2a03:5c00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:5c80::,2a03:5c80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:5d00::,2a03:5d00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:5d80::,2a03:5d80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:5e00::,2a03:5e00:ffff:ffff:ffff:ffff:ffff:ffff,BY
+2a03:5e80::,2a03:5e80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:5f00::,2a03:5f00:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:5f80::,2a03:5f80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6000::,2a03:6000:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:6080::,2a03:6087:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6100::,2a03:6100:ffff:ffff:ffff:ffff:ffff:ffff,HR
+2a03:6180::,2a03:6180:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:6200::,2a03:6200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6300::,2a03:6300:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a03:6380::,2a03:6380:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a03:6400::,2a03:6400:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:6480::,2a03:6480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:6500::,2a03:6500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6580::,2a03:6580:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:6600::,2a03:6600:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:6680::,2a03:6680:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:6700::,2a03:6700:ffff:ffff:ffff:ffff:ffff:ffff,KW
+2a03:6780::,2a03:6780:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:6800::,2a03:6800:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:6880::,2a03:6880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:6900::,2a03:6900:ffff:ffff:ffff:ffff:ffff:ffff,LB
+2a03:6980::,2a03:6980:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:6a00::,2a03:6a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:6a80::,2a03:6a80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:6b00::,2a03:6b00:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a03:6b80::,2a03:6b80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:6c00::,2a03:6c00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:6c80::,2a03:6c80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:6d00::,2a03:6d00:ffff:ffff:ffff:ffff:ffff:ffff,JO
+2a03:6d80::,2a03:6d80:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:6e00::,2a03:6e00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:6e80::,2a03:6e80:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:6f00::,2a03:6f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:6f80::,2a03:6f80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:7000::,2a03:7000:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:7080::,2a03:7080:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:7100::,2a03:7100:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:7180::,2a03:7180:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a03:7200::,2a03:7200:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:7280::,2a03:7280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:7300::,2a03:7300:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:7380::,2a03:7380:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a03:7400::,2a03:7400:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:7480::,2a03:7480:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:7500::,2a03:7500:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:7580::,2a03:7580:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:7600::,2a03:7600:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:7680::,2a03:7680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:7700::,2a03:7700:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:7780::,2a03:7780:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:7800::,2a03:7800:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:7880::,2a03:7880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:7900::,2a03:7900:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:7a00::,2a03:7a00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:7a80::,2a03:7a80:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a03:7b00::,2a03:7b00:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:7b80::,2a03:7b80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:7c00::,2a03:7c00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:7c80::,2a03:7c80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:7d00::,2a03:7d00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:7e00::,2a03:7e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:7e80::,2a03:7e80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:7f00::,2a03:7f00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:7f80::,2a03:7f80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8000::,2a03:8000:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:8080::,2a03:8080:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8100::,2a03:8100:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:8180::,2a03:8180:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:8200::,2a03:8200:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8280::,2a03:8280:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8300::,2a03:8300:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:8380::,2a03:8380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:8400::,2a03:8400:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8480::,2a03:8480:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a03:8500::,2a03:8500:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a03:8580::,2a03:8580:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:8600::,2a03:8600:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:8680::,2a03:8680:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8700::,2a03:8700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8780::,2a03:8780:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:8800::,2a03:8800:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:8880::,2a03:8880:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:8900::,2a03:8900:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:8980::,2a03:8980:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:8a00::,2a03:8a00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8a80::,2a03:8a80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:8b00::,2a03:8b00:ffff:ffff:ffff:ffff:ffff:ffff,SM
+2a03:8b80::,2a03:8b80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:8c00::,2a03:8c00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8c80::,2a03:8c87:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:8d00::,2a03:8d00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:8e00::,2a03:8e00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:8e80::,2a03:8e80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:8f00::,2a03:8f00:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:8f80::,2a03:8f80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:9000::,2a03:9000:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:9080::,2a03:9080:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:9100::,2a03:9100:ffff:ffff:ffff:ffff:ffff:ffff,TR
+2a03:9180::,2a03:9180:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:9280::,2a03:9280:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9300::,2a03:9300:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:9380::,2a03:9380:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9400::,2a03:9400:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:9480::,2a03:9480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:9500::,2a03:9500:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:9580::,2a03:9580:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:9600::,2a03:9600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9680::,2a03:9680:ffff:ffff:ffff:ffff:ffff:ffff,IL
+2a03:9700::,2a03:9700:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:9780::,2a03:9780:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:9800::,2a03:9800:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9880::,2a03:9880:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:9900::,2a03:9900:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:9980::,2a03:9980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:9a00::,2a03:9a00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:9a80::,2a03:9a80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:9b00::,2a03:9b00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:9b80::,2a03:9b80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:9c00::,2a03:9c00:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:9c80::,2a03:9c80:ffff:ffff:ffff:ffff:ffff:ffff,PT
+2a03:9d00::,2a03:9d00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:9d80::,2a03:9d80:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a03:9e00::,2a03:9e00:ffff:ffff:ffff:ffff:ffff:ffff,IM
+2a03:9e80::,2a03:9e80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9f00::,2a03:9f00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:9f80::,2a03:9f80:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:a000::,2a03:a000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:a080::,2a03:a080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:a100::,2a03:a100:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a03:a180::,2a03:a180:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:a200::,2a03:a200:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a03:a280::,2a03:a280:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:a300::,2a03:a300:ffff:ffff:ffff:ffff:ffff:ffff,KZ
+2a03:a380::,2a03:a380:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:a400::,2a03:a400:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:a480::,2a03:a480:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:a500::,2a03:a500:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:a580::,2a03:a580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:a600::,2a03:a600:ffff:ffff:ffff:ffff:ffff:ffff,UA
+2a03:a680::,2a03:a680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:a780::,2a03:a780:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:a800::,2a03:a800:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:a900::,2a03:a900:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:a980::,2a03:a980:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:aa00::,2a03:aa00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:aa80::,2a03:aa80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ab00::,2a03:ab00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:ab80::,2a03:ab80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:ac00::,2a03:ac00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:ac80::,2a03:ac80:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:ad00::,2a03:ad00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:ad80::,2a03:ad80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:ae00::,2a03:ae00:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:ae80::,2a03:ae80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:af00::,2a03:af00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:af80::,2a03:af80:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:b000::,2a03:b000:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:b080::,2a03:b080:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a03:b100::,2a03:b100:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:b180::,2a03:b180:ffff:ffff:ffff:ffff:ffff:ffff,AE
+2a03:b200::,2a03:b207:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:b280::,2a03:b280:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:b300::,2a03:b300:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:b380::,2a03:b380:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b400::,2a03:b400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b480::,2a03:b480:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b500::,2a03:b500:ffff:ffff:ffff:ffff:ffff:ffff,BE
+2a03:b580::,2a03:b580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b600::,2a03:b600:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:b680::,2a03:b680:ffff:ffff:ffff:ffff:ffff:ffff,IR
+2a03:b700::,2a03:b700:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:b780::,2a03:b780:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:b800::,2a03:b800:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:b880::,2a03:b887:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:b900::,2a03:b900:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:b980::,2a03:b980:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:ba00::,2a03:ba00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:ba80::,2a03:ba80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:bb00::,2a03:bb00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:bb80::,2a03:bb80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:bc00::,2a03:bc00:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:bc80::,2a03:bc80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:bd00::,2a03:bd00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:bd80::,2a03:bd80:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:be00::,2a03:be00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:be80::,2a03:be80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:bf00::,2a03:bf00:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:bf80::,2a03:bf80:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:c000::,2a03:c007:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:c080::,2a03:c080:ffff:ffff:ffff:ffff:ffff:ffff,SA
+2a03:c100::,2a03:c100:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:c180::,2a03:c180:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:c200::,2a03:c200:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:c280::,2a03:c280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:c300::,2a03:c300:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:c380::,2a03:c380:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:c400::,2a03:c400:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:c480::,2a03:c480:ffff:ffff:ffff:ffff:ffff:ffff,LU
+2a03:c500::,2a03:c500:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:c580::,2a03:c580:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:c600::,2a03:c600:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:c680::,2a03:c680:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:c700::,2a03:c700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:c780::,2a03:c780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:c800::,2a03:c800:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a03:c880::,2a03:c880:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:c900::,2a03:c900:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:c980::,2a03:c980:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ca00::,2a03:ca00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ca80::,2a03:ca80:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:cb00::,2a03:cb00:ffff:ffff:ffff:ffff:ffff:ffff,MT
+2a03:cb80::,2a03:cb80:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a03:cc00::,2a03:cc00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:cc80::,2a03:cc80:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a03:cd00::,2a03:cd00:ffff:ffff:ffff:ffff:ffff:ffff,US
+2a03:cd80::,2a03:cd80:ffff:ffff:ffff:ffff:ffff:ffff,SK
+2a03:ce00::,2a03:ce00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ce80::,2a03:ce80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:cf00::,2a03:cf00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:cf80::,2a03:cf80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:d000::,2a03:d000:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:d080::,2a03:d080:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:d100::,2a03:d100:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:d180::,2a03:d180:ffff:ffff:ffff:ffff:ffff:ffff,BG
+2a03:d200::,2a03:d200:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:d280::,2a03:d280:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:d300::,2a03:d300:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:d380::,2a03:d380:ffff:ffff:ffff:ffff:ffff:ffff,CH
+2a03:d400::,2a03:d400:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:d480::,2a03:d480:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:d500::,2a03:d500:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:d580::,2a03:d580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:d600::,2a03:d600:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:d680::,2a03:d680:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:d700::,2a03:d700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:d780::,2a03:d780:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:d800::,2a03:d800:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:d880::,2a03:d880:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:d900::,2a03:d900:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:d980::,2a03:d980:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:da00::,2a03:da00:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:da80::,2a03:da80:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:db00::,2a03:db00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:db80::,2a03:db80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:dc00::,2a03:dc00:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:dc80::,2a03:dc80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:dd00::,2a03:dd00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:dd80::,2a03:dd80:ffff:ffff:ffff:ffff:ffff:ffff,RS
+2a03:de00::,2a03:de00:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:de80::,2a03:de80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:df00::,2a03:df00:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:df80::,2a03:df80:ffff:ffff:ffff:ffff:ffff:ffff,AL
+2a03:e000::,2a03:e000:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:e080::,2a03:e080:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:e100::,2a03:e100:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:e180::,2a03:e180:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a03:e200::,2a03:e200:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:e280::,2a03:e280:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:e380::,2a03:e380:ffff:ffff:ffff:ffff:ffff:ffff,MK
+2a03:e400::,2a03:e400:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:e480::,2a03:e480:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:e500::,2a03:e500:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a03:e580::,2a03:e580:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:e600::,2a03:e600:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:e680::,2a03:e680:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:e700::,2a03:e700:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:e780::,2a03:e780:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:e800::,2a03:e800:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:e880::,2a03:e880:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:e900::,2a03:e900:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:e980::,2a03:e980:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a03:ea00::,2a03:ea00:ffff:ffff:ffff:ffff:ffff:ffff,NO
+2a03:ea80::,2a03:ea80:ffff:ffff:ffff:ffff:ffff:ffff,ES
+2a03:eb00::,2a03:eb00:ffff:ffff:ffff:ffff:ffff:ffff,FI
+2a03:eb80::,2a03:eb80:ffff:ffff:ffff:ffff:ffff:ffff,IS
+2a03:ec00::,2a03:ec00:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a03:ec80::,2a03:ec80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:ed00::,2a03:ed00:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:ed80::,2a03:ed80:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:ee00::,2a03:ee00:ffff:ffff:ffff:ffff:ffff:ffff,FO
+2a03:ee80::,2a03:ee80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:ef00::,2a03:ef00:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:ef80::,2a03:ef80:ffff:ffff:ffff:ffff:ffff:ffff,IT
+2a03:f000::,2a03:f000:ffff:ffff:ffff:ffff:ffff:ffff,GR
+2a03:f080::,2a03:f080:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:f100::,2a03:f100:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:f180::,2a03:f180:ffff:ffff:ffff:ffff:ffff:ffff,BA
+2a03:f200::,2a03:f200:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:f280::,2a03:f280:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:f300::,2a03:f300:ffff:ffff:ffff:ffff:ffff:ffff,CZ
+2a03:f380::,2a03:f380:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:f400::,2a03:f400:ffff:ffff:ffff:ffff:ffff:ffff,IE
+2a03:f480::,2a03:f480:ffff:ffff:ffff:ffff:ffff:ffff,EE
+2a03:f500::,2a03:f500:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:f580::,2a03:f580:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:f600::,2a03:f600:ffff:ffff:ffff:ffff:ffff:ffff,SE
+2a03:f680::,2a03:f680:ffff:ffff:ffff:ffff:ffff:ffff,MD
+2a03:f700::,2a03:f700:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:f780::,2a03:f780:ffff:ffff:ffff:ffff:ffff:ffff,HU
+2a03:f800::,2a03:f800:ffff:ffff:ffff:ffff:ffff:ffff,SI
+2a03:f880::,2a03:f880:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:f900::,2a03:f907:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:f980::,2a03:f980:ffff:ffff:ffff:ffff:ffff:ffff,PL
+2a03:fa00::,2a03:fa00:ffff:ffff:ffff:ffff:ffff:ffff,AT
+2a03:fa80::,2a03:fa80:ffff:ffff:ffff:ffff:ffff:ffff,RO
+2a03:fb00::,2a03:fb00:ffff:ffff:ffff:ffff:ffff:ffff,GB
+2a03:fb80::,2a03:fb80:ffff:ffff:ffff:ffff:ffff:ffff,DK
+2a03:fc00::,2a03:fc00:ffff:ffff:ffff:ffff:ffff:ffff,NL
+2a03:fc80::,2a03:fc80:ffff:ffff:ffff:ffff:ffff:ffff,DE
+2a03:fe00::,2a03:fe00:ffff:ffff:ffff:ffff:ffff:ffff,RU
+2a03:fe80::,2a03:fe80:ffff:ffff:ffff:ffff:ffff:ffff,FR
+2a03:ff00::,2a03:ff00:ffff:ffff:ffff:ffff:ffff:ffff,LV
+2a03:ff80::,2a03:ff80:ffff:ffff:ffff:ffff:ffff:ffff,EU
+2c0f:f800::,2c0f:f80f:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:f810::,2c0f:f810:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:f818::,2c0f:f818:ffff:ffff:ffff:ffff:ffff:ffff,LY
+2c0f:f820::,2c0f:f820:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:f828::,2c0f:f828:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:f830::,2c0f:f830:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:f838::,2c0f:f838:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:f840::,2c0f:f840:ffff:ffff:ffff:ffff:ffff:ffff,GQ
+2c0f:f848::,2c0f:f848:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:f850::,2c0f:f850:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:f858::,2c0f:f858:ffff:ffff:ffff:ffff:ffff:ffff,DZ
+2c0f:f860::,2c0f:f860:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2c0f:f868::,2c0f:f868:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:f870::,2c0f:f870:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:f878::,2c0f:f878:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:f880::,2c0f:f880:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:f888::,2c0f:f888:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa00::,2c0f:fa00:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fa08::,2c0f:fa08:ffff:ffff:ffff:ffff:ffff:ffff,CD
+2c0f:fa10::,2c0f:fa10:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fa18::,2c0f:fa18:ffff:ffff:ffff:ffff:ffff:ffff,MA
+2c0f:fa20::,2c0f:fa20:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:fa28::,2c0f:fa28:ffff:ffff:ffff:ffff:ffff:ffff,MG
+2c0f:fa30::,2c0f:fa30:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fa38::,2c0f:fa38:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa40::,2c0f:fa40:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa48::,2c0f:fa48:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa58::,2c0f:fa58:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa60::,2c0f:fa60:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa68::,2c0f:fa68:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fa70::,2c0f:fa70:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa78::,2c0f:fa78:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa80::,2c0f:fa80:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fa88::,2c0f:fa88:ffff:ffff:ffff:ffff:ffff:ffff,ST
+2c0f:fa90::,2c0f:fa90:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fa98::,2c0f:fa98:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:faa0::,2c0f:faa7:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:fab0::,2c0f:fabf:ffff:ffff:ffff:ffff:ffff:ffff,TN
+2c0f:fac0::,2c0f:fac0:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fac8::,2c0f:fac8:ffff:ffff:ffff:ffff:ffff:ffff,BW
+2c0f:fad0::,2c0f:fad0:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2c0f:fad8::,2c0f:fad8:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fae0::,2c0f:fae0:ffff:ffff:ffff:ffff:ffff:ffff,CM
+2c0f:fae8::,2c0f:fae8:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:faf0::,2c0f:faf0:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:faf8::,2c0f:faf8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb00::,2c0f:fb00:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fb08::,2c0f:fb08:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb10::,2c0f:fb10:ffff:ffff:ffff:ffff:ffff:ffff,LY
+2c0f:fb18::,2c0f:fb18:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb20::,2c0f:fb20:ffff:ffff:ffff:ffff:ffff:ffff,MA
+2c0f:fb28::,2c0f:fb28:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb30::,2c0f:fb30:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb38::,2c0f:fb38:ffff:ffff:ffff:ffff:ffff:ffff,SO
+2c0f:fb40::,2c0f:fb40:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb48::,2c0f:fb48:ffff:ffff:ffff:ffff:ffff:ffff,MZ
+2c0f:fb50::,2c0f:fb50:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fb58::,2c0f:fb58:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fb60::,2c0f:fb60:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fb68::,2c0f:fb68:ffff:ffff:ffff:ffff:ffff:ffff,LS
+2c0f:fb70::,2c0f:fb70:ffff:ffff:ffff:ffff:ffff:ffff,AO
+2c0f:fb78::,2c0f:fb78:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fb80::,2c0f:fb80:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fb88::,2c0f:fb88:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fb90::,2c0f:fb90:ffff:ffff:ffff:ffff:ffff:ffff,MZ
+2c0f:fb98::,2c0f:fb98:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fba0::,2c0f:fba0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fba8::,2c0f:fba8:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fbb0::,2c0f:fbb0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fbb8::,2c0f:fbb8:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fbc0::,2c0f:fbc0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fbc8::,2c0f:fbc8:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fbd0::,2c0f:fbd0:ffff:ffff:ffff:ffff:ffff:ffff,GN
+2c0f:fbd8::,2c0f:fbd8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fbe0::,2c0f:fc1f:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fc40::,2c0f:fc40:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2c0f:fc48::,2c0f:fc48:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fc50::,2c0f:fc50:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:fc58::,2c0f:fc58:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fc60::,2c0f:fc61:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fc68::,2c0f:fc68:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fc70::,2c0f:fc70:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fc78::,2c0f:fc78:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:fc80::,2c0f:fc80:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fc88::,2c0f:fc88:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2c0f:fc90::,2c0f:fc90:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fc98::,2c0f:fc98:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fca0::,2c0f:fca0:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fca8::,2c0f:fca8:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fcb0::,2c0f:fcb0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fcb8::,2c0f:fcb8:ffff:ffff:ffff:ffff:ffff:ffff,GM
+2c0f:fcc8::,2c0f:fcc8:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fcd0::,2c0f:fcd0:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fcd8::,2c0f:fcd8:ffff:ffff:ffff:ffff:ffff:ffff,SO
+2c0f:fce0::,2c0f:fce0:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fce8::,2c0f:fce8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fcf0::,2c0f:fcf0:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fcf8::,2c0f:fcf8:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fd00::,2c0f:fd00:ffff:ffff:ffff:ffff:ffff:ffff,LS
+2c0f:fd08::,2c0f:fd08:ffff:ffff:ffff:ffff:ffff:ffff,GM
+2c0f:fd10::,2c0f:fd10:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fd18::,2c0f:fd18:ffff:ffff:ffff:ffff:ffff:ffff,SC
+2c0f:fd20::,2c0f:fd20:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fd28::,2c0f:fd28:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fd30::,2c0f:fd30:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fd38::,2c0f:fd38:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fd40::,2c0f:fd40:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fd48::,2c0f:fd48:ffff:ffff:ffff:ffff:ffff:ffff,ZW
+2c0f:fd50::,2c0f:fd50:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fd58::,2c0f:fd58:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fd60::,2c0f:fd60:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fd68::,2c0f:fd68:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fd70::,2c0f:fd70:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fd78::,2c0f:fd78:ffff:ffff:ffff:ffff:ffff:ffff,BI
+2c0f:fd80::,2c0f:fd80:ffff:ffff:ffff:ffff:ffff:ffff,BF
+2c0f:fd88::,2c0f:fd88:ffff:ffff:ffff:ffff:ffff:ffff,GH
+2c0f:fd90::,2c0f:fd90:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fd98::,2c0f:fd98:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fda0::,2c0f:fda0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fda8::,2c0f:fda8:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fdb0::,2c0f:fdb0:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fdb8::,2c0f:fdb8:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fdc0::,2c0f:fdc0:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fdc8::,2c0f:fdc8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fdd0::,2c0f:fdd0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fdd8::,2c0f:fdd8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fde0::,2c0f:fde0:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fde8::,2c0f:fde8:ffff:ffff:ffff:ffff:ffff:ffff,MW
+2c0f:fdf0::,2c0f:fdf0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fdf8::,2c0f:fdf8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe08::,2c0f:fe08:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fe10::,2c0f:fe10:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fe18::,2c0f:fe18:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe20::,2c0f:fe20:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe28::,2c0f:fe28:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe30::,2c0f:fe30:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2c0f:fe38::,2c0f:fe38:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fe40::,2c0f:fe40:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fe48::,2c0f:fe48:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe50::,2c0f:fe50:ffff:ffff:ffff:ffff:ffff:ffff,DZ
+2c0f:fe58::,2c0f:fe58:ffff:ffff:ffff:ffff:ffff:ffff,LS
+2c0f:fe60::,2c0f:fe60:ffff:ffff:ffff:ffff:ffff:ffff,RW
+2c0f:fe68::,2c0f:fe68:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2c0f:fe70::,2c0f:fe70:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fe78::,2c0f:fe78:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe80::,2c0f:fe80:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fe88::,2c0f:fe88:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:fe90::,2c0f:fe90:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fe98::,2c0f:fe98:ffff:ffff:ffff:ffff:ffff:ffff,TZ
+2c0f:fea0::,2c0f:fea0:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fea8::,2c0f:fea8:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:feb0::,2c0f:feb0:ffff:ffff:ffff:ffff:ffff:ffff,MU
+2c0f:feb8::,2c0f:feb8:ffff:ffff:ffff:ffff:ffff:ffff,ZM
+2c0f:fec0::,2c0f:fec0:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:fec8::,2c0f:fec8:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:fed0::,2c0f:fed0:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fed8::,2c0f:fed8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:fee0::,2c0f:fee0:ffff:ffff:ffff:ffff:ffff:ffff,EG
+2c0f:fef0::,2c0f:fef0:ffff:ffff:ffff:ffff:ffff:ffff,SC
+2c0f:fef8::,2c0f:fef8:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:ff00::,2c0f:ff00:ffff:ffff:ffff:ffff:ffff:ffff,BW
+2c0f:ff08::,2c0f:ff08:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ff10::,2c0f:ff10:ffff:ffff:ffff:ffff:ffff:ffff,CD
+2c0f:ff18::,2c0f:ff18:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:ff20::,2c0f:ff20:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:ff28::,2c0f:ff28:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:ff30::,2c0f:ff30:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ff40::,2c0f:ff80:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ff88::,2c0f:ff88:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:ff90::,2c0f:ff90:ffff:ffff:ffff:ffff:ffff:ffff,KE
+2c0f:ff98::,2c0f:ff98:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:ffa0::,2c0f:ffa0:ffff:ffff:ffff:ffff:ffff:ffff,UG
+2c0f:ffa8::,2c0f:ffa8:ffff:ffff:ffff:ffff:ffff:ffff,LS
+2c0f:ffb0::,2c0f:ffb0:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:ffb8::,2c0f:ffb8:ffff:ffff:ffff:ffff:ffff:ffff,SD
+2c0f:ffc0::,2c0f:ffc0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffc8::,2c0f:ffc8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffd0::,2c0f:ffd0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffd8::,2c0f:ffd8:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffe0::,2c0f:ffe0:ffff:ffff:ffff:ffff:ffff:ffff,ZA
+2c0f:ffe8::,2c0f:ffe8:ffff:ffff:ffff:ffff:ffff:ffff,NG
+2c0f:fff0::,2c0f:fff0:ffff:ffff:ffff:ffff:ffff:ffff,NG
diff --git a/src/config/include.am b/src/config/include.am
new file mode 100644
index 000000000..35961b829
--- /dev/null
+++ b/src/config/include.am
@@ -0,0 +1,16 @@
+confdir = $(sysconfdir)/tor
+
+tordatadir = $(datadir)/tor
+
+EXTRA_DIST+= src/config/geoip src/config/geoip6
+# fallback-consensus
+
+conf_DATA = src/config/torrc.sample
+
+tordata_DATA = src/config/geoip src/config/geoip6
+# fallback_consensus
+
+# If we don't have it, fake it.
+src_config_fallback-consensus:
+ touch src/config/fallback-consensus
+
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index a1a08aa8f..c667efc5c 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -1,5 +1,5 @@
## Configuration file for a typical Tor user
-## Last updated 22 April 2012 for Tor 0.2.3.14-alpha.
+## Last updated 12 September 2012 for Tor 0.2.4.3-alpha.
## (may or may not work for much older or much newer versions of Tor.)
##
## Lines that begin with "## " try to explain what's going on. Lines
@@ -16,7 +16,7 @@
## configure one below. Set "SocksPort 0" if you plan to run Tor only
## as a relay, and not make any local application connections yourself.
#SocksPort 9050 # Default: Bind to localhost:9050 for local connections.
-#SocksPort 192.168.0.1:9100 # Bind to this adddress:port too.
+#SocksPort 192.168.0.1:9100 # Bind to this address:port too.
## Entry policies to allow/deny SOCKS requests based on IP address.
## First entry that matches wins. If no SocksPolicy is set, we accept
diff --git a/src/common/OpenBSD_malloc_Linux.c b/src/ext/OpenBSD_malloc_Linux.c
index da8272981..da8272981 100644
--- a/src/common/OpenBSD_malloc_Linux.c
+++ b/src/ext/OpenBSD_malloc_Linux.c
diff --git a/src/ext/README b/src/ext/README
new file mode 100644
index 000000000..58ba7f699
--- /dev/null
+++ b/src/ext/README
@@ -0,0 +1,44 @@
+
+OpenBSD_malloc_Linux.c:
+
+ The OpenBSD malloc implementation, ported to Linux. Used only when
+ --enable-openbsd-malloc is passed to the configure script.
+
+strlcat.c
+strlcpy.c
+
+ Implementations of strlcat and strlcpy, the more sane replacements
+ for strcat and strcpy. These are nonstandard, and some libc
+ implementations refuse to add them for religious reasons.
+
+eventdns.[ch]
+
+ A fork of Libevent's DNS implementation, used by Tor when Libevent
+ 2.0 or later is not available. Once Libevent 2.0 is required, we
+ should throw this away; it has diverged from evdns.[ch], and is
+ no longer easily mergeable.
+
+ht.h
+
+ An implementation of a hash table in the style of Niels Provos's
+ tree.h. Shared with Libevent.
+
+tinytest.[ch]
+tinytest_demos.c
+tinytest_macros.h
+
+ A unit testing framework. https://github.com/nmathewson/tinytest
+
+tor_queue.h
+
+ A copy of sys/queue.h from OpenBSD. We keep our own copy rather
+ than using sys/queue.h, since some platforms don't have a
+ sys/queue.h, and the ones that do have diverged in incompatible
+ ways. (CIRCLEQ or no CIRCLEQ? SIMPLQ or STAILQ?) We also rename
+ the identifiers with a TOR_ prefix to avoid conflicts with
+ the system headers.
+
+curve25519_donna/*.c
+
+ A copy of Adam Langley's curve25519-donna mostly-portable
+ implementations of curve25519.
diff --git a/src/ext/curve25519_donna/README b/src/ext/curve25519_donna/README
new file mode 100644
index 000000000..9f77bd7d9
--- /dev/null
+++ b/src/ext/curve25519_donna/README
@@ -0,0 +1,44 @@
+See http://code.google.com/p/curve25519-donna/ for details.
+
+BUILDING:
+
+If you run `make`, two .a archives will be built, similar to djb's curve25519
+code. Alternatively, read on:
+
+The C implementation is contained within curve25519-donna.c. It has no external
+dependancies and is BSD licenced. You can copy/include/link it directly in with
+your program. Recommended C flags: -O2
+
+The x86-64 bit implementation is contained within curve25519-donna-x86-64.c and
+curve25519-donna-x86-64.s. Build like this:
+
+% cpp curve25519-donna-x86-64.s > curve25519-donna-x86-64.s.pp
+% as -o curve25519-donna-x86-64.s.o curve25519-donna-x86-64.s.pp
+% gcc -O2 -c curve25519-donna-x86-64.c
+
+Then the two .o files can be linked in
+
+USAGE:
+
+The usage is exactly the same as djb's code (as described at
+http://cr.yp.to/ecdh.html) expect that the function is called curve25519_donna.
+
+In short,
+
+To generate a private key, generate 32 random bytes and:
+
+ mysecret[0] &= 248;
+ mysecret[31] &= 127;
+ mysecret[31] |= 64;
+
+To generate the public key, just do
+
+ static const uint8_t basepoint[32] = {9};
+ curve25519_donna(mypublic, mysecret, basepoint);
+
+To generate an agreed key do:
+ uint8_t shared_key[32];
+ curve25519_donna(shared_key, mysecret, theirpublic);
+
+And hash the shared_key with a cryptographic hash function before using.
+
diff --git a/src/ext/curve25519_donna/curve25519-donna-c64.c b/src/ext/curve25519_donna/curve25519-donna-c64.c
new file mode 100644
index 000000000..b68ff3695
--- /dev/null
+++ b/src/ext/curve25519_donna/curve25519-donna-c64.c
@@ -0,0 +1,451 @@
+/* Copyright 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Code released into the public domain.
+ *
+ * curve25519-donna: Curve25519 elliptic curve, public key function
+ *
+ * http://code.google.com/p/curve25519-donna/
+ *
+ * Adam Langley <agl@imperialviolet.org>
+ *
+ * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
+ *
+ * More information about curve25519 can be found here
+ * http://cr.yp.to/ecdh.html
+ *
+ * djb's sample implementation of curve25519 is written in a special assembly
+ * language called qhasm and uses the floating point registers.
+ *
+ * This is, almost, a clean room reimplementation from the curve25519 paper. It
+ * uses many of the tricks described therein. Only the crecip function is taken
+ * from the sample implementation.
+ */
+
+#include "orconfig.h"
+
+#include <string.h>
+#include "torint.h"
+
+typedef uint8_t u8;
+typedef uint64_t limb;
+typedef limb felem[5];
+// This is a special gcc mode for 128-bit integers. It's implemented on 64-bit
+// platforms only as far as I know.
+typedef unsigned uint128_t __attribute__((mode(TI)));
+
+#undef force_inline
+#define force_inline __attribute__((always_inline))
+
+/* Sum two numbers: output += in */
+static inline void force_inline
+fsum(limb *output, const limb *in) {
+ output[0] += in[0];
+ output[1] += in[1];
+ output[2] += in[2];
+ output[3] += in[3];
+ output[4] += in[4];
+}
+
+/* Find the difference of two numbers: output = in - output
+ * (note the order of the arguments!)
+ *
+ * Assumes that out[i] < 2**52
+ * On return, out[i] < 2**55
+ */
+static inline void force_inline
+fdifference_backwards(felem out, const felem in) {
+ /* 152 is 19 << 3 */
+ static const limb two54m152 = (((limb)1) << 54) - 152;
+ static const limb two54m8 = (((limb)1) << 54) - 8;
+
+ out[0] = in[0] + two54m152 - out[0];
+ out[1] = in[1] + two54m8 - out[1];
+ out[2] = in[2] + two54m8 - out[2];
+ out[3] = in[3] + two54m8 - out[3];
+ out[4] = in[4] + two54m8 - out[4];
+}
+
+/* Multiply a number by a scalar: output = in * scalar */
+static inline void force_inline
+fscalar_product(felem output, const felem in, const limb scalar) {
+ uint128_t a;
+
+ a = ((uint128_t) in[0]) * scalar;
+ output[0] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[1]) * scalar + ((limb) (a >> 51));
+ output[1] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[2]) * scalar + ((limb) (a >> 51));
+ output[2] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[3]) * scalar + ((limb) (a >> 51));
+ output[3] = ((limb)a) & 0x7ffffffffffff;
+
+ a = ((uint128_t) in[4]) * scalar + ((limb) (a >> 51));
+ output[4] = ((limb)a) & 0x7ffffffffffff;
+
+ output[0] += (a >> 51) * 19;
+}
+
+/* Multiply two numbers: output = in2 * in
+ *
+ * output must be distinct to both inputs. The inputs are reduced coefficient
+ * form, the output is not.
+ *
+ * Assumes that in[i] < 2**55 and likewise for in2.
+ * On return, output[i] < 2**52
+ */
+static inline void force_inline
+fmul(felem output, const felem in2, const felem in) {
+ uint128_t t[5];
+ limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c;
+
+ r0 = in[0];
+ r1 = in[1];
+ r2 = in[2];
+ r3 = in[3];
+ r4 = in[4];
+
+ s0 = in2[0];
+ s1 = in2[1];
+ s2 = in2[2];
+ s3 = in2[3];
+ s4 = in2[4];
+
+ t[0] = ((uint128_t) r0) * s0;
+ t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0;
+ t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1;
+ t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1;
+ t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2;
+
+ r4 *= 19;
+ r1 *= 19;
+ r2 *= 19;
+ r3 *= 19;
+
+ t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2;
+ t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3;
+ t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4;
+ t[3] += ((uint128_t) r4) * s4;
+
+ r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51);
+ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51);
+ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51);
+ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51);
+ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51);
+ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff;
+ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff;
+ r2 += c;
+
+ output[0] = r0;
+ output[1] = r1;
+ output[2] = r2;
+ output[3] = r3;
+ output[4] = r4;
+}
+
+static inline void force_inline
+fsquare_times(felem output, const felem in, limb count) {
+ uint128_t t[5];
+ limb r0,r1,r2,r3,r4,c;
+ limb d0,d1,d2,d4,d419;
+
+ r0 = in[0];
+ r1 = in[1];
+ r2 = in[2];
+ r3 = in[3];
+ r4 = in[4];
+
+ do {
+ d0 = r0 * 2;
+ d1 = r1 * 2;
+ d2 = r2 * 2 * 19;
+ d419 = r4 * 19;
+ d4 = d419 * 2;
+
+ t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 ));
+ t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19));
+ t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 ));
+ t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 ));
+ t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 ));
+
+ r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51);
+ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51);
+ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51);
+ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51);
+ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51);
+ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff;
+ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff;
+ r2 += c;
+ } while(--count);
+
+ output[0] = r0;
+ output[1] = r1;
+ output[2] = r2;
+ output[3] = r3;
+ output[4] = r4;
+}
+
+/* Load a little-endian 64-bit number */
+static limb
+load_limb(const u8 *in) {
+ return
+ ((limb)in[0]) |
+ (((limb)in[1]) << 8) |
+ (((limb)in[2]) << 16) |
+ (((limb)in[3]) << 24) |
+ (((limb)in[4]) << 32) |
+ (((limb)in[5]) << 40) |
+ (((limb)in[6]) << 48) |
+ (((limb)in[7]) << 56);
+}
+
+static void
+store_limb(u8 *out, limb in) {
+ out[0] = in & 0xff;
+ out[1] = (in >> 8) & 0xff;
+ out[2] = (in >> 16) & 0xff;
+ out[3] = (in >> 24) & 0xff;
+ out[4] = (in >> 32) & 0xff;
+ out[5] = (in >> 40) & 0xff;
+ out[6] = (in >> 48) & 0xff;
+ out[7] = (in >> 56) & 0xff;
+}
+
+/* Take a little-endian, 32-byte number and expand it into polynomial form */
+static void
+fexpand(limb *output, const u8 *in) {
+ output[0] = load_limb(in) & 0x7ffffffffffff;
+ output[1] = (load_limb(in+6) >> 3) & 0x7ffffffffffff;
+ output[2] = (load_limb(in+12) >> 6) & 0x7ffffffffffff;
+ output[3] = (load_limb(in+19) >> 1) & 0x7ffffffffffff;
+ output[4] = (load_limb(in+24) >> 12) & 0x7ffffffffffff;
+}
+
+/* Take a fully reduced polynomial form number and contract it into a
+ * little-endian, 32-byte array
+ */
+static void
+fcontract(u8 *output, const felem input) {
+ uint128_t t[5];
+
+ t[0] = input[0];
+ t[1] = input[1];
+ t[2] = input[2];
+ t[3] = input[3];
+ t[4] = input[4];
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
+
+ /* now t is between 0 and 2^255-1, properly carried. */
+ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */
+
+ t[0] += 19;
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff;
+
+ /* now between 19 and 2^255-1 in both cases, and offset by 19. */
+
+ t[0] += 0x8000000000000 - 19;
+ t[1] += 0x8000000000000 - 1;
+ t[2] += 0x8000000000000 - 1;
+ t[3] += 0x8000000000000 - 1;
+ t[4] += 0x8000000000000 - 1;
+
+ /* now between 2^255 and 2^256-20, and offset by 2^255. */
+
+ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff;
+ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff;
+ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff;
+ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff;
+ t[4] &= 0x7ffffffffffff;
+
+ store_limb(output, t[0] | (t[1] << 51));
+ store_limb(output+8, (t[1] >> 13) | (t[2] << 38));
+ store_limb(output+16, (t[2] >> 26) | (t[3] << 25));
+ store_limb(output+24, (t[3] >> 39) | (t[4] << 12));
+}
+
+/* Input: Q, Q', Q-Q'
+ * Output: 2Q, Q+Q'
+ *
+ * x2 z3: long form
+ * x3 z3: long form
+ * x z: short form, destroyed
+ * xprime zprime: short form, destroyed
+ * qmqp: short form, preserved
+ */
+static void
+fmonty(limb *x2, limb *z2, /* output 2Q */
+ limb *x3, limb *z3, /* output Q + Q' */
+ limb *x, limb *z, /* input Q */
+ limb *xprime, limb *zprime, /* input Q' */
+ const limb *qmqp /* input Q - Q' */) {
+ limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5],
+ zzprime[5], zzzprime[5];
+
+ memcpy(origx, x, 5 * sizeof(limb));
+ fsum(x, z);
+ fdifference_backwards(z, origx); // does x - z
+
+ memcpy(origxprime, xprime, sizeof(limb) * 5);
+ fsum(xprime, zprime);
+ fdifference_backwards(zprime, origxprime);
+ fmul(xxprime, xprime, z);
+ fmul(zzprime, x, zprime);
+ memcpy(origxprime, xxprime, sizeof(limb) * 5);
+ fsum(xxprime, zzprime);
+ fdifference_backwards(zzprime, origxprime);
+ fsquare_times(x3, xxprime, 1);
+ fsquare_times(zzzprime, zzprime, 1);
+ fmul(z3, zzzprime, qmqp);
+
+ fsquare_times(xx, x, 1);
+ fsquare_times(zz, z, 1);
+ fmul(x2, xx, zz);
+ fdifference_backwards(zz, xx); // does zz = xx - zz
+ fscalar_product(zzz, zz, 121665);
+ fsum(zzz, xx);
+ fmul(z2, zz, zzz);
+}
+
+// -----------------------------------------------------------------------------
+// Maybe swap the contents of two limb arrays (@a and @b), each @len elements
+// long. Perform the swap iff @swap is non-zero.
+//
+// This function performs the swap without leaking any side-channel
+// information.
+// -----------------------------------------------------------------------------
+static void
+swap_conditional(limb a[5], limb b[5], limb iswap) {
+ unsigned i;
+ const limb swap = -iswap;
+
+ for (i = 0; i < 5; ++i) {
+ const limb x = swap & (a[i] ^ b[i]);
+ a[i] ^= x;
+ b[i] ^= x;
+ }
+}
+
+/* Calculates nQ where Q is the x-coordinate of a point on the curve
+ *
+ * resultx/resultz: the x coordinate of the resulting curve point (short form)
+ * n: a little endian, 32-byte number
+ * q: a point of the curve (short form)
+ */
+static void
+cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
+ limb a[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0};
+ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
+ limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1};
+ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
+
+ unsigned i, j;
+
+ memcpy(nqpqx, q, sizeof(limb) * 5);
+
+ for (i = 0; i < 32; ++i) {
+ u8 byte = n[31 - i];
+ for (j = 0; j < 8; ++j) {
+ const limb bit = byte >> 7;
+
+ swap_conditional(nqx, nqpqx, bit);
+ swap_conditional(nqz, nqpqz, bit);
+ fmonty(nqx2, nqz2,
+ nqpqx2, nqpqz2,
+ nqx, nqz,
+ nqpqx, nqpqz,
+ q);
+ swap_conditional(nqx2, nqpqx2, bit);
+ swap_conditional(nqz2, nqpqz2, bit);
+
+ t = nqx;
+ nqx = nqx2;
+ nqx2 = t;
+ t = nqz;
+ nqz = nqz2;
+ nqz2 = t;
+ t = nqpqx;
+ nqpqx = nqpqx2;
+ nqpqx2 = t;
+ t = nqpqz;
+ nqpqz = nqpqz2;
+ nqpqz2 = t;
+
+ byte <<= 1;
+ }
+ }
+
+ memcpy(resultx, nqx, sizeof(limb) * 5);
+ memcpy(resultz, nqz, sizeof(limb) * 5);
+}
+
+
+// -----------------------------------------------------------------------------
+// Shamelessly copied from djb's code, tightened a little
+// -----------------------------------------------------------------------------
+static void
+crecip(felem out, const felem z) {
+ felem a,t0,b,c;
+
+ /* 2 */ fsquare_times(a, z, 1); // a = 2
+ /* 8 */ fsquare_times(t0, a, 2);
+ /* 9 */ fmul(b, t0, z); // b = 9
+ /* 11 */ fmul(a, b, a); // a = 11
+ /* 22 */ fsquare_times(t0, a, 1);
+ /* 2^5 - 2^0 = 31 */ fmul(b, t0, b);
+ /* 2^10 - 2^5 */ fsquare_times(t0, b, 5);
+ /* 2^10 - 2^0 */ fmul(b, t0, b);
+ /* 2^20 - 2^10 */ fsquare_times(t0, b, 10);
+ /* 2^20 - 2^0 */ fmul(c, t0, b);
+ /* 2^40 - 2^20 */ fsquare_times(t0, c, 20);
+ /* 2^40 - 2^0 */ fmul(t0, t0, c);
+ /* 2^50 - 2^10 */ fsquare_times(t0, t0, 10);
+ /* 2^50 - 2^0 */ fmul(b, t0, b);
+ /* 2^100 - 2^50 */ fsquare_times(t0, b, 50);
+ /* 2^100 - 2^0 */ fmul(c, t0, b);
+ /* 2^200 - 2^100 */ fsquare_times(t0, c, 100);
+ /* 2^200 - 2^0 */ fmul(t0, t0, c);
+ /* 2^250 - 2^50 */ fsquare_times(t0, t0, 50);
+ /* 2^250 - 2^0 */ fmul(t0, t0, b);
+ /* 2^255 - 2^5 */ fsquare_times(t0, t0, 5);
+ /* 2^255 - 21 */ fmul(out, t0, a);
+}
+
+int curve25519_donna(u8 *, const u8 *, const u8 *);
+
+int
+curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
+ limb bp[5], x[5], z[5], zmone[5];
+ uint8_t e[32];
+ int i;
+
+ for (i = 0;i < 32;++i) e[i] = secret[i];
+ e[0] &= 248;
+ e[31] &= 127;
+ e[31] |= 64;
+
+ fexpand(bp, basepoint);
+ cmult(x, z, e, bp);
+ crecip(zmone, z);
+ fmul(z, x, zmone);
+ fcontract(mypublic, z);
+ return 0;
+}
diff --git a/src/ext/curve25519_donna/curve25519-donna.c b/src/ext/curve25519_donna/curve25519-donna.c
new file mode 100644
index 000000000..5c6821ccd
--- /dev/null
+++ b/src/ext/curve25519_donna/curve25519-donna.c
@@ -0,0 +1,732 @@
+/* Copyright 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * curve25519-donna: Curve25519 elliptic curve, public key function
+ *
+ * http://code.google.com/p/curve25519-donna/
+ *
+ * Adam Langley <agl@imperialviolet.org>
+ *
+ * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
+ *
+ * More information about curve25519 can be found here
+ * http://cr.yp.to/ecdh.html
+ *
+ * djb's sample implementation of curve25519 is written in a special assembly
+ * language called qhasm and uses the floating point registers.
+ *
+ * This is, almost, a clean room reimplementation from the curve25519 paper. It
+ * uses many of the tricks described therein. Only the crecip function is taken
+ * from the sample implementation.
+ */
+
+#include "orconfig.h"
+
+#include <string.h>
+#include "torint.h"
+
+typedef uint8_t u8;
+typedef int32_t s32;
+typedef int64_t limb;
+
+/* Field element representation:
+ *
+ * Field elements are written as an array of signed, 64-bit limbs, least
+ * significant first. The value of the field element is:
+ * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
+ *
+ * i.e. the limbs are 26, 25, 26, 25, ... bits wide.
+ */
+
+/* Sum two numbers: output += in */
+static void fsum(limb *output, const limb *in) {
+ unsigned i;
+ for (i = 0; i < 10; i += 2) {
+ output[0+i] = (output[0+i] + in[0+i]);
+ output[1+i] = (output[1+i] + in[1+i]);
+ }
+}
+
+/* Find the difference of two numbers: output = in - output
+ * (note the order of the arguments!)
+ */
+static void fdifference(limb *output, const limb *in) {
+ unsigned i;
+ for (i = 0; i < 10; ++i) {
+ output[i] = (in[i] - output[i]);
+ }
+}
+
+/* Multiply a number by a scalar: output = in * scalar */
+static void fscalar_product(limb *output, const limb *in, const limb scalar) {
+ unsigned i;
+ for (i = 0; i < 10; ++i) {
+ output[i] = in[i] * scalar;
+ }
+}
+
+/* Multiply two numbers: output = in2 * in
+ *
+ * output must be distinct to both inputs. The inputs are reduced coefficient
+ * form, the output is not.
+ */
+static void fproduct(limb *output, const limb *in2, const limb *in) {
+ output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
+ output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[0]);
+ output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[0]);
+ output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[0]);
+ output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
+ 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[1])) +
+ ((limb) ((s32) in2[0])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[0]);
+ output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[0]);
+ output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[1])) +
+ ((limb) ((s32) in2[2])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[0]);
+ output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[0]);
+ output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
+ 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[1])) +
+ ((limb) ((s32) in2[2])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[0]);
+ output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[2]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[1]) +
+ ((limb) ((s32) in2[0])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[0]);
+ output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[1])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[1])) +
+ ((limb) ((s32) in2[4])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[2]);
+ output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[4]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[3]) +
+ ((limb) ((s32) in2[2])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[2]);
+ output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
+ 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[3])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[3])) +
+ ((limb) ((s32) in2[4])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[4]);
+ output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[7])) * ((s32) in[6]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[5]) +
+ ((limb) ((s32) in2[4])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[4]);
+ output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[5])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[5])) +
+ ((limb) ((s32) in2[6])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[6]);
+ output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
+ ((limb) ((s32) in2[8])) * ((s32) in[7]) +
+ ((limb) ((s32) in2[6])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[6]);
+ output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
+ 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[7]));
+ output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
+ ((limb) ((s32) in2[9])) * ((s32) in[8]);
+ output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
+}
+
+/* Reduce a long form to a short form by taking the input mod 2^255 - 19. */
+static void freduce_degree(limb *output) {
+ /* Each of these shifts and adds ends up multiplying the value by 19. */
+ output[8] += output[18] << 4;
+ output[8] += output[18] << 1;
+ output[8] += output[18];
+ output[7] += output[17] << 4;
+ output[7] += output[17] << 1;
+ output[7] += output[17];
+ output[6] += output[16] << 4;
+ output[6] += output[16] << 1;
+ output[6] += output[16];
+ output[5] += output[15] << 4;
+ output[5] += output[15] << 1;
+ output[5] += output[15];
+ output[4] += output[14] << 4;
+ output[4] += output[14] << 1;
+ output[4] += output[14];
+ output[3] += output[13] << 4;
+ output[3] += output[13] << 1;
+ output[3] += output[13];
+ output[2] += output[12] << 4;
+ output[2] += output[12] << 1;
+ output[2] += output[12];
+ output[1] += output[11] << 4;
+ output[1] += output[11] << 1;
+ output[1] += output[11];
+ output[0] += output[10] << 4;
+ output[0] += output[10] << 1;
+ output[0] += output[10];
+}
+
+#if (-1 & 3) != 3
+#error "This code only works on a two's complement system"
+#endif
+
+/* return v / 2^26, using only shifts and adds. */
+static inline limb
+div_by_2_26(const limb v)
+{
+ /* High word of v; no shift needed*/
+ const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
+ /* Set to all 1s if v was negative; else set to 0s. */
+ const int32_t sign = ((int32_t) highword) >> 31;
+ /* Set to 0x3ffffff if v was negative; else set to 0. */
+ const int32_t roundoff = ((uint32_t) sign) >> 6;
+ /* Should return v / (1<<26) */
+ return (v + roundoff) >> 26;
+}
+
+/* return v / (2^25), using only shifts and adds. */
+static inline limb
+div_by_2_25(const limb v)
+{
+ /* High word of v; no shift needed*/
+ const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
+ /* Set to all 1s if v was negative; else set to 0s. */
+ const int32_t sign = ((int32_t) highword) >> 31;
+ /* Set to 0x1ffffff if v was negative; else set to 0. */
+ const int32_t roundoff = ((uint32_t) sign) >> 7;
+ /* Should return v / (1<<25) */
+ return (v + roundoff) >> 25;
+}
+
+static inline s32
+div_s32_by_2_25(const s32 v)
+{
+ const s32 roundoff = ((uint32_t)(v >> 31)) >> 7;
+ return (v + roundoff) >> 25;
+}
+
+/* Reduce all coefficients of the short form input so that |x| < 2^26.
+ *
+ * On entry: |output[i]| < 2^62
+ */
+static void freduce_coefficients(limb *output) {
+ unsigned i;
+
+ output[10] = 0;
+
+ for (i = 0; i < 10; i += 2) {
+ limb over = div_by_2_26(output[i]);
+ output[i] -= over << 26;
+ output[i+1] += over;
+
+ over = div_by_2_25(output[i+1]);
+ output[i+1] -= over << 25;
+ output[i+2] += over;
+ }
+ /* Now |output[10]| < 2 ^ 38 and all other coefficients are reduced. */
+ output[0] += output[10] << 4;
+ output[0] += output[10] << 1;
+ output[0] += output[10];
+
+ output[10] = 0;
+
+ /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19 * 2^38
+ * So |over| will be no more than 77825 */
+ {
+ limb over = div_by_2_26(output[0]);
+ output[0] -= over << 26;
+ output[1] += over;
+ }
+
+ /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 77825
+ * So |over| will be no more than 1. */
+ {
+ /* output[1] fits in 32 bits, so we can use div_s32_by_2_25 here. */
+ s32 over32 = div_s32_by_2_25((s32) output[1]);
+ output[1] -= over32 << 25;
+ output[2] += over32;
+ }
+
+ /* Finally, output[0,1,3..9] are reduced, and output[2] is "nearly reduced":
+ * we have |output[2]| <= 2^26. This is good enough for all of our math,
+ * but it will require an extra freduce_coefficients before fcontract. */
+}
+
+/* A helpful wrapper around fproduct: output = in * in2.
+ *
+ * output must be distinct to both inputs. The output is reduced degree and
+ * reduced coefficient.
+ */
+static void
+fmul(limb *output, const limb *in, const limb *in2) {
+ limb t[19];
+ fproduct(t, in, in2);
+ freduce_degree(t);
+ freduce_coefficients(t);
+ memcpy(output, t, sizeof(limb) * 10);
+}
+
+static void fsquare_inner(limb *output, const limb *in) {
+ output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
+ output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
+ output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
+ ((limb) ((s32) in[0])) * ((s32) in[2]));
+ output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
+ ((limb) ((s32) in[0])) * ((s32) in[3]));
+ output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
+ 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
+ 2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
+ output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
+ ((limb) ((s32) in[1])) * ((s32) in[4]) +
+ ((limb) ((s32) in[0])) * ((s32) in[5]));
+ output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
+ ((limb) ((s32) in[2])) * ((s32) in[4]) +
+ ((limb) ((s32) in[0])) * ((s32) in[6]) +
+ 2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
+ output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
+ ((limb) ((s32) in[2])) * ((s32) in[5]) +
+ ((limb) ((s32) in[1])) * ((s32) in[6]) +
+ ((limb) ((s32) in[0])) * ((s32) in[7]));
+ output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
+ 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
+ ((limb) ((s32) in[0])) * ((s32) in[8]) +
+ 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
+ ((limb) ((s32) in[3])) * ((s32) in[5])));
+ output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
+ ((limb) ((s32) in[3])) * ((s32) in[6]) +
+ ((limb) ((s32) in[2])) * ((s32) in[7]) +
+ ((limb) ((s32) in[1])) * ((s32) in[8]) +
+ ((limb) ((s32) in[0])) * ((s32) in[9]));
+ output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
+ ((limb) ((s32) in[4])) * ((s32) in[6]) +
+ ((limb) ((s32) in[2])) * ((s32) in[8]) +
+ 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
+ ((limb) ((s32) in[1])) * ((s32) in[9])));
+ output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
+ ((limb) ((s32) in[4])) * ((s32) in[7]) +
+ ((limb) ((s32) in[3])) * ((s32) in[8]) +
+ ((limb) ((s32) in[2])) * ((s32) in[9]));
+ output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
+ 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
+ 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
+ ((limb) ((s32) in[3])) * ((s32) in[9])));
+ output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
+ ((limb) ((s32) in[5])) * ((s32) in[8]) +
+ ((limb) ((s32) in[4])) * ((s32) in[9]));
+ output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
+ ((limb) ((s32) in[6])) * ((s32) in[8]) +
+ 2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
+ output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
+ ((limb) ((s32) in[6])) * ((s32) in[9]));
+ output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
+ 4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
+ output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
+ output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
+}
+
+static void
+fsquare(limb *output, const limb *in) {
+ limb t[19];
+ fsquare_inner(t, in);
+ freduce_degree(t);
+ freduce_coefficients(t);
+ memcpy(output, t, sizeof(limb) * 10);
+}
+
+/* Take a little-endian, 32-byte number and expand it into polynomial form */
+static void
+fexpand(limb *output, const u8 *input) {
+#define F(n,start,shift,mask) \
+ output[n] = ((((limb) input[start + 0]) | \
+ ((limb) input[start + 1]) << 8 | \
+ ((limb) input[start + 2]) << 16 | \
+ ((limb) input[start + 3]) << 24) >> shift) & mask;
+ F(0, 0, 0, 0x3ffffff);
+ F(1, 3, 2, 0x1ffffff);
+ F(2, 6, 3, 0x3ffffff);
+ F(3, 9, 5, 0x1ffffff);
+ F(4, 12, 6, 0x3ffffff);
+ F(5, 16, 0, 0x1ffffff);
+ F(6, 19, 1, 0x3ffffff);
+ F(7, 22, 3, 0x1ffffff);
+ F(8, 25, 4, 0x3ffffff);
+ F(9, 28, 6, 0x1ffffff);
+#undef F
+}
+
+#if (-32 >> 1) != -16
+#error "This code only works when >> does sign-extension on negative numbers"
+#endif
+
+/* Take a fully reduced polynomial form number and contract it into a
+ * little-endian, 32-byte array
+ */
+static void
+fcontract(u8 *output, limb *input) {
+ int i;
+ int j;
+
+ for (j = 0; j < 2; ++j) {
+ for (i = 0; i < 9; ++i) {
+ if ((i & 1) == 1) {
+ /* This calculation is a time-invariant way to make input[i] positive
+ by borrowing from the next-larger limb.
+ */
+ const s32 mask = (s32)(input[i]) >> 31;
+ const s32 carry = -(((s32)(input[i]) & mask) >> 25);
+ input[i] = (s32)(input[i]) + (carry << 25);
+ input[i+1] = (s32)(input[i+1]) - carry;
+ } else {
+ const s32 mask = (s32)(input[i]) >> 31;
+ const s32 carry = -(((s32)(input[i]) & mask) >> 26);
+ input[i] = (s32)(input[i]) + (carry << 26);
+ input[i+1] = (s32)(input[i+1]) - carry;
+ }
+ }
+ {
+ const s32 mask = (s32)(input[9]) >> 31;
+ const s32 carry = -(((s32)(input[9]) & mask) >> 25);
+ input[9] = (s32)(input[9]) + (carry << 25);
+ input[0] = (s32)(input[0]) - (carry * 19);
+ }
+ }
+
+ /* The first borrow-propagation pass above ended with every limb
+ except (possibly) input[0] non-negative.
+
+ Since each input limb except input[0] is decreased by at most 1
+ by a borrow-propagation pass, the second borrow-propagation pass
+ could only have wrapped around to decrease input[0] again if the
+ first pass left input[0] negative *and* input[1] through input[9]
+ were all zero. In that case, input[1] is now 2^25 - 1, and this
+ last borrow-propagation step will leave input[1] non-negative.
+ */
+ {
+ const s32 mask = (s32)(input[0]) >> 31;
+ const s32 carry = -(((s32)(input[0]) & mask) >> 26);
+ input[0] = (s32)(input[0]) + (carry << 26);
+ input[1] = (s32)(input[1]) - carry;
+ }
+
+ /* Both passes through the above loop, plus the last 0-to-1 step, are
+ necessary: if input[9] is -1 and input[0] through input[8] are 0,
+ negative values will remain in the array until the end.
+ */
+
+ input[1] <<= 2;
+ input[2] <<= 3;
+ input[3] <<= 5;
+ input[4] <<= 6;
+ input[6] <<= 1;
+ input[7] <<= 3;
+ input[8] <<= 4;
+ input[9] <<= 6;
+#define F(i, s) \
+ output[s+0] |= input[i] & 0xff; \
+ output[s+1] = (input[i] >> 8) & 0xff; \
+ output[s+2] = (input[i] >> 16) & 0xff; \
+ output[s+3] = (input[i] >> 24) & 0xff;
+ output[0] = 0;
+ output[16] = 0;
+ F(0,0);
+ F(1,3);
+ F(2,6);
+ F(3,9);
+ F(4,12);
+ F(5,16);
+ F(6,19);
+ F(7,22);
+ F(8,25);
+ F(9,28);
+#undef F
+}
+
+/* Input: Q, Q', Q-Q'
+ * Output: 2Q, Q+Q'
+ *
+ * x2 z3: long form
+ * x3 z3: long form
+ * x z: short form, destroyed
+ * xprime zprime: short form, destroyed
+ * qmqp: short form, preserved
+ */
+static void fmonty(limb *x2, limb *z2, /* output 2Q */
+ limb *x3, limb *z3, /* output Q + Q' */
+ limb *x, limb *z, /* input Q */
+ limb *xprime, limb *zprime, /* input Q' */
+ const limb *qmqp /* input Q - Q' */) {
+ limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
+ zzprime[19], zzzprime[19], xxxprime[19];
+
+ memcpy(origx, x, 10 * sizeof(limb));
+ fsum(x, z);
+ fdifference(z, origx); // does x - z
+
+ memcpy(origxprime, xprime, sizeof(limb) * 10);
+ fsum(xprime, zprime);
+ fdifference(zprime, origxprime);
+ fproduct(xxprime, xprime, z);
+ fproduct(zzprime, x, zprime);
+ freduce_degree(xxprime);
+ freduce_coefficients(xxprime);
+ freduce_degree(zzprime);
+ freduce_coefficients(zzprime);
+ memcpy(origxprime, xxprime, sizeof(limb) * 10);
+ fsum(xxprime, zzprime);
+ fdifference(zzprime, origxprime);
+ fsquare(xxxprime, xxprime);
+ fsquare(zzzprime, zzprime);
+ fproduct(zzprime, zzzprime, qmqp);
+ freduce_degree(zzprime);
+ freduce_coefficients(zzprime);
+ memcpy(x3, xxxprime, sizeof(limb) * 10);
+ memcpy(z3, zzprime, sizeof(limb) * 10);
+
+ fsquare(xx, x);
+ fsquare(zz, z);
+ fproduct(x2, xx, zz);
+ freduce_degree(x2);
+ freduce_coefficients(x2);
+ fdifference(zz, xx); // does zz = xx - zz
+ memset(zzz + 10, 0, sizeof(limb) * 9);
+ fscalar_product(zzz, zz, 121665);
+ /* No need to call freduce_degree here:
+ fscalar_product doesn't increase the degree of its input. */
+ freduce_coefficients(zzz);
+ fsum(zzz, xx);
+ fproduct(z2, zz, zzz);
+ freduce_degree(z2);
+ freduce_coefficients(z2);
+}
+
+/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
+ * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
+ * side-channel attacks.
+ *
+ * NOTE that this function requires that 'iswap' be 1 or 0; other values give
+ * wrong results. Also, the two limb arrays must be in reduced-coefficient,
+ * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
+ * and all all values in a[0..9],b[0..9] must have magnitude less than
+ * INT32_MAX.
+ */
+static void
+swap_conditional(limb a[19], limb b[19], limb iswap) {
+ unsigned i;
+ const s32 swap = (s32) -iswap;
+
+ for (i = 0; i < 10; ++i) {
+ const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
+ a[i] = ((s32)a[i]) ^ x;
+ b[i] = ((s32)b[i]) ^ x;
+ }
+}
+
+/* Calculates nQ where Q is the x-coordinate of a point on the curve
+ *
+ * resultx/resultz: the x coordinate of the resulting curve point (short form)
+ * n: a little endian, 32-byte number
+ * q: a point of the curve (short form)
+ */
+static void
+cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
+ limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
+ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
+ limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
+ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
+
+ unsigned i, j;
+
+ memcpy(nqpqx, q, sizeof(limb) * 10);
+
+ for (i = 0; i < 32; ++i) {
+ u8 byte = n[31 - i];
+ for (j = 0; j < 8; ++j) {
+ const limb bit = byte >> 7;
+
+ swap_conditional(nqx, nqpqx, bit);
+ swap_conditional(nqz, nqpqz, bit);
+ fmonty(nqx2, nqz2,
+ nqpqx2, nqpqz2,
+ nqx, nqz,
+ nqpqx, nqpqz,
+ q);
+ swap_conditional(nqx2, nqpqx2, bit);
+ swap_conditional(nqz2, nqpqz2, bit);
+
+ t = nqx;
+ nqx = nqx2;
+ nqx2 = t;
+ t = nqz;
+ nqz = nqz2;
+ nqz2 = t;
+ t = nqpqx;
+ nqpqx = nqpqx2;
+ nqpqx2 = t;
+ t = nqpqz;
+ nqpqz = nqpqz2;
+ nqpqz2 = t;
+
+ byte <<= 1;
+ }
+ }
+
+ memcpy(resultx, nqx, sizeof(limb) * 10);
+ memcpy(resultz, nqz, sizeof(limb) * 10);
+}
+
+// -----------------------------------------------------------------------------
+// Shamelessly copied from djb's code
+// -----------------------------------------------------------------------------
+static void
+crecip(limb *out, const limb *z) {
+ limb z2[10];
+ limb z9[10];
+ limb z11[10];
+ limb z2_5_0[10];
+ limb z2_10_0[10];
+ limb z2_20_0[10];
+ limb z2_50_0[10];
+ limb z2_100_0[10];
+ limb t0[10];
+ limb t1[10];
+ int i;
+
+ /* 2 */ fsquare(z2,z);
+ /* 4 */ fsquare(t1,z2);
+ /* 8 */ fsquare(t0,t1);
+ /* 9 */ fmul(z9,t0,z);
+ /* 11 */ fmul(z11,z9,z2);
+ /* 22 */ fsquare(t0,z11);
+ /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
+
+ /* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
+ /* 2^7 - 2^2 */ fsquare(t1,t0);
+ /* 2^8 - 2^3 */ fsquare(t0,t1);
+ /* 2^9 - 2^4 */ fsquare(t1,t0);
+ /* 2^10 - 2^5 */ fsquare(t0,t1);
+ /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
+
+ /* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
+ /* 2^12 - 2^2 */ fsquare(t1,t0);
+ /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
+ /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
+
+ /* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
+ /* 2^22 - 2^2 */ fsquare(t1,t0);
+ /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
+ /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
+
+ /* 2^41 - 2^1 */ fsquare(t1,t0);
+ /* 2^42 - 2^2 */ fsquare(t0,t1);
+ /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
+ /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
+
+ /* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
+ /* 2^52 - 2^2 */ fsquare(t1,t0);
+ /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
+ /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
+
+ /* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
+ /* 2^102 - 2^2 */ fsquare(t0,t1);
+ /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
+ /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
+
+ /* 2^201 - 2^1 */ fsquare(t0,t1);
+ /* 2^202 - 2^2 */ fsquare(t1,t0);
+ /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
+ /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
+
+ /* 2^251 - 2^1 */ fsquare(t1,t0);
+ /* 2^252 - 2^2 */ fsquare(t0,t1);
+ /* 2^253 - 2^3 */ fsquare(t1,t0);
+ /* 2^254 - 2^4 */ fsquare(t0,t1);
+ /* 2^255 - 2^5 */ fsquare(t1,t0);
+ /* 2^255 - 21 */ fmul(out,t1,z11);
+}
+
+int curve25519_donna(u8 *, const u8 *, const u8 *);
+
+int
+curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
+ limb bp[10], x[10], z[11], zmone[10];
+ uint8_t e[32];
+ int i;
+
+ for (i = 0; i < 32; ++i) e[i] = secret[i];
+ e[0] &= 248;
+ e[31] &= 127;
+ e[31] |= 64;
+
+ fexpand(bp, basepoint);
+ cmult(x, z, e, bp);
+ crecip(zmone, z);
+ fmul(z, x, zmone);
+ freduce_coefficients(z);
+ fcontract(mypublic, z);
+ return 0;
+}
diff --git a/src/or/eventdns.c b/src/ext/eventdns.c
index 768693aba..66280cccd 100644
--- a/src/or/eventdns.c
+++ b/src/ext/eventdns.c
@@ -130,7 +130,7 @@ typedef int socklen_t;
#define mm_realloc(x,y) tor_realloc((x),(y))
#define mm_free(x) tor_free(x)
#define mm_strdup(x) tor_strdup(x)
-#define _mm_free(x) _tor_free(x)
+#define _mm_free(x) tor_free_(x)
#undef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
@@ -368,7 +368,11 @@ error_is_eagain(int err)
#define CLOSE_SOCKET(x) closesocket(x)
#else
#define last_error(sock) (errno)
+#if EAGAIN != EWOULDBLOCK
+#define error_is_eagain(err) ((err) == EAGAIN || (err) == EWOULDBLOCK)
+#else
#define error_is_eagain(err) ((err) == EAGAIN)
+#endif
#define CLOSE_SOCKET(x) close(x)
#endif
@@ -423,9 +427,9 @@ evdns_set_log_fn(evdns_debug_log_fn_type fn)
#define EVDNS_LOG_CHECK
#endif
-static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK;
+static void evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK;
static void
-_evdns_log(int warn, const char *fmt, ...)
+evdns_log(int warn, const char *fmt, ...)
{
va_list args;
static char buf[512];
@@ -442,8 +446,6 @@ _evdns_log(int warn, const char *fmt, ...)
va_end(args);
}
-#define log _evdns_log
-
static int
sockaddr_eq(const struct sockaddr *sa1, const struct sockaddr *sa2,
int include_port)
@@ -530,7 +532,7 @@ nameserver_probe_failed(struct nameserver *const ns) {
ns->failed_times++;
if (add_timeout_event(ns, (struct timeval *) timeout) < 0) {
- log(EVDNS_LOG_WARN,
+ evdns_log(EVDNS_LOG_WARN,
"Error from libevent when adding timer event for %s",
debug_ntop((struct sockaddr *)&ns->address));
/* ???? Do more? */
@@ -546,19 +548,19 @@ nameserver_failed(struct nameserver *const ns, const char *msg) {
/* then don't do anything */
if (!ns->state) return;
- log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s",
+ evdns_log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s",
debug_ntop((struct sockaddr *)&ns->address), msg);
global_good_nameservers--;
assert(global_good_nameservers >= 0);
if (global_good_nameservers == 0) {
- log(EVDNS_LOG_WARN, "All nameservers have failed");
+ evdns_log(EVDNS_LOG_WARN, "All nameservers have failed");
}
ns->state = 0;
ns->failed_times = 1;
if (add_timeout_event(ns, (struct timeval *) &global_nameserver_timeouts[0]) < 0) {
- log(EVDNS_LOG_WARN,
+ evdns_log(EVDNS_LOG_WARN,
"Error from libevent when adding timer event for %s",
debug_ntop((struct sockaddr *)&ns->address));
/* ???? Do more? */
@@ -589,7 +591,7 @@ nameserver_failed(struct nameserver *const ns, const char *msg) {
static void
nameserver_up(struct nameserver *const ns) {
if (ns->state) return;
- log(EVDNS_LOG_WARN, "Nameserver %s is back up",
+ evdns_log(EVDNS_LOG_WARN, "Nameserver %s is back up",
debug_ntop((struct sockaddr *)&ns->address));
del_timeout_event(ns);
ns->state = 1;
@@ -620,7 +622,7 @@ request_finished(struct evdns_request *const req, struct evdns_request **head) {
}
}
- log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx",
+ evdns_log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx",
(unsigned long) req);
del_timeout_event(req);
@@ -772,7 +774,7 @@ reply_handle(struct evdns_request *const req, u16 flags, u32 ttl, struct reply *
* confusing." Treat this as a timeout, not a failure.
*/
/*XXXX refactor the parts of */
- log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; "
+ evdns_log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; "
"will allow the request to time out.",
debug_ntop((struct sockaddr *)&req->ns->address));
break;
@@ -1264,7 +1266,7 @@ nameserver_read(struct nameserver *ns) {
}
/* XXX Match port too? */
if (!sockaddr_eq(sa, (struct sockaddr*)&ns->address, 0)) {
- log(EVDNS_LOG_WARN,
+ evdns_log(EVDNS_LOG_WARN,
"Address mismatch on received DNS packet. Address was %s",
debug_ntop(sa));
return;
@@ -1290,7 +1292,7 @@ server_port_read(struct evdns_server_port *s) {
if (r < 0) {
int err = last_error(s->socket);
if (error_is_eagain(err)) return;
- log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.",
+ evdns_log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.",
tor_socket_strerror(err), err);
return;
}
@@ -1310,7 +1312,7 @@ server_port_flush(struct evdns_server_port *port)
int err = last_error(port->socket);
if (error_is_eagain(err))
return;
- log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", tor_socket_strerror(err), err);
+ evdns_log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", tor_socket_strerror(err), err);
}
if (server_request_free(req)) {
/* we released the last reference to req->port. */
@@ -1327,7 +1329,7 @@ server_port_flush(struct evdns_server_port *port)
event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
server_port_ready_callback, port);
if (event_add(&port->event, NULL) < 0) {
- log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
+ evdns_log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
/* ???? Do more? */
}
}
@@ -1345,7 +1347,7 @@ nameserver_write_waiting(struct nameserver *ns, char waiting) {
event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
nameserver_ready_callback, ns);
if (event_add(&ns->event, NULL) < 0) {
- log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
+ evdns_log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
debug_ntop((struct sockaddr *)&ns->address));
/* ???? Do more? */
}
@@ -1855,7 +1857,7 @@ evdns_server_request_respond(struct evdns_server_request *_req, int err)
event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
if (event_add(&port->event, NULL) < 0) {
- log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
+ evdns_log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
}
}
@@ -1991,7 +1993,7 @@ evdns_request_timeout_callback(int fd, short events, void *arg) {
(void) fd;
(void) events;
- log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
+ evdns_log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
req->ns->timedout++;
if (req->ns->timedout > global_max_nameserver_timeout) {
@@ -2070,11 +2072,11 @@ evdns_request_transmit(struct evdns_request *req) {
* and make us retransmit the request anyway. */
default:
/* transmitted; we need to check for timeout. */
- log(EVDNS_LOG_DEBUG,
+ evdns_log(EVDNS_LOG_DEBUG,
"Setting timeout for request %lx", (unsigned long) req);
if (add_timeout_event(req, &global_timeout) < 0) {
- log(EVDNS_LOG_WARN,
+ evdns_log(EVDNS_LOG_WARN,
"Error from libevent when adding timer for request %lx",
(unsigned long) req);
/* ???? Do more? */
@@ -2122,7 +2124,7 @@ nameserver_send_probe(struct nameserver *const ns) {
addr = mm_malloc(sizeof(struct sockaddr_storage));
memcpy(addr, &ns->address, sizeof(struct sockaddr_storage));
- log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntop((struct sockaddr *)&ns->address));
+ evdns_log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntop((struct sockaddr *)&ns->address));
req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, addr);
if (!req) {
@@ -2278,14 +2280,14 @@ _evdns_nameserver_add_impl(const struct sockaddr *address,
if (server) {
do {
if (sockaddr_eq(address, (struct sockaddr *)&server->address, 1)) {
- log(EVDNS_LOG_DEBUG, "Duplicate nameserver.");
+ evdns_log(EVDNS_LOG_DEBUG, "Duplicate nameserver.");
return 3;
}
server = server->next;
} while (server != started_at);
}
if (addrlen > (int)sizeof(ns->address)) {
- log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
+ evdns_log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
return 2;
}
@@ -2304,21 +2306,26 @@ _evdns_nameserver_add_impl(const struct sockaddr *address,
ioctlsocket(ns->socket, FIONBIO, &nonblocking);
}
#else
- fcntl(ns->socket, F_SETFL, O_NONBLOCK);
+ if (fcntl(ns->socket, F_SETFL, O_NONBLOCK) == -1) {
+ evdns_log(EVDNS_LOG_WARN, "Error %s (%d) while settings file status flags.",
+ tor_socket_strerror(errno), errno);
+ err = 2;
+ goto out2;
+ }
#endif
if (global_bind_addr_is_set &&
!sockaddr_is_loopback((struct sockaddr*)&global_bind_address)) {
if (bind(ns->socket, (struct sockaddr *)&global_bind_address,
global_bind_addrlen) < 0) {
- log(EVDNS_LOG_DEBUG, "Couldn't bind to outgoing address.");
+ evdns_log(EVDNS_LOG_DEBUG, "Couldn't bind to outgoing address.");
err = 2;
goto out2;
}
}
if (connect(ns->socket, address, addrlen) != 0) {
- log(EVDNS_LOG_DEBUG, "Couldn't open socket to nameserver.");
+ evdns_log(EVDNS_LOG_DEBUG, "Couldn't open socket to nameserver.");
err = 2;
goto out2;
}
@@ -2327,12 +2334,12 @@ _evdns_nameserver_add_impl(const struct sockaddr *address,
ns->state = 1;
event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
if (event_add(&ns->event, NULL) < 0) {
- log(EVDNS_LOG_DEBUG, "Couldn't add event for nameserver.");
+ evdns_log(EVDNS_LOG_DEBUG, "Couldn't add event for nameserver.");
err = 2;
goto out2;
}
- log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntop(address));
+ evdns_log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntop(address));
/* insert this nameserver into the list of them */
if (!server_head) {
@@ -2356,7 +2363,7 @@ out2:
out1:
CLEAR(ns);
mm_free(ns);
- log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntop(address), err);
+ evdns_log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntop(address), err);
return err;
}
@@ -2389,18 +2396,18 @@ evdns_nameserver_ip_add(const char *ip_as_string) {
* ipv4
*/
- log(EVDNS_LOG_DEBUG, "Trying to add nameserver <%s>", ip_as_string);
+ evdns_log(EVDNS_LOG_DEBUG, "Trying to add nameserver <%s>", ip_as_string);
cp = strchr(ip_as_string, ':');
if (*ip_as_string == '[') {
size_t len;
if (!(cp = strchr(ip_as_string, ']'))) {
- log(EVDNS_LOG_DEBUG, "Nameserver missing closing ]");
+ evdns_log(EVDNS_LOG_DEBUG, "Nameserver missing closing ]");
return 4;
}
len = cp-(ip_as_string + 1);
if (len > sizeof(buf)-1) {
- log(EVDNS_LOG_DEBUG, "[Nameserver] does not fit in buffer.");
+ evdns_log(EVDNS_LOG_DEBUG, "[Nameserver] does not fit in buffer.");
return 4;
}
memcpy(buf, ip_as_string+1, len);
@@ -2418,7 +2425,7 @@ evdns_nameserver_ip_add(const char *ip_as_string) {
} else if (cp) {
is_ipv6 = 0;
if (cp - ip_as_string > (int)sizeof(buf)-1) {
- log(EVDNS_LOG_DEBUG, "Nameserver does not fit in buffer.");
+ evdns_log(EVDNS_LOG_DEBUG, "Nameserver does not fit in buffer.");
return 4;
}
memcpy(buf, ip_as_string, cp-ip_as_string);
@@ -2436,7 +2443,7 @@ evdns_nameserver_ip_add(const char *ip_as_string) {
} else {
port = strtoint(port_part);
if (port <= 0 || port > 65535) {
- log(EVDNS_LOG_DEBUG, "Nameserver port <%s> out of range",
+ evdns_log(EVDNS_LOG_DEBUG, "Nameserver port <%s> out of range",
port_part);
return 4;
}
@@ -2453,7 +2460,7 @@ evdns_nameserver_ip_add(const char *ip_as_string) {
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(port);
if (1 != tor_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr)) {
- log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part);
+ evdns_log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part);
return 4;
}
return _evdns_nameserver_add_impl((struct sockaddr*)&sin6,
@@ -2467,7 +2474,7 @@ evdns_nameserver_ip_add(const char *ip_as_string) {
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
if (!inet_aton(addr_part, &sin.sin_addr)) {
- log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part);
+ evdns_log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part);
return 4;
}
return _evdns_nameserver_add_impl((struct sockaddr*)&sin,
@@ -2590,7 +2597,7 @@ request_submit(struct evdns_request *const req) {
/* exported function */
int evdns_resolve_ipv4(const char *name, int flags,
evdns_callback_type callback, void *ptr) {
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+ evdns_log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
if (flags & DNS_QUERY_NO_SEARCH) {
struct evdns_request *const req =
request_new(TYPE_A, name, flags, callback, ptr);
@@ -2606,7 +2613,7 @@ int evdns_resolve_ipv4(const char *name, int flags,
/* exported function */
int evdns_resolve_ipv6(const char *name, int flags,
evdns_callback_type callback, void *ptr) {
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+ evdns_log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
if (flags & DNS_QUERY_NO_SEARCH) {
struct evdns_request *const req =
request_new(TYPE_AAAA, name, flags, callback, ptr);
@@ -2630,7 +2637,7 @@ int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_ty
(int)(u8)((a>>8 )&0xff),
(int)(u8)((a>>16)&0xff),
(int)(u8)((a>>24)&0xff));
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+ evdns_log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
req = request_new(TYPE_PTR, buf, flags, callback, ptr);
if (!req) return 1;
request_submit(req);
@@ -2654,7 +2661,7 @@ int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callb
}
assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+ evdns_log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
req = request_new(TYPE_PTR, buf, flags, callback, ptr);
if (!req) return 1;
request_submit(req);
@@ -2870,7 +2877,7 @@ search_try_next(struct evdns_request *const req) {
if (string_num_dots(req->search_origname) < req->search_state->ndots) {
/* yep, we need to try it raw */
struct evdns_request *const newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
- log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
+ evdns_log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
if (newreq) {
request_submit(newreq);
return 0;
@@ -2881,7 +2888,7 @@ search_try_next(struct evdns_request *const req) {
new_name = search_make_new(req->search_state, req->search_index, req->search_origname);
if (!new_name) return 1;
- log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
+ evdns_log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
mm_free(new_name);
if (!newreq) return 1;
@@ -2951,7 +2958,7 @@ evdns_set_option(const char *option, const char *val, int flags)
const int ndots = strtoint(val);
if (ndots == -1) return -1;
if (!(flags & DNS_OPTION_SEARCH)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
+ evdns_log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
if (!global_search_state) global_search_state = search_state_new();
if (!global_search_state) return -1;
global_search_state->ndots = ndots;
@@ -2959,20 +2966,20 @@ evdns_set_option(const char *option, const char *val, int flags)
const int timeout = strtoint(val);
if (timeout == -1) return -1;
if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout);
+ evdns_log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout);
global_timeout.tv_sec = timeout;
} else if (!strncmp(option, "max-timeouts:", 12)) {
const int maxtimeout = strtoint_clipped(val, 1, 255);
if (maxtimeout == -1) return -1;
if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
+ evdns_log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
maxtimeout);
global_max_nameserver_timeout = maxtimeout;
} else if (!strncmp(option, "max-inflight:", 13)) {
const int maxinflight = strtoint_clipped(val, 1, 65000);
if (maxinflight == -1) return -1;
if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
+ evdns_log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
maxinflight);
global_max_requests_inflight = maxinflight;
} else if (!strncmp(option, "attempts:", 9)) {
@@ -2980,12 +2987,12 @@ evdns_set_option(const char *option, const char *val, int flags)
if (retries == -1) return -1;
if (retries > 255) retries = 255;
if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
+ evdns_log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
global_max_retransmits = retries;
} else if (!strncmp(option, "randomize-case:", 15)) {
int randcase = strtoint(val);
if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting randomize_case to %d", randcase);
+ evdns_log(EVDNS_LOG_DEBUG, "Setting randomize_case to %d", randcase);
global_randomize_case = randcase;
}
return 0;
@@ -3043,7 +3050,7 @@ evdns_resolv_conf_parse(int flags, const char *const filename) {
char *start;
int err = 0;
- log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
+ evdns_log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
fd = tor_open_cloexec(filename, O_RDONLY, 0);
if (fd < 0) {
@@ -3142,13 +3149,13 @@ load_nameservers_with_getnetworkparams(void)
GetNetworkParams_fn_t fn;
if (!(handle = load_windows_system_library(TEXT("iphlpapi.dll")))) {
- log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
+ evdns_log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
/* right now status = 0, doesn't that mean "good" - mikec */
status = -1;
goto done;
}
if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, TEXT("GetNetworkParams")))) {
- log(EVDNS_LOG_WARN, "Could not get address of function.");
+ evdns_log(EVDNS_LOG_WARN, "Could not get address of function.");
/* same as above */
status = -1;
goto done;
@@ -3169,7 +3176,7 @@ load_nameservers_with_getnetworkparams(void)
fixed = buf;
r = fn(fixed, &size);
if (r != ERROR_SUCCESS) {
- log(EVDNS_LOG_DEBUG, "fn() failed.");
+ evdns_log(EVDNS_LOG_DEBUG, "fn() failed.");
status = -1;
goto done;
}
@@ -3181,12 +3188,12 @@ load_nameservers_with_getnetworkparams(void)
while (ns) {
r = evdns_nameserver_ip_add_line(ns->IpAddress.String);
if (r) {
- log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list, "
+ evdns_log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list, "
"error: %d; status: %d",
(ns->IpAddress.String),(int)GetLastError(), r);
status = r;
} else {
- log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
+ evdns_log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
added_any++;
}
@@ -3194,7 +3201,7 @@ load_nameservers_with_getnetworkparams(void)
}
if (!added_any) {
- log(EVDNS_LOG_DEBUG, "No nameservers added.");
+ evdns_log(EVDNS_LOG_DEBUG, "No nameservers added.");
if (status == 0)
status = -1;
} else {
@@ -3250,10 +3257,10 @@ load_nameservers_from_registry(void)
#define TRY(k, name) \
if (!found && config_nameserver_from_reg_key(k,TEXT(name)) == 0) { \
- log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
+ evdns_log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
found = 1; \
} else if (!found) { \
- log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
+ evdns_log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
#k,#name); \
}
@@ -3262,14 +3269,14 @@ load_nameservers_from_registry(void)
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
KEY_READ, &nt_key) != ERROR_SUCCESS) {
- log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
+ evdns_log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
return -1;
}
r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0,
KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
&interfaces_key);
if (r != ERROR_SUCCESS) {
- log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
+ evdns_log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
return -1;
}
TRY(nt_key, "NameServer");
@@ -3282,7 +3289,7 @@ load_nameservers_from_registry(void)
HKEY win_key = 0;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
KEY_READ, &win_key) != ERROR_SUCCESS) {
- log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
+ evdns_log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
return -1;
}
TRY(win_key, "NameServer");
@@ -3290,7 +3297,7 @@ load_nameservers_from_registry(void)
}
if (found == 0) {
- log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
+ evdns_log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
}
return found ? 0 : -1;
diff --git a/src/or/eventdns.h b/src/ext/eventdns.h
index 1c130b2a1..ad8c100dd 100644
--- a/src/or/eventdns.h
+++ b/src/ext/eventdns.h
@@ -209,8 +209,8 @@
* with the next probe.
*/
-#ifndef _TOR_EVENTDNS_H
-#define _TOR_EVENTDNS_H
+#ifndef TOR_EVENTDNS_H
+#define TOR_EVENTDNS_H
/* Error codes 0-5 are as described in RFC 1035. */
#define DNS_ERR_NONE 0
diff --git a/src/common/ht.h b/src/ext/ht.h
index 25156c416..62c458ad0 100644
--- a/src/common/ht.h
+++ b/src/ext/ht.h
@@ -1,12 +1,12 @@
/* Copyright (c) 2002, Christopher Clark.
* Copyright (c) 2005-2006, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See license at end. */
/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
-#ifndef _TOR_HT_H
-#define _TOR_HT_H
+#ifndef HT_H_INCLUDED_
+#define HT_H_INCLUDED_
#define HT_HEAD(name, type) \
struct name { \
@@ -168,7 +168,7 @@ ht_string_hash(const char *s)
} \
/* Insert the element 'elm' into the table 'head'. Do not call this \
* function if the table might already contain a matching element. */ \
- static INLINE void \
+ ATTR_UNUSED static INLINE void \
name##_HT_INSERT(struct name *head, struct type *elm) \
{ \
struct type **p; \
@@ -183,7 +183,7 @@ ht_string_hash(const char *s)
/* Insert the element 'elm' into the table 'head'. If there already \
* a matching element in the table, replace that element and return \
* it. */ \
- static INLINE struct type * \
+ ATTR_UNUSED static INLINE struct type * \
name##_HT_REPLACE(struct name *head, struct type *elm) \
{ \
struct type **p, *r; \
@@ -204,7 +204,7 @@ ht_string_hash(const char *s)
} \
/* Remove any element matching 'elm' from the table 'head'. If such \
* an element is found, return it; otherwise return NULL. */ \
- static INLINE struct type * \
+ ATTR_UNUSED static INLINE struct type * \
name##_HT_REMOVE(struct name *head, struct type *elm) \
{ \
struct type **p, *r; \
@@ -222,11 +222,11 @@ ht_string_hash(const char *s)
* using 'data' as its second argument. If the function returns \
* nonzero, remove the most recently examined element before invoking \
* the function again. */ \
- static INLINE void \
+ ATTR_UNUSED static INLINE void \
name##_HT_FOREACH_FN(struct name *head, \
int (*fn)(struct type *, void *), \
void *data) \
- { \
+{ \
unsigned idx; \
struct type **p, **nextp, *next; \
if (!head->hth_table) \
@@ -248,7 +248,7 @@ ht_string_hash(const char *s)
/* Return a pointer to the first element in the table 'head', under \
* an arbitrary order. This order is stable under remove operations, \
* but not under others. If the table is empty, return NULL. */ \
- static INLINE struct type ** \
+ ATTR_UNUSED static INLINE struct type ** \
name##_HT_START(struct name *head) \
{ \
unsigned b = 0; \
@@ -264,7 +264,7 @@ ht_string_hash(const char *s)
* NULL. If 'elm' is to be removed from the table, you must call \
* this function for the next value before you remove it. \
*/ \
- static INLINE struct type ** \
+ ATTR_UNUSED static INLINE struct type ** \
name##_HT_NEXT(struct name *head, struct type **elm) \
{ \
if ((*elm)->field.hte_next) { \
@@ -280,7 +280,7 @@ ht_string_hash(const char *s)
return NULL; \
} \
} \
- static INLINE struct type ** \
+ ATTR_UNUSED static INLINE struct type ** \
name##_HT_NEXT_RMV(struct name *head, struct type **elm) \
{ \
unsigned h = HT_ELT_HASH_(*elm, field, hashfn); \
diff --git a/src/ext/include.am b/src/ext/include.am
new file mode 100644
index 000000000..ea7e58e79
--- /dev/null
+++ b/src/ext/include.am
@@ -0,0 +1,17 @@
+
+AM_CPPFLAGS += -I$(srcdir)/src/ext -Isrc/ext
+
+EXTRA_DIST += src/ext/README
+
+EXTHEADERS = \
+ src/ext/ht.h \
+ src/ext/eventdns.h \
+ src/ext/tinytest.h \
+ src/ext/strlcat.c \
+ src/ext/strlcpy.c \
+ src/ext/tinytest_macros.h \
+ src/ext/tor_queue.h
+
+noinst_HEADERS+= $(EXTHEADERS)
+
+
diff --git a/src/common/strlcat.c b/src/ext/strlcat.c
index 316733bcc..316733bcc 100644
--- a/src/common/strlcat.c
+++ b/src/ext/strlcat.c
diff --git a/src/common/strlcpy.c b/src/ext/strlcpy.c
index 9fc47903a..9fc47903a 100644
--- a/src/common/strlcpy.c
+++ b/src/ext/strlcpy.c
diff --git a/src/test/tinytest.c b/src/ext/tinytest.c
index 4d9afacce..4d9afacce 100644
--- a/src/test/tinytest.c
+++ b/src/ext/tinytest.c
diff --git a/src/test/tinytest.h b/src/ext/tinytest.h
index bcac9f079..bcac9f079 100644
--- a/src/test/tinytest.h
+++ b/src/ext/tinytest.h
diff --git a/src/test/tinytest_demo.c b/src/ext/tinytest_demo.c
index be95ce4c1..be95ce4c1 100644
--- a/src/test/tinytest_demo.c
+++ b/src/ext/tinytest_demo.c
diff --git a/src/test/tinytest_macros.h b/src/ext/tinytest_macros.h
index 9ff69b1d5..9ff69b1d5 100644
--- a/src/test/tinytest_macros.h
+++ b/src/ext/tinytest_macros.h
diff --git a/src/ext/tor_queue.h b/src/ext/tor_queue.h
new file mode 100644
index 000000000..f05e48c18
--- /dev/null
+++ b/src/ext/tor_queue.h
@@ -0,0 +1,568 @@
+/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef TOR_QUEUE_H_
+#define TOR_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
+#define TOR_Q_INVALIDATE_(a) (a) = ((void *)-1)
+#else
+#define TOR_Q_INVALIDATE_(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define TOR_SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define TOR_SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define TOR_SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define TOR_SLIST_FIRST(head) ((head)->slh_first)
+#define TOR_SLIST_END(head) NULL
+#define TOR_SLIST_EMPTY(head) (SLIST_FIRST(head) == TOR_SLIST_END(head))
+#define TOR_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define TOR_SLIST_FOREACH(var, head, field) \
+ for((var) = TOR_SLIST_FIRST(head); \
+ (var) != TOR_SLIST_END(head); \
+ (var) = TOR_SLIST_NEXT(var, field))
+
+#define TOR_SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TOR_SLIST_FIRST(head); \
+ (var) && ((tvar) = TOR_SLIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define TOR_SLIST_INIT(head) { \
+ TOR_SLIST_FIRST(head) = TOR_SLIST_END(head); \
+}
+
+#define TOR_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define TOR_SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define TOR_SLIST_REMOVE_AFTER(elm, field) do { \
+ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
+} while (0)
+
+#define TOR_SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+#define TOR_SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ TOR_SLIST_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->slh_first; \
+ \
+ while (curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ TOR_Q_INVALIDATE_((elm)->field.sle_next); \
+ } \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define TOR_LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define TOR_LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define TOR_LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods
+ */
+#define TOR_LIST_FIRST(head) ((head)->lh_first)
+#define TOR_LIST_END(head) NULL
+#define TOR_LIST_EMPTY(head) (TOR_LIST_FIRST(head) == TOR_LIST_END(head))
+#define TOR_LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define TOR_LIST_FOREACH(var, head, field) \
+ for((var) = TOR_LIST_FIRST(head); \
+ (var)!= TOR_LIST_END(head); \
+ (var) = TOR_LIST_NEXT(var, field))
+
+#define TOR_LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TOR_LIST_FIRST(head); \
+ (var) && ((tvar) = TOR_LIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * List functions.
+ */
+#define TOR_LIST_INIT(head) do { \
+ TOR_LIST_FIRST(head) = TOR_LIST_END(head); \
+} while (0)
+
+#define TOR_LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define TOR_LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define TOR_LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define TOR_LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ TOR_Q_INVALIDATE_((elm)->field.le_prev); \
+ TOR_Q_INVALIDATE_((elm)->field.le_next); \
+} while (0)
+
+#define TOR_LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ TOR_Q_INVALIDATE_((elm)->field.le_prev); \
+ TOR_Q_INVALIDATE_((elm)->field.le_next); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define TOR_SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define TOR_SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define TOR_SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define TOR_SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define TOR_SIMPLEQ_END(head) NULL
+#define TOR_SIMPLEQ_EMPTY(head) (TOR_SIMPLEQ_FIRST(head) == TOR_SIMPLEQ_END(head))
+#define TOR_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define TOR_SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = TOR_SIMPLEQ_FIRST(head); \
+ (var) != TOR_SIMPLEQ_END(head); \
+ (var) = TOR_SIMPLEQ_NEXT(var, field))
+
+#define TOR_SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TOR_SIMPLEQ_FIRST(head); \
+ (var) && ((tvar) = TOR_SIMPLEQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Simple queue functions.
+ */
+#define TOR_SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define TOR_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define TOR_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define TOR_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define TOR_SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define TOR_SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+ == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TOR_TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TOR_TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TOR_TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * tail queue access methods
+ */
+#define TOR_TAILQ_FIRST(head) ((head)->tqh_first)
+#define TOR_TAILQ_END(head) NULL
+#define TOR_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TOR_TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TOR_TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TOR_TAILQ_EMPTY(head) \
+ (TOR_TAILQ_FIRST(head) == TOR_TAILQ_END(head))
+
+#define TOR_TAILQ_FOREACH(var, head, field) \
+ for((var) = TOR_TAILQ_FIRST(head); \
+ (var) != TOR_TAILQ_END(head); \
+ (var) = TOR_TAILQ_NEXT(var, field))
+
+#define TOR_TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TOR_TAILQ_FIRST(head); \
+ (var) != TOR_TAILQ_END(head) && \
+ ((tvar) = TOR_TAILQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+
+#define TOR_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TOR_TAILQ_LAST(head, headname); \
+ (var) != TOR_TAILQ_END(head); \
+ (var) = TOR_TAILQ_PREV(var, headname, field))
+
+#define TOR_TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TOR_TAILQ_LAST(head, headname); \
+ (var) != TOR_TAILQ_END(head) && \
+ ((tvar) = TOR_TAILQ_PREV(var, headname, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Tail queue functions.
+ */
+#define TOR_TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TOR_TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TOR_TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TOR_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TOR_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TOR_TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ TOR_Q_INVALIDATE_((elm)->field.tqe_prev); \
+ TOR_Q_INVALIDATE_((elm)->field.tqe_next); \
+} while (0)
+
+#define TOR_TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ TOR_Q_INVALIDATE_((elm)->field.tqe_prev); \
+ TOR_Q_INVALIDATE_((elm)->field.tqe_next); \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define TOR_CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define TOR_CIRCLEQ_HEAD_INITIALIZER(head) \
+ { TOR_CIRCLEQ_END(&head), TOR_CIRCLEQ_END(&head) }
+
+#define TOR_CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define TOR_CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define TOR_CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define TOR_CIRCLEQ_END(head) ((void *)(head))
+#define TOR_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define TOR_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+#define TOR_CIRCLEQ_EMPTY(head) \
+ (TOR_CIRCLEQ_FIRST(head) == TOR_CIRCLEQ_END(head))
+
+#define TOR_CIRCLEQ_FOREACH(var, head, field) \
+ for((var) = TOR_CIRCLEQ_FIRST(head); \
+ (var) != TOR_CIRCLEQ_END(head); \
+ (var) = TOR_CIRCLEQ_NEXT(var, field))
+
+#define TOR_CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TOR_CIRCLEQ_FIRST(head); \
+ (var) != TOR_CIRCLEQ_END(head) && \
+ ((tvar) = TOR_CIRCLEQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+#define TOR_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for((var) = TOR_CIRCLEQ_LAST(head); \
+ (var) != TOR_CIRCLEQ_END(head); \
+ (var) = TOR_CIRCLEQ_PREV(var, field))
+
+#define TOR_CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TOR_CIRCLEQ_LAST(head, headname); \
+ (var) != TOR_CIRCLEQ_END(head) && \
+ ((tvar) = TOR_CIRCLEQ_PREV(var, headname, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Circular queue functions.
+ */
+#define TOR_CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = TOR_CIRCLEQ_END(head); \
+ (head)->cqh_last = TOR_CIRCLEQ_END(head); \
+} while (0)
+
+#define TOR_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == TOR_CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (0)
+
+#define TOR_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == TOR_CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (0)
+
+#define TOR_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = TOR_CIRCLEQ_END(head); \
+ if ((head)->cqh_last == TOR_CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (0)
+
+#define TOR_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = TOR_CIRCLEQ_END(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == TOR_CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (0)
+
+#define TOR_CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == TOR_CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == TOR_CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+ TOR_Q_INVALIDATE_((elm)->field.cqe_prev); \
+ TOR_Q_INVALIDATE_((elm)->field.cqe_next); \
+} while (0)
+
+#define TOR_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
+ TOR_CIRCLEQ_END(head)) \
+ (head).cqh_last = (elm2); \
+ else \
+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
+ TOR_CIRCLEQ_END(head)) \
+ (head).cqh_first = (elm2); \
+ else \
+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
+ TOR_Q_INVALIDATE_((elm)->field.cqe_prev); \
+ TOR_Q_INVALIDATE_((elm)->field.cqe_next); \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/src/ext/tor_queue.txt b/src/ext/tor_queue.txt
new file mode 100644
index 000000000..f284e7192
--- /dev/null
+++ b/src/ext/tor_queue.txt
@@ -0,0 +1,883 @@
+Below follows the manpage for tor_queue.h, as included with OpenBSD's
+sys/queue.h. License follows at the end of the file.
+
+======================================================================
+QUEUE(3) OpenBSD Programmer's Manual QUEUE(3)
+
+NAME
+ SLIST_ENTRY, SLIST_HEAD, SLIST_HEAD_INITIALIZER, SLIST_FIRST, SLIST_NEXT,
+ SLIST_END, SLIST_EMPTY, SLIST_FOREACH, SLIST_FOREACH_SAFE, SLIST_INIT,
+ SLIST_INSERT_AFTER, SLIST_INSERT_HEAD, SLIST_REMOVE_AFTER,
+ SLIST_REMOVE_HEAD, SLIST_REMOVE, LIST_ENTRY, LIST_HEAD,
+ LIST_HEAD_INITIALIZER, LIST_FIRST, LIST_NEXT, LIST_END, LIST_EMPTY,
+ LIST_FOREACH, LIST_FOREACH_SAFE, LIST_INIT, LIST_INSERT_AFTER,
+ LIST_INSERT_BEFORE, LIST_INSERT_HEAD, LIST_REMOVE, LIST_REPLACE,
+ SIMPLEQ_ENTRY, SIMPLEQ_HEAD, SIMPLEQ_HEAD_INITIALIZER, SIMPLEQ_FIRST,
+ SIMPLEQ_NEXT, SIMPLEQ_END, SIMPLEQ_EMPTY, SIMPLEQ_FOREACH,
+ SIMPLEQ_FOREACH_SAFE, SIMPLEQ_INIT, SIMPLEQ_INSERT_AFTER,
+ SIMPLEQ_INSERT_HEAD, SIMPLEQ_INSERT_TAIL, SIMPLEQ_REMOVE_AFTER,
+ SIMPLEQ_REMOVE_HEAD, TAILQ_ENTRY, TAILQ_HEAD, TAILQ_HEAD_INITIALIZER,
+ TAILQ_FIRST, TAILQ_NEXT, TAILQ_END, TAILQ_LAST, TAILQ_PREV, TAILQ_EMPTY,
+ TAILQ_FOREACH, TAILQ_FOREACH_SAFE, TAILQ_FOREACH_REVERSE,
+ TAILQ_FOREACH_REVERSE_SAFE, TAILQ_INIT, TAILQ_INSERT_AFTER,
+ TAILQ_INSERT_BEFORE, TAILQ_INSERT_HEAD, TAILQ_INSERT_TAIL, TAILQ_REMOVE,
+ TAILQ_REPLACE, CIRCLEQ_ENTRY, CIRCLEQ_HEAD, CIRCLEQ_HEAD_INITIALIZER,
+ CIRCLEQ_FIRST, CIRCLEQ_LAST, CIRCLEQ_END, CIRCLEQ_NEXT, CIRCLEQ_PREV,
+ CIRCLEQ_EMPTY, CIRCLEQ_FOREACH, CIRCLEQ_FOREACH_SAFE,
+ CIRCLEQ_FOREACH_REVERSE_SAFE, CIRCLEQ_INIT, CIRCLEQ_INSERT_AFTER,
+ CIRCLEQ_INSERT_BEFORE, CIRCLEQ_INSERT_HEAD, CIRCLEQ_INSERT_TAIL,
+ CIRCLEQ_REMOVE, CIRCLEQ_REPLACE - implementations of singly-linked lists,
+ doubly-linked lists, simple queues, tail queues, and circular queues
+
+SYNOPSIS
+ #include <sys/queue.h>
+
+ SLIST_ENTRY(TYPE);
+
+ SLIST_HEAD(HEADNAME, TYPE);
+
+ SLIST_HEAD_INITIALIZER(SLIST_HEAD head);
+
+ struct TYPE *
+ SLIST_FIRST(SLIST_HEAD *head);
+
+ struct TYPE *
+ SLIST_NEXT(struct TYPE *listelm, SLIST_ENTRY NAME);
+
+ struct TYPE *
+ SLIST_END(SLIST_HEAD *head);
+
+ int
+ SLIST_EMPTY(SLIST_HEAD *head);
+
+ SLIST_FOREACH(VARNAME, SLIST_HEAD *head, SLIST_ENTRY NAME);
+
+ SLIST_FOREACH_SAFE(VARNAME, SLIST_HEAD *head, SLIST_ENTRY
+ NAME, TEMP_VARNAME);
+
+ void
+ SLIST_INIT(SLIST_HEAD *head);
+
+ void
+ SLIST_INSERT_AFTER(struct TYPE *listelm, struct TYPE *elm, SLIST_ENTRY
+ NAME);
+
+ void
+ SLIST_INSERT_HEAD(SLIST_HEAD *head, struct TYPE *elm, SLIST_ENTRY NAME);
+
+ void
+ SLIST_REMOVE_AFTER(struct TYPE *elm, SLIST_ENTRY NAME);
+
+ void
+ SLIST_REMOVE_HEAD(SLIST_HEAD *head, SLIST_ENTRY NAME);
+
+ void
+ SLIST_REMOVE(SLIST_HEAD *head, struct TYPE *elm, TYPE, SLIST_ENTRY NAME);
+
+ LIST_ENTRY(TYPE);
+
+ LIST_HEAD(HEADNAME, TYPE);
+
+ LIST_HEAD_INITIALIZER(LIST_HEAD head);
+
+ struct TYPE *
+ LIST_FIRST(LIST_HEAD *head);
+
+ struct TYPE *
+ LIST_NEXT(struct TYPE *listelm, LIST_ENTRY NAME);
+
+ struct TYPE *
+ LIST_END(LIST_HEAD *head);
+
+ int
+ LIST_EMPTY(LIST_HEAD *head);
+
+ LIST_FOREACH(VARNAME, LIST_HEAD *head, LIST_ENTRY NAME);
+
+ LIST_FOREACH_SAFE(VARNAME, LIST_HEAD *head, LIST_ENTRY
+ NAME, TEMP_VARNAME);
+
+ void
+ LIST_INIT(LIST_HEAD *head);
+
+ void
+ LIST_INSERT_AFTER(struct TYPE *listelm, struct TYPE *elm, LIST_ENTRY
+ NAME);
+
+ void
+ LIST_INSERT_BEFORE(struct TYPE *listelm, struct TYPE *elm, LIST_ENTRY
+ NAME);
+
+ void
+ LIST_INSERT_HEAD(LIST_HEAD *head, struct TYPE *elm, LIST_ENTRY NAME);
+
+ void
+ LIST_REMOVE(struct TYPE *elm, LIST_ENTRY NAME);
+
+ void
+ LIST_REPLACE(struct TYPE *elm, struct TYPE *elm2, LIST_ENTRY NAME);
+
+ SIMPLEQ_ENTRY(TYPE);
+
+ SIMPLEQ_HEAD(HEADNAME, TYPE);
+
+ SIMPLEQ_HEAD_INITIALIZER(SIMPLEQ_HEAD head);
+
+ struct TYPE *
+ SIMPLEQ_FIRST(SIMPLEQ_HEAD *head);
+
+ struct TYPE *
+ SIMPLEQ_NEXT(struct TYPE *listelm, SIMPLEQ_ENTRY NAME);
+
+ struct TYPE *
+ SIMPLEQ_END(SIMPLEQ_HEAD *head);
+
+ int
+ SIMPLEQ_EMPTY(SIMPLEQ_HEAD *head);
+
+ SIMPLEQ_FOREACH(VARNAME, SIMPLEQ_HEAD *head, SIMPLEQ_ENTRY NAME);
+
+ SIMPLEQ_FOREACH_SAFE(VARNAME, SIMPLEQ_HEAD *head, SIMPLEQ_ENTRY
+ NAME, TEMP_VARNAME);
+
+ void
+ SIMPLEQ_INIT(SIMPLEQ_HEAD *head);
+
+ void
+ SIMPLEQ_INSERT_AFTER(SIMPLEQ_HEAD *head, struct TYPE *listelm, struct
+ TYPE *elm, SIMPLEQ_ENTRY NAME);
+
+ void
+ SIMPLEQ_INSERT_HEAD(SIMPLEQ_HEAD *head, struct TYPE *elm, SIMPLEQ_ENTRY
+ NAME);
+
+ void
+ SIMPLEQ_INSERT_TAIL(SIMPLEQ_HEAD *head, struct TYPE *elm, SIMPLEQ_ENTRY
+ NAME);
+
+ void
+ SIMPLEQ_REMOVE_AFTER(SIMPLEQ_HEAD *head, struct TYPE *elm, SIMPLEQ_ENTRY
+ NAME);
+
+ void
+ SIMPLEQ_REMOVE_HEAD(SIMPLEQ_HEAD *head, SIMPLEQ_ENTRY NAME);
+
+ TAILQ_ENTRY(TYPE);
+
+ TAILQ_HEAD(HEADNAME, TYPE);
+
+ TAILQ_HEAD_INITIALIZER(TAILQ_HEAD head);
+
+ struct TYPE *
+ TAILQ_FIRST(TAILQ_HEAD *head);
+
+ struct TYPE *
+ TAILQ_NEXT(struct TYPE *listelm, TAILQ_ENTRY NAME);
+
+ struct TYPE *
+ TAILQ_END(TAILQ_HEAD *head);
+
+ struct TYPE *
+ TAILQ_LAST(TAILQ_HEAD *head, HEADNAME NAME);
+
+ struct TYPE *
+ TAILQ_PREV(struct TYPE *listelm, HEADNAME NAME, TAILQ_ENTRY NAME);
+
+ int
+ TAILQ_EMPTY(TAILQ_HEAD *head);
+
+ TAILQ_FOREACH(VARNAME, TAILQ_HEAD *head, TAILQ_ENTRY NAME);
+
+ TAILQ_FOREACH_SAFE(VARNAME, TAILQ_HEAD *head, TAILQ_ENTRY
+ NAME, TEMP_VARNAME);
+
+ TAILQ_FOREACH_REVERSE(VARNAME, TAILQ_HEAD *head, HEADNAME, TAILQ_ENTRY
+ NAME);
+
+ TAILQ_FOREACH_REVERSE_SAFE(VARNAME, TAILQ_HEAD
+ *head, HEADNAME, TAILQ_ENTRY NAME, TEMP_VARNAME);
+
+ void
+ TAILQ_INIT(TAILQ_HEAD *head);
+
+ void
+ TAILQ_INSERT_AFTER(TAILQ_HEAD *head, struct TYPE *listelm, struct TYPE
+ *elm, TAILQ_ENTRY NAME);
+
+ void
+ TAILQ_INSERT_BEFORE(struct TYPE *listelm, struct TYPE *elm, TAILQ_ENTRY
+ NAME);
+
+ void
+ TAILQ_INSERT_HEAD(TAILQ_HEAD *head, struct TYPE *elm, TAILQ_ENTRY NAME);
+
+ void
+ TAILQ_INSERT_TAIL(TAILQ_HEAD *head, struct TYPE *elm, TAILQ_ENTRY NAME);
+
+ void
+ TAILQ_REMOVE(TAILQ_HEAD *head, struct TYPE *elm, TAILQ_ENTRY NAME);
+
+ void
+ TAILQ_REPLACE(TAILQ_HEAD *head, struct TYPE *elm, struct TYPE
+ *elm2, TAILQ_ENTRY NAME);
+
+ CIRCLEQ_ENTRY(TYPE);
+
+ CIRCLEQ_HEAD(HEADNAME, TYPE);
+
+ CIRCLEQ_HEAD_INITIALIZER(CIRCLEQ_HEAD head);
+
+ struct TYPE *
+ CIRCLEQ_FIRST(CIRCLEQ_HEAD *head);
+
+ struct TYPE *
+ CIRCLEQ_LAST(CIRCLEQ_HEAD *head);
+
+ struct TYPE *
+ CIRCLEQ_END(CIRCLEQ_HEAD *head);
+
+ struct TYPE *
+ CIRCLEQ_NEXT(struct TYPE *listelm, CIRCLEQ_ENTRY NAME);
+
+ struct TYPE *
+ CIRCLEQ_PREV(struct TYPE *listelm, CIRCLEQ_ENTRY NAME);
+
+ int
+ CIRCLEQ_EMPTY(CIRCLEQ_HEAD *head);
+
+ CIRCLEQ_FOREACH(VARNAME, CIRCLEQ_HEAD *head, CIRCLEQ_ENTRY NAME);
+
+ CIRCLEQ_FOREACH_SAFE(VARNAME, CIRCLEQ_HEAD *head, CIRCLEQ_ENTRY
+ NAME, TEMP_VARNAME);
+
+ CIRCLEQ_FOREACH_REVERSE(VARNAME, CIRCLEQ_HEAD *head, CIRCLEQ_ENTRY NAME);
+
+ CIRCLEQ_FOREACH_REVERSE_SAFE(VARNAME, CIRCLEQ_HEAD *head, CIRCLEQ_ENTRY
+ NAME, TEMP_VARNAME);
+
+ void
+ CIRCLEQ_INIT(CIRCLEQ_HEAD *head);
+
+ void
+ CIRCLEQ_INSERT_AFTER(CIRCLEQ_HEAD *head, struct TYPE *listelm, struct
+ TYPE *elm, CIRCLEQ_ENTRY NAME);
+
+ void
+ CIRCLEQ_INSERT_BEFORE(CIRCLEQ_HEAD *head, struct TYPE *listelm, struct
+ TYPE *elm, CIRCLEQ_ENTRY NAME);
+
+ void
+ CIRCLEQ_INSERT_HEAD(CIRCLEQ_HEAD *head, struct TYPE *elm, CIRCLEQ_ENTRY
+ NAME);
+
+ void
+ CIRCLEQ_INSERT_TAIL(CIRCLEQ_HEAD *head, struct TYPE *elm, CIRCLEQ_ENTRY
+ NAME);
+
+ void
+ CIRCLEQ_REMOVE(CIRCLEQ_HEAD *head, struct TYPE *elm, CIRCLEQ_ENTRY NAME);
+
+ void
+ CIRCLEQ_REPLACE(CIRCLEQ_HEAD *head, struct TYPE *elm, struct TYPE
+ *elm2, CIRCLEQ_ENTRY NAME);
+
+DESCRIPTION
+ These macros define and operate on five types of data structures: singly-
+ linked lists, simple queues, lists, tail queues, and circular queues.
+ All five structures support the following functionality:
+
+ 1. Insertion of a new entry at the head of the list.
+ 2. Insertion of a new entry after any element in the list.
+ 3. Removal of an entry from the head of the list.
+ 4. Forward traversal through the list.
+
+ Singly-linked lists are the simplest of the five data structures and
+ support only the above functionality. Singly-linked lists are ideal for
+ applications with large datasets and few or no removals, or for
+ implementing a LIFO queue.
+
+ Simple queues add the following functionality:
+
+ 1. Entries can be added at the end of a list.
+
+ However:
+
+ 1. All list insertions must specify the head of the list.
+ 2. Each head entry requires two pointers rather than one.
+ 3. Code size is about 15% greater and operations run about 20%
+ slower than singly-linked lists.
+
+ Simple queues are ideal for applications with large datasets and few or
+ no removals, or for implementing a FIFO queue.
+
+ All doubly linked types of data structures (lists, tail queues, and
+ circle queues) additionally allow:
+
+ 1. Insertion of a new entry before any element in the list.
+ 2. Removal of any entry in the list.
+
+ However:
+
+ 1. Each element requires two pointers rather than one.
+ 2. Code size and execution time of operations (except for
+ removal) is about twice that of the singly-linked data-
+ structures.
+
+ Lists are the simplest of the doubly linked data structures and support
+ only the above functionality over singly-linked lists.
+
+ Tail queues add the following functionality:
+
+ 1. Entries can be added at the end of a list.
+ 2. They may be traversed backwards, at a cost.
+
+ However:
+
+ 1. All list insertions and removals must specify the head of the
+ list.
+ 2. Each head entry requires two pointers rather than one.
+ 3. Code size is about 15% greater and operations run about 20%
+ slower than singly-linked lists.
+
+ Circular queues add the following functionality:
+
+ 1. Entries can be added at the end of a list.
+ 2. They may be traversed backwards, from tail to head.
+
+ However:
+
+ 1. All list insertions and removals must specify the head of the
+ list.
+ 2. Each head entry requires two pointers rather than one.
+ 3. The termination condition for traversal is more complex.
+ 4. Code size is about 40% greater and operations run about 45%
+ slower than lists.
+
+ In the macro definitions, TYPE is the name tag of a user defined
+ structure that must contain a field of type SLIST_ENTRY, LIST_ENTRY,
+ SIMPLEQ_ENTRY, TAILQ_ENTRY, or CIRCLEQ_ENTRY, named NAME. The argument
+ HEADNAME is the name tag of a user defined structure that must be
+ declared using the macros SLIST_HEAD(), LIST_HEAD(), SIMPLEQ_HEAD(),
+ TAILQ_HEAD(), or CIRCLEQ_HEAD(). See the examples below for further
+ explanation of how these macros are used.
+
+SINGLY-LINKED LISTS
+ A singly-linked list is headed by a structure defined by the SLIST_HEAD()
+ macro. This structure contains a single pointer to the first element on
+ the list. The elements are singly linked for minimum space and pointer
+ manipulation overhead at the expense of O(n) removal for arbitrary
+ elements. New elements can be added to the list after an existing
+ element or at the head of the list. A SLIST_HEAD structure is declared
+ as follows:
+
+ SLIST_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the list. A pointer
+ to the head of the list can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The HEADNAME facility is often not used, leading to the following bizarre
+ code:
+
+ SLIST_HEAD(, TYPE) head, *headp;
+
+ The SLIST_ENTRY() macro declares a structure that connects the elements
+ in the list.
+
+ The SLIST_INIT() macro initializes the list referenced by head.
+
+ The list can also be initialized statically by using the
+ SLIST_HEAD_INITIALIZER() macro like this:
+
+ SLIST_HEAD(HEADNAME, TYPE) head = SLIST_HEAD_INITIALIZER(head);
+
+ The SLIST_INSERT_HEAD() macro inserts the new element elm at the head of
+ the list.
+
+ The SLIST_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The SLIST_REMOVE_HEAD() macro removes the first element of the list
+ pointed by head.
+
+ The SLIST_REMOVE_AFTER() macro removes the list element immediately
+ following elm.
+
+ The SLIST_REMOVE() macro removes the element elm of the list pointed by
+ head.
+
+ The SLIST_FIRST() and SLIST_NEXT() macros can be used to traverse the
+ list:
+
+ for (np = SLIST_FIRST(&head); np != NULL; np = SLIST_NEXT(np, NAME))
+
+ Or, for simplicity, one can use the SLIST_FOREACH() macro:
+
+ SLIST_FOREACH(np, head, NAME)
+
+ The macro SLIST_FOREACH_SAFE() traverses the list referenced by head in a
+ forward direction, assigning each element in turn to var. However,
+ unlike SLIST_FOREACH() it is permitted to remove var as well as free it
+ from within the loop safely without interfering with the traversal.
+
+ The SLIST_EMPTY() macro should be used to check whether a simple list is
+ empty.
+
+SINGLY-LINKED LIST EXAMPLE
+ SLIST_HEAD(listhead, entry) head;
+ struct entry {
+ ...
+ SLIST_ENTRY(entry) entries; /* Simple list. */
+ ...
+ } *n1, *n2, *np;
+
+ SLIST_INIT(&head); /* Initialize simple list. */
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ SLIST_INSERT_HEAD(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ SLIST_INSERT_AFTER(n1, n2, entries);
+
+ SLIST_FOREACH(np, &head, entries) /* Forward traversal. */
+ np-> ...
+
+ while (!SLIST_EMPTY(&head)) { /* Delete. */
+ n1 = SLIST_FIRST(&head);
+ SLIST_REMOVE_HEAD(&head, entries);
+ free(n1);
+ }
+
+
+LISTS
+ A list is headed by a structure defined by the LIST_HEAD() macro. This
+ structure contains a single pointer to the first element on the list.
+ The elements are doubly linked so that an arbitrary element can be
+ removed without traversing the list. New elements can be added to the
+ list after an existing element, before an existing element, or at the
+ head of the list. A LIST_HEAD structure is declared as follows:
+
+ LIST_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the list. A pointer
+ to the head of the list can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The HEADNAME facility is often not used, leading to the following bizarre
+ code:
+
+ LIST_HEAD(, TYPE) head, *headp;
+
+ The LIST_ENTRY() macro declares a structure that connects the elements in
+ the list.
+
+ The LIST_INIT() macro initializes the list referenced by head.
+
+ The list can also be initialized statically by using the
+ LIST_HEAD_INITIALIZER() macro like this:
+
+ LIST_HEAD(HEADNAME, TYPE) head = LIST_HEAD_INITIALIZER(head);
+
+ The LIST_INSERT_HEAD() macro inserts the new element elm at the head of
+ the list.
+
+ The LIST_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The LIST_INSERT_BEFORE() macro inserts the new element elm before the
+ element listelm.
+
+ The LIST_REMOVE() macro removes the element elm from the list.
+
+ The LIST_REPLACE() macro replaces the list element elm with the new
+ element elm2.
+
+ The LIST_FIRST() and LIST_NEXT() macros can be used to traverse the list:
+
+ for (np = LIST_FIRST(&head); np != NULL; np = LIST_NEXT(np, NAME))
+
+ Or, for simplicity, one can use the LIST_FOREACH() macro:
+
+ LIST_FOREACH(np, head, NAME)
+
+ The macro LIST_FOREACH_SAFE() traverses the list referenced by head in a
+ forward direction, assigning each element in turn to var. However,
+ unlike LIST_FOREACH() it is permitted to remove var as well as free it
+ from within the loop safely without interfering with the traversal.
+
+ The LIST_EMPTY() macro should be used to check whether a list is empty.
+
+LIST EXAMPLE
+ LIST_HEAD(listhead, entry) head;
+ struct entry {
+ ...
+ LIST_ENTRY(entry) entries; /* List. */
+ ...
+ } *n1, *n2, *np;
+
+ LIST_INIT(&head); /* Initialize list. */
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ LIST_INSERT_HEAD(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ LIST_INSERT_AFTER(n1, n2, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert before. */
+ LIST_INSERT_BEFORE(n1, n2, entries);
+ /* Forward traversal. */
+ LIST_FOREACH(np, &head, entries)
+ np-> ...
+
+ while (!LIST_EMPTY(&head)) /* Delete. */
+ n1 = LIST_FIRST(&head);
+ LIST_REMOVE(n1, entries);
+ free(n1);
+ }
+
+SIMPLE QUEUES
+ A simple queue is headed by a structure defined by the SIMPLEQ_HEAD()
+ macro. This structure contains a pair of pointers, one to the first
+ element in the simple queue and the other to the last element in the
+ simple queue. The elements are singly linked. New elements can be added
+ to the queue after an existing element, at the head of the queue or at
+ the tail of the queue. A SIMPLEQ_HEAD structure is declared as follows:
+
+ SIMPLEQ_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the queue. A pointer
+ to the head of the queue can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The SIMPLEQ_ENTRY() macro declares a structure that connects the elements
+ in the queue.
+
+ The SIMPLEQ_INIT() macro initializes the queue referenced by head.
+
+ The queue can also be initialized statically by using the
+ SIMPLEQ_HEAD_INITIALIZER() macro like this:
+
+ SIMPLEQ_HEAD(HEADNAME, TYPE) head = SIMPLEQ_HEAD_INITIALIZER(head);
+
+ The SIMPLEQ_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The SIMPLEQ_INSERT_HEAD() macro inserts the new element elm at the head
+ of the queue.
+
+ The SIMPLEQ_INSERT_TAIL() macro inserts the new element elm at the end of
+ the queue.
+
+ The SIMPLEQ_REMOVE_AFTER() macro removes the queue element immediately
+ following elm.
+
+ The SIMPLEQ_REMOVE_HEAD() macro removes the first element from the queue.
+
+ The SIMPLEQ_FIRST() and SIMPLEQ_NEXT() macros can be used to traverse the
+ queue. The SIMPLEQ_FOREACH() is used for queue traversal:
+
+ SIMPLEQ_FOREACH(np, head, NAME)
+
+ The macro SIMPLEQ_FOREACH_SAFE() traverses the queue referenced by head
+ in a forward direction, assigning each element in turn to var. However,
+ unlike SIMPLEQ_FOREACH() it is permitted to remove var as well as free it
+ from within the loop safely without interfering with the traversal.
+
+ The SIMPLEQ_EMPTY() macro should be used to check whether a list is
+ empty.
+
+SIMPLE QUEUE EXAMPLE
+ SIMPLEQ_HEAD(listhead, entry) head = SIMPLEQ_HEAD_INITIALIZER(head);
+ struct entry {
+ ...
+ SIMPLEQ_ENTRY(entry) entries; /* Simple queue. */
+ ...
+ } *n1, *n2, *np;
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ SIMPLEQ_INSERT_HEAD(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ SIMPLEQ_INSERT_AFTER(&head, n1, n2, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert at the tail. */
+ SIMPLEQ_INSERT_TAIL(&head, n2, entries);
+ /* Forward traversal. */
+ SIMPLEQ_FOREACH(np, &head, entries)
+ np-> ...
+ /* Delete. */
+ while (!SIMPLEQ_EMPTY(&head)) {
+ n1 = SIMPLEQ_FIRST(&head);
+ SIMPLEQ_REMOVE_HEAD(&head, entries);
+ free(n1);
+ }
+
+TAIL QUEUES
+ A tail queue is headed by a structure defined by the TAILQ_HEAD() macro.
+ This structure contains a pair of pointers, one to the first element in
+ the tail queue and the other to the last element in the tail queue. The
+ elements are doubly linked so that an arbitrary element can be removed
+ without traversing the tail queue. New elements can be added to the
+ queue after an existing element, before an existing element, at the head
+ of the queue, or at the end of the queue. A TAILQ_HEAD structure is
+ declared as follows:
+
+ TAILQ_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the tail queue. A
+ pointer to the head of the tail queue can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The TAILQ_ENTRY() macro declares a structure that connects the elements
+ in the tail queue.
+
+ The TAILQ_INIT() macro initializes the tail queue referenced by head.
+
+ The tail queue can also be initialized statically by using the
+ TAILQ_HEAD_INITIALIZER() macro.
+
+ The TAILQ_INSERT_HEAD() macro inserts the new element elm at the head of
+ the tail queue.
+
+ The TAILQ_INSERT_TAIL() macro inserts the new element elm at the end of
+ the tail queue.
+
+ The TAILQ_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The TAILQ_INSERT_BEFORE() macro inserts the new element elm before the
+ element listelm.
+
+ The TAILQ_REMOVE() macro removes the element elm from the tail queue.
+
+ The TAILQ_REPLACE() macro replaces the list element elm with the new
+ element elm2.
+
+ TAILQ_FOREACH() and TAILQ_FOREACH_REVERSE() are used for traversing a
+ tail queue. TAILQ_FOREACH() starts at the first element and proceeds
+ towards the last. TAILQ_FOREACH_REVERSE() starts at the last element and
+ proceeds towards the first.
+
+ TAILQ_FOREACH(np, &head, NAME)
+ TAILQ_FOREACH_REVERSE(np, &head, HEADNAME, NAME)
+
+ The macros TAILQ_FOREACH_SAFE() and TAILQ_FOREACH_REVERSE_SAFE() traverse
+ the list referenced by head in a forward or reverse direction
+ respectively, assigning each element in turn to var. However, unlike
+ their unsafe counterparts, they permit both the removal of var as well as
+ freeing it from within the loop safely without interfering with the
+ traversal.
+
+ The TAILQ_FIRST(), TAILQ_NEXT(), TAILQ_LAST() and TAILQ_PREV() macros can
+ be used to manually traverse a tail queue or an arbitrary part of one.
+
+ The TAILQ_EMPTY() macro should be used to check whether a tail queue is
+ empty.
+
+TAIL QUEUE EXAMPLE
+ TAILQ_HEAD(tailhead, entry) head;
+ struct entry {
+ ...
+ TAILQ_ENTRY(entry) entries; /* Tail queue. */
+ ...
+ } *n1, *n2, *np;
+
+ TAILQ_INIT(&head); /* Initialize queue. */
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ TAILQ_INSERT_HEAD(&head, n1, entries);
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the tail. */
+ TAILQ_INSERT_TAIL(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ TAILQ_INSERT_AFTER(&head, n1, n2, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert before. */
+ TAILQ_INSERT_BEFORE(n1, n2, entries);
+ /* Forward traversal. */
+ TAILQ_FOREACH(np, &head, entries)
+ np-> ...
+ /* Manual forward traversal. */
+ for (np = n2; np != NULL; np = TAILQ_NEXT(np, entries))
+ np-> ...
+ /* Delete. */
+ while ((np = TAILQ_FIRST(&head))) {
+ TAILQ_REMOVE(&head, np, entries);
+ free(np);
+ }
+
+
+CIRCULAR QUEUES
+ A circular queue is headed by a structure defined by the CIRCLEQ_HEAD()
+ macro. This structure contains a pair of pointers, one to the first
+ element in the circular queue and the other to the last element in the
+ circular queue. The elements are doubly linked so that an arbitrary
+ element can be removed without traversing the queue. New elements can be
+ added to the queue after an existing element, before an existing element,
+ at the head of the queue, or at the end of the queue. A CIRCLEQ_HEAD
+ structure is declared as follows:
+
+ CIRCLEQ_HEAD(HEADNAME, TYPE) head;
+
+ where HEADNAME is the name of the structure to be defined, and struct
+ TYPE is the type of the elements to be linked into the circular queue. A
+ pointer to the head of the circular queue can later be declared as:
+
+ struct HEADNAME *headp;
+
+ (The names head and headp are user selectable.)
+
+ The CIRCLEQ_ENTRY() macro declares a structure that connects the elements
+ in the circular queue.
+
+ The CIRCLEQ_INIT() macro initializes the circular queue referenced by
+ head.
+
+ The circular queue can also be initialized statically by using the
+ CIRCLEQ_HEAD_INITIALIZER() macro.
+
+ The CIRCLEQ_INSERT_HEAD() macro inserts the new element elm at the head
+ of the circular queue.
+
+ The CIRCLEQ_INSERT_TAIL() macro inserts the new element elm at the end of
+ the circular queue.
+
+ The CIRCLEQ_INSERT_AFTER() macro inserts the new element elm after the
+ element listelm.
+
+ The CIRCLEQ_INSERT_BEFORE() macro inserts the new element elm before the
+ element listelm.
+
+ The CIRCLEQ_REMOVE() macro removes the element elm from the circular
+ queue.
+
+ The CIRCLEQ_REPLACE() macro replaces the list element elm with the new
+ element elm2.
+
+ The CIRCLEQ_FIRST(), CIRCLEQ_LAST(), CIRCLEQ_END(), CIRCLEQ_NEXT() and
+ CIRCLEQ_PREV() macros can be used to traverse a circular queue. The
+ CIRCLEQ_FOREACH() is used for circular queue forward traversal:
+
+ CIRCLEQ_FOREACH(np, head, NAME)
+
+ The CIRCLEQ_FOREACH_REVERSE() macro acts like CIRCLEQ_FOREACH() but
+ traverses the circular queue backwards.
+
+ The macros CIRCLEQ_FOREACH_SAFE() and CIRCLEQ_FOREACH_REVERSE_SAFE()
+ traverse the list referenced by head in a forward or reverse direction
+ respectively, assigning each element in turn to var. However, unlike
+ their unsafe counterparts, they permit both the removal of var as well as
+ freeing it from within the loop safely without interfering with the
+ traversal.
+
+ The CIRCLEQ_EMPTY() macro should be used to check whether a circular
+ queue is empty.
+
+CIRCULAR QUEUE EXAMPLE
+ CIRCLEQ_HEAD(circleq, entry) head;
+ struct entry {
+ ...
+ CIRCLEQ_ENTRY(entry) entries; /* Circular queue. */
+ ...
+ } *n1, *n2, *np;
+
+ CIRCLEQ_INIT(&head); /* Initialize circular queue. */
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
+ CIRCLEQ_INSERT_HEAD(&head, n1, entries);
+
+ n1 = malloc(sizeof(struct entry)); /* Insert at the tail. */
+ CIRCLEQ_INSERT_TAIL(&head, n1, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert after. */
+ CIRCLEQ_INSERT_AFTER(&head, n1, n2, entries);
+
+ n2 = malloc(sizeof(struct entry)); /* Insert before. */
+ CIRCLEQ_INSERT_BEFORE(&head, n1, n2, entries);
+ /* Forward traversal. */
+ CIRCLEQ_FOREACH(np, &head, entries)
+ np-> ...
+ /* Reverse traversal. */
+ CIRCLEQ_FOREACH_REVERSE(np, &head, entries)
+ np-> ...
+ /* Delete. */
+ while (!CIRCLEQ_EMPTY(&head)) {
+ n1 = CIRCLEQ_FIRST(&head);
+ CIRCLEQ_REMOVE(&head, n1, entries);
+ free(n1);
+ }
+
+NOTES
+ It is an error to assume the next and previous fields are preserved after
+ an element has been removed from a list or queue. Using any macro
+ (except the various forms of insertion) on an element removed from a list
+ or queue is incorrect. An example of erroneous usage is removing the
+ same element twice.
+
+ The SLIST_END(), LIST_END(), SIMPLEQ_END() and TAILQ_END() macros are
+ provided for symmetry with CIRCLEQ_END(). They expand to NULL and don't
+ serve any useful purpose.
+
+ Trying to free a list in the following way is a common error:
+
+ LIST_FOREACH(var, head, entry)
+ free(var);
+ free(head);
+
+ Since var is free'd, the FOREACH macros refer to a pointer that may have
+ been reallocated already. A similar situation occurs when the current
+ element is deleted from the list. In cases like these the data
+ structure's FOREACH_SAFE macros should be used instead.
+
+HISTORY
+ The queue functions first appeared in 4.4BSD.
+
+OpenBSD 5.0 April 11, 2012 OpenBSD 5.0
+======================================================================
+.\" $OpenBSD: queue.3,v 1.56 2012/04/11 13:29:14 naddy Exp $
+.\" $NetBSD: queue.3,v 1.4 1995/07/03 00:25:36 mycroft Exp $
+.\"
+.\" Copyright (c) 1993 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+
diff --git a/src/include.am b/src/include.am
new file mode 100644
index 000000000..d0693e25b
--- /dev/null
+++ b/src/include.am
@@ -0,0 +1,7 @@
+include src/ext/include.am
+include src/common/include.am
+include src/or/include.am
+include src/test/include.am
+include src/tools/include.am
+include src/win32/include.am
+include src/config/include.am
diff --git a/src/or/Makefile.am b/src/or/Makefile.am
deleted file mode 100644
index 3cc789a1b..000000000
--- a/src/or/Makefile.am
+++ /dev/null
@@ -1,158 +0,0 @@
-bin_PROGRAMS = tor
-noinst_LIBRARIES = libtor.a
-
-if BUILD_NT_SERVICES
-tor_platform_source=ntmain.c
-else
-tor_platform_source=
-endif
-
-EXTRA_DIST=ntmain.c or_sha1.i Makefile.nmake
-
-if USE_EXTERNAL_EVDNS
-evdns_source=
-else
-evdns_source=eventdns.c
-endif
-
-libtor_a_SOURCES = \
- buffers.c \
- circuitbuild.c \
- circuitlist.c \
- circuituse.c \
- command.c \
- config.c \
- connection.c \
- connection_edge.c \
- connection_or.c \
- control.c \
- cpuworker.c \
- directory.c \
- dirserv.c \
- dirvote.c \
- dns.c \
- dnsserv.c \
- geoip.c \
- hibernate.c \
- main.c \
- microdesc.c \
- networkstatus.c \
- nodelist.c \
- onion.c \
- transports.c \
- policies.c \
- reasons.c \
- relay.c \
- rendclient.c \
- rendcommon.c \
- rendmid.c \
- rendservice.c \
- rephist.c \
- router.c \
- routerlist.c \
- routerparse.c \
- status.c \
- $(evdns_source) \
- $(tor_platform_source) \
- config_codedigest.c
-
-#libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
-# ../common/libor-event.a
-
-
-tor_SOURCES = tor_main.c
-
-AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
- -DLOCALSTATEDIR="\"$(localstatedir)\"" \
- -DBINDIR="\"$(bindir)\""
-
-# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
-# This seems to matter nowhere but on windows, but I assure you that it
-# matters a lot there, and is quite hard to debug if you forget to do it.
-
-
-tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
-tor_LDADD = ./libtor.a ../common/libor.a ../common/libor-crypto.a \
- ../common/libor-event.a \
- @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-noinst_HEADERS = \
- buffers.h \
- circuitbuild.h \
- circuitlist.h \
- circuituse.h \
- command.h \
- config.h \
- connection.h \
- connection_edge.h \
- connection_or.h \
- control.h \
- cpuworker.h \
- directory.h \
- dirserv.h \
- dirvote.h \
- dns.h \
- dnsserv.h \
- eventdns.h \
- eventdns_tor.h \
- geoip.h \
- hibernate.h \
- main.h \
- microdesc.h \
- networkstatus.h \
- nodelist.h \
- ntmain.h \
- onion.h \
- or.h \
- transports.h \
- policies.h \
- reasons.h \
- relay.h \
- rendclient.h \
- rendcommon.h \
- rendmid.h \
- rendservice.h \
- rephist.h \
- router.h \
- routerlist.h \
- routerparse.h \
- status.h \
- micro-revision.i
-
-config_codedigest.o: or_sha1.i
-
-tor_main.o: micro-revision.i
-
-micro-revision.i: FORCE
- @rm -f micro-revision.tmp; \
- if test -d "$(top_srcdir)/.git" && \
- test -x "`which git 2>&1;true`"; then \
- HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \
- echo \"$$HASH\" > micro-revision.tmp; \
- fi; \
- if test ! -f micro-revision.tmp ; then \
- if test ! -f micro-revision.i ; then \
- echo '""' > micro-revision.i; \
- fi; \
- elif test ! -f micro-revision.i || \
- test x"`cat micro-revision.tmp`" != x"`cat micro-revision.i`"; then \
- mv micro-revision.tmp micro-revision.i; \
- fi; true
-
-or_sha1.i: $(tor_SOURCES) $(libtor_a_SOURCES)
- if test "@SHA1SUM@" != none; then \
- (cd "$(srcdir)" && "@SHA1SUM@" $(tor_SOURCES) $(libtor_a_SOURCES)) | \
- "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > or_sha1.i; \
- elif test "@OPENSSL@" != none; then \
- (cd "$(srcdir)" && "@OPENSSL@" sha1 $(tor_SOURCES) $(libtor_a_SOURCES)) | \
- "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > or_sha1.i; \
- else \
- rm or_sha1.i; \
- touch or_sha1.i; \
- fi
-
-CLEANFILES = micro-revision.i
-
-#Dummy target to ensure that micro-revision.i _always_ gets built.
-FORCE:
diff --git a/src/or/Makefile.nmake b/src/or/Makefile.nmake
index 3181e79c2..3b627b1d0 100644
--- a/src/or/Makefile.nmake
+++ b/src/or/Makefile.nmake
@@ -1,28 +1,75 @@
all: tor.exe
-CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common
+CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common \
+ /I ..\ext
-LIBS = ..\..\..\build-alpha\lib\libevent.a \
- ..\..\..\build-alpha\lib\libcrypto.a \
- ..\..\..\build-alpha\lib\libssl.a \
- ..\..\..\build-alpha\lib\libz.a \
- ws2_32.lib advapi32.lib shell32.lib
+LIBS = ..\..\..\build-alpha\lib\libevent.lib \
+ ..\..\..\build-alpha\lib\libcrypto.lib \
+ ..\..\..\build-alpha\lib\libssl.lib \
+ ..\..\..\build-alpha\lib\libz.lib \
+ ws2_32.lib advapi32.lib shell32.lib \
+ crypt32.lib gdi32.lib user32.lib
-LIBTOR_OBJECTS = buffers.obj circuitbuild.obj circuitlist.obj circuituse.obj \
- command.obj config.obj connection.obj connection_edge.obj \
- connection_or.obj control.obj cpuworker.obj directory.obj \
- dirserv.obj dirvote.obj dns.obj dnsserv.obj geoip.obj \
- hibernate.obj main.obj microdesc.obj networkstatus.obj \
- nodelist.obj onion.obj policies.obj reasons.obj relay.obj \
- rendclient.obj rendcommon.obj rendmid.obj rendservice.obj \
- rephist.obj router.obj routerlist.obj routerparse.obj status.obj \
- config_codedigest.obj ntmain.obj
+LIBTOR_OBJECTS = \
+ addressmap.obj \
+ buffers.obj \
+ channel.obj \
+ channeltls.obj \
+ circuitbuild.obj \
+ circuitlist.obj \
+ circuitmux.obj \
+ circuitmux_ewma.obj \
+ circuitstats.obj \
+ circuituse.obj \
+ command.obj \
+ config.obj \
+ config_codedigest.obj \
+ confparse.obj \
+ connection.obj \
+ connection_edge.obj \
+ connection_or.obj \
+ control.obj \
+ cpuworker.obj \
+ directory.obj \
+ dirserv.obj \
+ dirvote.obj \
+ dns.obj \
+ dnsserv.obj \
+ fp_pair.obj \
+ entrynodes.obj \
+ geoip.obj \
+ hibernate.obj \
+ main.obj \
+ microdesc.obj \
+ networkstatus.obj \
+ nodelist.obj \
+ ntmain.obj \
+ onion.obj \
+ onion_fast.obj \
+ onion_ntor.obj \
+ onion_tap.obj \
+ policies.obj \
+ reasons.obj \
+ relay.obj \
+ rendclient.obj \
+ rendcommon.obj \
+ rendmid.obj \
+ rendservice.obj \
+ rephist.obj \
+ replaycache.obj \
+ router.obj \
+ routerlist.obj \
+ routerparse.obj \
+ routerset.obj \
+ statefile.obj \
+ status.obj \
+ transports.obj
libtor.lib: $(LIBTOR_OBJECTS)
- lib $(LIBTOR_OBJECTS) /out:libtor.lib
+ lib $(LIBTOR_OBJECTS) /out:$@
tor.exe: libtor.lib tor_main.obj
- $(CC) $(CFLAGS) $(LIBS) libtor.lib ..\common\*.lib tor_main.obj
+ $(CC) $(CFLAGS) $(LIBS) libtor.lib ..\common\*.lib tor_main.obj /Fe$@
clean:
del $(LIBTOR_OBJECTS) *.lib tor.exe
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
new file mode 100644
index 000000000..79e4b7c5e
--- /dev/null
+++ b/src/or/addressmap.c
@@ -0,0 +1,1078 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define ADDRESSMAP_PRIVATE
+
+#include "or.h"
+#include "addressmap.h"
+#include "circuituse.h"
+#include "config.h"
+#include "connection_edge.h"
+#include "control.h"
+#include "dns.h"
+#include "routerset.h"
+#include "nodelist.h"
+
+/** A client-side struct to remember requests to rewrite addresses
+ * to new addresses. These structs are stored in the hash table
+ * "addressmap" below.
+ *
+ * There are 5 ways to set an address mapping:
+ * - A MapAddress command from the controller [permanent]
+ * - An AddressMap directive in the torrc [permanent]
+ * - When a TrackHostExits torrc directive is triggered [temporary]
+ * - When a DNS resolve succeeds [temporary]
+ * - When a DNS resolve fails [temporary]
+ *
+ * When an addressmap request is made but one is already registered,
+ * the new one is replaced only if the currently registered one has
+ * no "new_address" (that is, it's in the process of DNS resolve),
+ * or if the new one is permanent (expires==0 or 1).
+ *
+ * (We overload the 'expires' field, using "0" for mappings set via
+ * the configuration file, "1" for mappings set from the control
+ * interface, and other values for DNS and TrackHostExit mappings that can
+ * expire.)
+ *
+ * A mapping may be 'wildcarded'. If "src_wildcard" is true, then
+ * any address that ends with a . followed by the key for this entry will
+ * get remapped by it. If "dst_wildcard" is also true, then only the
+ * matching suffix of such addresses will get replaced by new_address.
+ */
+typedef struct {
+ char *new_address;
+ time_t expires;
+ ENUM_BF(addressmap_entry_source_t) source:3;
+ unsigned src_wildcard:1;
+ unsigned dst_wildcard:1;
+ short num_resolve_failures;
+} addressmap_entry_t;
+
+/** Entry for mapping addresses to which virtual address we mapped them to. */
+typedef struct {
+ char *ipv4_address;
+ char *ipv6_address;
+ char *hostname_address;
+} virtaddress_entry_t;
+
+/** A hash table to store client-side address rewrite instructions. */
+static strmap_t *addressmap=NULL;
+
+/**
+ * Table mapping addresses to which virtual address, if any, we
+ * assigned them to.
+ *
+ * We maintain the following invariant: if [A,B] is in
+ * virtaddress_reversemap, then B must be a virtual address, and [A,B]
+ * must be in addressmap. We do not require that the converse hold:
+ * if it fails, then we could end up mapping two virtual addresses to
+ * the same address, which is no disaster.
+ **/
+static strmap_t *virtaddress_reversemap=NULL;
+
+/** Initialize addressmap. */
+void
+addressmap_init(void)
+{
+ addressmap = strmap_new();
+ virtaddress_reversemap = strmap_new();
+}
+
+/** Free the memory associated with the addressmap entry <b>_ent</b>. */
+static void
+addressmap_ent_free(void *_ent)
+{
+ addressmap_entry_t *ent;
+ if (!_ent)
+ return;
+
+ ent = _ent;
+ tor_free(ent->new_address);
+ tor_free(ent);
+}
+
+/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
+static void
+addressmap_virtaddress_ent_free(void *_ent)
+{
+ virtaddress_entry_t *ent;
+ if (!_ent)
+ return;
+
+ ent = _ent;
+ tor_free(ent->ipv4_address);
+ tor_free(ent->hostname_address);
+ tor_free(ent);
+}
+
+/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
+static void
+addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
+{
+ if (ent && ent->new_address &&
+ address_is_in_virtual_range(ent->new_address)) {
+ virtaddress_entry_t *ve =
+ strmap_get(virtaddress_reversemap, ent->new_address);
+ /*log_fn(LOG_NOTICE,"remove reverse mapping for %s",ent->new_address);*/
+ if (ve) {
+ if (!strcmp(address, ve->ipv4_address))
+ tor_free(ve->ipv4_address);
+ if (!strcmp(address, ve->hostname_address))
+ tor_free(ve->hostname_address);
+ if (!ve->ipv4_address && !ve->hostname_address) {
+ tor_free(ve);
+ strmap_remove(virtaddress_reversemap, ent->new_address);
+ }
+ }
+ }
+}
+
+/** Remove <b>ent</b> (which must be mapped to by <b>address</b>) from the
+ * client address maps. */
+static void
+addressmap_ent_remove(const char *address, addressmap_entry_t *ent)
+{
+ addressmap_virtaddress_remove(address, ent);
+ addressmap_ent_free(ent);
+}
+
+/** Unregister all TrackHostExits mappings from any address to
+ * *.exitname.exit. */
+void
+clear_trackexithost_mappings(const char *exitname)
+{
+ char *suffix = NULL;
+ if (!addressmap || !exitname)
+ return;
+ tor_asprintf(&suffix, ".%s.exit", exitname);
+ tor_strlower(suffix);
+
+ STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
+ if (ent->source == ADDRMAPSRC_TRACKEXIT &&
+ !strcmpend(ent->new_address, suffix)) {
+ addressmap_ent_remove(address, ent);
+ MAP_DEL_CURRENT(address);
+ }
+ } STRMAP_FOREACH_END;
+
+ tor_free(suffix);
+}
+
+/** Remove all TRACKEXIT mappings from the addressmap for which the target
+ * host is unknown or no longer allowed, or for which the source address
+ * is no longer in trackexithosts. */
+void
+addressmap_clear_excluded_trackexithosts(const or_options_t *options)
+{
+ const routerset_t *allow_nodes = options->ExitNodes;
+ const routerset_t *exclude_nodes = options->ExcludeExitNodesUnion_;
+
+ if (!addressmap)
+ return;
+ if (routerset_is_empty(allow_nodes))
+ allow_nodes = NULL;
+ if (allow_nodes == NULL && routerset_is_empty(exclude_nodes))
+ return;
+
+ STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
+ size_t len;
+ const char *target = ent->new_address, *dot;
+ char *nodename;
+ const node_t *node;
+
+ if (!target) {
+ /* DNS resolving in progress */
+ continue;
+ } else if (strcmpend(target, ".exit")) {
+ /* Not a .exit mapping */
+ continue;
+ } else if (ent->source != ADDRMAPSRC_TRACKEXIT) {
+ /* Not a trackexit mapping. */
+ continue;
+ }
+ len = strlen(target);
+ if (len < 6)
+ continue; /* malformed. */
+ dot = target + len - 6; /* dot now points to just before .exit */
+ while (dot > target && *dot != '.')
+ dot--;
+ if (*dot == '.') dot++;
+ nodename = tor_strndup(dot, len-5-(dot-target));;
+ node = node_get_by_nickname(nodename, 0);
+ tor_free(nodename);
+ if (!node ||
+ (allow_nodes && !routerset_contains_node(allow_nodes, node)) ||
+ routerset_contains_node(exclude_nodes, node) ||
+ !hostname_in_track_host_exits(options, address)) {
+ /* We don't know this one, or we want to be rid of it. */
+ addressmap_ent_remove(address, ent);
+ MAP_DEL_CURRENT(address);
+ }
+ } STRMAP_FOREACH_END;
+}
+
+/** Return true iff <b>address</b> is one that we are configured to
+ * automap on resolve according to <b>options</b>. */
+int
+addressmap_address_should_automap(const char *address,
+ const or_options_t *options)
+{
+ const smartlist_t *suffix_list = options->AutomapHostsSuffixes;
+
+ if (!suffix_list)
+ return 0;
+
+ SMARTLIST_FOREACH_BEGIN(suffix_list, const char *, suffix) {
+ if (!strcasecmpend(address, suffix))
+ return 1;
+ } SMARTLIST_FOREACH_END(suffix);
+ return 0;
+}
+
+/** Remove all AUTOMAP mappings from the addressmap for which the
+ * source address no longer matches AutomapHostsSuffixes, which is
+ * no longer allowed by AutomapHostsOnResolve, or for which the
+ * target address is no longer in the virtual network. */
+void
+addressmap_clear_invalid_automaps(const or_options_t *options)
+{
+ int clear_all = !options->AutomapHostsOnResolve;
+ const smartlist_t *suffixes = options->AutomapHostsSuffixes;
+
+ if (!addressmap)
+ return;
+
+ if (!suffixes)
+ clear_all = 1; /* This should be impossible, but let's be sure. */
+
+ STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) {
+ int remove = clear_all;
+ if (ent->source != ADDRMAPSRC_AUTOMAP)
+ continue; /* not an automap mapping. */
+
+ if (!remove) {
+ remove = ! addressmap_address_should_automap(src_address, options);
+ }
+
+ if (!remove && ! address_is_in_virtual_range(ent->new_address))
+ remove = 1;
+
+ if (remove) {
+ addressmap_ent_remove(src_address, ent);
+ MAP_DEL_CURRENT(src_address);
+ }
+ } STRMAP_FOREACH_END;
+}
+
+/** Remove all entries from the addressmap that were set via the
+ * configuration file or the command line. */
+void
+addressmap_clear_configured(void)
+{
+ addressmap_get_mappings(NULL, 0, 0, 0);
+}
+
+/** Remove all entries from the addressmap that are set to expire, ever. */
+void
+addressmap_clear_transient(void)
+{
+ addressmap_get_mappings(NULL, 2, TIME_MAX, 0);
+}
+
+/** Clean out entries from the addressmap cache that were
+ * added long enough ago that they are no longer valid.
+ */
+void
+addressmap_clean(time_t now)
+{
+ addressmap_get_mappings(NULL, 2, now, 0);
+}
+
+/** Free all the elements in the addressmap, and free the addressmap
+ * itself. */
+void
+addressmap_free_all(void)
+{
+ strmap_free(addressmap, addressmap_ent_free);
+ addressmap = NULL;
+
+ strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
+ virtaddress_reversemap = NULL;
+}
+
+/** Try to find a match for AddressMap expressions that use
+ * wildcard notation such as '*.c.d *.e.f' (so 'a.c.d' will map to 'a.e.f') or
+ * '*.c.d a.b.c' (so 'a.c.d' will map to a.b.c).
+ * Return the matching entry in AddressMap or NULL if no match is found.
+ * For expressions such as '*.c.d *.e.f', truncate <b>address</b> 'a.c.d'
+ * to 'a' before we return the matching AddressMap entry.
+ *
+ * This function does not handle the case where a pattern of the form "*.c.d"
+ * matches the address c.d -- that's done by the main addressmap_rewrite
+ * function.
+ */
+static addressmap_entry_t *
+addressmap_match_superdomains(char *address)
+{
+ addressmap_entry_t *val;
+ char *cp;
+
+ cp = address;
+ while ((cp = strchr(cp, '.'))) {
+ /* cp now points to a suffix of address that begins with a . */
+ val = strmap_get_lc(addressmap, cp+1);
+ if (val && val->src_wildcard) {
+ if (val->dst_wildcard)
+ *cp = '\0';
+ return val;
+ }
+ ++cp;
+ }
+ return NULL;
+}
+
+/** Look at address, and rewrite it until it doesn't want any
+ * more rewrites; but don't get into an infinite loop.
+ * Don't write more than maxlen chars into address. Return true if the
+ * address changed; false otherwise. Set *<b>expires_out</b> to the
+ * expiry time of the result, or to <b>time_max</b> if the result does
+ * not expire.
+ *
+ * If <b>exit_source_out</b> is non-null, we set it as follows. If we the
+ * address starts out as a non-exit address, and we remap it to an .exit
+ * address at any point, then set *<b>exit_source_out</b> to the
+ * address_entry_source_t of the first such rule. Set *<b>exit_source_out</b>
+ * to ADDRMAPSRC_NONE if there is no such rewrite, or if the original address
+ * was a .exit.
+ */
+int
+addressmap_rewrite(char *address, size_t maxlen,
+ unsigned flags,
+ time_t *expires_out,
+ addressmap_entry_source_t *exit_source_out)
+{
+ addressmap_entry_t *ent;
+ int rewrites;
+ time_t expires = TIME_MAX;
+ addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE;
+ char *addr_orig = tor_strdup(address);
+ char *log_addr_orig = NULL;
+
+ for (rewrites = 0; rewrites < 16; rewrites++) {
+ int exact_match = 0;
+ log_addr_orig = tor_strdup(escaped_safe_str_client(address));
+
+ ent = strmap_get(addressmap, address);
+
+ if (!ent || !ent->new_address) {
+ ent = addressmap_match_superdomains(address);
+ } else {
+ if (ent->src_wildcard && !ent->dst_wildcard &&
+ !strcasecmp(address, ent->new_address)) {
+ /* This is a rule like *.example.com example.com, and we just got
+ * "example.com" */
+ goto done;
+ }
+
+ exact_match = 1;
+ }
+
+ if (!ent || !ent->new_address) {
+ goto done;
+ }
+
+ if (ent && ent->source == ADDRMAPSRC_DNS) {
+ sa_family_t f;
+ tor_addr_t tmp;
+ f = tor_addr_parse(&tmp, ent->new_address);
+ if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS))
+ goto done;
+ else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS))
+ goto done;
+ }
+
+ if (ent->dst_wildcard && !exact_match) {
+ strlcat(address, ".", maxlen);
+ strlcat(address, ent->new_address, maxlen);
+ } else {
+ strlcpy(address, ent->new_address, maxlen);
+ }
+
+ if (!strcmpend(address, ".exit") &&
+ strcmpend(addr_orig, ".exit") &&
+ exit_source == ADDRMAPSRC_NONE) {
+ exit_source = ent->source;
+ }
+
+ log_info(LD_APP, "Addressmap: rewriting %s to %s",
+ log_addr_orig, escaped_safe_str_client(address));
+ if (ent->expires > 1 && ent->expires < expires)
+ expires = ent->expires;
+
+ tor_free(log_addr_orig);
+ }
+ log_warn(LD_CONFIG,
+ "Loop detected: we've rewritten %s 16 times! Using it as-is.",
+ escaped_safe_str_client(address));
+ /* it's fine to rewrite a rewrite, but don't loop forever */
+
+ done:
+ tor_free(addr_orig);
+ tor_free(log_addr_orig);
+ if (exit_source_out)
+ *exit_source_out = exit_source;
+ if (expires_out)
+ *expires_out = TIME_MAX;
+ return (rewrites > 0);
+}
+
+/** If we have a cached reverse DNS entry for the address stored in the
+ * <b>maxlen</b>-byte buffer <b>address</b> (typically, a dotted quad) then
+ * rewrite to the cached value and return 1. Otherwise return 0. Set
+ * *<b>expires_out</b> to the expiry time of the result, or to <b>time_max</b>
+ * if the result does not expire. */
+int
+addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags,
+ time_t *expires_out)
+{
+ char *s, *cp;
+ addressmap_entry_t *ent;
+ int r = 0;
+ {
+ sa_family_t f;
+ tor_addr_t tmp;
+ f = tor_addr_parse(&tmp, address);
+ if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS))
+ return 0;
+ else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS))
+ return 0;
+ }
+
+ tor_asprintf(&s, "REVERSE[%s]", address);
+ ent = strmap_get(addressmap, s);
+ if (ent) {
+ cp = tor_strdup(escaped_safe_str_client(ent->new_address));
+ log_info(LD_APP, "Rewrote reverse lookup %s -> %s",
+ escaped_safe_str_client(s), cp);
+ tor_free(cp);
+ strlcpy(address, ent->new_address, maxlen);
+ r = 1;
+ }
+
+ if (expires_out)
+ *expires_out = (ent && ent->expires > 1) ? ent->expires : TIME_MAX;
+
+ tor_free(s);
+ return r;
+}
+
+/** Return 1 if <b>address</b> is already registered, else return 0. If address
+ * is already registered, and <b>update_expires</b> is non-zero, then update
+ * the expiry time on the mapping with update_expires if it is a
+ * mapping created by TrackHostExits. */
+int
+addressmap_have_mapping(const char *address, int update_expiry)
+{
+ addressmap_entry_t *ent;
+ if (!(ent=strmap_get_lc(addressmap, address)))
+ return 0;
+ if (update_expiry && ent->source==ADDRMAPSRC_TRACKEXIT)
+ ent->expires=time(NULL) + update_expiry;
+ return 1;
+}
+
+/** Register a request to map <b>address</b> to <b>new_address</b>,
+ * which will expire on <b>expires</b> (or 0 if never expires from
+ * config file, 1 if never expires from controller, 2 if never expires
+ * (virtual address mapping) from the controller.)
+ *
+ * <b>new_address</b> should be a newly dup'ed string, which we'll use or
+ * free as appropriate. We will leave address alone.
+ *
+ * If <b>wildcard_addr</b> is true, then the mapping will match any address
+ * equal to <b>address</b>, or any address ending with a period followed by
+ * <b>address</b>. If <b>wildcard_addr</b> and <b>wildcard_new_addr</b> are
+ * both true, the mapping will rewrite addresses that end with
+ * ".<b>address</b>" into ones that end with ".<b>new_address</b>."
+ *
+ * If <b>new_address</b> is NULL, or <b>new_address</b> is equal to
+ * <b>address</b> and <b>wildcard_addr</b> is equal to
+ * <b>wildcard_new_addr</b>, remove any mappings that exist from
+ * <b>address</b>.
+ *
+ *
+ * It is an error to set <b>wildcard_new_addr</b> if <b>wildcard_addr</b> is
+ * not set. */
+void
+addressmap_register(const char *address, char *new_address, time_t expires,
+ addressmap_entry_source_t source,
+ const int wildcard_addr,
+ const int wildcard_new_addr)
+{
+ addressmap_entry_t *ent;
+
+ if (wildcard_new_addr)
+ tor_assert(wildcard_addr);
+
+ ent = strmap_get(addressmap, address);
+ if (!new_address || (!strcasecmp(address,new_address) &&
+ wildcard_addr == wildcard_new_addr)) {
+ /* Remove the mapping, if any. */
+ tor_free(new_address);
+ if (ent) {
+ addressmap_ent_remove(address,ent);
+ strmap_remove(addressmap, address);
+ }
+ return;
+ }
+ if (!ent) { /* make a new one and register it */
+ ent = tor_malloc_zero(sizeof(addressmap_entry_t));
+ strmap_set(addressmap, address, ent);
+ } else if (ent->new_address) { /* we need to clean up the old mapping. */
+ if (expires > 1) {
+ log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, "
+ "since it's already mapped to '%s'",
+ safe_str_client(address),
+ safe_str_client(new_address),
+ safe_str_client(ent->new_address));
+ tor_free(new_address);
+ return;
+ }
+ if (address_is_in_virtual_range(ent->new_address) &&
+ expires != 2) {
+ /* XXX This isn't the perfect test; we want to avoid removing
+ * mappings set from the control interface _as virtual mapping */
+ addressmap_virtaddress_remove(address, ent);
+ }
+ tor_free(ent->new_address);
+ } /* else { we have an in-progress resolve with no mapping. } */
+
+ ent->new_address = new_address;
+ ent->expires = expires==2 ? 1 : expires;
+ ent->num_resolve_failures = 0;
+ ent->source = source;
+ ent->src_wildcard = wildcard_addr ? 1 : 0;
+ ent->dst_wildcard = wildcard_new_addr ? 1 : 0;
+
+ log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
+ safe_str_client(address),
+ safe_str_client(ent->new_address));
+ control_event_address_mapped(address, ent->new_address, expires, NULL, 1);
+}
+
+/** An attempt to resolve <b>address</b> failed at some OR.
+ * Increment the number of resolve failures we have on record
+ * for it, and then return that number.
+ */
+int
+client_dns_incr_failures(const char *address)
+{
+ addressmap_entry_t *ent = strmap_get(addressmap, address);
+ if (!ent) {
+ ent = tor_malloc_zero(sizeof(addressmap_entry_t));
+ ent->expires = time(NULL) + MAX_DNS_ENTRY_AGE;
+ strmap_set(addressmap,address,ent);
+ }
+ if (ent->num_resolve_failures < SHORT_MAX)
+ ++ent->num_resolve_failures; /* don't overflow */
+ log_info(LD_APP, "Address %s now has %d resolve failures.",
+ safe_str_client(address),
+ ent->num_resolve_failures);
+ return ent->num_resolve_failures;
+}
+
+/** If <b>address</b> is in the client DNS addressmap, reset
+ * the number of resolve failures we have on record for it.
+ * This is used when we fail a stream because it won't resolve:
+ * otherwise future attempts on that address will only try once.
+ */
+void
+client_dns_clear_failures(const char *address)
+{
+ addressmap_entry_t *ent = strmap_get(addressmap, address);
+ if (ent)
+ ent->num_resolve_failures = 0;
+}
+
+/** Record the fact that <b>address</b> resolved to <b>name</b>.
+ * We can now use this in subsequent streams via addressmap_rewrite()
+ * so we can more correctly choose an exit that will allow <b>address</b>.
+ *
+ * If <b>exitname</b> is defined, then append the addresses with
+ * ".exitname.exit" before registering the mapping.
+ *
+ * If <b>ttl</b> is nonnegative, the mapping will be valid for
+ * <b>ttl</b>seconds; otherwise, we use the default.
+ */
+static void
+client_dns_set_addressmap_impl(entry_connection_t *for_conn,
+ const char *address, const char *name,
+ const char *exitname,
+ int ttl)
+{
+ char *extendedaddress=NULL, *extendedval=NULL;
+ (void)for_conn;
+
+ tor_assert(address);
+ tor_assert(name);
+
+ if (ttl<0)
+ ttl = DEFAULT_DNS_TTL;
+ else
+ ttl = dns_clip_ttl(ttl);
+
+ if (exitname) {
+ /* XXXX fails to ever get attempts to get an exit address of
+ * google.com.digest[=~]nickname.exit; we need a syntax for this that
+ * won't make strict RFC952-compliant applications (like us) barf. */
+ tor_asprintf(&extendedaddress,
+ "%s.%s.exit", address, exitname);
+ tor_asprintf(&extendedval,
+ "%s.%s.exit", name, exitname);
+ } else {
+ tor_asprintf(&extendedaddress,
+ "%s", address);
+ tor_asprintf(&extendedval,
+ "%s", name);
+ }
+ addressmap_register(extendedaddress, extendedval,
+ time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0);
+ tor_free(extendedaddress);
+}
+
+/** Record the fact that <b>address</b> resolved to <b>val</b>.
+ * We can now use this in subsequent streams via addressmap_rewrite()
+ * so we can more correctly choose an exit that will allow <b>address</b>.
+ *
+ * If <b>exitname</b> is defined, then append the addresses with
+ * ".exitname.exit" before registering the mapping.
+ *
+ * If <b>ttl</b> is nonnegative, the mapping will be valid for
+ * <b>ttl</b>seconds; otherwise, we use the default.
+ */
+void
+client_dns_set_addressmap(entry_connection_t *for_conn,
+ const char *address,
+ const tor_addr_t *val,
+ const char *exitname,
+ int ttl)
+{
+ tor_addr_t addr_tmp;
+ char valbuf[TOR_ADDR_BUF_LEN];
+
+ tor_assert(address);
+ tor_assert(val);
+
+ if (tor_addr_parse(&addr_tmp, address) >= 0)
+ return; /* If address was an IP address already, don't add a mapping. */
+
+ if (tor_addr_family(val) == AF_INET) {
+ if (! for_conn->cache_ipv4_answers)
+ return;
+ } else if (tor_addr_family(val) == AF_INET6) {
+ if (! for_conn->cache_ipv6_answers)
+ return;
+ }
+
+ if (! tor_addr_to_str(valbuf, val, sizeof(valbuf), 1))
+ return;
+
+ client_dns_set_addressmap_impl(for_conn, address, valbuf, exitname, ttl);
+}
+
+/** Add a cache entry noting that <b>address</b> (ordinarily a dotted quad)
+ * resolved via a RESOLVE_PTR request to the hostname <b>v</b>.
+ *
+ * If <b>exitname</b> is defined, then append the addresses with
+ * ".exitname.exit" before registering the mapping.
+ *
+ * If <b>ttl</b> is nonnegative, the mapping will be valid for
+ * <b>ttl</b>seconds; otherwise, we use the default.
+ */
+void
+client_dns_set_reverse_addressmap(entry_connection_t *for_conn,
+ const char *address, const char *v,
+ const char *exitname,
+ int ttl)
+{
+ char *s = NULL;
+ {
+ tor_addr_t tmp_addr;
+ sa_family_t f = tor_addr_parse(&tmp_addr, address);
+ if ((f == AF_INET && ! for_conn->cache_ipv4_answers) ||
+ (f == AF_INET6 && ! for_conn->cache_ipv6_answers))
+ return;
+ }
+ tor_asprintf(&s, "REVERSE[%s]", address);
+ client_dns_set_addressmap_impl(for_conn, s, v, exitname, ttl);
+ tor_free(s);
+}
+
+/* By default, we hand out 127.192.0.1 through 127.254.254.254.
+ * These addresses should map to localhost, so even if the
+ * application accidentally tried to connect to them directly (not
+ * via Tor), it wouldn't get too far astray.
+ *
+ * These options are configured by parse_virtual_addr_network().
+ */
+
+static virtual_addr_conf_t virtaddr_conf_ipv4;
+static virtual_addr_conf_t virtaddr_conf_ipv6;
+
+/** Read a netmask of the form 127.192.0.0/10 from "val", and check whether
+ * it's a valid set of virtual addresses to hand out in response to MAPADDRESS
+ * requests. Return 0 on success; set *msg (if provided) to a newly allocated
+ * string and return -1 on failure. If validate_only is false, sets the
+ * actual virtual address range to the parsed value. */
+int
+parse_virtual_addr_network(const char *val, sa_family_t family,
+ int validate_only,
+ char **msg)
+{
+ const int ipv6 = (family == AF_INET6);
+ tor_addr_t addr;
+ maskbits_t bits;
+ const int max_bits = ipv6 ? 40 : 16;
+ virtual_addr_conf_t *conf = ipv6 ? &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
+
+ if (tor_addr_parse_mask_ports(val, 0, &addr, &bits, NULL, NULL) < 0) {
+ if (msg)
+ tor_asprintf(msg, "Error parsing VirtualAddressNetwork%s %s",
+ ipv6?"IPv6":"", val);
+ return -1;
+ }
+ if (tor_addr_family(&addr) != family) {
+ if (msg)
+ tor_asprintf(msg, "Incorrect address type for VirtualAddressNetwork%s",
+ ipv6?"IPv6":"");
+ return -1;
+ }
+#if 0
+ if (port_min != 1 || port_max != 65535) {
+ if (msg)
+ tor_asprintf(msg, "Can't specify ports on VirtualAddressNetwork%s",
+ ipv6?"IPv6":"");
+ return -1;
+ }
+#endif
+
+ if (bits > max_bits) {
+ if (msg)
+ tor_asprintf(msg, "VirtualAddressNetwork%s expects a /%d "
+ "network or larger",ipv6?"IPv6":"", max_bits);
+ return -1;
+ }
+
+ if (validate_only)
+ return 0;
+
+ tor_addr_copy(&conf->addr, &addr);
+ conf->bits = bits;
+
+ return 0;
+}
+
+/**
+ * Return true iff <b>addr</b> is likely to have been returned by
+ * client_dns_get_unused_address.
+ **/
+int
+address_is_in_virtual_range(const char *address)
+{
+ tor_addr_t addr;
+ tor_assert(address);
+ if (!strcasecmpend(address, ".virtual")) {
+ return 1;
+ } else if (tor_addr_parse(&addr, address) >= 0) {
+ const virtual_addr_conf_t *conf = (tor_addr_family(&addr) == AF_INET6) ?
+ &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
+ if (tor_addr_compare_masked(&addr, &conf->addr, conf->bits, CMP_EXACT)==0)
+ return 1;
+ }
+ return 0;
+}
+
+/** Return a random address conforming to the virtual address configuration
+ * in <b>conf</b>.
+ */
+/* private */ void
+get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
+{
+ uint8_t tmp[4];
+ const uint8_t *addr_bytes;
+ uint8_t bytes[16];
+ const int ipv6 = tor_addr_family(&conf->addr) == AF_INET6;
+ const int total_bytes = ipv6 ? 16 : 4;
+
+ tor_assert(conf->bits <= total_bytes * 8);
+
+ /* Set addr_bytes to the bytes of the virtual network, in host order */
+ if (ipv6) {
+ addr_bytes = tor_addr_to_in6_addr8(&conf->addr);
+ } else {
+ set_uint32(tmp, tor_addr_to_ipv4n(&conf->addr));
+ addr_bytes = tmp;
+ }
+
+ /* Get an appropriate number of random bytes. */
+ crypto_rand((char*)bytes, total_bytes);
+
+ /* Now replace the first "conf->bits" bits of 'bytes' with addr_bytes*/
+ if (conf->bits >= 8)
+ memcpy(bytes, addr_bytes, conf->bits / 8);
+ if (conf->bits & 7) {
+ uint8_t mask = 0xff >> (conf->bits & 7);
+ bytes[conf->bits/8] &= mask;
+ bytes[conf->bits/8] |= addr_bytes[conf->bits/8] & ~mask;
+ }
+
+ if (ipv6)
+ tor_addr_from_ipv6_bytes(addr_out, (char*) bytes);
+ else
+ tor_addr_from_ipv4n(addr_out, get_uint32(bytes));
+
+ tor_assert(tor_addr_compare_masked(addr_out, &conf->addr,
+ conf->bits, CMP_EXACT)==0);
+}
+
+/** Return a newly allocated string holding an address of <b>type</b>
+ * (one of RESOLVED_TYPE_{IPV4|HOSTNAME}) that has not yet been mapped,
+ * and that is very unlikely to be the address of any real host.
+ *
+ * May return NULL if we have run out of virtual addresses.
+ */
+static char *
+addressmap_get_virtual_address(int type)
+{
+ char buf[64];
+ tor_assert(addressmap);
+
+ if (type == RESOLVED_TYPE_HOSTNAME) {
+ char rand[10];
+ do {
+ crypto_rand(rand, sizeof(rand));
+ base32_encode(buf,sizeof(buf),rand,sizeof(rand));
+ strlcat(buf, ".virtual", sizeof(buf));
+ } while (strmap_get(addressmap, buf));
+ return tor_strdup(buf);
+ } else if (type == RESOLVED_TYPE_IPV4 || type == RESOLVED_TYPE_IPV6) {
+ const int ipv6 = (type == RESOLVED_TYPE_IPV6);
+ const virtual_addr_conf_t *conf = ipv6 ?
+ &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
+
+ /* Don't try more than 1000 times. This gives us P < 1e-9 for
+ * failing to get a good address so long as the address space is
+ * less than ~97.95% full. That's always going to be true under
+ * sensible circumstances for an IPv6 /10, and it's going to be
+ * true for an IPv4 /10 as long as we've handed out less than
+ * 4.08 million addresses. */
+ uint32_t attempts = 1000;
+
+ tor_addr_t addr;
+
+ while (attempts--) {
+ get_random_virtual_addr(conf, &addr);
+
+ if (!ipv6) {
+ /* Don't hand out any .0 or .255 address. */
+ const uint32_t a = tor_addr_to_ipv4h(&addr);
+ if ((a & 0xff) == 0 || (a & 0xff) == 0xff)
+ continue;
+ }
+
+ tor_addr_to_str(buf, &addr, sizeof(buf), 1);
+ if (!strmap_get(addressmap, buf)) {
+ /* XXXX This code is to make sure I didn't add an undecorated version
+ * by mistake. I hope it's needless. */
+ char tmp[TOR_ADDR_BUF_LEN];
+ tor_addr_to_str(buf, &addr, sizeof(tmp), 0);
+ if (strmap_get(addressmap, tmp)) {
+ log_warn(LD_BUG, "%s wasn't in the addressmap, but %s was.",
+ buf, tmp);
+ continue;
+ }
+
+ return tor_strdup(buf);
+ }
+ }
+ log_warn(LD_CONFIG, "Ran out of virtual addresses!");
+ return NULL;
+ } else {
+ log_warn(LD_BUG, "Called with unsupported address type (%d)", type);
+ return NULL;
+ }
+}
+
+/** A controller has requested that we map some address of type
+ * <b>type</b> to the address <b>new_address</b>. Choose an address
+ * that is unlikely to be used, and map it, and return it in a newly
+ * allocated string. If another address of the same type is already
+ * mapped to <b>new_address</b>, try to return a copy of that address.
+ *
+ * The string in <b>new_address</b> may be freed or inserted into a map
+ * as appropriate. May return NULL if are out of virtual addresses.
+ **/
+const char *
+addressmap_register_virtual_address(int type, char *new_address)
+{
+ char **addrp;
+ virtaddress_entry_t *vent;
+ int vent_needs_to_be_added = 0;
+
+ tor_assert(new_address);
+ tor_assert(addressmap);
+ tor_assert(virtaddress_reversemap);
+
+ vent = strmap_get(virtaddress_reversemap, new_address);
+ if (!vent) {
+ vent = tor_malloc_zero(sizeof(virtaddress_entry_t));
+ vent_needs_to_be_added = 1;
+ }
+
+ if (type == RESOLVED_TYPE_IPV4)
+ addrp = &vent->ipv4_address;
+ else if (type == RESOLVED_TYPE_IPV6)
+ addrp = &vent->ipv6_address;
+ else
+ addrp = &vent->hostname_address;
+
+ if (*addrp) {
+ addressmap_entry_t *ent = strmap_get(addressmap, *addrp);
+ if (ent && ent->new_address &&
+ !strcasecmp(new_address, ent->new_address)) {
+ tor_free(new_address);
+ tor_assert(!vent_needs_to_be_added);
+ return tor_strdup(*addrp);
+ } else {
+ log_warn(LD_BUG,
+ "Internal confusion: I thought that '%s' was mapped to by "
+ "'%s', but '%s' really maps to '%s'. This is a harmless bug.",
+ safe_str_client(new_address),
+ safe_str_client(*addrp),
+ safe_str_client(*addrp),
+ ent?safe_str_client(ent->new_address):"(nothing)");
+ }
+ }
+
+ tor_free(*addrp);
+ *addrp = addressmap_get_virtual_address(type);
+ if (!*addrp) {
+ tor_free(vent);
+ tor_free(new_address);
+ return NULL;
+ }
+ log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
+ if (vent_needs_to_be_added)
+ strmap_set(virtaddress_reversemap, new_address, vent);
+ addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0);
+
+#if 0
+ {
+ /* Try to catch possible bugs */
+ addressmap_entry_t *ent;
+ ent = strmap_get(addressmap, *addrp);
+ tor_assert(ent);
+ tor_assert(!strcasecmp(ent->new_address,new_address));
+ vent = strmap_get(virtaddress_reversemap, new_address);
+ tor_assert(vent);
+ tor_assert(!strcasecmp(*addrp,
+ (type == RESOLVED_TYPE_IPV4) ?
+ vent->ipv4_address : vent->hostname_address));
+ log_info(LD_APP, "Map from %s to %s okay.",
+ safe_str_client(*addrp),
+ safe_str_client(new_address));
+ }
+#endif
+
+ return *addrp;
+}
+
+/** Return 1 if <b>address</b> has funny characters in it like colons. Return
+ * 0 if it's fine, or if we're configured to allow it anyway. <b>client</b>
+ * should be true if we're using this address as a client; false if we're
+ * using it as a server.
+ */
+int
+address_is_invalid_destination(const char *address, int client)
+{
+ if (client) {
+ if (get_options()->AllowNonRFC953Hostnames)
+ return 0;
+ } else {
+ if (get_options()->ServerDNSAllowNonRFC953Hostnames)
+ return 0;
+ }
+
+ /* It might be an IPv6 address! */
+ {
+ tor_addr_t a;
+ if (tor_addr_parse(&a, address) >= 0)
+ return 0;
+ }
+
+ while (*address) {
+ if (TOR_ISALNUM(*address) ||
+ *address == '-' ||
+ *address == '.' ||
+ *address == '_') /* Underscore is not allowed, but Windows does it
+ * sometimes, just to thumb its nose at the IETF. */
+ ++address;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/** Iterate over all address mappings which have expiry times between
+ * min_expires and max_expires, inclusive. If sl is provided, add an
+ * "old-addr new-addr expiry" string to sl for each mapping, omitting
+ * the expiry time if want_expiry is false. If sl is NULL, remove the
+ * mappings.
+ */
+void
+addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
+ time_t max_expires, int want_expiry)
+{
+ strmap_iter_t *iter;
+ const char *key;
+ void *val_;
+ addressmap_entry_t *val;
+
+ if (!addressmap)
+ addressmap_init();
+
+ for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) {
+ strmap_iter_get(iter, &key, &val_);
+ val = val_;
+ if (val->expires >= min_expires && val->expires <= max_expires) {
+ if (!sl) {
+ iter = strmap_iter_next_rmv(addressmap,iter);
+ addressmap_ent_remove(key, val);
+ continue;
+ } else if (val->new_address) {
+ const char *src_wc = val->src_wildcard ? "*." : "";
+ const char *dst_wc = val->dst_wildcard ? "*." : "";
+ if (want_expiry) {
+ if (val->expires < 3 || val->expires == TIME_MAX)
+ smartlist_add_asprintf(sl, "%s%s %s%s NEVER",
+ src_wc, key, dst_wc, val->new_address);
+ else {
+ char time[ISO_TIME_LEN+1];
+ format_iso_time(time, val->expires);
+ smartlist_add_asprintf(sl, "%s%s %s%s \"%s\"",
+ src_wc, key, dst_wc, val->new_address,
+ time);
+ }
+ } else {
+ smartlist_add_asprintf(sl, "%s%s %s%s",
+ src_wc, key, dst_wc, val->new_address);
+ }
+ }
+ }
+ iter = strmap_iter_next(addressmap,iter);
+ }
+}
+
diff --git a/src/or/addressmap.h b/src/or/addressmap.h
new file mode 100644
index 000000000..40210ee99
--- /dev/null
+++ b/src/or/addressmap.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_ADDRESSMAP_H
+#define TOR_ADDRESSMAP_H
+
+void addressmap_init(void);
+void addressmap_clear_excluded_trackexithosts(const or_options_t *options);
+void addressmap_clear_invalid_automaps(const or_options_t *options);
+void addressmap_clean(time_t now);
+void addressmap_clear_configured(void);
+void addressmap_clear_transient(void);
+void addressmap_free_all(void);
+#define AMR_FLAG_USE_IPV4_DNS (1u<<0)
+#define AMR_FLAG_USE_IPV6_DNS (1u<<1)
+int addressmap_rewrite(char *address, size_t maxlen, unsigned flags,
+ time_t *expires_out,
+ addressmap_entry_source_t *exit_source_out);
+int addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags,
+ time_t *expires_out);
+int addressmap_have_mapping(const char *address, int update_timeout);
+
+void addressmap_register(const char *address, char *new_address,
+ time_t expires, addressmap_entry_source_t source,
+ const int address_wildcard,
+ const int new_address_wildcard);
+int parse_virtual_addr_network(const char *val,
+ sa_family_t family, int validate_only,
+ char **msg);
+int client_dns_incr_failures(const char *address);
+void client_dns_clear_failures(const char *address);
+void client_dns_set_addressmap(entry_connection_t *for_conn,
+ const char *address, const tor_addr_t *val,
+ const char *exitname, int ttl);
+const char *addressmap_register_virtual_address(int type, char *new_address);
+void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
+ time_t max_expires, int want_expiry);
+int address_is_in_virtual_range(const char *addr);
+void clear_trackexithost_mappings(const char *exitname);
+void client_dns_set_reverse_addressmap(entry_connection_t *for_conn,
+ const char *address, const char *v,
+ const char *exitname, int ttl);
+int addressmap_address_should_automap(const char *address,
+ const or_options_t *options);
+
+#ifdef ADDRESSMAP_PRIVATE
+typedef struct virtual_addr_conf_t {
+ tor_addr_t addr;
+ maskbits_t bits;
+} virtual_addr_conf_t;
+
+void get_random_virtual_addr(const virtual_addr_conf_t *conf,
+ tor_addr_t *addr_out);
+#endif
+
+#endif
+
diff --git a/src/or/buffers.c b/src/or/buffers.c
index 9be0476f6..c4c847ec8 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,6 +12,7 @@
**/
#define BUFFERS_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
#include "config.h"
#include "connection_edge.h"
@@ -193,8 +194,6 @@ chunk_new_with_alloc_size(size_t alloc)
freelist->lowest_length = freelist->cur_length;
++freelist->n_hit;
} else {
- /* XXXX take advantage of tor_malloc_roundup, once we know how that
- * affects freelists. */
if (freelist)
++freelist->n_alloc;
else
@@ -217,7 +216,7 @@ static INLINE chunk_t *
chunk_new_with_alloc_size(size_t alloc)
{
chunk_t *ch;
- ch = tor_malloc_roundup(&alloc);
+ ch = tor_malloc(alloc);
ch->next = NULL;
ch->datalen = 0;
ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc);
@@ -337,11 +336,11 @@ buf_dump_freelist_sizes(int severity)
{
#ifdef ENABLE_BUF_FREELISTS
int i;
- log(severity, LD_MM, "====== Buffer freelists:");
+ tor_log(severity, LD_MM, "====== Buffer freelists:");
for (i = 0; freelists[i].alloc_size; ++i) {
uint64_t total = ((uint64_t)freelists[i].cur_length) *
freelists[i].alloc_size;
- log(severity, LD_MM,
+ tor_log(severity, LD_MM,
U64_FORMAT" bytes in %d %d-byte chunks ["U64_FORMAT
" misses; "U64_FORMAT" frees; "U64_FORMAT" hits]",
U64_PRINTF_ARG(total),
@@ -350,7 +349,7 @@ buf_dump_freelist_sizes(int severity)
U64_PRINTF_ARG(freelists[i].n_free),
U64_PRINTF_ARG(freelists[i].n_hit));
}
- log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes",
+ tor_log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes",
U64_PRINTF_ARG(n_freelist_miss));
#else
(void)severity;
@@ -1047,28 +1046,34 @@ cell_command_is_var_length(uint8_t command, int linkproto)
int
fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto)
{
- char hdr[VAR_CELL_HEADER_SIZE];
+ char hdr[VAR_CELL_MAX_HEADER_SIZE];
var_cell_t *result;
uint8_t command;
uint16_t length;
+ const int wide_circ_ids = linkproto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS;
+ const int circ_id_len = get_circ_id_size(wide_circ_ids);
+ const unsigned header_len = get_var_cell_header_size(wide_circ_ids);
check();
*out = NULL;
- if (buf->datalen < VAR_CELL_HEADER_SIZE)
+ if (buf->datalen < header_len)
return 0;
- peek_from_buf(hdr, sizeof(hdr), buf);
+ peek_from_buf(hdr, header_len, buf);
- command = get_uint8(hdr+2);
+ command = get_uint8(hdr + circ_id_len);
if (!(cell_command_is_var_length(command, linkproto)))
return 0;
- length = ntohs(get_uint16(hdr+3));
- if (buf->datalen < (size_t)(VAR_CELL_HEADER_SIZE+length))
+ length = ntohs(get_uint16(hdr + circ_id_len + 1));
+ if (buf->datalen < (size_t)(header_len+length))
return 1;
result = var_cell_new(length);
result->command = command;
- result->circ_id = ntohs(get_uint16(hdr));
+ if (wide_circ_ids)
+ result->circ_id = ntohl(get_uint32(hdr));
+ else
+ result->circ_id = ntohs(get_uint16(hdr));
- buf_remove_from_front(buf, VAR_CELL_HEADER_SIZE);
+ buf_remove_from_front(buf, header_len);
peek_from_buf((char*) result->payload, length, buf);
buf_remove_from_front(buf, length);
check();
@@ -1127,30 +1132,36 @@ fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out,
uint16_t cell_length;
var_cell_t *cell;
int result = 0;
+ const int wide_circ_ids = linkproto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS;
+ const int circ_id_len = get_circ_id_size(wide_circ_ids);
+ const unsigned header_len = get_var_cell_header_size(wide_circ_ids);
*out = NULL;
buf_len = evbuffer_get_length(buf);
- if (buf_len < VAR_CELL_HEADER_SIZE)
+ if (buf_len < header_len)
return 0;
- n = inspect_evbuffer(buf, &hdr, VAR_CELL_HEADER_SIZE, &free_hdr, NULL);
- tor_assert(n >= VAR_CELL_HEADER_SIZE);
+ n = inspect_evbuffer(buf, &hdr, header_len, &free_hdr, NULL);
+ tor_assert(n >= header_len);
- command = get_uint8(hdr+2);
+ command = get_uint8(hdr + circ_id_len);
if (!(cell_command_is_var_length(command, linkproto))) {
goto done;
}
- cell_length = ntohs(get_uint16(hdr+3));
- if (buf_len < (size_t)(VAR_CELL_HEADER_SIZE+cell_length)) {
+ cell_length = ntohs(get_uint16(hdr + circ_id_len + 1));
+ if (buf_len < (size_t)(header_len+cell_length)) {
result = 1; /* Not all here yet. */
goto done;
}
cell = var_cell_new(cell_length);
cell->command = command;
- cell->circ_id = ntohs(get_uint16(hdr));
- evbuffer_drain(buf, VAR_CELL_HEADER_SIZE);
+ if (wide_circ_ids)
+ cell->circ_id = ntohl(get_uint32(hdr));
+ else
+ cell->circ_id = ntohs(get_uint16(hdr));
+ evbuffer_drain(buf, header_len);
evbuffer_remove(buf, cell->payload, cell_length);
*out = cell;
result = 1;
@@ -1507,22 +1518,19 @@ log_unsafe_socks_warning(int socks_protocol, const char *address,
static ratelim_t socks_ratelim = RATELIM_INIT(SOCKS_WARN_INTERVAL);
const or_options_t *options = get_options();
- char *m = NULL;
if (! options->WarnUnsafeSocks)
return;
- if (safe_socks || (m = rate_limit_log(&socks_ratelim, approx_time()))) {
- log_warn(LD_APP,
+ if (safe_socks) {
+ log_fn_ratelim(&socks_ratelim, LOG_WARN, LD_APP,
"Your application (using socks%d to port %d) is giving "
"Tor only an IP address. Applications that do DNS resolves "
"themselves may leak information. Consider using Socks4A "
"(e.g. via privoxy or socat) instead. For more information, "
"please see https://wiki.torproject.org/TheOnionRouter/"
- "TorFAQ#SOCKSAndDNS.%s%s",
+ "TorFAQ#SOCKSAndDNS.%s",
socks_protocol,
(int)port,
- safe_socks ? " Rejecting." : "",
- m ? m : "");
- tor_free(m);
+ safe_socks ? " Rejecting." : "");
}
control_event_client_status(LOG_WARN,
"DANGEROUS_SOCKS PROTOCOL=SOCKS%d ADDRESS=%s:%d",
@@ -1743,7 +1751,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
return 0;
}
req->replylen = 2; /* 2 bytes of response */
- req->reply[0] = 5;
+ req->reply[0] = 1; /* authversion == 1 */
req->reply[1] = 0; /* authentication successful */
log_debug(LD_APP,
"socks5: Accepted username/password without checking.");
@@ -1774,6 +1782,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
if (req->socks_version != 5) { /* we need to negotiate a method */
unsigned char nummethods = (unsigned char)*(data+1);
+ int have_user_pass, have_no_auth;
int r=0;
tor_assert(!req->socks_version);
if (datalen < 2u+nummethods) {
@@ -1784,19 +1793,21 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
return -1;
req->replylen = 2; /* 2 bytes of response */
req->reply[0] = 5; /* socks5 reply */
- if (memchr(data+2, SOCKS_NO_AUTH, nummethods)) {
- req->reply[1] = SOCKS_NO_AUTH; /* tell client to use "none" auth
- method */
- req->socks_version = 5; /* remember we've already negotiated auth */
- log_debug(LD_APP,"socks5: accepted method 0 (no authentication)");
- r=0;
- } else if (memchr(data+2, SOCKS_USER_PASS, nummethods)) {
+ have_user_pass = (memchr(data+2, SOCKS_USER_PASS, nummethods) !=NULL);
+ have_no_auth = (memchr(data+2, SOCKS_NO_AUTH, nummethods) !=NULL);
+ if (have_user_pass && !(have_no_auth && req->socks_prefer_no_auth)) {
req->auth_type = SOCKS_USER_PASS;
req->reply[1] = SOCKS_USER_PASS; /* tell client to use "user/pass"
auth method */
req->socks_version = 5; /* remember we've already negotiated auth */
log_debug(LD_APP,"socks5: accepted method 2 (username/password)");
r=0;
+ } else if (have_no_auth) {
+ req->reply[1] = SOCKS_NO_AUTH; /* tell client to use "none" auth
+ method */
+ req->socks_version = 5; /* remember we've already negotiated auth */
+ log_debug(LD_APP,"socks5: accepted method 0 (no authentication)");
+ r=0;
} else {
log_warn(LD_APP,
"socks5: offered methods don't include 'no auth' or "
diff --git a/src/or/buffers.h b/src/or/buffers.h
index a5886adc7..c947f0ba9 100644
--- a/src/or/buffers.h
+++ b/src/or/buffers.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for buffers.c.
**/
-#ifndef _TOR_BUFFERS_H
-#define _TOR_BUFFERS_H
+#ifndef TOR_BUFFERS_H
+#define TOR_BUFFERS_H
buf_t *buf_new(void);
buf_t *buf_new_with_capacity(size_t size);
diff --git a/src/or/channel.c b/src/or/channel.c
new file mode 100644
index 000000000..1270eace7
--- /dev/null
+++ b/src/or/channel.c
@@ -0,0 +1,4132 @@
+/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file channel.c
+ * \brief OR-to-OR channel abstraction layer
+ **/
+
+/*
+ * Define this so channel.h gives us things only channel_t subclasses
+ * should touch.
+ */
+
+#define TOR_CHANNEL_INTERNAL_
+
+#include "or.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "circuitbuild.h"
+#include "circuitlist.h"
+#include "circuitstats.h"
+#include "connection_or.h" /* For var_cell_free() */
+#include "circuitmux.h"
+#include "entrynodes.h"
+#include "geoip.h"
+#include "nodelist.h"
+#include "relay.h"
+#include "rephist.h"
+#include "router.h"
+#include "routerlist.h"
+
+/* Cell queue structure */
+
+typedef struct cell_queue_entry_s cell_queue_entry_t;
+struct cell_queue_entry_s {
+ TOR_SIMPLEQ_ENTRY(cell_queue_entry_s) next;
+ enum {
+ CELL_QUEUE_FIXED,
+ CELL_QUEUE_VAR,
+ CELL_QUEUE_PACKED
+ } type;
+ union {
+ struct {
+ cell_t *cell;
+ } fixed;
+ struct {
+ var_cell_t *var_cell;
+ } var;
+ struct {
+ packed_cell_t *packed_cell;
+ } packed;
+ } u;
+};
+
+/* Global lists of channels */
+
+/* All channel_t instances */
+static smartlist_t *all_channels = NULL;
+
+/* All channel_t instances not in ERROR or CLOSED states */
+static smartlist_t *active_channels = NULL;
+
+/* All channel_t instances in ERROR or CLOSED states */
+static smartlist_t *finished_channels = NULL;
+
+/* All channel_listener_t instances */
+static smartlist_t *all_listeners = NULL;
+
+/* All channel_listener_t instances in LISTENING state */
+static smartlist_t *active_listeners = NULL;
+
+/* All channel_listener_t instances in LISTENING state */
+static smartlist_t *finished_listeners = NULL;
+
+/* Counter for ID numbers */
+static uint64_t n_channels_allocated = 0;
+
+/* Digest->channel map
+ *
+ * Similar to the one used in connection_or.c, this maps from the identity
+ * digest of a remote endpoint to a channel_t to that endpoint. Channels
+ * should be placed here when registered and removed when they close or error.
+ * If more than one channel exists, follow the next_with_same_id pointer
+ * as a linked list.
+ */
+HT_HEAD(channel_idmap, channel_idmap_entry_s) channel_identity_map =
+ HT_INITIALIZER();
+
+typedef struct channel_idmap_entry_s {
+ HT_ENTRY(channel_idmap_entry_s) node;
+ uint8_t digest[DIGEST_LEN];
+ TOR_LIST_HEAD(channel_list_s, channel_s) channel_list;
+} channel_idmap_entry_t;
+
+static INLINE unsigned
+channel_idmap_hash(const channel_idmap_entry_t *ent)
+{
+ const unsigned *a = (const unsigned *)ent->digest;
+#if SIZEOF_INT == 4
+ return a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4];
+#elif SIZEOF_INT == 8
+ return a[0] ^ a[1];
+#endif
+}
+
+static INLINE int
+channel_idmap_eq(const channel_idmap_entry_t *a,
+ const channel_idmap_entry_t *b)
+{
+ return tor_memeq(a->digest, b->digest, DIGEST_LEN);
+}
+
+HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
+ channel_idmap_eq);
+HT_GENERATE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
+ channel_idmap_eq, 0.5, tor_malloc, tor_realloc, tor_free_);
+
+static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q);
+static void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off);
+static int cell_queue_entry_is_padding(cell_queue_entry_t *q);
+static cell_queue_entry_t *
+cell_queue_entry_new_fixed(cell_t *cell);
+static cell_queue_entry_t *
+cell_queue_entry_new_var(var_cell_t *var_cell);
+
+/* Functions to maintain the digest map */
+static void channel_add_to_digest_map(channel_t *chan);
+static void channel_remove_from_digest_map(channel_t *chan);
+
+/*
+ * Flush cells from just the outgoing queue without trying to get them
+ * from circuits; used internall by channel_flush_some_cells().
+ */
+static ssize_t
+channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
+ ssize_t num_cells);
+static void channel_force_free(channel_t *chan);
+static void
+channel_free_list(smartlist_t *channels, int mark_for_close);
+static void
+channel_listener_free_list(smartlist_t *channels, int mark_for_close);
+static void channel_listener_force_free(channel_listener_t *chan_l);
+static void
+channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q);
+
+/***********************************
+ * Channel state utility functions *
+ **********************************/
+
+/**
+ * Indicate whether a given channel state is valid
+ */
+
+int
+channel_state_is_valid(channel_state_t state)
+{
+ int is_valid;
+
+ switch (state) {
+ case CHANNEL_STATE_CLOSED:
+ case CHANNEL_STATE_CLOSING:
+ case CHANNEL_STATE_ERROR:
+ case CHANNEL_STATE_MAINT:
+ case CHANNEL_STATE_OPENING:
+ case CHANNEL_STATE_OPEN:
+ is_valid = 1;
+ break;
+ case CHANNEL_STATE_LAST:
+ default:
+ is_valid = 0;
+ }
+
+ return is_valid;
+}
+
+/**
+ * Indicate whether a given channel listener state is valid
+ */
+
+int
+channel_listener_state_is_valid(channel_listener_state_t state)
+{
+ int is_valid;
+
+ switch (state) {
+ case CHANNEL_LISTENER_STATE_CLOSED:
+ case CHANNEL_LISTENER_STATE_LISTENING:
+ case CHANNEL_LISTENER_STATE_CLOSING:
+ case CHANNEL_LISTENER_STATE_ERROR:
+ is_valid = 1;
+ break;
+ case CHANNEL_LISTENER_STATE_LAST:
+ default:
+ is_valid = 0;
+ }
+
+ return is_valid;
+}
+
+/**
+ * Indicate whether a channel state transition is valid
+ *
+ * This function takes two channel states and indicates whether a
+ * transition between them is permitted (see the state definitions and
+ * transition table in or.h at the channel_state_t typedef).
+ */
+
+int
+channel_state_can_transition(channel_state_t from, channel_state_t to)
+{
+ int is_valid;
+
+ switch (from) {
+ case CHANNEL_STATE_CLOSED:
+ is_valid = (to == CHANNEL_STATE_OPENING);
+ break;
+ case CHANNEL_STATE_CLOSING:
+ is_valid = (to == CHANNEL_STATE_CLOSED ||
+ to == CHANNEL_STATE_ERROR);
+ break;
+ case CHANNEL_STATE_ERROR:
+ is_valid = 0;
+ break;
+ case CHANNEL_STATE_MAINT:
+ is_valid = (to == CHANNEL_STATE_CLOSING ||
+ to == CHANNEL_STATE_ERROR ||
+ to == CHANNEL_STATE_OPEN);
+ break;
+ case CHANNEL_STATE_OPENING:
+ is_valid = (to == CHANNEL_STATE_CLOSING ||
+ to == CHANNEL_STATE_ERROR ||
+ to == CHANNEL_STATE_OPEN);
+ break;
+ case CHANNEL_STATE_OPEN:
+ is_valid = (to == CHANNEL_STATE_CLOSING ||
+ to == CHANNEL_STATE_ERROR ||
+ to == CHANNEL_STATE_MAINT);
+ break;
+ case CHANNEL_STATE_LAST:
+ default:
+ is_valid = 0;
+ }
+
+ return is_valid;
+}
+
+/**
+ * Indicate whether a channel listener state transition is valid
+ *
+ * This function takes two channel listener states and indicates whether a
+ * transition between them is permitted (see the state definitions and
+ * transition table in or.h at the channel_listener_state_t typedef).
+ */
+
+int
+channel_listener_state_can_transition(channel_listener_state_t from,
+ channel_listener_state_t to)
+{
+ int is_valid;
+
+ switch (from) {
+ case CHANNEL_LISTENER_STATE_CLOSED:
+ is_valid = (to == CHANNEL_LISTENER_STATE_LISTENING);
+ break;
+ case CHANNEL_LISTENER_STATE_CLOSING:
+ is_valid = (to == CHANNEL_LISTENER_STATE_CLOSED ||
+ to == CHANNEL_LISTENER_STATE_ERROR);
+ break;
+ case CHANNEL_LISTENER_STATE_ERROR:
+ is_valid = 0;
+ break;
+ case CHANNEL_LISTENER_STATE_LISTENING:
+ is_valid = (to == CHANNEL_LISTENER_STATE_CLOSING ||
+ to == CHANNEL_LISTENER_STATE_ERROR);
+ break;
+ case CHANNEL_LISTENER_STATE_LAST:
+ default:
+ is_valid = 0;
+ }
+
+ return is_valid;
+}
+
+/**
+ * Return a human-readable description for a channel state
+ */
+
+const char *
+channel_state_to_string(channel_state_t state)
+{
+ const char *descr;
+
+ switch (state) {
+ case CHANNEL_STATE_CLOSED:
+ descr = "closed";
+ break;
+ case CHANNEL_STATE_CLOSING:
+ descr = "closing";
+ break;
+ case CHANNEL_STATE_ERROR:
+ descr = "channel error";
+ break;
+ case CHANNEL_STATE_MAINT:
+ descr = "temporarily suspended for maintenance";
+ break;
+ case CHANNEL_STATE_OPENING:
+ descr = "opening";
+ break;
+ case CHANNEL_STATE_OPEN:
+ descr = "open";
+ break;
+ case CHANNEL_STATE_LAST:
+ default:
+ descr = "unknown or invalid channel state";
+ }
+
+ return descr;
+}
+
+/**
+ * Return a human-readable description for a channel listenier state
+ */
+
+const char *
+channel_listener_state_to_string(channel_listener_state_t state)
+{
+ const char *descr;
+
+ switch (state) {
+ case CHANNEL_LISTENER_STATE_CLOSED:
+ descr = "closed";
+ break;
+ case CHANNEL_LISTENER_STATE_CLOSING:
+ descr = "closing";
+ break;
+ case CHANNEL_LISTENER_STATE_ERROR:
+ descr = "channel listener error";
+ break;
+ case CHANNEL_LISTENER_STATE_LISTENING:
+ descr = "listening";
+ break;
+ case CHANNEL_LISTENER_STATE_LAST:
+ default:
+ descr = "unknown or invalid channel listener state";
+ }
+
+ return descr;
+}
+
+/***************************************
+ * Channel registration/unregistration *
+ ***************************************/
+
+/**
+ * Register a channel
+ *
+ * This function registers a newly created channel in the global lists/maps
+ * of active channels.
+ */
+
+void
+channel_register(channel_t *chan)
+{
+ tor_assert(chan);
+
+ /* No-op if already registered */
+ if (chan->registered) return;
+
+ log_debug(LD_CHANNEL,
+ "Registering channel %p (ID " U64_FORMAT ") "
+ "in state %s (%d) with digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state), chan->state,
+ hex_str(chan->identity_digest, DIGEST_LEN));
+
+ /* Make sure we have all_channels, then add it */
+ if (!all_channels) all_channels = smartlist_new();
+ smartlist_add(all_channels, chan);
+
+ /* Is it finished? */
+ if (chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) {
+ /* Put it in the finished list, creating it if necessary */
+ if (!finished_channels) finished_channels = smartlist_new();
+ smartlist_add(finished_channels, chan);
+ } else {
+ /* Put it in the active list, creating it if necessary */
+ if (!active_channels) active_channels = smartlist_new();
+ smartlist_add(active_channels, chan);
+
+ if (chan->state != CHANNEL_STATE_CLOSING) {
+ /* It should have a digest set */
+ if (!tor_digest_is_zero(chan->identity_digest)) {
+ /* Yeah, we're good, add it to the map */
+ channel_add_to_digest_map(chan);
+ } else {
+ log_info(LD_CHANNEL,
+ "Channel %p (global ID " U64_FORMAT ") "
+ "in state %s (%d) registered with no identity digest",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state), chan->state);
+ }
+ }
+ }
+
+ /* Mark it as registered */
+ chan->registered = 1;
+}
+
+/**
+ * Unregister a channel
+ *
+ * This function removes a channel from the global lists and maps and is used
+ * when freeing a closed/errored channel.
+ */
+
+void
+channel_unregister(channel_t *chan)
+{
+ tor_assert(chan);
+
+ /* No-op if not registered */
+ if (!(chan->registered)) return;
+
+ /* Is it finished? */
+ if (chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) {
+ /* Get it out of the finished list */
+ if (finished_channels) smartlist_remove(finished_channels, chan);
+ } else {
+ /* Get it out of the active list */
+ if (active_channels) smartlist_remove(active_channels, chan);
+ }
+
+ /* Get it out of all_channels */
+ if (all_channels) smartlist_remove(all_channels, chan);
+
+ /* Mark it as unregistered */
+ chan->registered = 0;
+
+ /* Should it be in the digest map? */
+ if (!tor_digest_is_zero(chan->identity_digest) &&
+ !(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ /* Remove it */
+ channel_remove_from_digest_map(chan);
+ }
+}
+
+/**
+ * Register a channel listener
+ *
+ * This function registers a newly created channel listner in the global
+ * lists/maps of active channel listeners.
+ */
+
+void
+channel_listener_register(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ /* No-op if already registered */
+ if (chan_l->registered) return;
+
+ log_debug(LD_CHANNEL,
+ "Registering channel listener %p (ID " U64_FORMAT ") "
+ "in state %s (%d)",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier),
+ channel_listener_state_to_string(chan_l->state),
+ chan_l->state);
+
+ /* Make sure we have all_channels, then add it */
+ if (!all_listeners) all_listeners = smartlist_new();
+ smartlist_add(all_listeners, chan_l);
+
+ /* Is it finished? */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) {
+ /* Put it in the finished list, creating it if necessary */
+ if (!finished_listeners) finished_listeners = smartlist_new();
+ smartlist_add(finished_listeners, chan_l);
+ } else {
+ /* Put it in the active list, creating it if necessary */
+ if (!active_listeners) active_listeners = smartlist_new();
+ smartlist_add(active_listeners, chan_l);
+ }
+
+ /* Mark it as registered */
+ chan_l->registered = 1;
+}
+
+/**
+ * Unregister a channel listener
+ *
+ * This function removes a channel listener from the global lists and maps
+ * and is used when freeing a closed/errored channel listener.
+ */
+
+void
+channel_listener_unregister(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ /* No-op if not registered */
+ if (!(chan_l->registered)) return;
+
+ /* Is it finished? */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) {
+ /* Get it out of the finished list */
+ if (finished_listeners) smartlist_remove(finished_listeners, chan_l);
+ } else {
+ /* Get it out of the active list */
+ if (active_listeners) smartlist_remove(active_listeners, chan_l);
+ }
+
+ /* Get it out of all_channels */
+ if (all_listeners) smartlist_remove(all_listeners, chan_l);
+
+ /* Mark it as unregistered */
+ chan_l->registered = 0;
+}
+
+/*********************************
+ * Channel digest map maintenance
+ *********************************/
+
+/**
+ * Add a channel to the digest map
+ *
+ * This function adds a channel to the digest map and inserts it into the
+ * correct linked list if channels with that remote endpoint identity digest
+ * already exist.
+ */
+
+static void
+channel_add_to_digest_map(channel_t *chan)
+{
+ channel_idmap_entry_t *ent, search;
+
+ tor_assert(chan);
+
+ /* Assert that the state makes sense */
+ tor_assert(!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR));
+
+ /* Assert that there is a digest */
+ tor_assert(!tor_digest_is_zero(chan->identity_digest));
+
+ memcpy(search.digest, chan->identity_digest, DIGEST_LEN);
+ ent = HT_FIND(channel_idmap, &channel_identity_map, &search);
+ if (! ent) {
+ ent = tor_malloc(sizeof(channel_idmap_entry_t));
+ memcpy(ent->digest, chan->identity_digest, DIGEST_LEN);
+ TOR_LIST_INIT(&ent->channel_list);
+ HT_INSERT(channel_idmap, &channel_identity_map, ent);
+ }
+ TOR_LIST_INSERT_HEAD(&ent->channel_list, chan, next_with_same_id);
+
+ log_debug(LD_CHANNEL,
+ "Added channel %p (global ID " U64_FORMAT ") "
+ "to identity map in state %s (%d) with digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state), chan->state,
+ hex_str(chan->identity_digest, DIGEST_LEN));
+}
+
+/**
+ * Remove a channel from the digest map
+ *
+ * This function removes a channel from the digest map and the linked list of
+ * channels for that digest if more than one exists.
+ */
+
+static void
+channel_remove_from_digest_map(channel_t *chan)
+{
+ channel_idmap_entry_t *ent, search;
+
+ tor_assert(chan);
+
+ /* Assert that there is a digest */
+ tor_assert(!tor_digest_is_zero(chan->identity_digest));
+
+#if 0
+ /* Make sure we have a map */
+ if (!channel_identity_map) {
+ /*
+ * No identity map, so we can't find it by definition. This
+ * case is similar to digestmap_get() failing below.
+ */
+ log_warn(LD_BUG,
+ "Trying to remove channel %p (global ID " U64_FORMAT ") "
+ "with digest %s from identity map, but didn't have any identity "
+ "map",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ hex_str(chan->identity_digest, DIGEST_LEN));
+ /* Clear out its next/prev pointers */
+ if (chan->next_with_same_id) {
+ chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id;
+ }
+ if (chan->prev_with_same_id) {
+ chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id;
+ }
+ chan->next_with_same_id = NULL;
+ chan->prev_with_same_id = NULL;
+
+ return;
+ }
+#endif
+
+ /* Pull it out of its list, wherever that list is */
+ TOR_LIST_REMOVE(chan, next_with_same_id);
+
+ memcpy(search.digest, chan->identity_digest, DIGEST_LEN);
+ ent = HT_FIND(channel_idmap, &channel_identity_map, &search);
+
+ /* Look for it in the map */
+ if (ent) {
+ /* Okay, it's here */
+
+ if (TOR_LIST_EMPTY(&ent->channel_list)) {
+ HT_REMOVE(channel_idmap, &channel_identity_map, ent);
+ tor_free(ent);
+ }
+
+ log_debug(LD_CHANNEL,
+ "Removed channel %p (global ID " U64_FORMAT ") from "
+ "identity map in state %s (%d) with digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state), chan->state,
+ hex_str(chan->identity_digest, DIGEST_LEN));
+ } else {
+ /* Shouldn't happen */
+ log_warn(LD_BUG,
+ "Trying to remove channel %p (global ID " U64_FORMAT ") with "
+ "digest %s from identity map, but couldn't find any with "
+ "that digest",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ hex_str(chan->identity_digest, DIGEST_LEN));
+ }
+}
+
+/****************************
+ * Channel lookup functions *
+ ***************************/
+
+/**
+ * Find channel by global ID
+ *
+ * This function searches for a channel by the global_identifier assigned
+ * at initialization time. This identifier is unique for the lifetime of the
+ * Tor process.
+ */
+
+channel_t *
+channel_find_by_global_id(uint64_t global_identifier)
+{
+ channel_t *rv = NULL;
+
+ if (all_channels && smartlist_len(all_channels) > 0) {
+ SMARTLIST_FOREACH_BEGIN(all_channels, channel_t *, curr) {
+ if (curr->global_identifier == global_identifier) {
+ rv = curr;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(curr);
+ }
+
+ return rv;
+}
+
+/**
+ * Find channel by digest of the remote endpoint
+ *
+ * This function looks up a channel by the digest of its remote endpoint in
+ * the channel digest map. It's possible that more than one channel to a
+ * given endpoint exists. Use channel_next_with_digest() to walk the list.
+ */
+
+channel_t *
+channel_find_by_remote_digest(const char *identity_digest)
+{
+ channel_t *rv = NULL;
+ channel_idmap_entry_t *ent, search;
+
+ tor_assert(identity_digest);
+
+ memcpy(search.digest, identity_digest, DIGEST_LEN);
+ ent = HT_FIND(channel_idmap, &channel_identity_map, &search);
+ if (ent) {
+ rv = TOR_LIST_FIRST(&ent->channel_list);
+ }
+
+ return rv;
+}
+
+/**
+ * Get next channel with digest
+ *
+ * This function takes a channel and finds the next channel in the list
+ * with the same digest.
+ */
+
+channel_t *
+channel_next_with_digest(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return TOR_LIST_NEXT(chan, next_with_same_id);
+}
+
+/**
+ * Initialize a channel
+ *
+ * This function should be called by subclasses to set up some per-channel
+ * variables. I.e., this is the superclass constructor. Before this, the
+ * channel should be allocated with tor_malloc_zero().
+ */
+
+void
+channel_init(channel_t *chan)
+{
+ tor_assert(chan);
+
+ /* Assign an ID and bump the counter */
+ chan->global_identifier = n_channels_allocated++;
+
+ /* Init timestamp */
+ chan->timestamp_last_added_nonpadding = time(NULL);
+
+ /* Init next_circ_id */
+ chan->next_circ_id = crypto_rand_int(1 << 15);
+
+ /* Initialize queues. */
+ TOR_SIMPLEQ_INIT(&chan->incoming_queue);
+ TOR_SIMPLEQ_INIT(&chan->outgoing_queue);
+
+ /* Initialize list entries. */
+ memset(&chan->next_with_same_id, 0, sizeof(chan->next_with_same_id));
+
+ /* Timestamp it */
+ channel_timestamp_created(chan);
+
+ /* It hasn't been open yet. */
+ chan->has_been_open = 0;
+}
+
+/**
+ * Initialize a channel listener
+ *
+ * This function should be called by subclasses to set up some per-channel
+ * variables. I.e., this is the superclass constructor. Before this, the
+ * channel listener should be allocated with tor_malloc_zero().
+ */
+
+void
+channel_init_listener(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ /* Assign an ID and bump the counter */
+ chan_l->global_identifier = n_channels_allocated++;
+
+ /* Timestamp it */
+ channel_listener_timestamp_created(chan_l);
+}
+
+/**
+ * Free a channel; nothing outside of channel.c and subclasses should call
+ * this - it frees channels after they have closed and been unregistered.
+ */
+
+void
+channel_free(channel_t *chan)
+{
+ if (!chan) return;
+
+ /* It must be closed or errored */
+ tor_assert(chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+ /* It must be deregistered */
+ tor_assert(!(chan->registered));
+
+ log_debug(LD_CHANNEL,
+ "Freeing channel " U64_FORMAT " at %p",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+
+ /*
+ * Get rid of cmux policy before we do anything, so cmux policies don't
+ * see channels in weird half-freed states.
+ */
+ if (chan->cmux) {
+ circuitmux_set_policy(chan->cmux, NULL);
+ }
+
+ /* Call a free method if there is one */
+ if (chan->free) chan->free(chan);
+
+ channel_clear_remote_end(chan);
+
+ /* Get rid of cmux */
+ if (chan->cmux) {
+ circuitmux_detach_all_circuits(chan->cmux);
+ circuitmux_free(chan->cmux);
+ chan->cmux = NULL;
+ }
+
+ /* We're in CLOSED or ERROR, so the cell queue is already empty */
+
+ tor_free(chan);
+}
+
+/**
+ * Free a channel listener; nothing outside of channel.c and subclasses
+ * should call this - it frees channel listeners after they have closed and
+ * been unregistered.
+ */
+
+void
+channel_listener_free(channel_listener_t *chan_l)
+{
+ if (!chan_l) return;
+
+ log_debug(LD_CHANNEL,
+ "Freeing channel_listener_t " U64_FORMAT " at %p",
+ U64_PRINTF_ARG(chan_l->global_identifier),
+ chan_l);
+
+ /* It must be closed or errored */
+ tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR);
+ /* It must be deregistered */
+ tor_assert(!(chan_l->registered));
+
+ /* Call a free method if there is one */
+ if (chan_l->free) chan_l->free(chan_l);
+
+ /*
+ * We're in CLOSED or ERROR, so the incoming channel queue is already
+ * empty.
+ */
+
+ tor_free(chan_l);
+}
+
+/**
+ * Free a channel and skip the state/registration asserts; this internal-
+ * use-only function should be called only from channel_free_all() when
+ * shutting down the Tor process.
+ */
+
+static void
+channel_force_free(channel_t *chan)
+{
+ cell_queue_entry_t *cell, *cell_tmp;
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Force-freeing channel " U64_FORMAT " at %p",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+
+ /*
+ * Get rid of cmux policy before we do anything, so cmux policies don't
+ * see channels in weird half-freed states.
+ */
+ if (chan->cmux) {
+ circuitmux_set_policy(chan->cmux, NULL);
+ }
+
+ /* Call a free method if there is one */
+ if (chan->free) chan->free(chan);
+
+ channel_clear_remote_end(chan);
+
+ /* Get rid of cmux */
+ if (chan->cmux) {
+ circuitmux_free(chan->cmux);
+ chan->cmux = NULL;
+ }
+
+ /* We might still have a cell queue; kill it */
+ TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) {
+ cell_queue_entry_free(cell, 0);
+ }
+ TOR_SIMPLEQ_INIT(&chan->incoming_queue);
+
+ /* Outgoing cell queue is similar, but we can have to free packed cells */
+ TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) {
+ cell_queue_entry_free(cell, 0);
+ }
+ TOR_SIMPLEQ_INIT(&chan->outgoing_queue);
+
+ tor_free(chan);
+}
+
+/**
+ * Free a channel listener and skip the state/reigstration asserts; this
+ * internal-use-only function should be called only from channel_free_all()
+ * when shutting down the Tor process.
+ */
+
+static void
+channel_listener_force_free(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ log_debug(LD_CHANNEL,
+ "Force-freeing channel_listener_t " U64_FORMAT " at %p",
+ U64_PRINTF_ARG(chan_l->global_identifier),
+ chan_l);
+
+ /* Call a free method if there is one */
+ if (chan_l->free) chan_l->free(chan_l);
+
+ /*
+ * The incoming list just gets emptied and freed; we request close on
+ * any channels we find there, but since we got called while shutting
+ * down they will get deregistered and freed elsewhere anyway.
+ */
+ if (chan_l->incoming_list) {
+ SMARTLIST_FOREACH_BEGIN(chan_l->incoming_list,
+ channel_t *, qchan) {
+ channel_mark_for_close(qchan);
+ } SMARTLIST_FOREACH_END(qchan);
+
+ smartlist_free(chan_l->incoming_list);
+ chan_l->incoming_list = NULL;
+ }
+
+ tor_free(chan_l);
+}
+
+/**
+ * Return the current registered listener for a channel listener
+ *
+ * This function returns a function pointer to the current registered
+ * handler for new incoming channels on a channel listener.
+ */
+
+channel_listener_fn_ptr
+channel_listener_get_listener_fn(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ if (chan_l->state == CHANNEL_LISTENER_STATE_LISTENING)
+ return chan_l->listener;
+
+ return NULL;
+}
+
+/**
+ * Set the listener for a channel listener
+ *
+ * This function sets the handler for new incoming channels on a channel
+ * listener.
+ */
+
+void
+channel_listener_set_listener_fn(channel_listener_t *chan_l,
+ channel_listener_fn_ptr listener)
+{
+ tor_assert(chan_l);
+ tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_LISTENING);
+
+ log_debug(LD_CHANNEL,
+ "Setting listener callback for channel listener %p "
+ "(global ID " U64_FORMAT ") to %p",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier),
+ listener);
+
+ chan_l->listener = listener;
+ if (chan_l->listener) channel_listener_process_incoming(chan_l);
+}
+
+/**
+ * Return the fixed-length cell handler for a channel
+ *
+ * This function gets the handler for incoming fixed-length cells installed
+ * on a channel.
+ */
+
+channel_cell_handler_fn_ptr
+channel_get_cell_handler(channel_t *chan)
+{
+ tor_assert(chan);
+
+ if (chan->state == CHANNEL_STATE_OPENING ||
+ chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT)
+ return chan->cell_handler;
+
+ return NULL;
+}
+
+/**
+ * Return the variable-length cell handler for a channel
+ *
+ * This function gets the handler for incoming variable-length cells
+ * installed on a channel.
+ */
+
+channel_var_cell_handler_fn_ptr
+channel_get_var_cell_handler(channel_t *chan)
+{
+ tor_assert(chan);
+
+ if (chan->state == CHANNEL_STATE_OPENING ||
+ chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT)
+ return chan->var_cell_handler;
+
+ return NULL;
+}
+
+/**
+ * Set both cell handlers for a channel
+ *
+ * This function sets both the fixed-length and variable length cell handlers
+ * for a channel and processes any incoming cells that had been blocked in the
+ * queue because none were available.
+ */
+
+void
+channel_set_cell_handlers(channel_t *chan,
+ channel_cell_handler_fn_ptr cell_handler,
+ channel_var_cell_handler_fn_ptr
+ var_cell_handler)
+{
+ int try_again = 0;
+
+ tor_assert(chan);
+ tor_assert(chan->state == CHANNEL_STATE_OPENING ||
+ chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT);
+
+ log_debug(LD_CHANNEL,
+ "Setting cell_handler callback for channel %p to %p",
+ chan, cell_handler);
+ log_debug(LD_CHANNEL,
+ "Setting var_cell_handler callback for channel %p to %p",
+ chan, var_cell_handler);
+
+ /* Should we try the queue? */
+ if (cell_handler &&
+ cell_handler != chan->cell_handler) try_again = 1;
+ if (var_cell_handler &&
+ var_cell_handler != chan->var_cell_handler) try_again = 1;
+
+ /* Change them */
+ chan->cell_handler = cell_handler;
+ chan->var_cell_handler = var_cell_handler;
+
+ /* Re-run the queue if we have one and there's any reason to */
+ if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue) &&
+ try_again &&
+ (chan->cell_handler ||
+ chan->var_cell_handler)) channel_process_cells(chan);
+}
+
+/*
+ * On closing channels
+ *
+ * There are three functions that close channels, for use in
+ * different circumstances:
+ *
+ * - Use channel_mark_for_close() for most cases
+ * - Use channel_close_from_lower_layer() if you are connection_or.c
+ * and the other end closes the underlying connection.
+ * - Use channel_close_for_error() if you are connection_or.c and
+ * some sort of error has occurred.
+ */
+
+/**
+ * Mark a channel for closure
+ *
+ * This function tries to close a channel_t; it will go into the CLOSING
+ * state, and eventually the lower layer should put it into the CLOSED or
+ * ERROR state. Then, channel_run_cleanup() will eventually free it.
+ */
+
+void
+channel_mark_for_close(channel_t *chan)
+{
+ tor_assert(chan != NULL);
+ tor_assert(chan->close != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel %p (global ID " U64_FORMAT ") "
+ "by request",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ /* Note closing by request from above */
+ chan->reason_for_closing = CHANNEL_CLOSE_REQUESTED;
+
+ /* Change state to CLOSING */
+ channel_change_state(chan, CHANNEL_STATE_CLOSING);
+
+ /* Tell the lower layer */
+ chan->close(chan);
+
+ /*
+ * It's up to the lower layer to change state to CLOSED or ERROR when we're
+ * ready; we'll try to free channels that are in the finished list from
+ * channel_run_cleanup(). The lower layer should do this by calling
+ * channel_closed().
+ */
+}
+
+/**
+ * Mark a channel listener for closure
+ *
+ * This function tries to close a channel_listener_t; it will go into the
+ * CLOSING state, and eventually the lower layer should put it into the CLOSED
+ * or ERROR state. Then, channel_run_cleanup() will eventually free it.
+ */
+
+void
+channel_listener_mark_for_close(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l != NULL);
+ tor_assert(chan_l->close != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel listener %p (global ID " U64_FORMAT ") "
+ "by request",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
+
+ /* Note closing by request from above */
+ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_REQUESTED;
+
+ /* Change state to CLOSING */
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
+
+ /* Tell the lower layer */
+ chan_l->close(chan_l);
+
+ /*
+ * It's up to the lower layer to change state to CLOSED or ERROR when we're
+ * ready; we'll try to free channels that are in the finished list from
+ * channel_run_cleanup(). The lower layer should do this by calling
+ * channel_listener_closed().
+ */
+}
+
+/**
+ * Close a channel from the lower layer
+ *
+ * Notify the channel code that the channel is being closed due to a non-error
+ * condition in the lower layer. This does not call the close() method, since
+ * the lower layer already knows.
+ */
+
+void
+channel_close_from_lower_layer(channel_t *chan)
+{
+ tor_assert(chan != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel %p (global ID " U64_FORMAT ") "
+ "due to lower-layer event",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ /* Note closing by event from below */
+ chan->reason_for_closing = CHANNEL_CLOSE_FROM_BELOW;
+
+ /* Change state to CLOSING */
+ channel_change_state(chan, CHANNEL_STATE_CLOSING);
+}
+
+/**
+ * Close a channel listener from the lower layer
+ *
+ * Notify the channel code that the channel listener is being closed due to a
+ * non-error condition in the lower layer. This does not call the close()
+ * method, since the lower layer already knows.
+ */
+
+void
+channel_listener_close_from_lower_layer(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel listener %p (global ID " U64_FORMAT ") "
+ "due to lower-layer event",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
+
+ /* Note closing by event from below */
+ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FROM_BELOW;
+
+ /* Change state to CLOSING */
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
+}
+
+/**
+ * Notify that the channel is being closed due to an error condition
+ *
+ * This function is called by the lower layer implementing the transport
+ * when a channel must be closed due to an error condition. This does not
+ * call the channel's close method, since the lower layer already knows.
+ */
+
+void
+channel_close_for_error(channel_t *chan)
+{
+ tor_assert(chan != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel %p due to lower-layer error",
+ chan);
+
+ /* Note closing by event from below */
+ chan->reason_for_closing = CHANNEL_CLOSE_FOR_ERROR;
+
+ /* Change state to CLOSING */
+ channel_change_state(chan, CHANNEL_STATE_CLOSING);
+}
+
+/**
+ * Notify that the channel listener is being closed due to an error condition
+ *
+ * This function is called by the lower layer implementing the transport
+ * when a channel listener must be closed due to an error condition. This
+ * does not call the channel listener's close method, since the lower layer
+ * already knows.
+ */
+
+void
+channel_listener_close_for_error(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l != NULL);
+
+ /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
+
+ log_debug(LD_CHANNEL,
+ "Closing channel listener %p (global ID " U64_FORMAT ") "
+ "due to lower-layer error",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
+
+ /* Note closing by event from below */
+ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FOR_ERROR;
+
+ /* Change state to CLOSING */
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
+}
+
+/**
+ * Notify that the lower layer is finished closing the channel
+ *
+ * This function should be called by the lower layer when a channel
+ * is finished closing and it should be regarded as inactive and
+ * freed by the channel code.
+ */
+
+void
+channel_closed(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+
+ /* No-op if already inactive */
+ if (chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR) return;
+
+ /* Inform any pending (not attached) circs that they should
+ * give up. */
+ if (! chan->has_been_open)
+ circuit_n_chan_done(chan, 0);
+
+ /* Now close all the attached circuits on it. */
+ circuit_unlink_all_from_channel(chan, END_CIRC_REASON_CHANNEL_CLOSED);
+
+ if (chan->reason_for_closing != CHANNEL_CLOSE_FOR_ERROR) {
+ channel_change_state(chan, CHANNEL_STATE_CLOSED);
+ } else {
+ channel_change_state(chan, CHANNEL_STATE_ERROR);
+ }
+}
+
+/**
+ * Notify that the lower layer is finished closing the channel listener
+ *
+ * This function should be called by the lower layer when a channel listener
+ * is finished closing and it should be regarded as inactive and
+ * freed by the channel code.
+ */
+
+void
+channel_listener_closed(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+ tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR);
+
+ /* No-op if already inactive */
+ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
+
+ if (chan_l->reason_for_closing != CHANNEL_LISTENER_CLOSE_FOR_ERROR) {
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED);
+ } else {
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_ERROR);
+ }
+}
+
+/**
+ * Clear the identity_digest of a channel
+ *
+ * This function clears the identity digest of the remote endpoint for a
+ * channel; this is intended for use by the lower layer.
+ */
+
+void
+channel_clear_identity_digest(channel_t *chan)
+{
+ int state_not_in_map;
+
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Clearing remote endpoint digest on channel %p with "
+ "global ID " U64_FORMAT,
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ state_not_in_map =
+ (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+
+ if (!state_not_in_map && chan->registered &&
+ !tor_digest_is_zero(chan->identity_digest))
+ /* if it's registered get it out of the digest map */
+ channel_remove_from_digest_map(chan);
+
+ memset(chan->identity_digest, 0,
+ sizeof(chan->identity_digest));
+}
+
+/**
+ * Set the identity_digest of a channel
+ *
+ * This function sets the identity digest of the remote endpoint for a
+ * channel; this is intended for use by the lower layer.
+ */
+
+void
+channel_set_identity_digest(channel_t *chan,
+ const char *identity_digest)
+{
+ int was_in_digest_map, should_be_in_digest_map, state_not_in_map;
+
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Setting remote endpoint digest on channel %p with "
+ "global ID " U64_FORMAT " to digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ identity_digest ?
+ hex_str(identity_digest, DIGEST_LEN) : "(null)");
+
+ state_not_in_map =
+ (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+ was_in_digest_map =
+ !state_not_in_map &&
+ chan->registered &&
+ !tor_digest_is_zero(chan->identity_digest);
+ should_be_in_digest_map =
+ !state_not_in_map &&
+ chan->registered &&
+ (identity_digest &&
+ !tor_digest_is_zero(identity_digest));
+
+ if (was_in_digest_map)
+ /* We should always remove it; we'll add it back if we're writing
+ * in a new digest.
+ */
+ channel_remove_from_digest_map(chan);
+
+ if (identity_digest) {
+ memcpy(chan->identity_digest,
+ identity_digest,
+ sizeof(chan->identity_digest));
+ } else {
+ memset(chan->identity_digest, 0,
+ sizeof(chan->identity_digest));
+ }
+
+ /* Put it in the digest map if we should */
+ if (should_be_in_digest_map)
+ channel_add_to_digest_map(chan);
+}
+
+/**
+ * Clear the remote end metadata (identity_digest/nickname) of a channel
+ *
+ * This function clears all the remote end info from a channel; this is
+ * intended for use by the lower layer.
+ */
+
+void
+channel_clear_remote_end(channel_t *chan)
+{
+ int state_not_in_map;
+
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Clearing remote endpoint identity on channel %p with "
+ "global ID " U64_FORMAT,
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ state_not_in_map =
+ (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+
+ if (!state_not_in_map && chan->registered &&
+ !tor_digest_is_zero(chan->identity_digest))
+ /* if it's registered get it out of the digest map */
+ channel_remove_from_digest_map(chan);
+
+ memset(chan->identity_digest, 0,
+ sizeof(chan->identity_digest));
+ tor_free(chan->nickname);
+}
+
+/**
+ * Set the remote end metadata (identity_digest/nickname) of a channel
+ *
+ * This function sets new remote end info on a channel; this is intended
+ * for use by the lower layer.
+ */
+
+void
+channel_set_remote_end(channel_t *chan,
+ const char *identity_digest,
+ const char *nickname)
+{
+ int was_in_digest_map, should_be_in_digest_map, state_not_in_map;
+
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Setting remote endpoint identity on channel %p with "
+ "global ID " U64_FORMAT " to nickname %s, digest %s",
+ chan, U64_PRINTF_ARG(chan->global_identifier),
+ nickname ? nickname : "(null)",
+ identity_digest ?
+ hex_str(identity_digest, DIGEST_LEN) : "(null)");
+
+ state_not_in_map =
+ (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR);
+ was_in_digest_map =
+ !state_not_in_map &&
+ chan->registered &&
+ !tor_digest_is_zero(chan->identity_digest);
+ should_be_in_digest_map =
+ !state_not_in_map &&
+ chan->registered &&
+ (identity_digest &&
+ !tor_digest_is_zero(identity_digest));
+
+ if (was_in_digest_map)
+ /* We should always remove it; we'll add it back if we're writing
+ * in a new digest.
+ */
+ channel_remove_from_digest_map(chan);
+
+ if (identity_digest) {
+ memcpy(chan->identity_digest,
+ identity_digest,
+ sizeof(chan->identity_digest));
+
+ } else {
+ memset(chan->identity_digest, 0,
+ sizeof(chan->identity_digest));
+ }
+
+ tor_free(chan->nickname);
+ if (nickname)
+ chan->nickname = tor_strdup(nickname);
+
+ /* Put it in the digest map if we should */
+ if (should_be_in_digest_map)
+ channel_add_to_digest_map(chan);
+}
+
+/**
+ * Duplicate a cell queue entry; this is a shallow copy intended for use
+ * in channel_write_cell_queue_entry().
+ */
+
+static cell_queue_entry_t *
+cell_queue_entry_dup(cell_queue_entry_t *q)
+{
+ cell_queue_entry_t *rv = NULL;
+
+ tor_assert(q);
+
+ rv = tor_malloc(sizeof(*rv));
+ memcpy(rv, q, sizeof(*rv));
+
+ return rv;
+}
+
+/**
+ * Free a cell_queue_entry_t; the handed_off parameter indicates whether
+ * the contents were passed to the lower layer (it is responsible for
+ * them) or not (we should free).
+ */
+
+static void
+cell_queue_entry_free(cell_queue_entry_t *q, int handed_off)
+{
+ if (!q) return;
+
+ if (!handed_off) {
+ /*
+ * If we handed it off, the recipient becomes responsible (or
+ * with packed cells the channel_t subclass calls packed_cell
+ * free after writing out its contents; see, e.g.,
+ * channel_tls_write_packed_cell_method(). Otherwise, we have
+ * to take care of it here if possible.
+ */
+ switch (q->type) {
+ case CELL_QUEUE_FIXED:
+ if (q->u.fixed.cell) {
+ /*
+ * There doesn't seem to be a cell_free() function anywhere in the
+ * pre-channel code; just use tor_free()
+ */
+ tor_free(q->u.fixed.cell);
+ }
+ break;
+ case CELL_QUEUE_PACKED:
+ if (q->u.packed.packed_cell) {
+ packed_cell_free(q->u.packed.packed_cell);
+ }
+ break;
+ case CELL_QUEUE_VAR:
+ if (q->u.var.var_cell) {
+ /*
+ * This one's in connection_or.c; it'd be nice to figure out the
+ * whole flow of cells from one end to the other and factor the
+ * cell memory management functions like this out of the specific
+ * TLS lower layer.
+ */
+ var_cell_free(q->u.var.var_cell);
+ }
+ break;
+ default:
+ /*
+ * Nothing we can do if we don't know the type; this will
+ * have been warned about elsewhere.
+ */
+ break;
+ }
+ }
+ tor_free(q);
+}
+
+/**
+ * Check whether a cell queue entry is padding; this is a helper function
+ * for channel_write_cell_queue_entry()
+ */
+
+static int
+cell_queue_entry_is_padding(cell_queue_entry_t *q)
+{
+ tor_assert(q);
+
+ if (q->type == CELL_QUEUE_FIXED) {
+ if (q->u.fixed.cell) {
+ if (q->u.fixed.cell->command == CELL_PADDING ||
+ q->u.fixed.cell->command == CELL_VPADDING) {
+ return 1;
+ }
+ }
+ } else if (q->type == CELL_QUEUE_VAR) {
+ if (q->u.var.var_cell) {
+ if (q->u.var.var_cell->command == CELL_PADDING ||
+ q->u.var.var_cell->command == CELL_VPADDING) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Allocate a new cell queue entry for a fixed-size cell
+ */
+
+static cell_queue_entry_t *
+cell_queue_entry_new_fixed(cell_t *cell)
+{
+ cell_queue_entry_t *q = NULL;
+
+ tor_assert(cell);
+
+ q = tor_malloc(sizeof(*q));
+ q->type = CELL_QUEUE_FIXED;
+ q->u.fixed.cell = cell;
+
+ return q;
+}
+
+/**
+ * Allocate a new cell queue entry for a variable-size cell
+ */
+
+static cell_queue_entry_t *
+cell_queue_entry_new_var(var_cell_t *var_cell)
+{
+ cell_queue_entry_t *q = NULL;
+
+ tor_assert(var_cell);
+
+ q = tor_malloc(sizeof(*q));
+ q->type = CELL_QUEUE_VAR;
+ q->u.var.var_cell = var_cell;
+
+ return q;
+}
+
+/**
+ * Write to a channel based on a cell_queue_entry_t
+ *
+ * Given a cell_queue_entry_t filled out by the caller, try to send the cell
+ * and queue it if we can't.
+ */
+
+static void
+channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
+{
+ int result = 0, sent = 0;
+ cell_queue_entry_t *tmp = NULL;
+
+ tor_assert(chan);
+ tor_assert(q);
+
+ /* Assert that the state makes sense for a cell write */
+ tor_assert(chan->state == CHANNEL_STATE_OPENING ||
+ chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT);
+
+ /* Increment the timestamp unless it's padding */
+ if (!cell_queue_entry_is_padding(q)) {
+ chan->timestamp_last_added_nonpadding = approx_time();
+ }
+
+ /* Can we send it right out? If so, try */
+ if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue) &&
+ chan->state == CHANNEL_STATE_OPEN) {
+ /* Pick the right write function for this cell type and save the result */
+ switch (q->type) {
+ case CELL_QUEUE_FIXED:
+ tor_assert(chan->write_cell);
+ tor_assert(q->u.fixed.cell);
+ result = chan->write_cell(chan, q->u.fixed.cell);
+ break;
+ case CELL_QUEUE_PACKED:
+ tor_assert(chan->write_packed_cell);
+ tor_assert(q->u.packed.packed_cell);
+ result = chan->write_packed_cell(chan, q->u.packed.packed_cell);
+ break;
+ case CELL_QUEUE_VAR:
+ tor_assert(chan->write_var_cell);
+ tor_assert(q->u.var.var_cell);
+ result = chan->write_var_cell(chan, q->u.var.var_cell);
+ break;
+ default:
+ tor_assert(1);
+ }
+
+ /* Check if we got it out */
+ if (result > 0) {
+ sent = 1;
+ /* Timestamp for transmission */
+ channel_timestamp_xmit(chan);
+ /* If we're here the queue is empty, so it's drained too */
+ channel_timestamp_drained(chan);
+ /* Update the counter */
+ ++(chan->n_cells_xmitted);
+ }
+ }
+
+ if (!sent) {
+ /* Not sent, queue it */
+ /*
+ * We have to copy the queue entry passed in, since the caller probably
+ * used the stack.
+ */
+ tmp = cell_queue_entry_dup(q);
+ TOR_SIMPLEQ_INSERT_TAIL(&chan->outgoing_queue, tmp, next);
+ /* Try to process the queue? */
+ if (chan->state == CHANNEL_STATE_OPEN) channel_flush_cells(chan);
+ }
+}
+
+/**
+ * Write a cell to a channel
+ *
+ * Write a fixed-length cell to a channel using the write_cell() method.
+ * This is equivalent to the pre-channels connection_or_write_cell_to_buf();
+ * it is called by the transport-independent code to deliver a cell to a
+ * channel for transmission.
+ */
+
+void
+channel_write_cell(channel_t *chan, cell_t *cell)
+{
+ cell_queue_entry_t q;
+
+ tor_assert(chan);
+ tor_assert(cell);
+
+ if (chan->state == CHANNEL_STATE_CLOSING) {
+ log_debug(LD_CHANNEL, "Discarding cell_t %p on closing channel %p with "
+ "global ID "U64_FORMAT, cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ tor_free(cell);
+ return;
+ }
+
+ log_debug(LD_CHANNEL,
+ "Writing cell_t %p to channel %p with global ID "
+ U64_FORMAT,
+ cell, chan, U64_PRINTF_ARG(chan->global_identifier));
+
+ q.type = CELL_QUEUE_FIXED;
+ q.u.fixed.cell = cell;
+ channel_write_cell_queue_entry(chan, &q);
+}
+
+/**
+ * Write a packed cell to a channel
+ *
+ * Write a packed cell to a channel using the write_cell() method. This is
+ * called by the transport-independent code to deliver a packed cell to a
+ * channel for transmission.
+ */
+
+void
+channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell)
+{
+ cell_queue_entry_t q;
+
+ tor_assert(chan);
+ tor_assert(packed_cell);
+
+ if (chan->state == CHANNEL_STATE_CLOSING) {
+ log_debug(LD_CHANNEL, "Discarding packed_cell_t %p on closing channel %p "
+ "with global ID "U64_FORMAT, packed_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ packed_cell_free(packed_cell);
+ return;
+ }
+
+ log_debug(LD_CHANNEL,
+ "Writing packed_cell_t %p to channel %p with global ID "
+ U64_FORMAT,
+ packed_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+
+ q.type = CELL_QUEUE_PACKED;
+ q.u.packed.packed_cell = packed_cell;
+ channel_write_cell_queue_entry(chan, &q);
+}
+
+/**
+ * Write a variable-length cell to a channel
+ *
+ * Write a variable-length cell to a channel using the write_cell() method.
+ * This is equivalent to the pre-channels
+ * connection_or_write_var_cell_to_buf(); it's called by the transport-
+ * independent code to deliver a var_cell to a channel for transmission.
+ */
+
+void
+channel_write_var_cell(channel_t *chan, var_cell_t *var_cell)
+{
+ cell_queue_entry_t q;
+
+ tor_assert(chan);
+ tor_assert(var_cell);
+
+ if (chan->state == CHANNEL_STATE_CLOSING) {
+ log_debug(LD_CHANNEL, "Discarding var_cell_t %p on closing channel %p "
+ "with global ID "U64_FORMAT, var_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ var_cell_free(var_cell);
+ return;
+ }
+
+ log_debug(LD_CHANNEL,
+ "Writing var_cell_t %p to channel %p with global ID "
+ U64_FORMAT,
+ var_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+
+ q.type = CELL_QUEUE_VAR;
+ q.u.var.var_cell = var_cell;
+ channel_write_cell_queue_entry(chan, &q);
+}
+
+/**
+ * Change channel state
+ *
+ * This internal and subclass use only function is used to change channel
+ * state, performing all transition validity checks and whatever actions
+ * are appropriate to the state transition in question.
+ */
+
+void
+channel_change_state(channel_t *chan, channel_state_t to_state)
+{
+ channel_state_t from_state;
+ unsigned char was_active, is_active;
+ unsigned char was_in_id_map, is_in_id_map;
+
+ tor_assert(chan);
+ from_state = chan->state;
+
+ tor_assert(channel_state_is_valid(from_state));
+ tor_assert(channel_state_is_valid(to_state));
+ tor_assert(channel_state_can_transition(chan->state, to_state));
+
+ /* Check for no-op transitions */
+ if (from_state == to_state) {
+ log_debug(LD_CHANNEL,
+ "Got no-op transition from \"%s\" to itself on channel %p"
+ "(global ID " U64_FORMAT ")",
+ channel_state_to_string(to_state),
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ return;
+ }
+
+ /* If we're going to a closing or closed state, we must have a reason set */
+ if (to_state == CHANNEL_STATE_CLOSING ||
+ to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR) {
+ tor_assert(chan->reason_for_closing != CHANNEL_NOT_CLOSING);
+ }
+
+ /*
+ * We need to maintain the queues here for some transitions:
+ * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT)
+ * we may have a backlog of cells to transmit, so drain the queues in
+ * that case, and when going to CHANNEL_STATE_CLOSED the subclass
+ * should have made sure to finish sending things (or gone to
+ * CHANNEL_STATE_ERROR if not possible), so we assert for that here.
+ */
+
+ log_debug(LD_CHANNEL,
+ "Changing state of channel %p (global ID " U64_FORMAT
+ ") from \"%s\" to \"%s\"",
+ chan,
+ U64_PRINTF_ARG(chan->global_identifier),
+ channel_state_to_string(chan->state),
+ channel_state_to_string(to_state));
+
+ chan->state = to_state;
+
+ /* Need to add to the right lists if the channel is registered */
+ if (chan->registered) {
+ was_active = !(from_state == CHANNEL_STATE_CLOSED ||
+ from_state == CHANNEL_STATE_ERROR);
+ is_active = !(to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR);
+
+ /* Need to take off active list and put on finished list? */
+ if (was_active && !is_active) {
+ if (active_channels) smartlist_remove(active_channels, chan);
+ if (!finished_channels) finished_channels = smartlist_new();
+ smartlist_add(finished_channels, chan);
+ }
+ /* Need to put on active list? */
+ else if (!was_active && is_active) {
+ if (finished_channels) smartlist_remove(finished_channels, chan);
+ if (!active_channels) active_channels = smartlist_new();
+ smartlist_add(active_channels, chan);
+ }
+
+ if (!tor_digest_is_zero(chan->identity_digest)) {
+ /* Now we need to handle the identity map */
+ was_in_id_map = !(from_state == CHANNEL_STATE_CLOSING ||
+ from_state == CHANNEL_STATE_CLOSED ||
+ from_state == CHANNEL_STATE_ERROR);
+ is_in_id_map = !(to_state == CHANNEL_STATE_CLOSING ||
+ to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR);
+
+ if (!was_in_id_map && is_in_id_map) channel_add_to_digest_map(chan);
+ else if (was_in_id_map && !is_in_id_map)
+ channel_remove_from_digest_map(chan);
+ }
+ }
+
+ /* Tell circuits if we opened and stuff */
+ if (to_state == CHANNEL_STATE_OPEN) {
+ channel_do_open_actions(chan);
+ chan->has_been_open = 1;
+
+ /* Check for queued cells to process */
+ if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
+ channel_process_cells(chan);
+ if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue))
+ channel_flush_cells(chan);
+ } else if (to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR) {
+ /* Assert that all queues are empty */
+ tor_assert(TOR_SIMPLEQ_EMPTY(&chan->incoming_queue));
+ tor_assert(TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue));
+ }
+}
+
+/**
+ * Change channel listener state
+ *
+ * This internal and subclass use only function is used to change channel
+ * listener state, performing all transition validity checks and whatever
+ * actions are appropriate to the state transition in question.
+ */
+
+void
+channel_listener_change_state(channel_listener_t *chan_l,
+ channel_listener_state_t to_state)
+{
+ channel_listener_state_t from_state;
+ unsigned char was_active, is_active;
+
+ tor_assert(chan_l);
+ from_state = chan_l->state;
+
+ tor_assert(channel_listener_state_is_valid(from_state));
+ tor_assert(channel_listener_state_is_valid(to_state));
+ tor_assert(channel_listener_state_can_transition(chan_l->state, to_state));
+
+ /* Check for no-op transitions */
+ if (from_state == to_state) {
+ log_debug(LD_CHANNEL,
+ "Got no-op transition from \"%s\" to itself on channel "
+ "listener %p (global ID " U64_FORMAT ")",
+ channel_listener_state_to_string(to_state),
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
+ return;
+ }
+
+ /* If we're going to a closing or closed state, we must have a reason set */
+ if (to_state == CHANNEL_LISTENER_STATE_CLOSING ||
+ to_state == CHANNEL_LISTENER_STATE_CLOSED ||
+ to_state == CHANNEL_LISTENER_STATE_ERROR) {
+ tor_assert(chan_l->reason_for_closing != CHANNEL_LISTENER_NOT_CLOSING);
+ }
+
+ /*
+ * We need to maintain the queues here for some transitions:
+ * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT)
+ * we may have a backlog of cells to transmit, so drain the queues in
+ * that case, and when going to CHANNEL_STATE_CLOSED the subclass
+ * should have made sure to finish sending things (or gone to
+ * CHANNEL_STATE_ERROR if not possible), so we assert for that here.
+ */
+
+ log_debug(LD_CHANNEL,
+ "Changing state of channel listener %p (global ID " U64_FORMAT
+ "from \"%s\" to \"%s\"",
+ chan_l, U64_PRINTF_ARG(chan_l->global_identifier),
+ channel_listener_state_to_string(chan_l->state),
+ channel_listener_state_to_string(to_state));
+
+ chan_l->state = to_state;
+
+ /* Need to add to the right lists if the channel listener is registered */
+ if (chan_l->registered) {
+ was_active = !(from_state == CHANNEL_LISTENER_STATE_CLOSED ||
+ from_state == CHANNEL_LISTENER_STATE_ERROR);
+ is_active = !(to_state == CHANNEL_LISTENER_STATE_CLOSED ||
+ to_state == CHANNEL_LISTENER_STATE_ERROR);
+
+ /* Need to take off active list and put on finished list? */
+ if (was_active && !is_active) {
+ if (active_listeners) smartlist_remove(active_listeners, chan_l);
+ if (!finished_listeners) finished_listeners = smartlist_new();
+ smartlist_add(finished_listeners, chan_l);
+ }
+ /* Need to put on active list? */
+ else if (!was_active && is_active) {
+ if (finished_listeners) smartlist_remove(finished_listeners, chan_l);
+ if (!active_listeners) active_listeners = smartlist_new();
+ smartlist_add(active_listeners, chan_l);
+ }
+ }
+
+ if (to_state == CHANNEL_LISTENER_STATE_CLOSED ||
+ to_state == CHANNEL_LISTENER_STATE_ERROR) {
+ /* Assert that the queue is empty */
+ tor_assert(!(chan_l->incoming_list) ||
+ smartlist_len(chan_l->incoming_list) == 0);
+ }
+}
+
+/**
+ * Try to flush cells to the lower layer
+ *
+ * this is called by the lower layer to indicate that it wants more cells;
+ * it will try to write up to num_cells cells from the channel's cell queue or
+ * from circuits active on that channel, or as many as it has available if
+ * num_cells == -1.
+ */
+
+#define MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED 256
+
+ssize_t
+channel_flush_some_cells(channel_t *chan, ssize_t num_cells)
+{
+ unsigned int unlimited = 0;
+ ssize_t flushed = 0;
+ int num_cells_from_circs, clamped_num_cells;
+
+ tor_assert(chan);
+
+ if (num_cells < 0) unlimited = 1;
+ if (!unlimited && num_cells <= flushed) goto done;
+
+ /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */
+ if (chan->state == CHANNEL_STATE_OPEN) {
+ /* Try to flush as much as we can that's already queued */
+ flushed += channel_flush_some_cells_from_outgoing_queue(chan,
+ (unlimited ? -1 : num_cells - flushed));
+ if (!unlimited && num_cells <= flushed) goto done;
+
+ if (circuitmux_num_cells(chan->cmux) > 0) {
+ /* Calculate number of cells, including clamp */
+ if (unlimited) {
+ clamped_num_cells = MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED;
+ } else {
+ if (num_cells - flushed >
+ MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED) {
+ clamped_num_cells = MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED;
+ } else {
+ clamped_num_cells = (int)(num_cells - flushed);
+ }
+ }
+ /* Try to get more cells from any active circuits */
+ num_cells_from_circs = channel_flush_from_first_active_circuit(
+ chan, clamped_num_cells);
+
+ /* If it claims we got some, process the queue again */
+ if (num_cells_from_circs > 0) {
+ flushed += channel_flush_some_cells_from_outgoing_queue(chan,
+ (unlimited ? -1 : num_cells - flushed));
+ }
+ }
+ }
+
+ done:
+ return flushed;
+}
+
+/**
+ * Flush cells from just the channel's outgoing cell queue
+ *
+ * This gets called from channel_flush_some_cells() above to flush cells
+ * just from the queue without trying for active_circuits.
+ */
+
+static ssize_t
+channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
+ ssize_t num_cells)
+{
+ unsigned int unlimited = 0;
+ ssize_t flushed = 0;
+ cell_queue_entry_t *q = NULL;
+
+ tor_assert(chan);
+ tor_assert(chan->write_cell);
+ tor_assert(chan->write_packed_cell);
+ tor_assert(chan->write_var_cell);
+
+ if (num_cells < 0) unlimited = 1;
+ if (!unlimited && num_cells <= flushed) return 0;
+
+ /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */
+ if (chan->state == CHANNEL_STATE_OPEN) {
+ while ((unlimited || num_cells > flushed) &&
+ NULL != (q = TOR_SIMPLEQ_FIRST(&chan->outgoing_queue))) {
+
+ if (1) {
+ /*
+ * Okay, we have a good queue entry, try to give it to the lower
+ * layer.
+ */
+ switch (q->type) {
+ case CELL_QUEUE_FIXED:
+ if (q->u.fixed.cell) {
+ if (chan->write_cell(chan,
+ q->u.fixed.cell)) {
+ ++flushed;
+ channel_timestamp_xmit(chan);
+ ++(chan->n_cells_xmitted);
+ cell_queue_entry_free(q, 1);
+ q = NULL;
+ }
+ /* Else couldn't write it; leave it on the queue */
+ } else {
+ /* This shouldn't happen */
+ log_info(LD_CHANNEL,
+ "Saw broken cell queue entry of type CELL_QUEUE_FIXED "
+ "with no cell on channel %p "
+ "(global ID " U64_FORMAT ").",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ /* Throw it away */
+ cell_queue_entry_free(q, 0);
+ q = NULL;
+ }
+ break;
+ case CELL_QUEUE_PACKED:
+ if (q->u.packed.packed_cell) {
+ if (chan->write_packed_cell(chan,
+ q->u.packed.packed_cell)) {
+ ++flushed;
+ channel_timestamp_xmit(chan);
+ ++(chan->n_cells_xmitted);
+ cell_queue_entry_free(q, 1);
+ q = NULL;
+ }
+ /* Else couldn't write it; leave it on the queue */
+ } else {
+ /* This shouldn't happen */
+ log_info(LD_CHANNEL,
+ "Saw broken cell queue entry of type CELL_QUEUE_PACKED "
+ "with no cell on channel %p "
+ "(global ID " U64_FORMAT ").",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ /* Throw it away */
+ cell_queue_entry_free(q, 0);
+ q = NULL;
+ }
+ break;
+ case CELL_QUEUE_VAR:
+ if (q->u.var.var_cell) {
+ if (chan->write_var_cell(chan,
+ q->u.var.var_cell)) {
+ ++flushed;
+ channel_timestamp_xmit(chan);
+ ++(chan->n_cells_xmitted);
+ cell_queue_entry_free(q, 1);
+ q = NULL;
+ }
+ /* Else couldn't write it; leave it on the queue */
+ } else {
+ /* This shouldn't happen */
+ log_info(LD_CHANNEL,
+ "Saw broken cell queue entry of type CELL_QUEUE_VAR "
+ "with no cell on channel %p "
+ "(global ID " U64_FORMAT ").",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ /* Throw it away */
+ cell_queue_entry_free(q, 0);
+ q = NULL;
+ }
+ break;
+ default:
+ /* Unknown type, log and free it */
+ log_info(LD_CHANNEL,
+ "Saw an unknown cell queue entry type %d on channel %p "
+ "(global ID " U64_FORMAT "; ignoring it."
+ " Someone should fix this.",
+ q->type, chan, U64_PRINTF_ARG(chan->global_identifier));
+ cell_queue_entry_free(q, 0);
+ q = NULL;
+ }
+
+ /* if q got NULLed out, we used it and should remove the queue entry */
+ if (!q) TOR_SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next);
+ /* No cell removed from list, so we can't go on any further */
+ else break;
+ }
+ }
+ }
+
+ /* Did we drain the queue? */
+ if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) {
+ channel_timestamp_drained(chan);
+ }
+
+ return flushed;
+}
+
+/**
+ * Flush as many cells as we possibly can from the queue
+ *
+ * This tries to flush as many cells from the queue as the lower layer
+ * will take. It just calls channel_flush_some_cells_from_outgoing_queue()
+ * in unlimited mode.
+ */
+
+void
+channel_flush_cells(channel_t *chan)
+{
+ channel_flush_some_cells_from_outgoing_queue(chan, -1);
+}
+
+/**
+ * Check if any cells are available
+ *
+ * This gets used from the lower layer to check if any more cells are
+ * available.
+ */
+
+int
+channel_more_to_flush(channel_t *chan)
+{
+ tor_assert(chan);
+
+ /* Check if we have any queued */
+ if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
+ return 1;
+
+ /* Check if any circuits would like to queue some */
+ if (circuitmux_num_cells(chan->cmux) > 0) return 1;
+
+ /* Else no */
+ return 0;
+}
+
+/**
+ * Notify the channel we're done flushing the output in the lower layer
+ *
+ * Connection.c will call this when we've flushed the output; there's some
+ * dirreq-related maintenance to do.
+ */
+
+void
+channel_notify_flushed(channel_t *chan)
+{
+ tor_assert(chan);
+
+ if (chan->dirreq_id != 0)
+ geoip_change_dirreq_state(chan->dirreq_id,
+ DIRREQ_TUNNELED,
+ DIRREQ_CHANNEL_BUFFER_FLUSHED);
+}
+
+/**
+ * Process the queue of incoming channels on a listener
+ *
+ * Use a listener's registered callback to process as many entries in the
+ * queue of incoming channels as possible.
+ */
+
+void
+channel_listener_process_incoming(channel_listener_t *listener)
+{
+ tor_assert(listener);
+
+ /*
+ * CHANNEL_LISTENER_STATE_CLOSING permitted because we drain the queue
+ * while closing a listener.
+ */
+ tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING ||
+ listener->state == CHANNEL_LISTENER_STATE_CLOSING);
+ tor_assert(listener->listener);
+
+ log_debug(LD_CHANNEL,
+ "Processing queue of incoming connections for channel "
+ "listener %p (global ID " U64_FORMAT ")",
+ listener, U64_PRINTF_ARG(listener->global_identifier));
+
+ if (!(listener->incoming_list)) return;
+
+ SMARTLIST_FOREACH_BEGIN(listener->incoming_list,
+ channel_t *, chan) {
+ tor_assert(chan);
+
+ log_debug(LD_CHANNEL,
+ "Handling incoming channel %p (" U64_FORMAT ") "
+ "for listener %p (" U64_FORMAT ")",
+ chan,
+ U64_PRINTF_ARG(chan->global_identifier),
+ listener,
+ U64_PRINTF_ARG(listener->global_identifier));
+ /* Make sure this is set correctly */
+ channel_mark_incoming(chan);
+ listener->listener(listener, chan);
+ } SMARTLIST_FOREACH_END(chan);
+
+ smartlist_free(listener->incoming_list);
+ listener->incoming_list = NULL;
+}
+
+/**
+ * Take actions required when a channel becomes open
+ *
+ * Handle actions we should do when we know a channel is open; a lot of
+ * this comes from the old connection_or_set_state_open() of connection_or.c.
+ *
+ * Because of this mechanism, future channel_t subclasses should take care
+ * not to change a channel to from CHANNEL_STATE_OPENING to CHANNEL_STATE_OPEN
+ * until there is positive confirmation that the network is operational.
+ * In particular, anything UDP-based should not make this transition until a
+ * packet is received from the other side.
+ */
+
+void
+channel_do_open_actions(channel_t *chan)
+{
+ tor_addr_t remote_addr;
+ int started_here, not_using = 0;
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ started_here = channel_is_outgoing(chan);
+
+ if (started_here) {
+ circuit_build_times_network_is_live(&circ_times);
+ rep_hist_note_connect_succeeded(chan->identity_digest, now);
+ if (entry_guard_register_connect_status(
+ chan->identity_digest, 1, 0, now) < 0) {
+ /* Close any circuits pending on this channel. We leave it in state
+ * 'open' though, because it didn't actually *fail* -- we just
+ * chose not to use it. */
+ log_debug(LD_OR,
+ "New entry guard was reachable, but closing this "
+ "connection so we can retry the earlier entry guards.");
+ circuit_n_chan_done(chan, 0);
+ not_using = 1;
+ }
+ router_set_status(chan->identity_digest, 1);
+ } else {
+ /* only report it to the geoip module if it's not a known router */
+ if (!router_get_by_id_digest(chan->identity_digest)) {
+ if (channel_get_addr_if_possible(chan, &remote_addr)) {
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &remote_addr,
+ now);
+ }
+ /* Otherwise the underlying transport can't tell us this, so skip it */
+ }
+ }
+
+ if (!not_using) circuit_n_chan_done(chan, 1);
+}
+
+/**
+ * Queue an incoming channel on a listener
+ *
+ * Internal and subclass use only function to queue an incoming channel from
+ * a listener. A subclass of channel_listener_t should call this when a new
+ * incoming channel is created.
+ */
+
+void
+channel_listener_queue_incoming(channel_listener_t *listener,
+ channel_t *incoming)
+{
+ int need_to_queue = 0;
+
+ tor_assert(listener);
+ tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING);
+ tor_assert(incoming);
+
+ log_debug(LD_CHANNEL,
+ "Queueing incoming channel %p (global ID " U64_FORMAT ") on "
+ "channel listener %p (global ID " U64_FORMAT ")",
+ incoming, U64_PRINTF_ARG(incoming->global_identifier),
+ listener, U64_PRINTF_ARG(listener->global_identifier));
+
+ /* Do we need to queue it, or can we just call the listener right away? */
+ if (!(listener->listener)) need_to_queue = 1;
+ if (listener->incoming_list &&
+ (smartlist_len(listener->incoming_list) > 0))
+ need_to_queue = 1;
+
+ /* If we need to queue and have no queue, create one */
+ if (need_to_queue && !(listener->incoming_list)) {
+ listener->incoming_list = smartlist_new();
+ }
+
+ /* Bump the counter and timestamp it */
+ channel_listener_timestamp_active(listener);
+ channel_listener_timestamp_accepted(listener);
+ ++(listener->n_accepted);
+
+ /* If we don't need to queue, process it right away */
+ if (!need_to_queue) {
+ tor_assert(listener->listener);
+ listener->listener(listener, incoming);
+ }
+ /*
+ * Otherwise, we need to queue; queue and then process the queue if
+ * we can.
+ */
+ else {
+ tor_assert(listener->incoming_list);
+ smartlist_add(listener->incoming_list, incoming);
+ if (listener->listener) channel_listener_process_incoming(listener);
+ }
+}
+
+/**
+ * Process queued incoming cells
+ *
+ * Process as many queued cells as we can from the incoming
+ * cell queue.
+ */
+
+void
+channel_process_cells(channel_t *chan)
+{
+ cell_queue_entry_t *q;
+ tor_assert(chan);
+ tor_assert(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_MAINT ||
+ chan->state == CHANNEL_STATE_OPEN);
+
+ log_debug(LD_CHANNEL,
+ "Processing as many incoming cells as we can for channel %p",
+ chan);
+
+ /* Nothing we can do if we have no registered cell handlers */
+ if (!(chan->cell_handler ||
+ chan->var_cell_handler)) return;
+ /* Nothing we can do if we have no cells */
+ if (TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) return;
+
+ /*
+ * Process cells until we're done or find one we have no current handler
+ * for.
+ */
+ while (NULL != (q = TOR_SIMPLEQ_FIRST(&chan->incoming_queue))) {
+ tor_assert(q);
+ tor_assert(q->type == CELL_QUEUE_FIXED ||
+ q->type == CELL_QUEUE_VAR);
+
+ if (q->type == CELL_QUEUE_FIXED &&
+ chan->cell_handler) {
+ /* Handle a fixed-length cell */
+ TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next);
+ tor_assert(q->u.fixed.cell);
+ log_debug(LD_CHANNEL,
+ "Processing incoming cell_t %p for channel %p (global ID "
+ U64_FORMAT ")",
+ q->u.fixed.cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ chan->cell_handler(chan, q->u.fixed.cell);
+ tor_free(q);
+ } else if (q->type == CELL_QUEUE_VAR &&
+ chan->var_cell_handler) {
+ /* Handle a variable-length cell */
+ TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next);
+ tor_assert(q->u.var.var_cell);
+ log_debug(LD_CHANNEL,
+ "Processing incoming var_cell_t %p for channel %p (global ID "
+ U64_FORMAT ")",
+ q->u.var.var_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ chan->var_cell_handler(chan, q->u.var.var_cell);
+ tor_free(q);
+ } else {
+ /* Can't handle this one */
+ break;
+ }
+ }
+}
+
+/**
+ * Queue incoming cell
+ *
+ * This should be called by a channel_t subclass to queue an incoming fixed-
+ * length cell for processing, and process it if possible.
+ */
+
+void
+channel_queue_cell(channel_t *chan, cell_t *cell)
+{
+ int need_to_queue = 0;
+ cell_queue_entry_t *q;
+
+ tor_assert(chan);
+ tor_assert(cell);
+ tor_assert(chan->state == CHANNEL_STATE_OPEN);
+
+ /* Do we need to queue it, or can we just call the handler right away? */
+ if (!(chan->cell_handler)) need_to_queue = 1;
+ if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
+ need_to_queue = 1;
+
+ /* Timestamp for receiving */
+ channel_timestamp_recv(chan);
+
+ /* Update the counter */
+ ++(chan->n_cells_recved);
+
+ /* If we don't need to queue we can just call cell_handler */
+ if (!need_to_queue) {
+ tor_assert(chan->cell_handler);
+ log_debug(LD_CHANNEL,
+ "Directly handling incoming cell_t %p for channel %p "
+ "(global ID " U64_FORMAT ")",
+ cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ chan->cell_handler(chan, cell);
+ } else {
+ /* Otherwise queue it and then process the queue if possible. */
+ q = cell_queue_entry_new_fixed(cell);
+ log_debug(LD_CHANNEL,
+ "Queueing incoming cell_t %p for channel %p "
+ "(global ID " U64_FORMAT ")",
+ cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next);
+ if (chan->cell_handler ||
+ chan->var_cell_handler) {
+ channel_process_cells(chan);
+ }
+ }
+}
+
+/**
+ * Queue incoming variable-length cell
+ *
+ * This should be called by a channel_t subclass to queue an incoming
+ * variable-length cell for processing, and process it if possible.
+ */
+
+void
+channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
+{
+ int need_to_queue = 0;
+ cell_queue_entry_t *q;
+
+ tor_assert(chan);
+ tor_assert(var_cell);
+ tor_assert(chan->state == CHANNEL_STATE_OPEN);
+
+ /* Do we need to queue it, or can we just call the handler right away? */
+ if (!(chan->var_cell_handler)) need_to_queue = 1;
+ if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
+ need_to_queue = 1;
+
+ /* Timestamp for receiving */
+ channel_timestamp_recv(chan);
+
+ /* Update the counter */
+ ++(chan->n_cells_recved);
+
+ /* If we don't need to queue we can just call cell_handler */
+ if (!need_to_queue) {
+ tor_assert(chan->var_cell_handler);
+ log_debug(LD_CHANNEL,
+ "Directly handling incoming var_cell_t %p for channel %p "
+ "(global ID " U64_FORMAT ")",
+ var_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ chan->var_cell_handler(chan, var_cell);
+ } else {
+ /* Otherwise queue it and then process the queue if possible. */
+ q = cell_queue_entry_new_var(var_cell);
+ log_debug(LD_CHANNEL,
+ "Queueing incoming var_cell_t %p for channel %p "
+ "(global ID " U64_FORMAT ")",
+ var_cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next);
+ if (chan->cell_handler ||
+ chan->var_cell_handler) {
+ channel_process_cells(chan);
+ }
+ }
+}
+
+/**
+ * Send destroy cell on a channel
+ *
+ * Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>
+ * onto channel <b>chan</b>. Don't perform range-checking on reason:
+ * we may want to propagate reasons from other cells.
+ */
+
+int
+channel_send_destroy(circid_t circ_id, channel_t *chan, int reason)
+{
+ cell_t cell;
+
+ tor_assert(chan);
+
+ /* Check to make sure we can send on this channel first */
+ if (!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ memset(&cell, 0, sizeof(cell_t));
+ cell.circ_id = circ_id;
+ cell.command = CELL_DESTROY;
+ cell.payload[0] = (uint8_t) reason;
+ log_debug(LD_OR,
+ "Sending destroy (circID %u) on channel %p "
+ "(global ID " U64_FORMAT ")",
+ (unsigned)circ_id, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+
+ channel_write_cell(chan, &cell);
+ } else {
+ log_warn(LD_BUG,
+ "Someone called channel_send_destroy() for circID %u "
+ "on a channel " U64_FORMAT " at %p in state %s (%d)",
+ (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier),
+ chan, channel_state_to_string(chan->state),
+ chan->state);
+ }
+
+ return 0;
+}
+
+/**
+ * Dump channel statistics to the log
+ *
+ * This is called from dumpstats() in main.c and spams the log with
+ * statistics on channels.
+ */
+
+void
+channel_dumpstats(int severity)
+{
+ if (all_channels && smartlist_len(all_channels) > 0) {
+ tor_log(severity, LD_GENERAL,
+ "Dumping statistics about %d channels:",
+ smartlist_len(all_channels));
+ tor_log(severity, LD_GENERAL,
+ "%d are active, and %d are done and waiting for cleanup",
+ (active_channels != NULL) ?
+ smartlist_len(active_channels) : 0,
+ (finished_channels != NULL) ?
+ smartlist_len(finished_channels) : 0);
+
+ SMARTLIST_FOREACH(all_channels, channel_t *, chan,
+ channel_dump_statistics(chan, severity));
+
+ tor_log(severity, LD_GENERAL,
+ "Done spamming about channels now");
+ } else {
+ tor_log(severity, LD_GENERAL,
+ "No channels to dump");
+ }
+}
+
+/**
+ * Dump channel listener statistics to the log
+ *
+ * This is called from dumpstats() in main.c and spams the log with
+ * statistics on channel listeners.
+ */
+
+void
+channel_listener_dumpstats(int severity)
+{
+ if (all_listeners && smartlist_len(all_listeners) > 0) {
+ tor_log(severity, LD_GENERAL,
+ "Dumping statistics about %d channel listeners:",
+ smartlist_len(all_listeners));
+ tor_log(severity, LD_GENERAL,
+ "%d are active and %d are done and waiting for cleanup",
+ (active_listeners != NULL) ?
+ smartlist_len(active_listeners) : 0,
+ (finished_listeners != NULL) ?
+ smartlist_len(finished_listeners) : 0);
+
+ SMARTLIST_FOREACH(all_listeners, channel_listener_t *, chan_l,
+ channel_listener_dump_statistics(chan_l, severity));
+
+ tor_log(severity, LD_GENERAL,
+ "Done spamming about channel listeners now");
+ } else {
+ tor_log(severity, LD_GENERAL,
+ "No channel listeners to dump");
+ }
+}
+
+/**
+ * Set the cmux policy on all active channels
+ */
+
+void
+channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol)
+{
+ if (!active_channels) return;
+
+ SMARTLIST_FOREACH_BEGIN(active_channels, channel_t *, curr) {
+ if (curr->cmux) {
+ circuitmux_set_policy(curr->cmux, pol);
+ }
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Clean up channels
+ *
+ * This gets called periodically from run_scheduled_events() in main.c;
+ * it cleans up after closed channels.
+ */
+
+void
+channel_run_cleanup(void)
+{
+ channel_t *tmp = NULL;
+
+ /* Check if we need to do anything */
+ if (!finished_channels || smartlist_len(finished_channels) == 0) return;
+
+ /* Iterate through finished_channels and get rid of them */
+ SMARTLIST_FOREACH_BEGIN(finished_channels, channel_t *, curr) {
+ tmp = curr;
+ /* Remove it from the list */
+ SMARTLIST_DEL_CURRENT(finished_channels, curr);
+ /* Also unregister it */
+ channel_unregister(tmp);
+ /* ... and free it */
+ channel_free(tmp);
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Clean up channel listeners
+ *
+ * This gets called periodically from run_scheduled_events() in main.c;
+ * it cleans up after closed channel listeners.
+ */
+
+void
+channel_listener_run_cleanup(void)
+{
+ channel_listener_t *tmp = NULL;
+
+ /* Check if we need to do anything */
+ if (!finished_listeners || smartlist_len(finished_listeners) == 0) return;
+
+ /* Iterate through finished_channels and get rid of them */
+ SMARTLIST_FOREACH_BEGIN(finished_listeners, channel_listener_t *, curr) {
+ tmp = curr;
+ /* Remove it from the list */
+ SMARTLIST_DEL_CURRENT(finished_listeners, curr);
+ /* Also unregister it */
+ channel_listener_unregister(tmp);
+ /* ... and free it */
+ channel_listener_free(tmp);
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Free a list of channels for channel_free_all()
+ */
+
+static void
+channel_free_list(smartlist_t *channels, int mark_for_close)
+{
+ if (!channels) return;
+
+ SMARTLIST_FOREACH_BEGIN(channels, channel_t *, curr) {
+ /* Deregister and free it */
+ tor_assert(curr);
+ log_debug(LD_CHANNEL,
+ "Cleaning up channel %p (global ID " U64_FORMAT ") "
+ "in state %s (%d)",
+ curr, U64_PRINTF_ARG(curr->global_identifier),
+ channel_state_to_string(curr->state), curr->state);
+ /* Detach circuits early so they can find the channel */
+ if (curr->cmux) {
+ circuitmux_detach_all_circuits(curr->cmux);
+ }
+ channel_unregister(curr);
+ if (mark_for_close) {
+ if (!(curr->state == CHANNEL_STATE_CLOSING ||
+ curr->state == CHANNEL_STATE_CLOSED ||
+ curr->state == CHANNEL_STATE_ERROR)) {
+ channel_mark_for_close(curr);
+ }
+ channel_force_free(curr);
+ } else channel_free(curr);
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Free a list of channel listeners for channel_free_all()
+ */
+
+static void
+channel_listener_free_list(smartlist_t *listeners, int mark_for_close)
+{
+ if (!listeners) return;
+
+ SMARTLIST_FOREACH_BEGIN(listeners, channel_listener_t *, curr) {
+ /* Deregister and free it */
+ tor_assert(curr);
+ log_debug(LD_CHANNEL,
+ "Cleaning up channel listener %p (global ID " U64_FORMAT ") "
+ "in state %s (%d)",
+ curr, U64_PRINTF_ARG(curr->global_identifier),
+ channel_listener_state_to_string(curr->state), curr->state);
+ channel_listener_unregister(curr);
+ if (mark_for_close) {
+ if (!(curr->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ curr->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ curr->state == CHANNEL_LISTENER_STATE_ERROR)) {
+ channel_listener_mark_for_close(curr);
+ }
+ channel_listener_force_free(curr);
+ } else channel_listener_free(curr);
+ } SMARTLIST_FOREACH_END(curr);
+}
+
+/**
+ * Close all channels and free everything
+ *
+ * This gets called from tor_free_all() in main.c to clean up on exit.
+ * It will close all registered channels and free associated storage,
+ * then free the all_channels, active_channels, listening_channels and
+ * finished_channels lists and also channel_identity_map.
+ */
+
+void
+channel_free_all(void)
+{
+ log_debug(LD_CHANNEL,
+ "Shutting down channels...");
+
+ /* First, let's go for finished channels */
+ if (finished_channels) {
+ channel_free_list(finished_channels, 0);
+ smartlist_free(finished_channels);
+ finished_channels = NULL;
+ }
+
+ /* Now the finished listeners */
+ if (finished_listeners) {
+ channel_listener_free_list(finished_listeners, 0);
+ smartlist_free(finished_listeners);
+ finished_listeners = NULL;
+ }
+
+ /* Now all active channels */
+ if (active_channels) {
+ channel_free_list(active_channels, 1);
+ smartlist_free(active_channels);
+ active_channels = NULL;
+ }
+
+ /* Now all active listeners */
+ if (active_listeners) {
+ channel_listener_free_list(active_listeners, 1);
+ smartlist_free(active_listeners);
+ active_listeners = NULL;
+ }
+
+ /* Now all channels, in case any are left over */
+ if (all_channels) {
+ channel_free_list(all_channels, 1);
+ smartlist_free(all_channels);
+ all_channels = NULL;
+ }
+
+ /* Now all listeners, in case any are left over */
+ if (all_listeners) {
+ channel_listener_free_list(all_listeners, 1);
+ smartlist_free(all_listeners);
+ all_listeners = NULL;
+ }
+
+ /* Now free channel_identity_map */
+ log_debug(LD_CHANNEL,
+ "Freeing channel_identity_map");
+ /* Geez, anything still left over just won't die ... let it leak then */
+ HT_CLEAR(channel_idmap, &channel_identity_map);
+
+ log_debug(LD_CHANNEL,
+ "Done cleaning up after channels");
+}
+
+/**
+ * Connect to a given addr/port/digest
+ *
+ * This sets up a new outgoing channel; in the future if multiple
+ * channel_t subclasses are available, this is where the selection policy
+ * should go. It may also be desirable to fold port into tor_addr_t
+ * or make a new type including a tor_addr_t and port, so we have a
+ * single abstract object encapsulating all the protocol details of
+ * how to contact an OR.
+ */
+
+channel_t *
+channel_connect(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest)
+{
+ return channel_tls_connect(addr, port, id_digest);
+}
+
+/**
+ * Decide which of two channels to prefer for extending a circuit
+ *
+ * This function is called while extending a circuit and returns true iff
+ * a is 'better' than b. The most important criterion here is that a
+ * canonical channel is always better than a non-canonical one, but the
+ * number of circuits and the age are used as tie-breakers.
+ *
+ * This is based on the former connection_or_is_better() of connection_or.c
+ */
+
+int
+channel_is_better(time_t now, channel_t *a, channel_t *b,
+ int forgive_new_connections)
+{
+ int a_grace, b_grace;
+ int a_is_canonical, b_is_canonical;
+ int a_has_circs, b_has_circs;
+
+ /*
+ * Do not definitively deprecate a new channel with no circuits on it
+ * until this much time has passed.
+ */
+#define NEW_CHAN_GRACE_PERIOD (15*60)
+
+ tor_assert(a);
+ tor_assert(b);
+
+ /* Check if one is canonical and the other isn't first */
+ a_is_canonical = channel_is_canonical(a);
+ b_is_canonical = channel_is_canonical(b);
+
+ if (a_is_canonical && !b_is_canonical) return 1;
+ if (!a_is_canonical && b_is_canonical) return 0;
+
+ /*
+ * Okay, if we're here they tied on canonicity. Next we check if
+ * they have any circuits, and if one does and the other doesn't,
+ * we prefer the one that does, unless we are forgiving and the
+ * one that has no circuits is in its grace period.
+ */
+
+ a_has_circs = (channel_num_circuits(a) > 0);
+ b_has_circs = (channel_num_circuits(b) > 0);
+ a_grace = (forgive_new_connections &&
+ (now < channel_when_created(a) + NEW_CHAN_GRACE_PERIOD));
+ b_grace = (forgive_new_connections &&
+ (now < channel_when_created(b) + NEW_CHAN_GRACE_PERIOD));
+
+ if (a_has_circs && !b_has_circs && !b_grace) return 1;
+ if (!a_has_circs && b_has_circs && !a_grace) return 0;
+
+ /* They tied on circuits too; just prefer whichever is newer */
+
+ if (channel_when_created(a) > channel_when_created(b)) return 1;
+ else return 0;
+}
+
+/**
+ * Get a channel to extend a circuit
+ *
+ * Pick a suitable channel to extend a circuit to given the desired digest
+ * the address we believe is correct for that digest; this tries to see
+ * if we already have one for the requested endpoint, but if there is no good
+ * channel, set *msg_out to a message describing the channel's state
+ * and our next action, and set *launch_out to a boolean indicated whether
+ * the caller should try to launch a new channel with channel_connect().
+ */
+
+channel_t *
+channel_get_for_extend(const char *digest,
+ const tor_addr_t *target_addr,
+ const char **msg_out,
+ int *launch_out)
+{
+ channel_t *chan, *best = NULL;
+ int n_inprogress_goodaddr = 0, n_old = 0;
+ int n_noncanonical = 0, n_possible = 0;
+ time_t now = approx_time();
+
+ tor_assert(msg_out);
+ tor_assert(launch_out);
+
+ chan = channel_find_by_remote_digest(digest);
+
+ /* Walk the list, unrefing the old one and refing the new at each
+ * iteration.
+ */
+ for (; chan; chan = channel_next_with_digest(chan)) {
+ tor_assert(tor_memeq(chan->identity_digest,
+ digest, DIGEST_LEN));
+
+ if (chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)
+ continue;
+
+ /* Never return a channel on which the other end appears to be
+ * a client. */
+ if (channel_is_client(chan)) {
+ continue;
+ }
+
+ /* Never return a non-open connection. */
+ if (chan->state != CHANNEL_STATE_OPEN) {
+ /* If the address matches, don't launch a new connection for this
+ * circuit. */
+ if (channel_matches_target_addr_for_extend(chan, target_addr))
+ ++n_inprogress_goodaddr;
+ continue;
+ }
+
+ /* Never return a connection that shouldn't be used for circs. */
+ if (channel_is_bad_for_new_circs(chan)) {
+ ++n_old;
+ continue;
+ }
+
+ /* Never return a non-canonical connection using a recent link protocol
+ * if the address is not what we wanted.
+ *
+ * The channel_is_canonical_is_reliable() function asks the lower layer
+ * if we should trust channel_is_canonical(). The below is from the
+ * comments of the old circuit_or_get_for_extend() and applies when
+ * the lower-layer transport is channel_tls_t.
+ *
+ * (For old link protocols, we can't rely on is_canonical getting
+ * set properly if we're talking to the right address, since we might
+ * have an out-of-date descriptor, and we will get no NETINFO cell to
+ * tell us about the right address.)
+ */
+ if (!channel_is_canonical(chan) &&
+ channel_is_canonical_is_reliable(chan) &&
+ !channel_matches_target_addr_for_extend(chan, target_addr)) {
+ ++n_noncanonical;
+ continue;
+ }
+
+ ++n_possible;
+
+ if (!best) {
+ best = chan; /* If we have no 'best' so far, this one is good enough. */
+ continue;
+ }
+
+ if (channel_is_better(now, chan, best, 0))
+ best = chan;
+ }
+
+ if (best) {
+ *msg_out = "Connection is fine; using it.";
+ *launch_out = 0;
+ return best;
+ } else if (n_inprogress_goodaddr) {
+ *msg_out = "Connection in progress; waiting.";
+ *launch_out = 0;
+ return NULL;
+ } else if (n_old || n_noncanonical) {
+ *msg_out = "Connections all too old, or too non-canonical. "
+ " Launching a new one.";
+ *launch_out = 1;
+ return NULL;
+ } else {
+ *msg_out = "Not connected. Connecting.";
+ *launch_out = 1;
+ return NULL;
+ }
+}
+
+/**
+ * Describe the transport subclass for a channel
+ *
+ * Invoke a method to get a string description of the lower-layer
+ * transport for this channel.
+ */
+
+const char *
+channel_describe_transport(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->describe_transport);
+
+ return chan->describe_transport(chan);
+}
+
+/**
+ * Describe the transport subclass for a channel listener
+ *
+ * Invoke a method to get a string description of the lower-layer
+ * transport for this channel listener.
+ */
+
+const char *
+channel_listener_describe_transport(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+ tor_assert(chan_l->describe_transport);
+
+ return chan_l->describe_transport(chan_l);
+}
+
+/**
+ * Return the number of entries in <b>queue</b>
+ */
+static int
+chan_cell_queue_len(const chan_cell_queue_t *queue)
+{
+ int r = 0;
+ cell_queue_entry_t *cell;
+ TOR_SIMPLEQ_FOREACH(cell, queue, next)
+ ++r;
+ return r;
+}
+
+/**
+ * Dump channel statistics
+ *
+ * Dump statistics for one channel to the log
+ */
+
+void
+channel_dump_statistics(channel_t *chan, int severity)
+{
+ double avg, interval, age;
+ time_t now = time(NULL);
+ tor_addr_t remote_addr;
+ int have_remote_addr;
+ char *remote_addr_str;
+
+ tor_assert(chan);
+
+ age = (double)(now - chan->timestamp_created);
+
+ tor_log(severity, LD_GENERAL,
+ "Channel " U64_FORMAT " (at %p) with transport %s is in state "
+ "%s (%d)",
+ U64_PRINTF_ARG(chan->global_identifier), chan,
+ channel_describe_transport(chan),
+ channel_state_to_string(chan->state), chan->state);
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " was created at " U64_FORMAT
+ " (" U64_FORMAT " seconds ago) "
+ "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_created),
+ U64_PRINTF_ARG(now - chan->timestamp_created),
+ U64_PRINTF_ARG(chan->timestamp_active),
+ U64_PRINTF_ARG(now - chan->timestamp_active));
+
+ /* Handle digest and nickname */
+ if (!tor_digest_is_zero(chan->identity_digest)) {
+ if (chan->nickname) {
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " says it is connected "
+ "to an OR with digest %s and nickname %s",
+ U64_PRINTF_ARG(chan->global_identifier),
+ hex_str(chan->identity_digest, DIGEST_LEN),
+ chan->nickname);
+ } else {
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " says it is connected "
+ "to an OR with digest %s and no known nickname",
+ U64_PRINTF_ARG(chan->global_identifier),
+ hex_str(chan->identity_digest, DIGEST_LEN));
+ }
+ } else {
+ if (chan->nickname) {
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " does not know the digest"
+ " of the OR it is connected to, but reports its nickname is %s",
+ U64_PRINTF_ARG(chan->global_identifier),
+ chan->nickname);
+ } else {
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " does not know the digest"
+ " or the nickname of the OR it is connected to",
+ U64_PRINTF_ARG(chan->global_identifier));
+ }
+ }
+
+ /* Handle remote address and descriptions */
+ have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr);
+ if (have_remote_addr) {
+ char *actual = tor_strdup(channel_get_actual_remote_descr(chan));
+ remote_addr_str = tor_dup_addr(&remote_addr);
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " says its remote address"
+ " is %s, and gives a canonical description of \"%s\" and an "
+ "actual description of \"%s\"",
+ U64_PRINTF_ARG(chan->global_identifier),
+ remote_addr_str,
+ channel_get_canonical_remote_descr(chan),
+ actual);
+ tor_free(remote_addr_str);
+ tor_free(actual);
+ } else {
+ char *actual = tor_strdup(channel_get_actual_remote_descr(chan));
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " does not know its remote "
+ "address, but gives a canonical description of \"%s\" and an "
+ "actual description of \"%s\"",
+ U64_PRINTF_ARG(chan->global_identifier),
+ channel_get_canonical_remote_descr(chan),
+ actual);
+ tor_free(actual);
+ }
+
+ /* Handle marks */
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has these marks: %s %s %s "
+ "%s %s %s",
+ U64_PRINTF_ARG(chan->global_identifier),
+ channel_is_bad_for_new_circs(chan) ?
+ "bad_for_new_circs" : "!bad_for_new_circs",
+ channel_is_canonical(chan) ?
+ "canonical" : "!canonical",
+ channel_is_canonical_is_reliable(chan) ?
+ "is_canonical_is_reliable" :
+ "!is_canonical_is_reliable",
+ channel_is_client(chan) ?
+ "client" : "!client",
+ channel_is_local(chan) ?
+ "local" : "!local",
+ channel_is_incoming(chan) ?
+ "incoming" : "outgoing");
+
+ /* Describe queues */
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has %d queued incoming cells"
+ " and %d queued outgoing cells",
+ U64_PRINTF_ARG(chan->global_identifier),
+ chan_cell_queue_len(&chan->incoming_queue),
+ chan_cell_queue_len(&chan->outgoing_queue));
+
+ /* Describe circuits */
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has %d active circuits out of"
+ " %d in total",
+ U64_PRINTF_ARG(chan->global_identifier),
+ (chan->cmux != NULL) ?
+ circuitmux_num_active_circuits(chan->cmux) : 0,
+ (chan->cmux != NULL) ?
+ circuitmux_num_circuits(chan->cmux) : 0);
+
+ /* Describe timestamps */
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " was last used by a "
+ "client at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_client),
+ U64_PRINTF_ARG(now - chan->timestamp_client));
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " was last drained at "
+ U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_drained),
+ U64_PRINTF_ARG(now - chan->timestamp_drained));
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " last received a cell "
+ "at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_recv),
+ U64_PRINTF_ARG(now - chan->timestamp_recv));
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " last trasmitted a cell "
+ "at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->timestamp_xmit),
+ U64_PRINTF_ARG(now - chan->timestamp_xmit));
+
+ /* Describe counters and rates */
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has received "
+ U64_FORMAT " cells and transmitted " U64_FORMAT,
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->n_cells_recved),
+ U64_PRINTF_ARG(chan->n_cells_xmitted));
+ if (now > chan->timestamp_created &&
+ chan->timestamp_created > 0) {
+ if (chan->n_cells_recved > 0) {
+ avg = (double)(chan->n_cells_recved) / age;
+ if (avg >= 1.0) {
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "cells received per second",
+ U64_PRINTF_ARG(chan->global_identifier), avg);
+ } else if (avg >= 0.0) {
+ interval = 1.0 / avg;
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "seconds between received cells",
+ U64_PRINTF_ARG(chan->global_identifier), interval);
+ }
+ }
+ if (chan->n_cells_xmitted > 0) {
+ avg = (double)(chan->n_cells_xmitted) / age;
+ if (avg >= 1.0) {
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "cells transmitted per second",
+ U64_PRINTF_ARG(chan->global_identifier), avg);
+ } else if (avg >= 0.0) {
+ interval = 1.0 / avg;
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "seconds between transmitted cells",
+ U64_PRINTF_ARG(chan->global_identifier), interval);
+ }
+ }
+ }
+
+ /* Dump anything the lower layer has to say */
+ channel_dump_transport_statistics(chan, severity);
+}
+
+/**
+ * Dump channel listener statistics
+ *
+ * Dump statistics for one channel listener to the log
+ */
+
+void
+channel_listener_dump_statistics(channel_listener_t *chan_l, int severity)
+{
+ double avg, interval, age;
+ time_t now = time(NULL);
+
+ tor_assert(chan_l);
+
+ age = (double)(now - chan_l->timestamp_created);
+
+ tor_log(severity, LD_GENERAL,
+ "Channel listener " U64_FORMAT " (at %p) with transport %s is in "
+ "state %s (%d)",
+ U64_PRINTF_ARG(chan_l->global_identifier), chan_l,
+ channel_listener_describe_transport(chan_l),
+ channel_listener_state_to_string(chan_l->state), chan_l->state);
+ tor_log(severity, LD_GENERAL,
+ " * Channel listener " U64_FORMAT " was created at " U64_FORMAT
+ " (" U64_FORMAT " seconds ago) "
+ "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
+ U64_PRINTF_ARG(chan_l->global_identifier),
+ U64_PRINTF_ARG(chan_l->timestamp_created),
+ U64_PRINTF_ARG(now - chan_l->timestamp_created),
+ U64_PRINTF_ARG(chan_l->timestamp_active),
+ U64_PRINTF_ARG(now - chan_l->timestamp_active));
+
+ tor_log(severity, LD_GENERAL,
+ " * Channel listener " U64_FORMAT " last accepted an incoming "
+ "channel at " U64_FORMAT " (" U64_FORMAT " seconds ago) "
+ "and has accepted " U64_FORMAT " channels in total",
+ U64_PRINTF_ARG(chan_l->global_identifier),
+ U64_PRINTF_ARG(chan_l->timestamp_accepted),
+ U64_PRINTF_ARG(now - chan_l->timestamp_accepted),
+ U64_PRINTF_ARG(chan_l->n_accepted));
+
+ /*
+ * If it's sensible to do so, get the rate of incoming channels on this
+ * listener
+ */
+ if (now > chan_l->timestamp_created &&
+ chan_l->timestamp_created > 0 &&
+ chan_l->n_accepted > 0) {
+ avg = (double)(chan_l->n_accepted) / age;
+ if (avg >= 1.0) {
+ tor_log(severity, LD_GENERAL,
+ " * Channel listener " U64_FORMAT " has averaged %f incoming "
+ "channels per second",
+ U64_PRINTF_ARG(chan_l->global_identifier), avg);
+ } else if (avg >= 0.0) {
+ interval = 1.0 / avg;
+ tor_log(severity, LD_GENERAL,
+ " * Channel listener " U64_FORMAT " has averaged %f seconds "
+ "between incoming channels",
+ U64_PRINTF_ARG(chan_l->global_identifier), interval);
+ }
+ }
+
+ /* Dump anything the lower layer has to say */
+ channel_listener_dump_transport_statistics(chan_l, severity);
+}
+
+/**
+ * Invoke transport-specific stats dump for channel
+ *
+ * If there is a lower-layer statistics dump method, invoke it
+ */
+
+void
+channel_dump_transport_statistics(channel_t *chan, int severity)
+{
+ tor_assert(chan);
+
+ if (chan->dumpstats) chan->dumpstats(chan, severity);
+}
+
+/**
+ * Invoke transport-specific stats dump for channel listener
+ *
+ * If there is a lower-layer statistics dump method, invoke it
+ */
+
+void
+channel_listener_dump_transport_statistics(channel_listener_t *chan_l,
+ int severity)
+{
+ tor_assert(chan_l);
+
+ if (chan_l->dumpstats) chan_l->dumpstats(chan_l, severity);
+}
+
+/**
+ * Return text description of the remote endpoint
+ *
+ * This function return a test provided by the lower layer of the remote
+ * endpoint for this channel; it should specify the actual address connected
+ * to/from.
+ *
+ * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
+ * may invalidate the return value from this function.
+ */
+const char *
+channel_get_actual_remote_descr(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->get_remote_descr);
+
+ /* Param 1 indicates the actual description */
+ return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL);
+}
+
+/**
+ * Return the text address of the remote endpoint.
+ *
+ * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
+ * may invalidate the return value from this function.
+ */
+const char *
+channel_get_actual_remote_address(channel_t *chan)
+{
+ /* Param 1 indicates the actual description */
+ return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY);
+}
+
+/**
+ * Return text description of the remote endpoint canonical address
+ *
+ * This function return a test provided by the lower layer of the remote
+ * endpoint for this channel; it should use the known canonical address for
+ * this OR's identity digest if possible.
+ *
+ * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
+ * may invalidate the return value from this function.
+ */
+const char *
+channel_get_canonical_remote_descr(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->get_remote_descr);
+
+ /* Param 0 indicates the canonicalized description */
+ return chan->get_remote_descr(chan, 0);
+}
+
+/**
+ * Get remote address if possible.
+ *
+ * Write the remote address out to a tor_addr_t if the underlying transport
+ * supports this operation, and return 1. Return 0 if the underlying transport
+ * doesn't let us do this.
+ */
+int
+channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out)
+{
+ tor_assert(chan);
+ tor_assert(addr_out);
+
+ if (chan->get_remote_addr)
+ return chan->get_remote_addr(chan, addr_out);
+ /* Else no support, method not implemented */
+ else return 0;
+}
+
+/**
+ * Check if there are outgoing queue writes on this channel
+ *
+ * Indicate if either we have queued cells, or if not, whether the underlying
+ * lower-layer transport thinks it has an output queue.
+ */
+
+int
+channel_has_queued_writes(channel_t *chan)
+{
+ int has_writes = 0;
+
+ tor_assert(chan);
+ tor_assert(chan->has_queued_writes);
+
+ if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) {
+ has_writes = 1;
+ } else {
+ /* Check with the lower layer */
+ has_writes = chan->has_queued_writes(chan);
+ }
+
+ return has_writes;
+}
+
+/**
+ * Check the is_bad_for_new_circs flag
+ *
+ * This function returns the is_bad_for_new_circs flag of the specified
+ * channel.
+ */
+
+int
+channel_is_bad_for_new_circs(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->is_bad_for_new_circs;
+}
+
+/**
+ * Mark a channel as bad for new circuits
+ *
+ * Set the is_bad_for_new_circs_flag on chan.
+ */
+
+void
+channel_mark_bad_for_new_circs(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_bad_for_new_circs = 1;
+}
+
+/**
+ * Get the client flag
+ *
+ * This returns the client flag of a channel, which will be set if
+ * command_process_create_cell() in command.c thinks this is a connection
+ * from a client.
+ */
+
+int
+channel_is_client(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->is_client;
+}
+
+/**
+ * Set the client flag
+ *
+ * Mark a channel as being from a client
+ */
+
+void
+channel_mark_client(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_client = 1;
+}
+
+/**
+ * Get the canonical flag for a channel
+ *
+ * This returns the is_canonical for a channel; this flag is determined by
+ * the lower layer and can't be set in a transport-independent way.
+ */
+
+int
+channel_is_canonical(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->is_canonical);
+
+ return chan->is_canonical(chan, 0);
+}
+
+/**
+ * Test if the canonical flag is reliable
+ *
+ * This function asks if the lower layer thinks it's safe to trust the
+ * result of channel_is_canonical()
+ */
+
+int
+channel_is_canonical_is_reliable(channel_t *chan)
+{
+ tor_assert(chan);
+ tor_assert(chan->is_canonical);
+
+ return chan->is_canonical(chan, 1);
+}
+
+/**
+ * Test incoming flag
+ *
+ * This function gets the incoming flag; this is set when a listener spawns
+ * a channel. If this returns true the channel was remotely initiated.
+ */
+
+int
+channel_is_incoming(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->is_incoming;
+}
+
+/**
+ * Set the incoming flag
+ *
+ * This function is called when a channel arrives on a listening channel
+ * to mark it as incoming.
+ */
+
+void
+channel_mark_incoming(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_incoming = 1;
+}
+
+/**
+ * Test local flag
+ *
+ * This function gets the local flag; the lower layer should set this when
+ * setting up the channel if is_local_addr() is true for all of the
+ * destinations it will communicate with on behalf of this channel. It's
+ * used to decide whether to declare the network reachable when seeing incoming
+ * traffic on the channel.
+ */
+
+int
+channel_is_local(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->is_local;
+}
+
+/**
+ * Set the local flag
+ *
+ * This internal-only function should be called by the lower layer if the
+ * channel is to a local address. See channel_is_local() above or the
+ * description of the is_local bit in channel.h
+ */
+
+void
+channel_mark_local(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_local = 1;
+}
+
+/**
+ * Test outgoing flag
+ *
+ * This function gets the outgoing flag; this is the inverse of the incoming
+ * bit set when a listener spawns a channel. If this returns true the channel
+ * was locally initiated.
+ */
+
+int
+channel_is_outgoing(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return !(chan->is_incoming);
+}
+
+/**
+ * Mark a channel as outgoing
+ *
+ * This function clears the incoming flag and thus marks a channel as
+ * outgoing.
+ */
+
+void
+channel_mark_outgoing(channel_t *chan)
+{
+ tor_assert(chan);
+
+ chan->is_incoming = 0;
+}
+
+/*********************
+ * Timestamp updates *
+ ********************/
+
+/**
+ * Update the created timestamp for a channel
+ *
+ * This updates the channel's created timestamp and should only be called
+ * from channel_init().
+ */
+
+void
+channel_timestamp_created(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_created = now;
+}
+
+/**
+ * Update the created timestamp for a channel listener
+ *
+ * This updates the channel listener's created timestamp and should only be
+ * called from channel_init_listener().
+ */
+
+void
+channel_listener_timestamp_created(channel_listener_t *chan_l)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan_l);
+
+ chan_l->timestamp_created = now;
+}
+
+/**
+ * Update the last active timestamp for a channel
+ *
+ * This function updates the channel's last active timestamp; it should be
+ * called by the lower layer whenever there is activity on the channel which
+ * does not lead to a cell being transmitted or received; the active timestamp
+ * is also updated from channel_timestamp_recv() and channel_timestamp_xmit(),
+ * but it should be updated for things like the v3 handshake and stuff that
+ * produce activity only visible to the lower layer.
+ */
+
+void
+channel_timestamp_active(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_active = now;
+}
+
+/**
+ * Update the last active timestamp for a channel listener
+ */
+
+void
+channel_listener_timestamp_active(channel_listener_t *chan_l)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan_l);
+
+ chan_l->timestamp_active = now;
+}
+
+/**
+ * Update the last accepted timestamp.
+ *
+ * This function updates the channel listener's last accepted timestamp; it
+ * should be called whenever a new incoming channel is accepted on a
+ * listener.
+ */
+
+void
+channel_listener_timestamp_accepted(channel_listener_t *chan_l)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan_l);
+
+ chan_l->timestamp_active = now;
+ chan_l->timestamp_accepted = now;
+}
+
+/**
+ * Update client timestamp
+ *
+ * This function is called by relay.c to timestamp a channel that appears to
+ * be used as a client.
+ */
+
+void
+channel_timestamp_client(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_client = now;
+}
+
+/**
+ * Update the last drained timestamp
+ *
+ * This is called whenever we transmit a cell which leaves the outgoing cell
+ * queue completely empty. It also updates the xmit time and the active time.
+ */
+
+void
+channel_timestamp_drained(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_active = now;
+ chan->timestamp_drained = now;
+ chan->timestamp_xmit = now;
+}
+
+/**
+ * Update the recv timestamp
+ *
+ * This is called whenever we get an incoming cell from the lower layer.
+ * This also updates the active timestamp.
+ */
+
+void
+channel_timestamp_recv(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_active = now;
+ chan->timestamp_recv = now;
+}
+
+/**
+ * Update the xmit timestamp
+ * This is called whenever we pass an outgoing cell to the lower layer. This
+ * also updates the active timestamp.
+ */
+
+void
+channel_timestamp_xmit(channel_t *chan)
+{
+ time_t now = time(NULL);
+
+ tor_assert(chan);
+
+ chan->timestamp_active = now;
+ chan->timestamp_xmit = now;
+}
+
+/***************************************************************
+ * Timestamp queries - see above for definitions of timestamps *
+ **************************************************************/
+
+/**
+ * Query created timestamp for a channel
+ */
+
+time_t
+channel_when_created(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_created;
+}
+
+/**
+ * Query created timestamp for a channel listener
+ */
+
+time_t
+channel_listener_when_created(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return chan_l->timestamp_created;
+}
+
+/**
+ * Query last active timestamp for a channel
+ */
+
+time_t
+channel_when_last_active(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_active;
+}
+
+/**
+ * Query last active timestamp for a channel listener
+ */
+
+time_t
+channel_listener_when_last_active(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return chan_l->timestamp_active;
+}
+
+/**
+ * Query last accepted timestamp for a channel listener
+ */
+
+time_t
+channel_listener_when_last_accepted(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return chan_l->timestamp_accepted;
+}
+
+/**
+ * Query client timestamp
+ */
+
+time_t
+channel_when_last_client(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_client;
+}
+
+/**
+ * Query drained timestamp
+ */
+
+time_t
+channel_when_last_drained(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_drained;
+}
+
+/**
+ * Query recv timestamp
+ */
+
+time_t
+channel_when_last_recv(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_recv;
+}
+
+/**
+ * Query xmit timestamp
+ */
+
+time_t
+channel_when_last_xmit(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->timestamp_xmit;
+}
+
+/**
+ * Query accepted counter
+ */
+
+uint64_t
+channel_listener_count_accepted(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return chan_l->n_accepted;
+}
+
+/**
+ * Query received cell counter
+ */
+
+uint64_t
+channel_count_recved(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->n_cells_recved;
+}
+
+/**
+ * Query transmitted cell counter
+ */
+
+uint64_t
+channel_count_xmitted(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->n_cells_xmitted;
+}
+
+/**
+ * Check if a channel matches an extend_info_t
+ *
+ * This function calls the lower layer and asks if this channel matches a
+ * given extend_info_t.
+ */
+
+int
+channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info)
+{
+ tor_assert(chan);
+ tor_assert(chan->matches_extend_info);
+ tor_assert(extend_info);
+
+ return chan->matches_extend_info(chan, extend_info);
+}
+
+/**
+ * Check if a channel matches a given target address; return true iff we do.
+ *
+ * This function calls into the lower layer and asks if this channel thinks
+ * it matches a given target address for circuit extension purposes.
+ */
+
+int
+channel_matches_target_addr_for_extend(channel_t *chan,
+ const tor_addr_t *target)
+{
+ tor_assert(chan);
+ tor_assert(chan->matches_target);
+ tor_assert(target);
+
+ return chan->matches_target(chan, target);
+}
+
+/**
+ * Return the total number of circuits used by a channel
+ *
+ * @param chan Channel to query
+ * @return Number of circuits using this as n_chan or p_chan
+ */
+
+unsigned int
+channel_num_circuits(channel_t *chan)
+{
+ tor_assert(chan);
+
+ return chan->num_n_circuits +
+ chan->num_p_circuits;
+}
+
+/**
+ * Set up circuit ID generation
+ *
+ * This is called when setting up a channel and replaces the old
+ * connection_or_set_circid_type()
+ */
+void
+channel_set_circid_type(channel_t *chan,
+ crypto_pk_t *identity_rcvd,
+ int consider_identity)
+{
+ int started_here;
+ crypto_pk_t *our_identity;
+
+ tor_assert(chan);
+
+ started_here = channel_is_outgoing(chan);
+
+ if (! consider_identity) {
+ if (started_here)
+ chan->circ_id_type = CIRC_ID_TYPE_HIGHER;
+ else
+ chan->circ_id_type = CIRC_ID_TYPE_LOWER;
+ return;
+ }
+
+ our_identity = started_here ?
+ get_tlsclient_identity_key() : get_server_identity_key();
+
+ if (identity_rcvd) {
+ if (crypto_pk_cmp_keys(our_identity, identity_rcvd) < 0) {
+ chan->circ_id_type = CIRC_ID_TYPE_LOWER;
+ } else {
+ chan->circ_id_type = CIRC_ID_TYPE_HIGHER;
+ }
+ } else {
+ chan->circ_id_type = CIRC_ID_TYPE_NEITHER;
+ }
+}
+
diff --git a/src/or/channel.h b/src/or/channel.h
new file mode 100644
index 000000000..2dca81705
--- /dev/null
+++ b/src/or/channel.h
@@ -0,0 +1,484 @@
+/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file channel.h
+ * \brief Header file for channel.c
+ **/
+
+#ifndef TOR_CHANNEL_H
+#define TOR_CHANNEL_H
+
+#include "or.h"
+#include "tor_queue.h"
+#include "circuitmux.h"
+
+/* Channel handler function pointer typedefs */
+typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *);
+typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *);
+typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *);
+
+struct cell_queue_entry_s;
+TOR_SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s) incoming_queue;
+typedef struct chan_cell_queue chan_cell_queue_t;
+
+/*
+ * Channel struct; see the channel_t typedef in or.h. A channel is an
+ * abstract interface for the OR-to-OR connection, similar to connection_or_t,
+ * but without the strong coupling to the underlying TLS implementation. They
+ * are constructed by calling a protocol-specific function to open a channel
+ * to a particular node, and once constructed support the abstract operations
+ * defined below.
+ */
+
+struct channel_s {
+ /* Magic number for type-checking cast macros */
+ uint32_t magic;
+
+ /* Current channel state */
+ channel_state_t state;
+
+ /* Globally unique ID number for a channel over the lifetime of a Tor
+ * process.
+ */
+ uint64_t global_identifier;
+
+ /* Should we expect to see this channel in the channel lists? */
+ unsigned char registered:1;
+
+ /** has this channel ever been open? */
+ unsigned int has_been_open:1;
+
+ /** Why did we close?
+ */
+ enum {
+ CHANNEL_NOT_CLOSING = 0,
+ CHANNEL_CLOSE_REQUESTED,
+ CHANNEL_CLOSE_FROM_BELOW,
+ CHANNEL_CLOSE_FOR_ERROR
+ } reason_for_closing;
+
+ /* Timestamps for both cell channels and listeners */
+ time_t timestamp_created; /* Channel created */
+ time_t timestamp_active; /* Any activity */
+
+ /* Methods implemented by the lower layer */
+
+ /* Free a channel */
+ void (*free)(channel_t *);
+ /* Close an open channel */
+ void (*close)(channel_t *);
+ /* Describe the transport subclass for this channel */
+ const char * (*describe_transport)(channel_t *);
+ /* Optional method to dump transport-specific statistics on the channel */
+ void (*dumpstats)(channel_t *, int);
+
+ /* Registered handlers for incoming cells */
+ channel_cell_handler_fn_ptr cell_handler;
+ channel_var_cell_handler_fn_ptr var_cell_handler;
+
+ /* Methods implemented by the lower layer */
+
+ /*
+ * Ask the underlying transport what the remote endpoint address is, in
+ * a tor_addr_t. This is optional and subclasses may leave this NULL.
+ * If they implement it, they should write the address out to the
+ * provided tor_addr_t *, and return 1 if successful or 0 if no address
+ * available.
+ */
+ int (*get_remote_addr)(channel_t *, tor_addr_t *);
+#define GRD_FLAG_ORIGINAL 1
+#define GRD_FLAG_ADDR_ONLY 2
+ /*
+ * Get a text description of the remote endpoint; canonicalized if the flag
+ * GRD_FLAG_ORIGINAL is not set, or the one we originally connected
+ * to/received from if it is. If GRD_FLAG_ADDR_ONLY is set, we return only
+ * the original address.
+ */
+ const char * (*get_remote_descr)(channel_t *, int);
+ /* Check if the lower layer has queued writes */
+ int (*has_queued_writes)(channel_t *);
+ /*
+ * If the second param is zero, ask the lower layer if this is
+ * 'canonical', for a transport-specific definition of canonical; if
+ * it is 1, ask if the answer to the preceding query is safe to rely
+ * on.
+ */
+ int (*is_canonical)(channel_t *, int);
+ /* Check if this channel matches a specified extend_info_t */
+ int (*matches_extend_info)(channel_t *, extend_info_t *);
+ /* Check if this channel matches a target address when extending */
+ int (*matches_target)(channel_t *, const tor_addr_t *);
+ /* Write a cell to an open channel */
+ int (*write_cell)(channel_t *, cell_t *);
+ /* Write a packed cell to an open channel */
+ int (*write_packed_cell)(channel_t *, packed_cell_t *);
+ /* Write a variable-length cell to an open channel */
+ int (*write_var_cell)(channel_t *, var_cell_t *);
+
+ /*
+ * Hash of the public RSA key for the other side's identity key, or
+ * zeroes if the other side hasn't shown us a valid identity key.
+ */
+ char identity_digest[DIGEST_LEN];
+ /* Nickname of the OR on the other side, or NULL if none. */
+ char *nickname;
+
+ /*
+ * Linked list of channels with the same identity digest, for the
+ * digest->channel map
+ */
+ TOR_LIST_ENTRY(channel_s) next_with_same_id;
+
+ /* List of incoming cells to handle */
+ chan_cell_queue_t incoming_queue;
+
+ /* List of queued outgoing cells */
+ chan_cell_queue_t outgoing_queue;
+
+ /* Circuit mux for circuits sending on this channel */
+ circuitmux_t *cmux;
+
+ /* Circuit ID generation stuff for use by circuitbuild.c */
+
+ /*
+ * When we send CREATE cells along this connection, which half of the
+ * space should we use?
+ */
+ ENUM_BF(circ_id_type_t) circ_id_type:2;
+ /** DOCDOC*/
+ unsigned wide_circ_ids:1;
+ /*
+ * Which circ_id do we try to use next on this connection? This is
+ * always in the range 0..1<<15-1.
+ */
+ circid_t next_circ_id;
+
+ /* For how many circuits are we n_chan? What about p_chan? */
+ unsigned int num_n_circuits, num_p_circuits;
+
+ /*
+ * True iff this channel shouldn't get any new circs attached to it,
+ * because the connection is too old, or because there's a better one.
+ * More generally, this flag is used to note an unhealthy connection;
+ * for example, if a bad connection fails we shouldn't assume that the
+ * router itself has a problem.
+ */
+ unsigned int is_bad_for_new_circs:1;
+
+ /** True iff we have decided that the other end of this connection
+ * is a client. Channels with this flag set should never be used
+ * to satisfy an EXTEND request. */
+ unsigned int is_client:1;
+
+ /** Set if the channel was initiated remotely (came from a listener) */
+ unsigned int is_incoming:1;
+
+ /** Set by lower layer if this is local; i.e., everything it communicates
+ * with for this channel returns true for is_local_addr(). This is used
+ * to decide whether to declare reachability when we receive something on
+ * this channel in circuitbuild.c
+ */
+ unsigned int is_local:1;
+
+ /** Channel timestamps for cell channels */
+ time_t timestamp_client; /* Client used this, according to relay.c */
+ time_t timestamp_drained; /* Output queue empty */
+ time_t timestamp_recv; /* Cell received from lower layer */
+ time_t timestamp_xmit; /* Cell sent to lower layer */
+
+ /* Timestamp for relay.c */
+ time_t timestamp_last_added_nonpadding;
+
+ /** Unique ID for measuring direct network status requests;vtunneled ones
+ * come over a circuit_t, which has a dirreq_id field as well, but is a
+ * distinct namespace. */
+ uint64_t dirreq_id;
+
+ /** Channel counters for cell channels */
+ uint64_t n_cells_recved;
+ uint64_t n_cells_xmitted;
+};
+
+struct channel_listener_s {
+ /* Current channel listener state */
+ channel_listener_state_t state;
+
+ /* Globally unique ID number for a channel over the lifetime of a Tor
+ * process.
+ */
+ uint64_t global_identifier;
+
+ /* Should we expect to see this channel in the channel lists? */
+ unsigned char registered:1;
+
+ /** Why did we close?
+ */
+ enum {
+ CHANNEL_LISTENER_NOT_CLOSING = 0,
+ CHANNEL_LISTENER_CLOSE_REQUESTED,
+ CHANNEL_LISTENER_CLOSE_FROM_BELOW,
+ CHANNEL_LISTENER_CLOSE_FOR_ERROR
+ } reason_for_closing;
+
+ /* Timestamps for both cell channels and listeners */
+ time_t timestamp_created; /* Channel created */
+ time_t timestamp_active; /* Any activity */
+
+ /* Methods implemented by the lower layer */
+
+ /* Free a channel */
+ void (*free)(channel_listener_t *);
+ /* Close an open channel */
+ void (*close)(channel_listener_t *);
+ /* Describe the transport subclass for this channel */
+ const char * (*describe_transport)(channel_listener_t *);
+ /* Optional method to dump transport-specific statistics on the channel */
+ void (*dumpstats)(channel_listener_t *, int);
+
+ /* Registered listen handler to call on incoming connection */
+ channel_listener_fn_ptr listener;
+
+ /* List of pending incoming connections */
+ smartlist_t *incoming_list;
+
+ /* Timestamps for listeners */
+ time_t timestamp_accepted;
+
+ /* Counters for listeners */
+ uint64_t n_accepted;
+};
+
+/* Channel state manipulations */
+
+int channel_state_is_valid(channel_state_t state);
+int channel_listener_state_is_valid(channel_listener_state_t state);
+
+int channel_state_can_transition(channel_state_t from, channel_state_t to);
+int channel_listener_state_can_transition(channel_listener_state_t from,
+ channel_listener_state_t to);
+
+const char * channel_state_to_string(channel_state_t state);
+const char *
+channel_listener_state_to_string(channel_listener_state_t state);
+
+/* Abstract channel operations */
+
+void channel_mark_for_close(channel_t *chan);
+void channel_write_cell(channel_t *chan, cell_t *cell);
+void channel_write_packed_cell(channel_t *chan, packed_cell_t *cell);
+void channel_write_var_cell(channel_t *chan, var_cell_t *cell);
+
+void channel_listener_mark_for_close(channel_listener_t *chan_l);
+
+/* Channel callback registrations */
+
+/* Listener callback */
+channel_listener_fn_ptr
+channel_listener_get_listener_fn(channel_listener_t *chan);
+
+void channel_listener_set_listener_fn(channel_listener_t *chan,
+ channel_listener_fn_ptr listener);
+
+/* Incoming cell callbacks */
+channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan);
+
+channel_var_cell_handler_fn_ptr
+channel_get_var_cell_handler(channel_t *chan);
+
+void channel_set_cell_handlers(channel_t *chan,
+ channel_cell_handler_fn_ptr cell_handler,
+ channel_var_cell_handler_fn_ptr
+ var_cell_handler);
+
+/* Clean up closed channels and channel listeners periodically; these are
+ * called from run_scheduled_events() in main.c.
+ */
+void channel_run_cleanup(void);
+void channel_listener_run_cleanup(void);
+
+/* Close all channels and deallocate everything */
+void channel_free_all(void);
+
+/* Dump some statistics in the log */
+void channel_dumpstats(int severity);
+void channel_listener_dumpstats(int severity);
+
+/* Set the cmux policy on all active channels */
+void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol);
+
+#ifdef TOR_CHANNEL_INTERNAL_
+
+/* Channel operations for subclasses and internal use only */
+
+/* Initialize a newly allocated channel - do this first in subclass
+ * constructors.
+ */
+
+void channel_init(channel_t *chan);
+void channel_init_listener(channel_listener_t *chan);
+
+/* Channel registration/unregistration */
+void channel_register(channel_t *chan);
+void channel_unregister(channel_t *chan);
+
+/* Channel listener registration/unregistration */
+void channel_listener_register(channel_listener_t *chan_l);
+void channel_listener_unregister(channel_listener_t *chan_l);
+
+/* Close from below */
+void channel_close_from_lower_layer(channel_t *chan);
+void channel_close_for_error(channel_t *chan);
+void channel_closed(channel_t *chan);
+
+void channel_listener_close_from_lower_layer(channel_listener_t *chan_l);
+void channel_listener_close_for_error(channel_listener_t *chan_l);
+void channel_listener_closed(channel_listener_t *chan_l);
+
+/* Free a channel */
+void channel_free(channel_t *chan);
+void channel_listener_free(channel_listener_t *chan_l);
+
+/* State/metadata setters */
+
+void channel_change_state(channel_t *chan, channel_state_t to_state);
+void channel_clear_identity_digest(channel_t *chan);
+void channel_clear_remote_end(channel_t *chan);
+void channel_mark_local(channel_t *chan);
+void channel_mark_incoming(channel_t *chan);
+void channel_mark_outgoing(channel_t *chan);
+void channel_set_identity_digest(channel_t *chan,
+ const char *identity_digest);
+void channel_set_remote_end(channel_t *chan,
+ const char *identity_digest,
+ const char *nickname);
+
+void channel_listener_change_state(channel_listener_t *chan_l,
+ channel_listener_state_t to_state);
+
+/* Timestamp updates */
+void channel_timestamp_created(channel_t *chan);
+void channel_timestamp_active(channel_t *chan);
+void channel_timestamp_drained(channel_t *chan);
+void channel_timestamp_recv(channel_t *chan);
+void channel_timestamp_xmit(channel_t *chan);
+
+void channel_listener_timestamp_created(channel_listener_t *chan_l);
+void channel_listener_timestamp_active(channel_listener_t *chan_l);
+void channel_listener_timestamp_accepted(channel_listener_t *chan_l);
+
+/* Incoming channel handling */
+void channel_listener_process_incoming(channel_listener_t *listener);
+void channel_listener_queue_incoming(channel_listener_t *listener,
+ channel_t *incoming);
+
+/* Incoming cell handling */
+void channel_process_cells(channel_t *chan);
+void channel_queue_cell(channel_t *chan, cell_t *cell);
+void channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell);
+
+/* Outgoing cell handling */
+void channel_flush_cells(channel_t *chan);
+
+/* Request from lower layer for more cells if available */
+ssize_t channel_flush_some_cells(channel_t *chan, ssize_t num_cells);
+
+/* Query if data available on this channel */
+int channel_more_to_flush(channel_t *chan);
+
+/* Notify flushed outgoing for dirreq handling */
+void channel_notify_flushed(channel_t *chan);
+
+/* Handle stuff we need to do on open like notifying circuits */
+void channel_do_open_actions(channel_t *chan);
+
+#endif
+
+/* Helper functions to perform operations on channels */
+
+int channel_send_destroy(circid_t circ_id, channel_t *chan,
+ int reason);
+
+/*
+ * Outside abstract interfaces that should eventually get turned into
+ * something transport/address format independent.
+ */
+
+channel_t * channel_connect(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest);
+
+channel_t * channel_get_for_extend(const char *digest,
+ const tor_addr_t *target_addr,
+ const char **msg_out,
+ int *launch_out);
+
+/* Ask which of two channels is better for circuit-extension purposes */
+int channel_is_better(time_t now,
+ channel_t *a, channel_t *b,
+ int forgive_new_connections);
+
+/** Channel lookups
+ */
+
+channel_t * channel_find_by_global_id(uint64_t global_identifier);
+channel_t * channel_find_by_remote_digest(const char *identity_digest);
+
+/** For things returned by channel_find_by_remote_digest(), walk the list.
+ */
+channel_t * channel_next_with_digest(channel_t *chan);
+
+/*
+ * Metadata queries/updates
+ */
+
+const char * channel_describe_transport(channel_t *chan);
+void channel_dump_statistics(channel_t *chan, int severity);
+void channel_dump_transport_statistics(channel_t *chan, int severity);
+const char * channel_get_actual_remote_descr(channel_t *chan);
+const char * channel_get_actual_remote_address(channel_t *chan);
+int channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out);
+const char * channel_get_canonical_remote_descr(channel_t *chan);
+int channel_has_queued_writes(channel_t *chan);
+int channel_is_bad_for_new_circs(channel_t *chan);
+void channel_mark_bad_for_new_circs(channel_t *chan);
+int channel_is_canonical(channel_t *chan);
+int channel_is_canonical_is_reliable(channel_t *chan);
+int channel_is_client(channel_t *chan);
+int channel_is_local(channel_t *chan);
+int channel_is_incoming(channel_t *chan);
+int channel_is_outgoing(channel_t *chan);
+void channel_mark_client(channel_t *chan);
+int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info);
+int channel_matches_target_addr_for_extend(channel_t *chan,
+ const tor_addr_t *target);
+unsigned int channel_num_circuits(channel_t *chan);
+void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd,
+ int consider_identity);
+void channel_timestamp_client(channel_t *chan);
+
+const char * channel_listener_describe_transport(channel_listener_t *chan_l);
+void channel_listener_dump_statistics(channel_listener_t *chan_l,
+ int severity);
+void channel_listener_dump_transport_statistics(channel_listener_t *chan_l,
+ int severity);
+
+/* Timestamp queries */
+time_t channel_when_created(channel_t *chan);
+time_t channel_when_last_active(channel_t *chan);
+time_t channel_when_last_client(channel_t *chan);
+time_t channel_when_last_drained(channel_t *chan);
+time_t channel_when_last_recv(channel_t *chan);
+time_t channel_when_last_xmit(channel_t *chan);
+
+time_t channel_listener_when_created(channel_listener_t *chan_l);
+time_t channel_listener_when_last_active(channel_listener_t *chan_l);
+time_t channel_listener_when_last_accepted(channel_listener_t *chan_l);
+
+/* Counter queries */
+uint64_t channel_count_recved(channel_t *chan);
+uint64_t channel_count_xmitted(channel_t *chan);
+
+uint64_t channel_listener_count_accepted(channel_listener_t *chan_l);
+
+#endif
+
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
new file mode 100644
index 000000000..d5428c1ab
--- /dev/null
+++ b/src/or/channeltls.c
@@ -0,0 +1,2037 @@
+/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file channeltls.c
+ * \brief channel_t concrete subclass using or_connection_t
+ **/
+
+/*
+ * Define this so channel.h gives us things only channel_t subclasses
+ * should touch.
+ */
+
+#define TOR_CHANNEL_INTERNAL_
+
+#include "or.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "circuitmux.h"
+#include "circuitmux_ewma.h"
+#include "config.h"
+#include "connection.h"
+#include "connection_or.h"
+#include "control.h"
+#include "relay.h"
+#include "router.h"
+#include "routerlist.h"
+
+/** How many CELL_PADDING cells have we received, ever? */
+uint64_t stats_n_padding_cells_processed = 0;
+/** How many CELL_VERSIONS cells have we received, ever? */
+uint64_t stats_n_versions_cells_processed = 0;
+/** How many CELL_NETINFO cells have we received, ever? */
+uint64_t stats_n_netinfo_cells_processed = 0;
+/** How many CELL_VPADDING cells have we received, ever? */
+uint64_t stats_n_vpadding_cells_processed = 0;
+/** How many CELL_CERTS cells have we received, ever? */
+uint64_t stats_n_certs_cells_processed = 0;
+/** How many CELL_AUTH_CHALLENGE cells have we received, ever? */
+uint64_t stats_n_auth_challenge_cells_processed = 0;
+/** How many CELL_AUTHENTICATE cells have we received, ever? */
+uint64_t stats_n_authenticate_cells_processed = 0;
+/** How many CELL_AUTHORIZE cells have we received, ever? */
+uint64_t stats_n_authorize_cells_processed = 0;
+
+/** Active listener, if any */
+channel_listener_t *channel_tls_listener = NULL;
+
+/* Utility function declarations */
+static void channel_tls_common_init(channel_tls_t *tlschan);
+
+/* channel_tls_t method declarations */
+
+static void channel_tls_close_method(channel_t *chan);
+static const char * channel_tls_describe_transport_method(channel_t *chan);
+static void channel_tls_free_method(channel_t *chan);
+static int
+channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out);
+static const char *
+channel_tls_get_remote_descr_method(channel_t *chan, int flags);
+static int channel_tls_has_queued_writes_method(channel_t *chan);
+static int channel_tls_is_canonical_method(channel_t *chan, int req);
+static int
+channel_tls_matches_extend_info_method(channel_t *chan,
+ extend_info_t *extend_info);
+static int channel_tls_matches_target_method(channel_t *chan,
+ const tor_addr_t *target);
+static int channel_tls_write_cell_method(channel_t *chan,
+ cell_t *cell);
+static int channel_tls_write_packed_cell_method(channel_t *chan,
+ packed_cell_t *packed_cell);
+static int channel_tls_write_var_cell_method(channel_t *chan,
+ var_cell_t *var_cell);
+
+/* channel_listener_tls_t method declarations */
+
+static void channel_tls_listener_close_method(channel_listener_t *chan_l);
+static const char *
+channel_tls_listener_describe_transport_method(channel_listener_t *chan_l);
+
+/** Handle incoming cells for the handshake stuff here rather than
+ * passing them on up. */
+
+static void channel_tls_process_versions_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+static void channel_tls_process_netinfo_cell(cell_t *cell,
+ channel_tls_t *tlschan);
+static void channel_tls_process_certs_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+static void channel_tls_process_auth_challenge_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+static void channel_tls_process_authenticate_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+static int command_allowed_before_handshake(uint8_t command);
+static int enter_v3_handshake_with_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
+
+/**
+ * Do parts of channel_tls_t initialization common to channel_tls_connect()
+ * and channel_tls_handle_incoming().
+ */
+
+static void
+channel_tls_common_init(channel_tls_t *tlschan)
+{
+ channel_t *chan;
+
+ tor_assert(tlschan);
+
+ chan = &(tlschan->base_);
+ channel_init(chan);
+ chan->magic = TLS_CHAN_MAGIC;
+ chan->state = CHANNEL_STATE_OPENING;
+ chan->close = channel_tls_close_method;
+ chan->describe_transport = channel_tls_describe_transport_method;
+ chan->free = channel_tls_free_method;
+ chan->get_remote_addr = channel_tls_get_remote_addr_method;
+ chan->get_remote_descr = channel_tls_get_remote_descr_method;
+ chan->has_queued_writes = channel_tls_has_queued_writes_method;
+ chan->is_canonical = channel_tls_is_canonical_method;
+ chan->matches_extend_info = channel_tls_matches_extend_info_method;
+ chan->matches_target = channel_tls_matches_target_method;
+ chan->write_cell = channel_tls_write_cell_method;
+ chan->write_packed_cell = channel_tls_write_packed_cell_method;
+ chan->write_var_cell = channel_tls_write_var_cell_method;
+
+ chan->cmux = circuitmux_alloc();
+ if (cell_ewma_enabled()) {
+ circuitmux_set_policy(chan->cmux, &ewma_policy);
+ }
+}
+
+/**
+ * Start a new TLS channel
+ *
+ * Launch a new OR connection to <b>addr</b>:<b>port</b> and expect to
+ * handshake with an OR with identity digest <b>id_digest</b>, and wrap
+ * it in a channel_tls_t.
+ */
+
+channel_t *
+channel_tls_connect(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest)
+{
+ channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan));
+ channel_t *chan = &(tlschan->base_);
+
+ channel_tls_common_init(tlschan);
+
+ log_debug(LD_CHANNEL,
+ "In channel_tls_connect() for channel %p "
+ "(global id " U64_FORMAT ")",
+ tlschan,
+ U64_PRINTF_ARG(chan->global_identifier));
+
+ if (is_local_addr(addr)) channel_mark_local(chan);
+ channel_mark_outgoing(chan);
+
+ /* Set up or_connection stuff */
+ tlschan->conn = connection_or_connect(addr, port, id_digest, tlschan);
+ /* connection_or_connect() will fill in tlschan->conn */
+ if (!(tlschan->conn)) {
+ chan->reason_for_closing = CHANNEL_CLOSE_FOR_ERROR;
+ channel_change_state(chan, CHANNEL_STATE_ERROR);
+ goto err;
+ }
+
+ log_debug(LD_CHANNEL,
+ "Got orconn %p for channel with global id " U64_FORMAT,
+ tlschan->conn, U64_PRINTF_ARG(chan->global_identifier));
+
+ goto done;
+
+ err:
+ circuitmux_free(chan->cmux);
+ tor_free(tlschan);
+ chan = NULL;
+
+ done:
+ /* If we got one, we should register it */
+ if (chan) channel_register(chan);
+
+ return chan;
+}
+
+/**
+ * Return the current channel_tls_t listener
+ *
+ * Returns the current channel listener for incoming TLS connections, or
+ * NULL if none has been established
+ */
+
+channel_listener_t *
+channel_tls_get_listener(void)
+{
+ return channel_tls_listener;
+}
+
+/**
+ * Start a channel_tls_t listener if necessary
+ *
+ * Return the current channel_tls_t listener, or start one if we haven't yet,
+ * and return that.
+ */
+
+channel_listener_t *
+channel_tls_start_listener(void)
+{
+ channel_listener_t *listener;
+
+ if (!channel_tls_listener) {
+ listener = tor_malloc_zero(sizeof(*listener));
+ channel_init_listener(listener);
+ listener->state = CHANNEL_LISTENER_STATE_LISTENING;
+ listener->close = channel_tls_listener_close_method;
+ listener->describe_transport =
+ channel_tls_listener_describe_transport_method;
+
+ channel_tls_listener = listener;
+
+ log_debug(LD_CHANNEL,
+ "Starting TLS channel listener %p with global id " U64_FORMAT,
+ listener, U64_PRINTF_ARG(listener->global_identifier));
+
+ channel_listener_register(listener);
+ } else listener = channel_tls_listener;
+
+ return listener;
+}
+
+/**
+ * Free everything on shutdown
+ *
+ * Not much to do here, since channel_free_all() takes care of a lot, but let's
+ * get rid of the listener.
+ */
+
+void
+channel_tls_free_all(void)
+{
+ channel_listener_t *old_listener = NULL;
+
+ log_debug(LD_CHANNEL,
+ "Shutting down TLS channels...");
+
+ if (channel_tls_listener) {
+ /*
+ * When we close it, channel_tls_listener will get nulled out, so save
+ * a pointer so we can free it.
+ */
+ old_listener = channel_tls_listener;
+ log_debug(LD_CHANNEL,
+ "Closing channel_tls_listener with ID " U64_FORMAT
+ " at %p.",
+ U64_PRINTF_ARG(old_listener->global_identifier),
+ old_listener);
+ channel_listener_unregister(old_listener);
+ channel_listener_mark_for_close(old_listener);
+ channel_listener_free(old_listener);
+ tor_assert(channel_tls_listener == NULL);
+ }
+
+ log_debug(LD_CHANNEL,
+ "Done shutting down TLS channels");
+}
+
+/**
+ * Create a new channel around an incoming or_connection_t
+ */
+
+channel_t *
+channel_tls_handle_incoming(or_connection_t *orconn)
+{
+ channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan));
+ channel_t *chan = &(tlschan->base_);
+
+ tor_assert(orconn);
+ tor_assert(!(orconn->chan));
+
+ channel_tls_common_init(tlschan);
+
+ /* Link the channel and orconn to each other */
+ tlschan->conn = orconn;
+ orconn->chan = tlschan;
+
+ if (is_local_addr(&(TO_CONN(orconn)->addr))) channel_mark_local(chan);
+ channel_mark_incoming(chan);
+
+ /* If we got one, we should register it */
+ if (chan) channel_register(chan);
+
+ return chan;
+}
+
+/*********
+ * Casts *
+ ********/
+
+/**
+ * Cast a channel_tls_t to a channel_t.
+ */
+
+channel_t *
+channel_tls_to_base(channel_tls_t *tlschan)
+{
+ if (!tlschan) return NULL;
+
+ return &(tlschan->base_);
+}
+
+/**
+ * Cast a channel_t to a channel_tls_t, with appropriate type-checking
+ * asserts.
+ */
+
+channel_tls_t *
+channel_tls_from_base(channel_t *chan)
+{
+ if (!chan) return NULL;
+
+ tor_assert(chan->magic == TLS_CHAN_MAGIC);
+
+ return (channel_tls_t *)(chan);
+}
+
+/********************************************
+ * Method implementations for channel_tls_t *
+ *******************************************/
+
+/**
+ * Close a channel_tls_t
+ *
+ * This implements the close method for channel_tls_t
+ */
+
+static void
+channel_tls_close_method(channel_t *chan)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+
+ if (tlschan->conn) connection_or_close_normally(tlschan->conn, 1);
+ else {
+ /* Weird - we'll have to change the state ourselves, I guess */
+ log_info(LD_CHANNEL,
+ "Tried to close channel_tls_t %p with NULL conn",
+ tlschan);
+ channel_change_state(chan, CHANNEL_STATE_ERROR);
+ }
+}
+
+/**
+ * Describe the transport for a channel_tls_t
+ *
+ * This returns the string "TLS channel on connection <id>" to the upper
+ * layer.
+ */
+
+static const char *
+channel_tls_describe_transport_method(channel_t *chan)
+{
+ static char *buf = NULL;
+ uint64_t id;
+ channel_tls_t *tlschan;
+ const char *rv = NULL;
+
+ tor_assert(chan);
+
+ tlschan = BASE_CHAN_TO_TLS(chan);
+
+ if (tlschan->conn) {
+ id = TO_CONN(tlschan->conn)->global_identifier;
+
+ if (buf) tor_free(buf);
+ tor_asprintf(&buf,
+ "TLS channel (connection " U64_FORMAT ")",
+ U64_PRINTF_ARG(id));
+
+ rv = buf;
+ } else {
+ rv = "TLS channel (no connection)";
+ }
+
+ return rv;
+}
+
+/**
+ * Free a channel_tls_t
+ *
+ * This is called by the generic channel layer when freeing a channel_tls_t;
+ * this happens either on a channel which has already reached
+ * CHANNEL_STATE_CLOSED or CHANNEL_STATE_ERROR from channel_run_cleanup() or
+ * on shutdown from channel_free_all(). In the latter case we might still
+ * have an orconn active (which connection_free_all() will get to later),
+ * so we should null out its channel pointer now.
+ */
+
+static void
+channel_tls_free_method(channel_t *chan)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+
+ if (tlschan->conn) {
+ tlschan->conn->chan = NULL;
+ tlschan->conn = NULL;
+ }
+}
+
+/**
+ * Get the remote address of a channel_tls_t
+ *
+ * This implements the get_remote_addr method for channel_tls_t; copy the
+ * remote endpoint of the channel to addr_out and return 1 (always
+ * succeeds for this transport).
+ */
+
+static int
+channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out)
+{
+ int rv = 0;
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(addr_out);
+
+ if (tlschan->conn) {
+ tor_addr_copy(addr_out, &(TO_CONN(tlschan->conn)->addr));
+ rv = 1;
+ } else tor_addr_make_unspec(addr_out);
+
+ return rv;
+}
+
+/**
+ * Get endpoint description of a channel_tls_t
+ *
+ * This implements the get_remote_descr method for channel_tls_t; it returns
+ * a text description of the remote endpoint of the channel suitable for use
+ * in log messages. The req parameter is 0 for the canonical address or 1 for
+ * the actual address seen.
+ */
+
+static const char *
+channel_tls_get_remote_descr_method(channel_t *chan, int flags)
+{
+#define MAX_DESCR_LEN 32
+
+ static char buf[MAX_DESCR_LEN + 1];
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ connection_t *conn;
+ const char *answer = NULL;
+ char *addr_str;
+
+ tor_assert(tlschan);
+
+ if (tlschan->conn) {
+ conn = TO_CONN(tlschan->conn);
+ switch (flags) {
+ case 0:
+ /* Canonical address with port*/
+ tor_snprintf(buf, MAX_DESCR_LEN + 1,
+ "%s:%u", conn->address, conn->port);
+ answer = buf;
+ break;
+ case GRD_FLAG_ORIGINAL:
+ /* Actual address with port */
+ addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
+ tor_snprintf(buf, MAX_DESCR_LEN + 1,
+ "%s:%u", addr_str, conn->port);
+ tor_free(addr_str);
+ answer = buf;
+ break;
+ case GRD_FLAG_ADDR_ONLY:
+ /* Canonical address, no port */
+ strlcpy(buf, conn->address, sizeof(buf));
+ answer = buf;
+ break;
+ case GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY:
+ /* Actual address, no port */
+ addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
+ strlcpy(buf, addr_str, sizeof(buf));
+ tor_free(addr_str);
+ answer = buf;
+ break;
+ default:
+ /* Something's broken in channel.c */
+ tor_assert(1);
+ }
+ } else {
+ strlcpy(buf, "(No connection)", sizeof(buf));
+ answer = buf;
+ }
+
+ return answer;
+}
+
+/**
+ * Tell the upper layer if we have queued writes
+ *
+ * This implements the has_queued_writes method for channel_tls t_; it returns
+ * 1 iff we have queued writes on the outbuf of the underlying or_connection_t.
+ */
+
+static int
+channel_tls_has_queued_writes_method(channel_t *chan)
+{
+ size_t outbuf_len;
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ if (!(tlschan->conn)) {
+ log_info(LD_CHANNEL,
+ "something called has_queued_writes on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ }
+
+ outbuf_len = (tlschan->conn != NULL) ?
+ connection_get_outbuf_len(TO_CONN(tlschan->conn)) :
+ 0;
+
+ return (outbuf_len > 0);
+}
+
+/**
+ * Tell the upper layer if we're canonical
+ *
+ * This implements the is_canonical method for channel_tls_t; if req is zero,
+ * it returns whether this is a canonical channel, and if it is one it returns
+ * whether that can be relied upon.
+ */
+
+static int
+channel_tls_is_canonical_method(channel_t *chan, int req)
+{
+ int answer = 0;
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+
+ if (tlschan->conn) {
+ switch (req) {
+ case 0:
+ answer = tlschan->conn->is_canonical;
+ break;
+ case 1:
+ /*
+ * Is the is_canonical bit reliable? In protocols version 2 and up
+ * we get the canonical address from a NETINFO cell, but in older
+ * versions it might be based on an obsolete descriptor.
+ */
+ answer = (tlschan->conn->link_proto >= 2);
+ break;
+ default:
+ /* This shouldn't happen; channel.c is broken if it does */
+ tor_assert(1);
+ }
+ }
+ /* else return 0 for tlschan->conn == NULL */
+
+ return answer;
+}
+
+/**
+ * Check if we match an extend_info_t
+ *
+ * This implements the matches_extend_info method for channel_tls_t; the upper
+ * layer wants to know if this channel matches an extend_info_t.
+ */
+
+static int
+channel_tls_matches_extend_info_method(channel_t *chan,
+ extend_info_t *extend_info)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(extend_info);
+
+ /* Never match if we have no conn */
+ if (!(tlschan->conn)) {
+ log_info(LD_CHANNEL,
+ "something called matches_extend_info on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ return 0;
+ }
+
+ return (tor_addr_eq(&(extend_info->addr),
+ &(TO_CONN(tlschan->conn)->addr)) &&
+ (extend_info->port == TO_CONN(tlschan->conn)->port));
+}
+
+/**
+ * Check if we match a target address; return true iff we do.
+ *
+ * This implements the matches_target method for channel_tls t_; the upper
+ * layer wants to know if this channel matches a target address when extending
+ * a circuit.
+ */
+
+static int
+channel_tls_matches_target_method(channel_t *chan,
+ const tor_addr_t *target)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(target);
+
+ /* Never match if we have no conn */
+ if (!(tlschan->conn)) {
+ log_info(LD_CHANNEL,
+ "something called matches_target on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ return 0;
+ }
+
+ return tor_addr_eq(&(tlschan->conn->real_addr), target);
+}
+
+/**
+ * Write a cell to a channel_tls_t
+ *
+ * This implements the write_cell method for channel_tls_t; given a
+ * channel_tls_t and a cell_t, transmit the cell_t.
+ */
+
+static int
+channel_tls_write_cell_method(channel_t *chan, cell_t *cell)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ int written = 0;
+
+ tor_assert(tlschan);
+ tor_assert(cell);
+
+ if (tlschan->conn) {
+ connection_or_write_cell_to_buf(cell, tlschan->conn);
+ ++written;
+ } else {
+ log_info(LD_CHANNEL,
+ "something called write_cell on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ }
+
+ return written;
+}
+
+/**
+ * Write a packed cell to a channel_tls_t
+ *
+ * This implements the write_packed_cell method for channel_tls_t; given a
+ * channel_tls_t and a packed_cell_t, transmit the packed_cell_t.
+ */
+
+static int
+channel_tls_write_packed_cell_method(channel_t *chan,
+ packed_cell_t *packed_cell)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ size_t cell_network_size = get_cell_network_size(chan->wide_circ_ids);
+ int written = 0;
+
+ tor_assert(tlschan);
+ tor_assert(packed_cell);
+
+ if (tlschan->conn) {
+ connection_write_to_buf(packed_cell->body, cell_network_size,
+ TO_CONN(tlschan->conn));
+
+ /* This is where the cell is finished; used to be done from relay.c */
+ packed_cell_free(packed_cell);
+ ++written;
+ } else {
+ log_info(LD_CHANNEL,
+ "something called write_packed_cell on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ }
+
+ return written;
+}
+
+/**
+ * Write a variable-length cell to a channel_tls_t
+ *
+ * This implements the write_var_cell method for channel_tls_t; given a
+ * channel_tls_t and a var_cell_t, transmit the var_cell_t.
+ */
+
+static int
+channel_tls_write_var_cell_method(channel_t *chan, var_cell_t *var_cell)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ int written = 0;
+
+ tor_assert(tlschan);
+ tor_assert(var_cell);
+
+ if (tlschan->conn) {
+ connection_or_write_var_cell_to_buf(var_cell, tlschan->conn);
+ ++written;
+ } else {
+ log_info(LD_CHANNEL,
+ "something called write_var_cell on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ }
+
+ return written;
+}
+
+/*************************************************
+ * Method implementations for channel_listener_t *
+ ************************************************/
+
+/**
+ * Close a channel_listener_t
+ *
+ * This implements the close method for channel_listener_t
+ */
+
+static void
+channel_tls_listener_close_method(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ /*
+ * Listeners we just go ahead and change state through to CLOSED, but
+ * make sure to check if they're channel_tls_listener to NULL it out.
+ */
+ if (chan_l == channel_tls_listener)
+ channel_tls_listener = NULL;
+
+ if (!(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
+ chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR)) {
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
+ }
+
+ if (chan_l->incoming_list) {
+ SMARTLIST_FOREACH_BEGIN(chan_l->incoming_list,
+ channel_t *, ichan) {
+ channel_mark_for_close(ichan);
+ } SMARTLIST_FOREACH_END(ichan);
+
+ smartlist_free(chan_l->incoming_list);
+ chan_l->incoming_list = NULL;
+ }
+
+ if (!(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
+ chan_l->state == CHANNEL_LISTENER_STATE_ERROR)) {
+ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED);
+ }
+}
+
+/**
+ * Describe the transport for a channel_listener_t
+ *
+ * This returns the string "TLS channel (listening)" to the upper
+ * layer.
+ */
+
+static const char *
+channel_tls_listener_describe_transport_method(channel_listener_t *chan_l)
+{
+ tor_assert(chan_l);
+
+ return "TLS channel (listening)";
+}
+
+/*******************************************************
+ * Functions for handling events on an or_connection_t *
+ ******************************************************/
+
+/**
+ * Handle an orconn state change
+ *
+ * This function will be called by connection_or.c when the or_connection_t
+ * associated with this channel_tls_t changes state.
+ */
+
+void
+channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
+ or_connection_t *conn,
+ uint8_t old_state,
+ uint8_t state)
+{
+ channel_t *base_chan;
+
+ tor_assert(chan);
+ tor_assert(conn);
+ tor_assert(conn->chan == chan);
+ tor_assert(chan->conn == conn);
+ /* -Werror appeasement */
+ tor_assert(old_state == old_state);
+
+ base_chan = TLS_CHAN_TO_BASE(chan);
+
+ /* Make sure the base connection state makes sense - shouldn't be error,
+ * closed or listening. */
+
+ tor_assert(base_chan->state == CHANNEL_STATE_OPENING ||
+ base_chan->state == CHANNEL_STATE_OPEN ||
+ base_chan->state == CHANNEL_STATE_MAINT ||
+ base_chan->state == CHANNEL_STATE_CLOSING);
+
+ /* Did we just go to state open? */
+ if (state == OR_CONN_STATE_OPEN) {
+ /*
+ * We can go to CHANNEL_STATE_OPEN from CHANNEL_STATE_OPENING or
+ * CHANNEL_STATE_MAINT on this.
+ */
+ channel_change_state(base_chan, CHANNEL_STATE_OPEN);
+ } else {
+ /*
+ * Not open, so from CHANNEL_STATE_OPEN we go to CHANNEL_STATE_MAINT,
+ * otherwise no change.
+ */
+ if (base_chan->state == CHANNEL_STATE_OPEN) {
+ channel_change_state(base_chan, CHANNEL_STATE_MAINT);
+ }
+ }
+}
+
+/**
+ * Flush cells from a channel_tls_t
+ *
+ * Try to flush up to about num_cells cells, and return how many we flushed.
+ */
+
+ssize_t
+channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells)
+{
+ ssize_t flushed = 0;
+
+ tor_assert(chan);
+
+ if (flushed >= num_cells) goto done;
+
+ /*
+ * If channel_tls_t ever buffers anything below the channel_t layer, flush
+ * that first here.
+ */
+
+ flushed += channel_flush_some_cells(TLS_CHAN_TO_BASE(chan),
+ num_cells - flushed);
+
+ /*
+ * If channel_tls_t ever buffers anything below the channel_t layer, check
+ * how much we actually got and push it on down here.
+ */
+
+ done:
+ return flushed;
+}
+
+/**
+ * Check if a channel_tls_t has anything to flush
+ *
+ * Return true if there is any more to flush on this channel (cells in queue
+ * or active circuits).
+ */
+
+int
+channel_tls_more_to_flush(channel_tls_t *chan)
+{
+ tor_assert(chan);
+
+ /*
+ * If channel_tls_t ever buffers anything below channel_t, the
+ * check for that should go here first.
+ */
+
+ return channel_more_to_flush(TLS_CHAN_TO_BASE(chan));
+}
+
+#ifdef KEEP_TIMING_STATS
+
+/**
+ * Timing states wrapper
+ *
+ * This is a wrapper function around the actual function that processes the
+ * <b>cell</b> that just arrived on <b>chan</b>. Increment <b>*time</b>
+ * by the number of microseconds used by the call to <b>*func(cell, chan)</b>.
+ */
+
+static void
+channel_tls_time_process_cell(cell_t *cell, channel_tls_t *chan, int *time,
+ void (*func)(cell_t *, channel_tls_t *))
+{
+ struct timeval start, end;
+ long time_passed;
+
+ tor_gettimeofday(&start);
+
+ (*func)(cell, chan);
+
+ tor_gettimeofday(&end);
+ time_passed = tv_udiff(&start, &end) ;
+
+ if (time_passed > 10000) { /* more than 10ms */
+ log_debug(LD_OR,"That call just took %ld ms.",time_passed/1000);
+ }
+
+ if (time_passed < 0) {
+ log_info(LD_GENERAL,"That call took us back in time!");
+ time_passed = 0;
+ }
+
+ *time += time_passed;
+}
+#endif
+
+/**
+ * Handle an incoming cell on a channel_tls_t
+ *
+ * This is called from connection_or.c to handle an arriving cell; it checks
+ * for cell types specific to the handshake for this transport protocol and
+ * handles them, and queues all other cells to the channel_t layer, which
+ * eventually will hand them off to command.c.
+ */
+
+void
+channel_tls_handle_cell(cell_t *cell, or_connection_t *conn)
+{
+ channel_tls_t *chan;
+ int handshaking;
+
+#ifdef KEEP_TIMING_STATS
+#define PROCESS_CELL(tp, cl, cn) STMT_BEGIN { \
+ ++num ## tp; \
+ channel_tls_time_process_cell(cl, cn, & tp ## time , \
+ channel_tls_process_ ## tp ## _cell); \
+ } STMT_END
+#else
+#define PROCESS_CELL(tp, cl, cn) channel_tls_process_ ## tp ## _cell(cl, cn)
+#endif
+
+ tor_assert(cell);
+ tor_assert(conn);
+
+ chan = conn->chan;
+
+ if (!chan) {
+ log_warn(LD_CHANNEL,
+ "Got a cell_t on an OR connection with no channel");
+ return;
+ }
+
+ handshaking = (TO_CONN(conn)->state != OR_CONN_STATE_OPEN);
+
+ if (conn->base_.marked_for_close)
+ return;
+
+ /* Reject all but VERSIONS and NETINFO when handshaking. */
+ /* (VERSIONS should actually be impossible; it's variable-length.) */
+ if (handshaking && cell->command != CELL_VERSIONS &&
+ cell->command != CELL_NETINFO) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received unexpected cell command %d in chan state %s / "
+ "conn state %s; closing the connection.",
+ (int)cell->command,
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state));
+ connection_or_close_for_error(conn, 0);
+ return;
+ }
+
+ if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
+ or_handshake_state_record_cell(conn, conn->handshake_state, cell, 1);
+
+ switch (cell->command) {
+ case CELL_PADDING:
+ ++stats_n_padding_cells_processed;
+ /* do nothing */
+ break;
+ case CELL_VERSIONS:
+ tor_fragile_assert();
+ break;
+ case CELL_NETINFO:
+ ++stats_n_netinfo_cells_processed;
+ PROCESS_CELL(netinfo, cell, chan);
+ break;
+ case CELL_CREATE:
+ case CELL_CREATE_FAST:
+ case CELL_CREATED:
+ case CELL_CREATED_FAST:
+ case CELL_RELAY:
+ case CELL_RELAY_EARLY:
+ case CELL_DESTROY:
+ case CELL_CREATE2:
+ case CELL_CREATED2:
+ /*
+ * These are all transport independent and we pass them up through the
+ * channel_t mechanism. They are ultimately handled in command.c.
+ */
+ channel_queue_cell(TLS_CHAN_TO_BASE(chan), cell);
+ break;
+ default:
+ log_fn(LOG_INFO, LD_PROTOCOL,
+ "Cell of unknown type (%d) received in channeltls.c. "
+ "Dropping.",
+ cell->command);
+ break;
+ }
+}
+
+/**
+ * Handle an incoming variable-length cell on a channel_tls_t
+ *
+ * Process a <b>var_cell</b> that was just received on <b>conn</b>. Keep
+ * internal statistics about how many of each cell we've processed so far
+ * this second, and the total number of microseconds it took to
+ * process each type of cell. All the var_cell commands are handshake-
+ * related and live below the channel_t layer, so no variable-length
+ * cells ever get delivered in the current implementation, but I've left
+ * the mechanism in place for future use.
+ */
+
+void
+channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn)
+{
+ channel_tls_t *chan;
+
+#ifdef KEEP_TIMING_STATS
+ /* how many of each cell have we seen so far this second? needs better
+ * name. */
+ static int num_versions = 0, num_certs = 0;
+ static time_t current_second = 0; /* from previous calls to time */
+ time_t now = time(NULL);
+
+ if (current_second == 0) current_second = now;
+ if (now > current_second) { /* the second has rolled over */
+ /* print stats */
+ log_info(LD_OR,
+ "At end of second: %d versions (%d ms), %d certs (%d ms)",
+ num_versions, versions_time / ((now - current_second) * 1000),
+ num_certs, certs_time / ((now - current_second) * 1000));
+
+ num_versions = num_certs = 0;
+ versions_time = certs_time = 0;
+
+ /* remember which second it is, for next time */
+ current_second = now;
+ }
+#endif
+
+ tor_assert(var_cell);
+ tor_assert(conn);
+
+ chan = conn->chan;
+
+ if (!chan) {
+ log_warn(LD_CHANNEL,
+ "Got a var_cell_t on an OR connection with no channel");
+ return;
+ }
+
+ if (TO_CONN(conn)->marked_for_close)
+ return;
+
+ switch (TO_CONN(conn)->state) {
+ case OR_CONN_STATE_OR_HANDSHAKING_V2:
+ if (var_cell->command != CELL_VERSIONS) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received a cell with command %d in unexpected "
+ "orconn state \"%s\" [%d], channel state \"%s\" [%d]; "
+ "closing the connection.",
+ (int)(var_cell->command),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state),
+ TO_CONN(conn)->state,
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(TLS_CHAN_TO_BASE(chan)->state));
+ /*
+ * The code in connection_or.c will tell channel_t to close for
+ * error; it will go to CHANNEL_STATE_CLOSING, and then to
+ * CHANNEL_STATE_ERROR when conn is closed.
+ */
+ connection_or_close_for_error(conn, 0);
+ return;
+ }
+ break;
+ case OR_CONN_STATE_TLS_HANDSHAKING:
+ /* If we're using bufferevents, it's entirely possible for us to
+ * notice "hey, data arrived!" before we notice "hey, the handshake
+ * finished!" And we need to be accepting both at once to handle both
+ * the v2 and v3 handshakes. */
+
+ /* fall through */
+ case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
+ if (!(command_allowed_before_handshake(var_cell->command))) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received a cell with command %d in unexpected "
+ "orconn state \"%s\" [%d], channel state \"%s\" [%d]; "
+ "closing the connection.",
+ (int)(var_cell->command),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state),
+ (int)(TO_CONN(conn)->state),
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(TLS_CHAN_TO_BASE(chan)->state));
+ /* see above comment about CHANNEL_STATE_ERROR */
+ connection_or_close_for_error(conn, 0);
+ return;
+ } else {
+ if (enter_v3_handshake_with_cell(var_cell, chan) < 0)
+ return;
+ }
+ break;
+ case OR_CONN_STATE_OR_HANDSHAKING_V3:
+ if (var_cell->command != CELL_AUTHENTICATE)
+ or_handshake_state_record_var_cell(conn, conn->handshake_state,
+ var_cell, 1);
+ break; /* Everything is allowed */
+ case OR_CONN_STATE_OPEN:
+ if (conn->link_proto < 3) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received a variable-length cell with command %d in orconn "
+ "state %s [%d], channel state %s [%d] with link protocol %d; "
+ "ignoring it.",
+ (int)(var_cell->command),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state),
+ (int)(TO_CONN(conn)->state),
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(conn->link_proto));
+ return;
+ }
+ break;
+ default:
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received var-length cell with command %d in unexpected "
+ "orconn state \"%s\" [%d], channel state \"%s\" [%d]; "
+ "ignoring it.",
+ (int)(var_cell->command),
+ conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state),
+ (int)(TO_CONN(conn)->state),
+ channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state),
+ (int)(TLS_CHAN_TO_BASE(chan)->state));
+ return;
+ }
+
+ /* Now handle the cell */
+
+ switch (var_cell->command) {
+ case CELL_VERSIONS:
+ ++stats_n_versions_cells_processed;
+ PROCESS_CELL(versions, var_cell, chan);
+ break;
+ case CELL_VPADDING:
+ ++stats_n_vpadding_cells_processed;
+ /* Do nothing */
+ break;
+ case CELL_CERTS:
+ ++stats_n_certs_cells_processed;
+ PROCESS_CELL(certs, var_cell, chan);
+ break;
+ case CELL_AUTH_CHALLENGE:
+ ++stats_n_auth_challenge_cells_processed;
+ PROCESS_CELL(auth_challenge, var_cell, chan);
+ break;
+ case CELL_AUTHENTICATE:
+ ++stats_n_authenticate_cells_processed;
+ PROCESS_CELL(authenticate, var_cell, chan);
+ break;
+ case CELL_AUTHORIZE:
+ ++stats_n_authorize_cells_processed;
+ /* Ignored so far. */
+ break;
+ default:
+ log_fn(LOG_INFO, LD_PROTOCOL,
+ "Variable-length cell of unknown type (%d) received.",
+ (int)(var_cell->command));
+ break;
+ }
+}
+
+/**
+ * Check if this cell type is allowed before the handshake is finished
+ *
+ * Return true if <b>command</b> is a cell command that's allowed to start a
+ * V3 handshake.
+ */
+
+static int
+command_allowed_before_handshake(uint8_t command)
+{
+ switch (command) {
+ case CELL_VERSIONS:
+ case CELL_VPADDING:
+ case CELL_AUTHORIZE:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Start a V3 handshake on an incoming connection
+ *
+ * Called when we as a server receive an appropriate cell while waiting
+ * either for a cell or a TLS handshake. Set the connection's state to
+ * "handshaking_v3', initializes the or_handshake_state field as needed,
+ * and add the cell to the hash of incoming cells.)
+ */
+
+static int
+enter_v3_handshake_with_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ int started_here = 0;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+ started_here = connection_or_nonopen_was_started_here(chan->conn);
+
+ tor_assert(TO_CONN(chan->conn)->state == OR_CONN_STATE_TLS_HANDSHAKING ||
+ TO_CONN(chan->conn)->state ==
+ OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
+
+ if (started_here) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a cell while TLS-handshaking, not in "
+ "OR_HANDSHAKING_V3, on a connection we originated.");
+ }
+ connection_or_block_renegotiation(chan->conn);
+ chan->conn->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ if (connection_init_or_handshake_state(chan->conn, started_here) < 0) {
+ connection_or_close_for_error(chan->conn, 0);
+ return -1;
+ }
+ or_handshake_state_record_var_cell(chan->conn,
+ chan->conn->handshake_state, cell, 1);
+ return 0;
+}
+
+/**
+ * Process a 'versions' cell.
+ *
+ * This function is called to handle an incoming VERSIONS cell; the current
+ * link protocol version must be 0 to indicate that no version has yet been
+ * negotiated. We compare the versions in the cell to the list of versions
+ * we support, pick the highest version we have in common, and continue the
+ * negotiation from there.
+ */
+
+static void
+channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ int highest_supported_version = 0;
+ const uint8_t *cp, *end;
+ int started_here = 0;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+ started_here = connection_or_nonopen_was_started_here(chan->conn);
+
+ if (chan->conn->link_proto != 0 ||
+ (chan->conn->handshake_state &&
+ chan->conn->handshake_state->received_versions)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a VERSIONS cell on a connection with its version "
+ "already set to %d; dropping",
+ (int)(chan->conn->link_proto));
+ return;
+ }
+ switch (chan->conn->base_.state)
+ {
+ case OR_CONN_STATE_OR_HANDSHAKING_V2:
+ case OR_CONN_STATE_OR_HANDSHAKING_V3:
+ break;
+ case OR_CONN_STATE_TLS_HANDSHAKING:
+ case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
+ default:
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "VERSIONS cell while in unexpected state");
+ return;
+ }
+
+ tor_assert(chan->conn->handshake_state);
+ end = cell->payload + cell->payload_len;
+ for (cp = cell->payload; cp+1 < end; cp += 2) {
+ uint16_t v = ntohs(get_uint16(cp));
+ if (is_or_protocol_version_known(v) && v > highest_supported_version)
+ highest_supported_version = v;
+ }
+ if (!highest_supported_version) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Couldn't find a version in common between my version list and the "
+ "list in the VERSIONS cell; closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ } else if (highest_supported_version == 1) {
+ /* Negotiating version 1 makes no sense, since version 1 has no VERSIONS
+ * cells. */
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Used version negotiation protocol to negotiate a v1 connection. "
+ "That's crazily non-compliant. Closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ } else if (highest_supported_version < 3 &&
+ chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Negotiated link protocol 2 or lower after doing a v3 TLS "
+ "handshake. Closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ } else if (highest_supported_version != 2 &&
+ chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V2) {
+ /* XXXX This should eventually be a log_protocol_warn */
+ log_fn(LOG_WARN, LD_OR,
+ "Negotiated link with non-2 protocol after doing a v2 TLS "
+ "handshake with %s. Closing connection.",
+ fmt_addr(&chan->conn->base_.addr));
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+
+ chan->conn->link_proto = highest_supported_version;
+ chan->conn->handshake_state->received_versions = 1;
+
+ if (chan->conn->link_proto == 2) {
+ log_info(LD_OR,
+ "Negotiated version %d with %s:%d; sending NETINFO.",
+ highest_supported_version,
+ safe_str_client(chan->conn->base_.address),
+ chan->conn->base_.port);
+
+ if (connection_or_send_netinfo(chan->conn) < 0) {
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ } else {
+ const int send_versions = !started_here;
+ /* If we want to authenticate, send a CERTS cell */
+ const int send_certs = !started_here || public_server_mode(get_options());
+ /* If we're a host that got a connection, ask for authentication. */
+ const int send_chall = !started_here;
+ /* If our certs cell will authenticate us, we can send a netinfo cell
+ * right now. */
+ const int send_netinfo = !started_here;
+ const int send_any =
+ send_versions || send_certs || send_chall || send_netinfo;
+ tor_assert(chan->conn->link_proto >= 3);
+
+ log_info(LD_OR,
+ "Negotiated version %d with %s:%d; %s%s%s%s%s",
+ highest_supported_version,
+ safe_str_client(chan->conn->base_.address),
+ chan->conn->base_.port,
+ send_any ? "Sending cells:" : "Waiting for CERTS cell",
+ send_versions ? " VERSIONS" : "",
+ send_certs ? " CERTS" : "",
+ send_chall ? " AUTH_CHALLENGE" : "",
+ send_netinfo ? " NETINFO" : "");
+
+#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
+ if (1) {
+ connection_or_close_normally(chan->conn, 1);
+ return;
+ }
+#endif
+
+ if (send_versions) {
+ if (connection_or_send_versions(chan->conn, 1) < 0) {
+ log_warn(LD_OR, "Couldn't send versions cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ }
+
+ /* We set this after sending the verions cell. */
+ /*XXXXX symbolic const.*/
+ chan->base_.wide_circ_ids =
+ chan->conn->link_proto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS;
+ chan->conn->wide_circ_ids = chan->base_.wide_circ_ids;
+
+ if (send_certs) {
+ if (connection_or_send_certs_cell(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send certs cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ }
+ if (send_chall) {
+ if (connection_or_send_auth_challenge_cell(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send auth_challenge cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ }
+ if (send_netinfo) {
+ if (connection_or_send_netinfo(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send netinfo cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * 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".
+ */
+
+static void
+channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
+{
+ time_t timestamp;
+ uint8_t my_addr_type;
+ uint8_t my_addr_len;
+ const uint8_t *my_addr_ptr;
+ const uint8_t *cp, *end;
+ uint8_t n_other_addrs;
+ time_t now = time(NULL);
+
+ long apparent_skew = 0;
+ tor_addr_t my_apparent_addr = TOR_ADDR_NULL;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+ if (chan->conn->link_proto < 2) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a NETINFO cell on %s connection; dropping.",
+ chan->conn->link_proto == 0 ? "non-versioned" : "a v1");
+ return;
+ }
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 &&
+ chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a NETINFO cell on non-handshaking connection; dropping.");
+ return;
+ }
+ tor_assert(chan->conn->handshake_state &&
+ chan->conn->handshake_state->received_versions);
+
+ if (chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) {
+ tor_assert(chan->conn->link_proto >= 3);
+ if (chan->conn->handshake_state->started_here) {
+ if (!(chan->conn->handshake_state->authenticated)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Got a NETINFO cell from server, "
+ "but no authentication. Closing the connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ } else {
+ /* we're the server. If the client never authenticated, we have
+ some housekeeping to do.*/
+ if (!(chan->conn->handshake_state->authenticated)) {
+ tor_assert(tor_digest_is_zero(
+ (const char*)(chan->conn->handshake_state->
+ authenticated_peer_id)));
+ channel_set_circid_type(TLS_CHAN_TO_BASE(chan), NULL,
+ chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS);
+
+ connection_or_init_conn_from_address(chan->conn,
+ &(chan->conn->base_.addr),
+ chan->conn->base_.port,
+ (const char*)(chan->conn->handshake_state->
+ authenticated_peer_id),
+ 0);
+ }
+ }
+ }
+
+ /* Decode the cell. */
+ timestamp = ntohl(get_uint32(cell->payload));
+ if (labs(now - chan->conn->handshake_state->sent_versions_at) < 180) {
+ apparent_skew = now - timestamp;
+ }
+
+ my_addr_type = (uint8_t) cell->payload[4];
+ my_addr_len = (uint8_t) cell->payload[5];
+ my_addr_ptr = (uint8_t*) cell->payload + 6;
+ end = cell->payload + CELL_PAYLOAD_SIZE;
+ cp = cell->payload + 6 + my_addr_len;
+ if (cp >= end) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Addresses too long in netinfo cell; closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ } else if (my_addr_type == RESOLVED_TYPE_IPV4 && my_addr_len == 4) {
+ tor_addr_from_ipv4n(&my_apparent_addr, get_uint32(my_addr_ptr));
+ } else if (my_addr_type == RESOLVED_TYPE_IPV6 && my_addr_len == 16) {
+ tor_addr_from_ipv6_bytes(&my_apparent_addr, (const char *) my_addr_ptr);
+ }
+
+ n_other_addrs = (uint8_t) *cp++;
+ while (n_other_addrs && cp < end-2) {
+ /* Consider all the other addresses; if any matches, this connection is
+ * "canonical." */
+ tor_addr_t addr;
+ const uint8_t *next =
+ decode_address_from_payload(&addr, cp, (int)(end-cp));
+ if (next == NULL) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Bad address in netinfo cell; closing connection.");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ if (tor_addr_eq(&addr, &(chan->conn->real_addr))) {
+ chan->conn->is_canonical = 1;
+ break;
+ }
+ cp = next;
+ --n_other_addrs;
+ }
+
+ /* 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 &&
+ router_get_by_id_digest(chan->conn->identity_digest)) {
+ char dbuf[64];
+ int severity;
+ /*XXXX be smarter about when everybody says we are skewed. */
+ if (router_digest_is_trusted_dir(chan->conn->identity_digest))
+ severity = LOG_WARN;
+ else
+ severity = LOG_INFO;
+ format_time_interval(dbuf, sizeof(dbuf), apparent_skew);
+ log_fn(severity, LD_GENERAL,
+ "Received NETINFO cell with skewed time from "
+ "server at %s:%d. It seems that our clock is %s by %s, or "
+ "that theirs is %s. Tor requires an accurate clock to work: "
+ "please check your time and date settings.",
+ chan->conn->base_.address,
+ (int)(chan->conn->base_.port),
+ apparent_skew > 0 ? "ahead" : "behind",
+ dbuf,
+ apparent_skew > 0 ? "behind" : "ahead");
+ if (severity == LOG_WARN) /* only tell the controller if an authority */
+ control_event_general_status(LOG_WARN,
+ "CLOCK_SKEW SKEW=%ld SOURCE=OR:%s:%d",
+ apparent_skew,
+ chan->conn->base_.address,
+ chan->conn->base_.port);
+ }
+
+ /* XXX maybe act on my_apparent_addr, if the source is sufficiently
+ * trustworthy. */
+
+ if (! chan->conn->handshake_state->sent_netinfo) {
+ /* If we were prepared to authenticate, but we never got an AUTH_CHALLENGE
+ * cell, then we would not previously have sent a NETINFO cell. Do so
+ * now. */
+ if (connection_or_send_netinfo(chan->conn) < 0) {
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ }
+
+ if (connection_or_set_state_open(chan->conn) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Got good NETINFO cell from %s:%d; but "
+ "was unable to make the OR connection become open.",
+ safe_str_client(chan->conn->base_.address),
+ chan->conn->base_.port);
+ connection_or_close_for_error(chan->conn, 0);
+ } else {
+ log_info(LD_OR,
+ "Got good NETINFO cell from %s:%d; OR connection is now "
+ "open, using protocol version %d. Its ID digest is %s. "
+ "Our address is apparently %s.",
+ safe_str_client(chan->conn->base_.address),
+ chan->conn->base_.port,
+ (int)(chan->conn->link_proto),
+ hex_str(TLS_CHAN_TO_BASE(chan)->identity_digest,
+ DIGEST_LEN),
+ tor_addr_is_null(&my_apparent_addr) ?
+ "<none>" : fmt_and_decorate_addr(&my_apparent_addr));
+ }
+ assert_connection_ok(TO_CONN(chan->conn),time(NULL));
+}
+
+/**
+ * Process a CERTS cell from a channel.
+ *
+ * This function is called to process an incoming CERTS cell on a
+ * channel_tls_t:
+ *
+ * If the other side should not have sent us a CERTS cell, or the cell is
+ * malformed, or it is supposed to authenticate the TLS key but it doesn't,
+ * then mark the connection.
+ *
+ * If the cell has a good cert chain and we're doing a v3 handshake, then
+ * store the certificates in or_handshake_state. If this is the client side
+ * of the connection, we then authenticate the server or mark the connection.
+ * If it's the server side, wait for an AUTHENTICATE cell.
+ */
+
+static void
+channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ tor_cert_t *link_cert = NULL;
+ tor_cert_t *id_cert = NULL;
+ tor_cert_t *auth_cert = NULL;
+ uint8_t *ptr;
+ int n_certs, i;
+ int send_netinfo = 0;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+#define ERR(s) \
+ do { \
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
+ "Received a bad CERTS cell from %s:%d: %s", \
+ safe_str(chan->conn->base_.address), \
+ chan->conn->base_.port, (s)); \
+ connection_or_close_for_error(chan->conn, 0); \
+ goto err; \
+ } while (0)
+
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
+ ERR("We're not doing a v3 handshake!");
+ if (chan->conn->link_proto < 3)
+ ERR("We're not using link protocol >= 3");
+ if (chan->conn->handshake_state->received_certs_cell)
+ ERR("We already got one");
+ if (chan->conn->handshake_state->authenticated) {
+ /* Should be unreachable, but let's make sure. */
+ ERR("We're already authenticated!");
+ }
+ if (cell->payload_len < 1)
+ ERR("It had no body");
+ if (cell->circ_id)
+ ERR("It had a nonzero circuit ID");
+
+ n_certs = cell->payload[0];
+ ptr = cell->payload + 1;
+ for (i = 0; i < n_certs; ++i) {
+ uint8_t cert_type;
+ uint16_t cert_len;
+ if (ptr + 3 > cell->payload + cell->payload_len) {
+ goto truncated;
+ }
+ cert_type = *ptr;
+ cert_len = ntohs(get_uint16(ptr+1));
+ if (ptr + 3 + cert_len > cell->payload + cell->payload_len) {
+ goto truncated;
+ }
+ if (cert_type == OR_CERT_TYPE_TLS_LINK ||
+ cert_type == OR_CERT_TYPE_ID_1024 ||
+ cert_type == OR_CERT_TYPE_AUTH_1024) {
+ tor_cert_t *cert = tor_cert_decode(ptr + 3, cert_len);
+ if (!cert) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received undecodable certificate in CERTS cell from %s:%d",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+ } else {
+ if (cert_type == OR_CERT_TYPE_TLS_LINK) {
+ if (link_cert) {
+ tor_cert_free(cert);
+ ERR("Too many TLS_LINK certificates");
+ }
+ link_cert = cert;
+ } else if (cert_type == OR_CERT_TYPE_ID_1024) {
+ if (id_cert) {
+ tor_cert_free(cert);
+ ERR("Too many ID_1024 certificates");
+ }
+ id_cert = cert;
+ } else if (cert_type == OR_CERT_TYPE_AUTH_1024) {
+ if (auth_cert) {
+ tor_cert_free(cert);
+ ERR("Too many AUTH_1024 certificates");
+ }
+ auth_cert = cert;
+ } else {
+ tor_cert_free(cert);
+ }
+ }
+ }
+ ptr += 3 + cert_len;
+ continue;
+
+ truncated:
+ ERR("It ends in the middle of a certificate");
+ }
+
+ if (chan->conn->handshake_state->started_here) {
+ int severity;
+ if (! (id_cert && link_cert))
+ ERR("The certs we wanted were missing");
+ /* Okay. We should be able to check the certificates now. */
+ if (! tor_tls_cert_matches_key(chan->conn->tls, link_cert)) {
+ ERR("The link certificate didn't match the TLS public key");
+ }
+ /* Note that this warns more loudly about time and validity if we were
+ * _trying_ to connect to an authority, not necessarily if we _did_ connect
+ * to one. */
+ if (router_digest_is_trusted_dir(
+ TLS_CHAN_TO_BASE(chan)->identity_digest))
+ severity = LOG_WARN;
+ else
+ severity = LOG_PROTOCOL_WARN;
+
+ if (! tor_tls_cert_is_valid(severity, link_cert, id_cert, 0))
+ ERR("The link certificate was not valid");
+ if (! tor_tls_cert_is_valid(severity, id_cert, id_cert, 1))
+ ERR("The ID certificate was not valid");
+
+ chan->conn->handshake_state->authenticated = 1;
+ {
+ const digests_t *id_digests = tor_cert_get_id_digests(id_cert);
+ crypto_pk_t *identity_rcvd;
+ if (!id_digests)
+ ERR("Couldn't compute digests for key in ID cert");
+
+ identity_rcvd = tor_tls_cert_get_key(id_cert);
+ if (!identity_rcvd)
+ ERR("Internal error: Couldn't get RSA key from ID cert.");
+ memcpy(chan->conn->handshake_state->authenticated_peer_id,
+ id_digests->d[DIGEST_SHA1], DIGEST_LEN);
+ channel_set_circid_type(TLS_CHAN_TO_BASE(chan), identity_rcvd,
+ chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS);
+ crypto_pk_free(identity_rcvd);
+ }
+
+ if (connection_or_client_learned_peer_id(chan->conn,
+ chan->conn->handshake_state->authenticated_peer_id) < 0)
+ ERR("Problem setting or checking peer id");
+
+ log_info(LD_OR,
+ "Got some good certificates from %s:%d: Authenticated it.",
+ safe_str(chan->conn->base_.address), chan->conn->base_.port);
+
+ chan->conn->handshake_state->id_cert = id_cert;
+ id_cert = NULL;
+
+ if (!public_server_mode(get_options())) {
+ /* If we initiated the connection and we are not a public server, we
+ * aren't planning to authenticate at all. At this point we know who we
+ * are talking to, so we can just send a netinfo now. */
+ send_netinfo = 1;
+ }
+ } else {
+ if (! (id_cert && auth_cert))
+ ERR("The certs we wanted were missing");
+
+ /* Remember these certificates so we can check an AUTHENTICATE cell */
+ if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, auth_cert, id_cert, 1))
+ ERR("The authentication certificate was not valid");
+ if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, id_cert, id_cert, 1))
+ ERR("The ID certificate was not valid");
+
+ log_info(LD_OR,
+ "Got some good certificates from %s:%d: "
+ "Waiting for AUTHENTICATE.",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+ /* XXXX check more stuff? */
+
+ chan->conn->handshake_state->id_cert = id_cert;
+ chan->conn->handshake_state->auth_cert = auth_cert;
+ id_cert = auth_cert = NULL;
+ }
+
+ chan->conn->handshake_state->received_certs_cell = 1;
+
+ if (send_netinfo) {
+ if (connection_or_send_netinfo(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send netinfo cell");
+ connection_or_close_for_error(chan->conn, 0);
+ goto err;
+ }
+ }
+
+ err:
+ tor_cert_free(id_cert);
+ tor_cert_free(link_cert);
+ tor_cert_free(auth_cert);
+#undef ERR
+}
+
+/**
+ * Process an AUTH_CHALLENGE cell from a channel_tls_t
+ *
+ * This function is called to handle an incoming AUTH_CHALLENGE cell on a
+ * channel_tls_t; if we weren't supposed to get one (for example, because we're
+ * not the originator of the channel), or it's ill-formed, or we aren't doing
+ * a v3 handshake, mark the channel. If the cell is well-formed but we don't
+ * want to authenticate, just drop it. If the cell is well-formed *and* we
+ * want to authenticate, send an AUTHENTICATE cell and then a NETINFO cell.
+ */
+
+static void
+channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ int n_types, i, use_type = -1;
+ uint8_t *cp;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+#define ERR(s) \
+ do { \
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
+ "Received a bad AUTH_CHALLENGE cell from %s:%d: %s", \
+ safe_str(chan->conn->base_.address), \
+ chan->conn->base_.port, (s)); \
+ connection_or_close_for_error(chan->conn, 0); \
+ return; \
+ } while (0)
+
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
+ ERR("We're not currently doing a v3 handshake");
+ if (chan->conn->link_proto < 3)
+ ERR("We're not using link protocol >= 3");
+ if (!(chan->conn->handshake_state->started_here))
+ ERR("We didn't originate this connection");
+ if (chan->conn->handshake_state->received_auth_challenge)
+ ERR("We already received one");
+ if (!(chan->conn->handshake_state->received_certs_cell))
+ ERR("We haven't gotten a CERTS cell yet");
+ if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2)
+ ERR("It was too short");
+ if (cell->circ_id)
+ ERR("It had a nonzero circuit ID");
+
+ n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN));
+ if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types)
+ ERR("It looks truncated");
+
+ /* Now see if there is an authentication type we can use */
+ cp = cell->payload+OR_AUTH_CHALLENGE_LEN + 2;
+ for (i = 0; i < n_types; ++i, cp += 2) {
+ uint16_t authtype = ntohs(get_uint16(cp));
+ if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET)
+ use_type = authtype;
+ }
+
+ chan->conn->handshake_state->received_auth_challenge = 1;
+
+ if (! public_server_mode(get_options())) {
+ /* If we're not a public server then we don't want to authenticate on a
+ connection we originated, and we already sent a NETINFO cell when we
+ got the CERTS cell. We have nothing more to do. */
+ return;
+ }
+
+ if (use_type >= 0) {
+ log_info(LD_OR,
+ "Got an AUTH_CHALLENGE cell from %s:%d: Sending "
+ "authentication",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+
+ if (connection_or_send_authenticate_cell(chan->conn, use_type) < 0) {
+ log_warn(LD_OR,
+ "Couldn't send authenticate cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+ } else {
+ log_info(LD_OR,
+ "Got an AUTH_CHALLENGE cell from %s:%d, but we don't "
+ "know any of its authentication types. Not authenticating.",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+ }
+
+ if (connection_or_send_netinfo(chan->conn) < 0) {
+ log_warn(LD_OR, "Couldn't send netinfo cell");
+ connection_or_close_for_error(chan->conn, 0);
+ return;
+ }
+
+#undef ERR
+}
+
+/**
+ * Process an AUTHENTICATE cell from a channel_tls_t
+ *
+ * If it's ill-formed or we weren't supposed to get one or we're not doing a
+ * v3 handshake, then mark the connection. If it does not authenticate the
+ * other side of the connection successfully (because it isn't signed right,
+ * we didn't get a CERTS cell, etc) mark the connection. Otherwise, accept
+ * the identity of the router on the other side of the connection.
+ */
+
+static void
+channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
+{
+ uint8_t expected[V3_AUTH_FIXED_PART_LEN];
+ const uint8_t *auth;
+ int authlen;
+
+ tor_assert(cell);
+ tor_assert(chan);
+ tor_assert(chan->conn);
+
+#define ERR(s) \
+ do { \
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
+ "Received a bad AUTHENTICATE cell from %s:%d: %s", \
+ safe_str(chan->conn->base_.address), \
+ chan->conn->base_.port, (s)); \
+ connection_or_close_for_error(chan->conn, 0); \
+ return; \
+ } while (0)
+
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
+ ERR("We're not doing a v3 handshake");
+ if (chan->conn->link_proto < 3)
+ ERR("We're not using link protocol >= 3");
+ if (chan->conn->handshake_state->started_here)
+ ERR("We originated this connection");
+ if (chan->conn->handshake_state->received_authenticate)
+ ERR("We already got one!");
+ if (chan->conn->handshake_state->authenticated) {
+ /* Should be impossible given other checks */
+ ERR("The peer is already authenticated");
+ }
+ if (!(chan->conn->handshake_state->received_certs_cell))
+ ERR("We never got a certs cell");
+ if (chan->conn->handshake_state->auth_cert == NULL)
+ ERR("We never got an authentication certificate");
+ if (chan->conn->handshake_state->id_cert == NULL)
+ ERR("We never got an identity certificate");
+ if (cell->payload_len < 4)
+ ERR("Cell was way too short");
+
+ auth = cell->payload;
+ {
+ uint16_t type = ntohs(get_uint16(auth));
+ uint16_t len = ntohs(get_uint16(auth+2));
+ if (4 + len > cell->payload_len)
+ ERR("Authenticator was truncated");
+
+ if (type != AUTHTYPE_RSA_SHA256_TLSSECRET)
+ ERR("Authenticator type was not recognized");
+
+ auth += 4;
+ authlen = len;
+ }
+
+ if (authlen < V3_AUTH_BODY_LEN + 1)
+ ERR("Authenticator was too short");
+
+ if (connection_or_compute_authenticate_cell_body(
+ chan->conn, expected, sizeof(expected), NULL, 1) < 0)
+ ERR("Couldn't compute expected AUTHENTICATE cell body");
+
+ if (tor_memneq(expected, auth, sizeof(expected)))
+ ERR("Some field in the AUTHENTICATE cell body was not as expected");
+
+ {
+ crypto_pk_t *pk = tor_tls_cert_get_key(
+ chan->conn->handshake_state->auth_cert);
+ char d[DIGEST256_LEN];
+ char *signed_data;
+ size_t keysize;
+ int signed_len;
+
+ if (!pk)
+ ERR("Internal error: couldn't get RSA key from AUTH cert.");
+ crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256);
+
+ keysize = crypto_pk_keysize(pk);
+ signed_data = tor_malloc(keysize);
+ signed_len = crypto_pk_public_checksig(pk, signed_data, keysize,
+ (char*)auth + V3_AUTH_BODY_LEN,
+ authlen - V3_AUTH_BODY_LEN);
+ crypto_pk_free(pk);
+ if (signed_len < 0) {
+ tor_free(signed_data);
+ ERR("Signature wasn't valid");
+ }
+ if (signed_len < DIGEST256_LEN) {
+ tor_free(signed_data);
+ ERR("Not enough data was signed");
+ }
+ /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here,
+ * in case they're later used to hold a SHA3 digest or something. */
+ if (tor_memneq(signed_data, d, DIGEST256_LEN)) {
+ tor_free(signed_data);
+ ERR("Signature did not match data to be signed.");
+ }
+ tor_free(signed_data);
+ }
+
+ /* Okay, we are authenticated. */
+ chan->conn->handshake_state->received_authenticate = 1;
+ chan->conn->handshake_state->authenticated = 1;
+ chan->conn->handshake_state->digest_received_data = 0;
+ {
+ crypto_pk_t *identity_rcvd =
+ tor_tls_cert_get_key(chan->conn->handshake_state->id_cert);
+ const digests_t *id_digests =
+ tor_cert_get_id_digests(chan->conn->handshake_state->id_cert);
+
+ /* This must exist; we checked key type when reading the cert. */
+ tor_assert(id_digests);
+
+ memcpy(chan->conn->handshake_state->authenticated_peer_id,
+ id_digests->d[DIGEST_SHA1], DIGEST_LEN);
+
+ channel_set_circid_type(TLS_CHAN_TO_BASE(chan), identity_rcvd,
+ chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS);
+ crypto_pk_free(identity_rcvd);
+
+ connection_or_init_conn_from_address(chan->conn,
+ &(chan->conn->base_.addr),
+ chan->conn->base_.port,
+ (const char*)(chan->conn->handshake_state->
+ authenticated_peer_id),
+ 0);
+
+ log_info(LD_OR,
+ "Got an AUTHENTICATE cell from %s:%d: Looks good.",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+ }
+
+#undef ERR
+}
+
diff --git a/src/or/channeltls.h b/src/or/channeltls.h
new file mode 100644
index 000000000..b4a7e2bea
--- /dev/null
+++ b/src/or/channeltls.h
@@ -0,0 +1,57 @@
+/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file channeltls.h
+ * \brief Header file for channeltls.c
+ **/
+
+#ifndef TOR_CHANNELTLS_H
+#define TOR_CHANNELTLS_H
+
+#include "or.h"
+#include "channel.h"
+
+#define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c)))
+#define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c)))
+
+#define TLS_CHAN_MAGIC 0x8a192427U
+
+#ifdef TOR_CHANNEL_INTERNAL_
+
+struct channel_tls_s {
+ /* Base channel_t struct */
+ channel_t base_;
+ /* or_connection_t pointer */
+ or_connection_t *conn;
+};
+
+#endif /* TOR_CHANNEL_INTERNAL_ */
+
+channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest);
+channel_listener_t * channel_tls_get_listener(void);
+channel_listener_t * channel_tls_start_listener(void);
+channel_t * channel_tls_handle_incoming(or_connection_t *orconn);
+
+/* Casts */
+
+channel_t * channel_tls_to_base(channel_tls_t *tlschan);
+channel_tls_t * channel_tls_from_base(channel_t *chan);
+
+/* Things for connection_or.c to call back into */
+ssize_t channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells);
+int channel_tls_more_to_flush(channel_tls_t *chan);
+void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn);
+void channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
+ or_connection_t *conn,
+ uint8_t old_state,
+ uint8_t state);
+void channel_tls_handle_var_cell(var_cell_t *var_cell,
+ or_connection_t *conn);
+
+/* Cleanup at shutdown */
+void channel_tls_free_all(void);
+
+#endif
+
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 1c692ab87..43d2ffe4d 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,22 +9,28 @@
* \brief The actual details of building circuits.
**/
-#define CIRCUIT_PRIVATE
-
#include "or.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitstats.h"
#include "circuituse.h"
+#include "command.h"
#include "config.h"
+#include "confparse.h"
#include "connection.h"
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
#include "directory.h"
+#include "entrynodes.h"
#include "main.h"
+#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "onion.h"
+#include "onion_tap.h"
+#include "onion_fast.h"
#include "policies.h"
#include "transports.h"
#include "relay.h"
@@ -32,1645 +38,55 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "routerset.h"
#include "crypto.h"
-#undef log
-#include <math.h>
+#include "connection_edge.h"
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
-#define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2))
-
/********* START VARIABLES **********/
-/** Global list of circuit build times */
-// XXXX: Add this as a member for entry_guard_t instead of global?
-// Then we could do per-guard statistics, as guards are likely to
-// vary in their own latency. The downside of this is that guards
-// can change frequently, so we'd be building a lot more circuits
-// most likely.
-/* XXXX024 Make this static; add accessor functions. */
-circuit_build_times_t circ_times;
/** A global list of all circuits at this hop. */
extern circuit_t *global_circuitlist;
-/** An entry_guard_t represents our information about a chosen long-term
- * first hop, known as a "helper" node in the literature. We can't just
- * use a node_t, since we want to remember these even when we
- * don't have any directory info. */
-typedef struct {
- char nickname[MAX_NICKNAME_LEN+1];
- char identity[DIGEST_LEN];
- time_t chosen_on_date; /**< Approximately when was this guard added?
- * "0" if we don't know. */
- char *chosen_by_version; /**< What tor version added this guard? NULL
- * if we don't know. */
- unsigned int made_contact : 1; /**< 0 if we have never connected to this
- * router, 1 if we have. */
- unsigned int can_retry : 1; /**< Should we retry connecting to this entry,
- * in spite of having it marked as unreachable?*/
- unsigned int path_bias_notice : 1; /**< Did we alert the user about path bias
- * for this node already? */
- unsigned int path_bias_disabled : 1; /**< Have we disabled this node because
- * of path bias issues? */
- time_t bad_since; /**< 0 if this guard is currently usable, or the time at
- * which it was observed to become (according to the
- * directory or the user configuration) unusable. */
- time_t unreachable_since; /**< 0 if we can connect to this guard, or the
- * time at which we first noticed we couldn't
- * connect to it. */
- time_t last_attempted; /**< 0 if we can connect to this guard, or the time
- * at which we last failed to connect to it. */
-
- unsigned first_hops; /**< Number of first hops this guard has completed */
- unsigned circuit_successes; /**< Number of successfully built circuits using
- * this guard as first hop. */
-} entry_guard_t;
-
-/** Information about a configured bridge. Currently this just matches the
- * ones in the torrc file, but one day we may be able to learn about new
- * bridges on our own, and remember them in the state file. */
-typedef struct {
- /** Address of the bridge. */
- tor_addr_t addr;
- /** TLS port for the bridge. */
- uint16_t port;
- /** Boolean: We are re-parsing our bridge list, and we are going to remove
- * this one if we don't find it in the list of configured bridges. */
- unsigned marked_for_removal : 1;
- /** Expected identity digest, or all zero bytes if we don't know what the
- * digest should be. */
- char identity[DIGEST_LEN];
-
- /** Name of pluggable transport protocol taken from its config line. */
- char *transport_name;
-
- /** When should we next try to fetch a descriptor for this bridge? */
- download_status_t fetch_status;
-} bridge_info_t;
-
-/** A list of our chosen entry guards. */
-static smartlist_t *entry_guards = NULL;
-/** A value of 1 means that the entry_guards list has changed
- * and those changes need to be flushed to disk. */
-static int entry_guards_dirty = 0;
-
-/** If set, we're running the unit tests: we should avoid clobbering
- * our state file or accessing get_options() or get_or_state() */
-static int unit_tests = 0;
-
/********* END VARIABLES ************/
+static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
+ uint16_t port,
+ const char *id_digest);
static int circuit_deliver_create_cell(circuit_t *circ,
- uint8_t cell_type, const char *payload);
+ const create_cell_t *create_cell,
+ int relayed);
static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
static int onion_extend_cpath(origin_circuit_t *circ);
static int count_acceptable_nodes(smartlist_t *routers);
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
+static int entry_guard_inc_circ_attempt_count(entry_guard_t *guard);
+static void pathbias_count_build_success(origin_circuit_t *circ);
+static void pathbias_count_successful_close(origin_circuit_t *circ);
+static void pathbias_count_collapse(origin_circuit_t *circ);
+static void pathbias_count_use_failed(origin_circuit_t *circ);
+static void pathbias_measure_use_rate(entry_guard_t *guard);
+static void pathbias_measure_close_rate(entry_guard_t *guard);
+static void pathbias_scale_use_rates(entry_guard_t *guard);
-static void entry_guards_changed(void);
-static entry_guard_t *entry_guard_get_by_id_digest(const char *digest);
-
-static void bridge_free(bridge_info_t *bridge);
-
-static int entry_guard_inc_first_hop_count(entry_guard_t *guard);
-static void pathbias_count_success(origin_circuit_t *circ);
-
-/**
- * This function decides if CBT learning should be disabled. It returns
- * true if one or more of the following four conditions are met:
- *
- * 1. If the cbtdisabled consensus parameter is set.
- * 2. If the torrc option LearnCircuitBuildTimeout is false.
- * 3. If we are a directory authority
- * 4. If we fail to write circuit build time history to our state file.
- */
-int
-circuit_build_times_disabled(void)
-{
- if (unit_tests) {
- return 0;
- } else {
- int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled",
- 0, 0, 1);
- int config_disabled = !get_options()->LearnCircuitBuildTimeout;
- int dirauth_disabled = get_options()->AuthoritativeDir;
- int state_disabled = did_last_state_file_write_fail() ? 1 : 0;
-
- if (consensus_disabled || config_disabled || dirauth_disabled ||
- state_disabled) {
- log_debug(LD_CIRC,
- "CircuitBuildTime learning is disabled. "
- "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d",
- consensus_disabled, config_disabled, dirauth_disabled,
- state_disabled);
- return 1;
- } else {
- log_debug(LD_CIRC,
- "CircuitBuildTime learning is not disabled. "
- "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d",
- consensus_disabled, config_disabled, dirauth_disabled,
- state_disabled);
- return 0;
- }
- }
-}
-
-/**
- * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter.
- *
- * Effect: When this many timeouts happen in the last 'cbtrecentcount'
- * circuit attempts, the client should discard all of its history and
- * begin learning a fresh timeout value.
- */
-static int32_t
-circuit_build_times_max_timeouts(void)
-{
- int32_t cbt_maxtimeouts;
-
- cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts",
- CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT,
- CBT_MIN_MAX_RECENT_TIMEOUT_COUNT,
- CBT_MAX_MAX_RECENT_TIMEOUT_COUNT);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is"
- " %d",
- cbt_maxtimeouts);
- }
-
- return cbt_maxtimeouts;
-}
-
-/**
- * Retrieve and bounds-check the cbtnummodes consensus paramter.
- *
- * Effect: This value governs how many modes to use in the weighted
- * average calculation of Pareto parameter Xm. A value of 3 introduces
- * some bias (2-5% of CDF) under ideal conditions, but allows for better
- * performance in the event that a client chooses guard nodes of radically
- * different performance characteristics.
- */
-static int32_t
-circuit_build_times_default_num_xm_modes(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbtnummodes",
- CBT_DEFAULT_NUM_XM_MODES,
- CBT_MIN_NUM_XM_MODES,
- CBT_MAX_NUM_XM_MODES);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_default_num_xm_modes() called, cbtnummodes"
- " is %d",
- num);
- }
-
- return num;
-}
-
-/**
- * Retrieve and bounds-check the cbtmincircs consensus paramter.
- *
- * Effect: This is the minimum number of circuits to build before
- * computing a timeout.
- */
-static int32_t
-circuit_build_times_min_circs_to_observe(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbtmincircs",
- CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE,
- CBT_MIN_MIN_CIRCUITS_TO_OBSERVE,
- CBT_MAX_MIN_CIRCUITS_TO_OBSERVE);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_min_circs_to_observe() called, cbtmincircs"
- " is %d",
- num);
- }
-
- return num;
-}
-
-/** Return true iff <b>cbt</b> has recorded enough build times that we
- * want to start acting on the timeout it implies. */
-int
-circuit_build_times_enough_to_compute(circuit_build_times_t *cbt)
-{
- return cbt->total_build_times >= circuit_build_times_min_circs_to_observe();
-}
-
-/**
- * Retrieve and bounds-check the cbtquantile consensus paramter.
- *
- * Effect: This is the position on the quantile curve to use to set the
- * timeout value. It is a percent (10-99).
- */
-double
-circuit_build_times_quantile_cutoff(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbtquantile",
- CBT_DEFAULT_QUANTILE_CUTOFF,
- CBT_MIN_QUANTILE_CUTOFF,
- CBT_MAX_QUANTILE_CUTOFF);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_quantile_cutoff() called, cbtquantile"
- " is %d",
- num);
- }
-
- return num/100.0;
-}
-
-/* DOCDOC circuit_build_times_get_bw_scale */
-int
-circuit_build_times_get_bw_scale(networkstatus_t *ns)
-{
- return networkstatus_get_param(ns, "bwweightscale",
- BW_WEIGHT_SCALE,
- BW_MIN_WEIGHT_SCALE,
- BW_MAX_WEIGHT_SCALE);
-}
-
-/**
- * Retrieve and bounds-check the cbtclosequantile consensus paramter.
- *
- * Effect: This is the position on the quantile curve to use to set the
- * timeout value to use to actually close circuits. It is a percent
- * (0-99).
- */
-static double
-circuit_build_times_close_quantile(void)
-{
- int32_t param;
- /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */
- int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff());
- param = networkstatus_get_param(NULL, "cbtclosequantile",
- CBT_DEFAULT_CLOSE_QUANTILE,
- CBT_MIN_CLOSE_QUANTILE,
- CBT_MAX_CLOSE_QUANTILE);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_close_quantile() called, cbtclosequantile"
- " is %d", param);
- }
-
- if (param < min) {
- log_warn(LD_DIR, "Consensus parameter cbtclosequantile is "
- "too small, raising to %d", min);
- param = min;
- }
- return param / 100.0;
-}
-
-/**
- * Retrieve and bounds-check the cbttestfreq consensus paramter.
- *
- * Effect: Describes how often in seconds to build a test circuit to
- * gather timeout values. Only applies if less than 'cbtmincircs'
- * have been recorded.
- */
-static int32_t
-circuit_build_times_test_frequency(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbttestfreq",
- CBT_DEFAULT_TEST_FREQUENCY,
- CBT_MIN_TEST_FREQUENCY,
- CBT_MAX_TEST_FREQUENCY);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_test_frequency() called, cbttestfreq is %d",
- num);
- }
-
- return num;
-}
-
-/**
- * Retrieve and bounds-check the cbtmintimeout consensus parameter.
- *
- * Effect: This is the minimum allowed timeout value in milliseconds.
- * The minimum is to prevent rounding to 0 (we only check once
- * per second).
- */
-static int32_t
-circuit_build_times_min_timeout(void)
-{
- int32_t num = networkstatus_get_param(NULL, "cbtmintimeout",
- CBT_DEFAULT_TIMEOUT_MIN_VALUE,
- CBT_MIN_TIMEOUT_MIN_VALUE,
- CBT_MAX_TIMEOUT_MIN_VALUE);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_min_timeout() called, cbtmintimeout is %d",
- num);
- }
-
- return num;
-}
-
-/**
- * Retrieve and bounds-check the cbtinitialtimeout consensus paramter.
- *
- * Effect: This is the timeout value to use before computing a timeout,
- * in milliseconds.
- */
-int32_t
-circuit_build_times_initial_timeout(void)
-{
- int32_t min = circuit_build_times_min_timeout();
- int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout",
- CBT_DEFAULT_TIMEOUT_INITIAL_VALUE,
- CBT_MIN_TIMEOUT_INITIAL_VALUE,
- CBT_MAX_TIMEOUT_INITIAL_VALUE);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_initial_timeout() called, "
- "cbtinitialtimeout is %d",
- param);
- }
-
- if (param < min) {
- log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, "
- "raising to %d", min);
- param = min;
- }
- return param;
-}
-
-/**
- * Retrieve and bounds-check the cbtrecentcount consensus paramter.
- *
- * Effect: This is the number of circuit build times to keep track of
- * for deciding if we hit cbtmaxtimeouts and need to reset our state
- * and learn a new timeout.
- */
-static int32_t
-circuit_build_times_recent_circuit_count(networkstatus_t *ns)
-{
- int32_t num;
- num = networkstatus_get_param(ns, "cbtrecentcount",
- CBT_DEFAULT_RECENT_CIRCUITS,
- CBT_MIN_RECENT_CIRCUITS,
- CBT_MAX_RECENT_CIRCUITS);
-
- if (!(get_options()->LearnCircuitBuildTimeout)) {
- log_debug(LD_BUG,
- "circuit_build_times_recent_circuit_count() called, "
- "cbtrecentcount is %d",
- num);
- }
-
- return num;
-}
-
-/**
- * This function is called when we get a consensus update.
- *
- * It checks to see if we have changed any consensus parameters
- * that require reallocation or discard of previous stats.
- */
-void
-circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
- networkstatus_t *ns)
-{
- int32_t num;
-
- /*
- * First check if we're doing adaptive timeouts at all; nothing to
- * update if we aren't.
- */
-
- if (!circuit_build_times_disabled()) {
- num = circuit_build_times_recent_circuit_count(ns);
-
- if (num > 0) {
- if (num != cbt->liveness.num_recent_circs) {
- int8_t *recent_circs;
- log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many "
- "circuits we must track to detect network failures from %d "
- "to %d.", cbt->liveness.num_recent_circs, num);
-
- tor_assert(cbt->liveness.timeouts_after_firsthop ||
- cbt->liveness.num_recent_circs == 0);
-
- /*
- * Technically this is a circular array that we are reallocating
- * and memcopying. However, since it only consists of either 1s
- * or 0s, and is only used in a statistical test to determine when
- * we should discard our history after a sufficient number of 1's
- * have been reached, it is fine if order is not preserved or
- * elements are lost.
- *
- * cbtrecentcount should only be changing in cases of severe network
- * distress anyway, so memory correctness here is paramount over
- * doing acrobatics to preserve the array.
- */
- recent_circs = tor_malloc_zero(sizeof(int8_t)*num);
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop,
- sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs));
- }
-
- // Adjust the index if it needs it.
- if (num < cbt->liveness.num_recent_circs) {
- cbt->liveness.after_firsthop_idx = MIN(num-1,
- cbt->liveness.after_firsthop_idx);
- }
-
- tor_free(cbt->liveness.timeouts_after_firsthop);
- cbt->liveness.timeouts_after_firsthop = recent_circs;
- cbt->liveness.num_recent_circs = num;
- }
- /* else no change, nothing to do */
- } else { /* num == 0 */
- /*
- * Weird. This probably shouldn't happen, so log a warning, but try
- * to do something sensible anyway.
- */
-
- log_warn(LD_CIRC,
- "The cbtrecentcircs consensus parameter came back zero! "
- "This disables adaptive timeouts since we can't keep track of "
- "any recent circuits.");
-
- circuit_build_times_free_timeouts(cbt);
- }
- } else {
- /*
- * Adaptive timeouts are disabled; this might be because of the
- * LearnCircuitBuildTimes config parameter, and hence permanent, or
- * the cbtdisabled consensus parameter, so it may be a new condition.
- * Treat it like getting num == 0 above and free the circuit history
- * if we have any.
- */
-
- circuit_build_times_free_timeouts(cbt);
- }
-}
-
-/** Make a note that we're running unit tests (rather than running Tor
- * itself), so we avoid clobbering our state file. */
-void
-circuitbuild_running_unit_tests(void)
-{
- unit_tests = 1;
-}
-
-/**
- * Return the initial default or configured timeout in milliseconds
- */
-static double
-circuit_build_times_get_initial_timeout(void)
-{
- double timeout;
-
- /*
- * Check if we have LearnCircuitBuildTimeout, and if we don't,
- * always use CircuitBuildTimeout, no questions asked.
- */
- if (get_options()->LearnCircuitBuildTimeout) {
- if (!unit_tests && get_options()->CircuitBuildTimeout) {
- timeout = get_options()->CircuitBuildTimeout*1000;
- if (timeout < circuit_build_times_min_timeout()) {
- log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds",
- circuit_build_times_min_timeout()/1000);
- timeout = circuit_build_times_min_timeout();
- }
- } else {
- timeout = circuit_build_times_initial_timeout();
- }
- } else {
- timeout = get_options()->CircuitBuildTimeout*1000;
- }
-
- return timeout;
-}
-
-/**
- * Reset the build time state.
- *
- * Leave estimated parameters, timeout and network liveness intact
- * for future use.
- */
-void
-circuit_build_times_reset(circuit_build_times_t *cbt)
-{
- memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times));
- cbt->total_build_times = 0;
- cbt->build_times_idx = 0;
- cbt->have_computed_timeout = 0;
-}
-
-/**
- * Initialize the buildtimes structure for first use.
- *
- * Sets the initial timeout values based on either the config setting,
- * the consensus param, or the default (CBT_DEFAULT_TIMEOUT_INITIAL_VALUE).
- */
-void
-circuit_build_times_init(circuit_build_times_t *cbt)
-{
- memset(cbt, 0, sizeof(*cbt));
- /*
- * Check if we really are using adaptive timeouts, and don't keep
- * track of this stuff if not.
- */
- if (!circuit_build_times_disabled()) {
- cbt->liveness.num_recent_circs =
- circuit_build_times_recent_circuit_count(NULL);
- cbt->liveness.timeouts_after_firsthop =
- tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs);
- } else {
- cbt->liveness.num_recent_circs = 0;
- cbt->liveness.timeouts_after_firsthop = NULL;
- }
- cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout();
- control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
-}
-
-/**
- * Free the saved timeouts, if the cbtdisabled consensus parameter got turned
- * on or something.
- */
-
-void
-circuit_build_times_free_timeouts(circuit_build_times_t *cbt)
-{
- if (!cbt) return;
-
- if (cbt->liveness.timeouts_after_firsthop) {
- tor_free(cbt->liveness.timeouts_after_firsthop);
- }
-
- cbt->liveness.num_recent_circs = 0;
-}
-
-#if 0
-/**
- * Rewind our build time history by n positions.
- */
-static void
-circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
-{
- int i = 0;
-
- cbt->build_times_idx -= n;
- cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE;
-
- for (i = 0; i < n; i++) {
- cbt->circuit_build_times[(i+cbt->build_times_idx)
- %CBT_NCIRCUITS_TO_OBSERVE]=0;
- }
-
- if (cbt->total_build_times > n) {
- cbt->total_build_times -= n;
- } else {
- cbt->total_build_times = 0;
- }
-
- log_info(LD_CIRC,
- "Rewound history by %d places. Current index: %d. "
- "Total: %d", n, cbt->build_times_idx, cbt->total_build_times);
-}
-#endif
-
-/**
- * Add a new build time value <b>time</b> to the set of build times. Time
- * units are milliseconds.
- *
- * circuit_build_times <b>cbt</b> is a circular array, so loop around when
- * array is full.
- */
-int
-circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
-{
- if (time <= 0 || time > CBT_BUILD_TIME_MAX) {
- log_warn(LD_BUG, "Circuit build time is too large (%u)."
- "This is probably a bug.", time);
- tor_fragile_assert();
- return -1;
- }
-
- log_debug(LD_CIRC, "Adding circuit build time %u", time);
-
- cbt->circuit_build_times[cbt->build_times_idx] = time;
- cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE;
- if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
- cbt->total_build_times++;
-
- if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) {
- /* Save state every n circuit builds */
- if (!unit_tests && !get_options()->AvoidDiskWrites)
- or_state_mark_dirty(get_or_state(), 0);
- }
-
- return 0;
-}
-
-/**
- * Return maximum circuit build time
- */
-static build_time_t
-circuit_build_times_max(circuit_build_times_t *cbt)
-{
- int i = 0;
- build_time_t max_build_time = 0;
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] > max_build_time
- && cbt->circuit_build_times[i] != CBT_BUILD_ABANDONED)
- max_build_time = cbt->circuit_build_times[i];
- }
- return max_build_time;
-}
-
-#if 0
-/** Return minimum circuit build time */
-build_time_t
-circuit_build_times_min(circuit_build_times_t *cbt)
-{
- int i = 0;
- build_time_t min_build_time = CBT_BUILD_TIME_MAX;
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */
- cbt->circuit_build_times[i] < min_build_time)
- min_build_time = cbt->circuit_build_times[i];
- }
- if (min_build_time == CBT_BUILD_TIME_MAX) {
- log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!");
- }
- return min_build_time;
-}
-#endif
-
-/**
- * Calculate and return a histogram for the set of build times.
- *
- * Returns an allocated array of histrogram bins representing
- * the frequency of index*CBT_BIN_WIDTH millisecond
- * build times. Also outputs the number of bins in nbins.
- *
- * The return value must be freed by the caller.
- */
-static uint32_t *
-circuit_build_times_create_histogram(circuit_build_times_t *cbt,
- build_time_t *nbins)
-{
- uint32_t *histogram;
- build_time_t max_build_time = circuit_build_times_max(cbt);
- int i, c;
-
- *nbins = 1 + (max_build_time / CBT_BIN_WIDTH);
- histogram = tor_malloc_zero(*nbins * sizeof(build_time_t));
-
- // calculate histogram
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] == 0
- || cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED)
- continue; /* 0 <-> uninitialized */
-
- c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH);
- histogram[c]++;
- }
-
- return histogram;
-}
-
-/**
- * Return the Pareto start-of-curve parameter Xm.
- *
- * Because we are not a true Pareto curve, we compute this as the
- * weighted average of the N most frequent build time bins. N is either
- * 1 if we don't have enough circuit build time data collected, or
- * determined by the consensus parameter cbtnummodes (default 3).
- */
-static build_time_t
-circuit_build_times_get_xm(circuit_build_times_t *cbt)
-{
- build_time_t i, nbins;
- build_time_t *nth_max_bin;
- int32_t bin_counts=0;
- build_time_t ret = 0;
- uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins);
- int n=0;
- int num_modes = circuit_build_times_default_num_xm_modes();
-
- tor_assert(nbins > 0);
- tor_assert(num_modes > 0);
-
- // Only use one mode if < 1000 buildtimes. Not enough data
- // for multiple.
- if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
- num_modes = 1;
-
- nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t));
-
- /* Determine the N most common build times */
- for (i = 0; i < nbins; i++) {
- if (histogram[i] >= histogram[nth_max_bin[0]]) {
- nth_max_bin[0] = i;
- }
-
- for (n = 1; n < num_modes; n++) {
- if (histogram[i] >= histogram[nth_max_bin[n]] &&
- (!histogram[nth_max_bin[n-1]]
- || histogram[i] < histogram[nth_max_bin[n-1]])) {
- nth_max_bin[n] = i;
- }
- }
- }
-
- for (n = 0; n < num_modes; n++) {
- bin_counts += histogram[nth_max_bin[n]];
- ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]];
- log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]),
- histogram[nth_max_bin[n]]);
- }
-
- /* The following assert is safe, because we don't get called when we
- * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */
- tor_assert(bin_counts > 0);
-
- ret /= bin_counts;
- tor_free(histogram);
- tor_free(nth_max_bin);
-
- return ret;
-}
-
-/**
- * Output a histogram of current circuit build times to
- * the or_state_t state structure.
- */
-void
-circuit_build_times_update_state(circuit_build_times_t *cbt,
- or_state_t *state)
-{
- uint32_t *histogram;
- build_time_t i = 0;
- build_time_t nbins = 0;
- config_line_t **next, *line;
-
- histogram = circuit_build_times_create_histogram(cbt, &nbins);
- // write to state
- config_free_lines(state->BuildtimeHistogram);
- next = &state->BuildtimeHistogram;
- *next = NULL;
-
- state->TotalBuildTimes = cbt->total_build_times;
- state->CircuitBuildAbandonedCount = 0;
-
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED)
- state->CircuitBuildAbandonedCount++;
- }
-
- for (i = 0; i < nbins; i++) {
- // compress the histogram by skipping the blanks
- if (histogram[i] == 0) continue;
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("CircuitBuildTimeBin");
- tor_asprintf(&line->value, "%d %d",
- CBT_BIN_TO_MS(i), histogram[i]);
- next = &(line->next);
- }
-
- if (!unit_tests) {
- if (!get_options()->AvoidDiskWrites)
- or_state_mark_dirty(get_or_state(), 0);
- }
-
- tor_free(histogram);
-}
-
-/**
- * Shuffle the build times array.
- *
- * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
- */
-static void
-circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
- build_time_t *raw_times,
- uint32_t num_times)
-{
- uint32_t n = num_times;
- if (num_times > CBT_NCIRCUITS_TO_OBSERVE) {
- log_notice(LD_CIRC, "The number of circuit times that this Tor version "
- "uses to calculate build times is less than the number stored "
- "in your state file. Decreasing the circuit time history from "
- "%lu to %d.", (unsigned long)num_times,
- CBT_NCIRCUITS_TO_OBSERVE);
- }
-
- if (n > INT_MAX-1) {
- log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build "
- "observations in your state file. That's far too many; probably "
- "there's a bug here.", (unsigned long)n);
- n = INT_MAX-1;
- }
-
- /* This code can only be run on a compact array */
- while (n-- > 1) {
- int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */
- build_time_t tmp = raw_times[k];
- raw_times[k] = raw_times[n];
- raw_times[n] = tmp;
- }
-
- /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE
- * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */
- for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) {
- circuit_build_times_add_time(cbt, raw_times[n]);
- }
-}
-
-/**
- * Filter old synthetic timeouts that were created before the
- * new right-censored Pareto calculation was deployed.
- *
- * Once all clients before 0.2.1.13-alpha are gone, this code
- * will be unused.
- */
-static int
-circuit_build_times_filter_timeouts(circuit_build_times_t *cbt)
-{
- int num_filtered=0, i=0;
- double timeout_rate = 0;
- build_time_t max_timeout = 0;
-
- timeout_rate = circuit_build_times_timeout_rate(cbt);
- max_timeout = (build_time_t)cbt->close_ms;
-
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] > max_timeout) {
- build_time_t replaced = cbt->circuit_build_times[i];
- num_filtered++;
- cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED;
-
- log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced,
- cbt->circuit_build_times[i]);
- }
- }
-
- log_info(LD_CIRC,
- "We had %d timeouts out of %d build times, "
- "and filtered %d above the max of %u",
- (int)(cbt->total_build_times*timeout_rate),
- cbt->total_build_times, num_filtered, max_timeout);
-
- return num_filtered;
-}
-
-/**
- * Load histogram from <b>state</b>, shuffling the resulting array
- * after we do so. Use this result to estimate parameters and
- * calculate the timeout.
- *
- * Return -1 on error.
- */
-int
-circuit_build_times_parse_state(circuit_build_times_t *cbt,
- or_state_t *state)
-{
- int tot_values = 0;
- uint32_t loaded_cnt = 0, N = 0;
- config_line_t *line;
- unsigned int i;
- build_time_t *loaded_times;
- int err = 0;
- circuit_build_times_init(cbt);
-
- if (circuit_build_times_disabled()) {
- return 0;
- }
-
- /* build_time_t 0 means uninitialized */
- loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes);
-
- for (line = state->BuildtimeHistogram; line; line = line->next) {
- smartlist_t *args = smartlist_new();
- smartlist_split_string(args, line->value, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- if (smartlist_len(args) < 2) {
- log_warn(LD_GENERAL, "Unable to parse circuit build times: "
- "Too few arguments to CircuitBuildTime");
- err = 1;
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- break;
- } else {
- const char *ms_str = smartlist_get(args,0);
- const char *count_str = smartlist_get(args,1);
- uint32_t count, k;
- build_time_t ms;
- int ok;
- ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0,
- CBT_BUILD_TIME_MAX, &ok, NULL);
- if (!ok) {
- log_warn(LD_GENERAL, "Unable to parse circuit build times: "
- "Unparsable bin number");
- err = 1;
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- break;
- }
- count = (uint32_t)tor_parse_ulong(count_str, 0, 0,
- UINT32_MAX, &ok, NULL);
- if (!ok) {
- log_warn(LD_GENERAL, "Unable to parse circuit build times: "
- "Unparsable bin count");
- err = 1;
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- break;
- }
-
- if (loaded_cnt+count+state->CircuitBuildAbandonedCount
- > state->TotalBuildTimes) {
- log_warn(LD_CIRC,
- "Too many build times in state file. "
- "Stopping short before %d",
- loaded_cnt+count);
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- break;
- }
-
- for (k = 0; k < count; k++) {
- loaded_times[loaded_cnt++] = ms;
- }
- N++;
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- }
- }
-
- log_info(LD_CIRC,
- "Adding %d timeouts.", state->CircuitBuildAbandonedCount);
- for (i=0; i < state->CircuitBuildAbandonedCount; i++) {
- loaded_times[loaded_cnt++] = CBT_BUILD_ABANDONED;
- }
-
- if (loaded_cnt != state->TotalBuildTimes) {
- log_warn(LD_CIRC,
- "Corrupt state file? Build times count mismatch. "
- "Read %d times, but file says %d", loaded_cnt,
- state->TotalBuildTimes);
- err = 1;
- circuit_build_times_reset(cbt);
- goto done;
- }
-
- circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt);
-
- /* Verify that we didn't overwrite any indexes */
- for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (!cbt->circuit_build_times[i])
- break;
- tot_values++;
- }
- log_info(LD_CIRC,
- "Loaded %d/%d values from %d lines in circuit time histogram",
- tot_values, cbt->total_build_times, N);
-
- if (cbt->total_build_times != tot_values
- || cbt->total_build_times > CBT_NCIRCUITS_TO_OBSERVE) {
- log_warn(LD_CIRC,
- "Corrupt state file? Shuffled build times mismatch. "
- "Read %d times, but file says %d", tot_values,
- state->TotalBuildTimes);
- err = 1;
- circuit_build_times_reset(cbt);
- goto done;
- }
-
- circuit_build_times_set_timeout(cbt);
-
- if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) {
- circuit_build_times_filter_timeouts(cbt);
- }
-
- done:
- tor_free(loaded_times);
- return err ? -1 : 0;
-}
-
-/**
- * Estimates the Xm and Alpha parameters using
- * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation
- *
- * The notable difference is that we use mode instead of min to estimate Xm.
- * This is because our distribution is frechet-like. We claim this is
- * an acceptable approximation because we are only concerned with the
- * accuracy of the CDF of the tail.
- */
-int
-circuit_build_times_update_alpha(circuit_build_times_t *cbt)
-{
- build_time_t *x=cbt->circuit_build_times;
- double a = 0;
- int n=0,i=0,abandoned_count=0;
- build_time_t max_time=0;
-
- /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */
- /* We sort of cheat here and make our samples slightly more pareto-like
- * and less frechet-like. */
- cbt->Xm = circuit_build_times_get_xm(cbt);
-
- tor_assert(cbt->Xm > 0);
-
- for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (!x[i]) {
- continue;
- }
-
- if (x[i] < cbt->Xm) {
- a += tor_mathlog(cbt->Xm);
- } else if (x[i] == CBT_BUILD_ABANDONED) {
- abandoned_count++;
- } else {
- a += tor_mathlog(x[i]);
- if (x[i] > max_time)
- max_time = x[i];
- }
- n++;
- }
-
- /*
- * We are erring and asserting here because this can only happen
- * in codepaths other than startup. The startup state parsing code
- * performs this same check, and resets state if it hits it. If we
- * hit it at runtime, something serious has gone wrong.
- */
- if (n!=cbt->total_build_times) {
- log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n,
- cbt->total_build_times);
- }
- tor_assert(n==cbt->total_build_times);
-
- if (max_time <= 0) {
- /* This can happen if Xm is actually the *maximum* value in the set.
- * It can also happen if we've abandoned every single circuit somehow.
- * In either case, tell the caller not to compute a new build timeout. */
- log_warn(LD_BUG,
- "Could not determine largest build time (%d). "
- "Xm is %dms and we've abandoned %d out of %d circuits.", max_time,
- cbt->Xm, abandoned_count, n);
- return 0;
- }
-
- a += abandoned_count*tor_mathlog(max_time);
-
- a -= n*tor_mathlog(cbt->Xm);
- // Estimator comes from Eq #4 in:
- // "Bayesian estimation based on trimmed samples from Pareto populations"
- // by Arturo J. Fernández. We are right-censored only.
- a = (n-abandoned_count)/a;
-
- cbt->alpha = a;
-
- return 1;
-}
-
-/**
- * This is the Pareto Quantile Function. It calculates the point x
- * in the distribution such that F(x) = quantile (ie quantile*100%
- * of the mass of the density function is below x on the curve).
- *
- * We use it to calculate the timeout and also to generate synthetic
- * values of time for circuits that timeout before completion.
- *
- * See http://en.wikipedia.org/wiki/Quantile_function,
- * http://en.wikipedia.org/wiki/Inverse_transform_sampling and
- * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_
- * random_sample_from_Pareto_distribution
- * That's right. I'll cite wikipedia all day long.
- *
- * Return value is in milliseconds.
- */
-double
-circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
- double quantile)
-{
- double ret;
- tor_assert(quantile >= 0);
- tor_assert(1.0-quantile > 0);
- tor_assert(cbt->Xm > 0);
-
- ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha);
- if (ret > INT32_MAX) {
- ret = INT32_MAX;
- }
- tor_assert(ret > 0);
- return ret;
-}
-
-/** Pareto CDF */
-double
-circuit_build_times_cdf(circuit_build_times_t *cbt, double x)
-{
- double ret;
- tor_assert(cbt->Xm > 0);
- ret = 1.0-pow(cbt->Xm/x,cbt->alpha);
- tor_assert(0 <= ret && ret <= 1.0);
- return ret;
-}
-
-/**
- * Generate a synthetic time using our distribution parameters.
- *
- * The return value will be within the [q_lo, q_hi) quantile points
- * on the CDF.
- */
-build_time_t
-circuit_build_times_generate_sample(circuit_build_times_t *cbt,
- double q_lo, double q_hi)
-{
- double randval = crypto_rand_double();
- build_time_t ret;
- double u;
-
- /* Generate between [q_lo, q_hi) */
- /*XXXX This is what nextafter is supposed to be for; we should use it on the
- * platforms that support it. */
- q_hi -= 1.0/(INT32_MAX);
-
- tor_assert(q_lo >= 0);
- tor_assert(q_hi < 1);
- tor_assert(q_lo < q_hi);
-
- u = q_lo + (q_hi-q_lo)*randval;
-
- tor_assert(0 <= u && u < 1.0);
- /* circuit_build_times_calculate_timeout returns <= INT32_MAX */
- ret = (build_time_t)
- tor_lround(circuit_build_times_calculate_timeout(cbt, u));
- tor_assert(ret > 0);
- return ret;
-}
-
-/**
- * Estimate an initial alpha parameter by solving the quantile
- * function with a quantile point and a specific timeout value.
- */
-void
-circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
- double quantile, double timeout_ms)
-{
- // Q(u) = Xm/((1-u)^(1/a))
- // Q(0.8) = Xm/((1-0.8))^(1/a)) = CircBuildTimeout
- // CircBuildTimeout = Xm/((1-0.8))^(1/a))
- // CircBuildTimeout = Xm*((1-0.8))^(-1/a))
- // ln(CircBuildTimeout) = ln(Xm)+ln(((1-0.8)))*(-1/a)
- // -ln(1-0.8)/(ln(CircBuildTimeout)-ln(Xm))=a
- tor_assert(quantile >= 0);
- tor_assert(cbt->Xm > 0);
- cbt->alpha = tor_mathlog(1.0-quantile)/
- (tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms));
- tor_assert(cbt->alpha > 0);
-}
-
-/**
- * Returns true if we need circuits to be built
- */
-int
-circuit_build_times_needs_circuits(circuit_build_times_t *cbt)
-{
- /* Return true if < MIN_CIRCUITS_TO_OBSERVE */
- return !circuit_build_times_enough_to_compute(cbt);
-}
-
-/**
- * Returns true if we should build a timeout test circuit
- * right now.
- */
-int
-circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt)
-{
- return circuit_build_times_needs_circuits(cbt) &&
- approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency();
-}
-
-/**
- * Called to indicate that the network showed some signs of liveness,
- * i.e. we received a cell.
- *
- * This is used by circuit_build_times_network_check_live() to decide
- * if we should record the circuit build timeout or not.
- *
- * This function is called every time we receive a cell. Avoid
- * syscalls, events, and other high-intensity work.
- */
-void
-circuit_build_times_network_is_live(circuit_build_times_t *cbt)
-{
- time_t now = approx_time();
- if (cbt->liveness.nonlive_timeouts > 0) {
- log_notice(LD_CIRC,
- "Tor now sees network activity. Restoring circuit build "
- "timeout recording. Network was down for %d seconds "
- "during %d circuit attempts.",
- (int)(now - cbt->liveness.network_last_live),
- cbt->liveness.nonlive_timeouts);
- }
- cbt->liveness.network_last_live = now;
- cbt->liveness.nonlive_timeouts = 0;
-}
-
-/**
- * Called to indicate that we completed a circuit. Because this circuit
- * succeeded, it doesn't count as a timeout-after-the-first-hop.
- *
- * This is used by circuit_build_times_network_check_changed() to determine
- * if we had too many recent timeouts and need to reset our learned timeout
- * to something higher.
- */
-void
-circuit_build_times_network_circ_success(circuit_build_times_t *cbt)
-{
- /* Check for NULLness because we might not be using adaptive timeouts */
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]
- = 0;
- cbt->liveness.after_firsthop_idx++;
- cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
- }
-}
-
-/**
- * A circuit just timed out. If it failed after the first hop, record it
- * in our history for later deciding if the network speed has changed.
- *
- * This is used by circuit_build_times_network_check_changed() to determine
- * if we had too many recent timeouts and need to reset our learned timeout
- * to something higher.
+/** This function tries to get a channel to the specified endpoint,
+ * and then calls command_setup_channel() to give it the right
+ * callbacks.
*/
-static void
-circuit_build_times_network_timeout(circuit_build_times_t *cbt,
- int did_onehop)
+static channel_t *
+channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest)
{
- /* Check for NULLness because we might not be using adaptive timeouts */
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- if (did_onehop) {
- cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]
- = 1;
- cbt->liveness.after_firsthop_idx++;
- cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
- }
- }
-}
+ channel_t *chan;
-/**
- * A circuit was just forcibly closed. If there has been no recent network
- * activity at all, but this circuit was launched back when we thought the
- * network was live, increment the number of "nonlive" circuit timeouts.
- *
- * This is used by circuit_build_times_network_check_live() to decide
- * if we should record the circuit build timeout or not.
- */
-static void
-circuit_build_times_network_close(circuit_build_times_t *cbt,
- int did_onehop, time_t start_time)
-{
- time_t now = time(NULL);
- /*
- * Check if this is a timeout that was for a circuit that spent its
- * entire existence during a time where we have had no network activity.
- */
- if (cbt->liveness.network_last_live < start_time) {
- if (did_onehop) {
- char last_live_buf[ISO_TIME_LEN+1];
- char start_time_buf[ISO_TIME_LEN+1];
- char now_buf[ISO_TIME_LEN+1];
- format_local_iso_time(last_live_buf, cbt->liveness.network_last_live);
- format_local_iso_time(start_time_buf, start_time);
- format_local_iso_time(now_buf, now);
- log_warn(LD_BUG,
- "Circuit somehow completed a hop while the network was "
- "not live. Network was last live at %s, but circuit launched "
- "at %s. It's now %s.", last_live_buf, start_time_buf,
- now_buf);
- }
- cbt->liveness.nonlive_timeouts++;
- if (cbt->liveness.nonlive_timeouts == 1) {
- log_notice(LD_CIRC,
- "Tor has not observed any network activity for the past %d "
- "seconds. Disabling circuit build timeout recording.",
- (int)(now - cbt->liveness.network_last_live));
- } else {
- log_info(LD_CIRC,
- "Got non-live timeout. Current count is: %d",
- cbt->liveness.nonlive_timeouts);
- }
- }
-}
-
-/**
- * When the network is not live, we do not record circuit build times.
- *
- * The network is considered not live if there has been at least one
- * circuit build that began and ended (had its close_ms measurement
- * period expire) since we last received a cell.
- *
- * Also has the side effect of rewinding the circuit time history
- * in the case of recent liveness changes.
- */
-int
-circuit_build_times_network_check_live(circuit_build_times_t *cbt)
-{
- if (cbt->liveness.nonlive_timeouts > 0) {
- return 0;
- }
+ chan = channel_connect(addr, port, id_digest);
+ if (chan) command_setup_channel(chan);
- return 1;
-}
-
-/**
- * Returns true if we have seen more than MAX_RECENT_TIMEOUT_COUNT of
- * the past RECENT_CIRCUITS time out after the first hop. Used to detect
- * if the network connection has changed significantly, and if so,
- * resets our circuit build timeout to the default.
- *
- * Also resets the entire timeout history in this case and causes us
- * to restart the process of building test circuits and estimating a
- * new timeout.
- */
-int
-circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
-{
- int total_build_times = cbt->total_build_times;
- int timeout_count=0;
- int i;
-
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- /* how many of our recent circuits made it to the first hop but then
- * timed out? */
- for (i = 0; i < cbt->liveness.num_recent_circs; i++) {
- timeout_count += cbt->liveness.timeouts_after_firsthop[i];
- }
- }
-
- /* If 80% of our recent circuits are timing out after the first hop,
- * we need to re-estimate a new initial alpha and timeout. */
- if (timeout_count < circuit_build_times_max_timeouts()) {
- return 0;
- }
-
- circuit_build_times_reset(cbt);
- if (cbt->liveness.timeouts_after_firsthop &&
- cbt->liveness.num_recent_circs > 0) {
- memset(cbt->liveness.timeouts_after_firsthop, 0,
- sizeof(*cbt->liveness.timeouts_after_firsthop)*
- cbt->liveness.num_recent_circs);
- }
- cbt->liveness.after_firsthop_idx = 0;
-
- /* Check to see if this has happened before. If so, double the timeout
- * to give people on abysmally bad network connections a shot at access */
- if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) {
- if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) {
- log_warn(LD_CIRC, "Insanely large circuit build timeout value. "
- "(timeout = %fmsec, close = %fmsec)",
- cbt->timeout_ms, cbt->close_ms);
- } else {
- cbt->timeout_ms *= 2;
- cbt->close_ms *= 2;
- }
- } else {
- cbt->close_ms = cbt->timeout_ms
- = circuit_build_times_get_initial_timeout();
- }
-
- control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
-
- log_notice(LD_CIRC,
- "Your network connection speed appears to have changed. Resetting "
- "timeout to %lds after %d timeouts and %d buildtimes.",
- tor_lround(cbt->timeout_ms/1000), timeout_count,
- total_build_times);
-
- return 1;
-}
-
-/**
- * Count the number of timeouts in a set of cbt data.
- */
-double
-circuit_build_times_timeout_rate(const circuit_build_times_t *cbt)
-{
- int i=0,timeouts=0;
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] >= cbt->timeout_ms) {
- timeouts++;
- }
- }
-
- if (!cbt->total_build_times)
- return 0;
-
- return ((double)timeouts)/cbt->total_build_times;
-}
-
-/**
- * Count the number of closed circuits in a set of cbt data.
- */
-double
-circuit_build_times_close_rate(const circuit_build_times_t *cbt)
-{
- int i=0,closed=0;
- for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
- if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) {
- closed++;
- }
- }
-
- if (!cbt->total_build_times)
- return 0;
-
- return ((double)closed)/cbt->total_build_times;
-}
-
-/**
- * Store a timeout as a synthetic value.
- *
- * Returns true if the store was successful and we should possibly
- * update our timeout estimate.
- */
-int
-circuit_build_times_count_close(circuit_build_times_t *cbt,
- int did_onehop,
- time_t start_time)
-{
- if (circuit_build_times_disabled()) {
- cbt->close_ms = cbt->timeout_ms
- = circuit_build_times_get_initial_timeout();
- return 0;
- }
-
- /* Record this force-close to help determine if the network is dead */
- circuit_build_times_network_close(cbt, did_onehop, start_time);
-
- /* Only count timeouts if network is live.. */
- if (!circuit_build_times_network_check_live(cbt)) {
- return 0;
- }
-
- circuit_build_times_add_time(cbt, CBT_BUILD_ABANDONED);
- return 1;
-}
-
-/**
- * Update timeout counts to determine if we need to expire
- * our build time history due to excessive timeouts.
- *
- * We do not record any actual time values at this stage;
- * we are only interested in recording the fact that a timeout
- * happened. We record the time values via
- * circuit_build_times_count_close() and circuit_build_times_add_time().
- */
-void
-circuit_build_times_count_timeout(circuit_build_times_t *cbt,
- int did_onehop)
-{
- if (circuit_build_times_disabled()) {
- cbt->close_ms = cbt->timeout_ms
- = circuit_build_times_get_initial_timeout();
- return;
- }
-
- /* Register the fact that a timeout just occurred. */
- circuit_build_times_network_timeout(cbt, did_onehop);
-
- /* If there are a ton of timeouts, we should reset
- * the circuit build timeout. */
- circuit_build_times_network_check_changed(cbt);
-}
-
-/**
- * Estimate a new timeout based on history and set our timeout
- * variable accordingly.
- */
-static int
-circuit_build_times_set_timeout_worker(circuit_build_times_t *cbt)
-{
- build_time_t max_time;
- if (!circuit_build_times_enough_to_compute(cbt))
- return 0;
-
- if (!circuit_build_times_update_alpha(cbt))
- return 0;
-
- cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt,
- circuit_build_times_quantile_cutoff());
-
- cbt->close_ms = circuit_build_times_calculate_timeout(cbt,
- circuit_build_times_close_quantile());
-
- max_time = circuit_build_times_max(cbt);
-
- /* Sometimes really fast guard nodes give us such a steep curve
- * that this ends up being not that much greater than timeout_ms.
- * Make it be at least 1 min to handle this case. */
- cbt->close_ms = MAX(cbt->close_ms, circuit_build_times_initial_timeout());
-
- if (cbt->timeout_ms > max_time) {
- log_info(LD_CIRC,
- "Circuit build timeout of %dms is beyond the maximum build "
- "time we have ever observed. Capping it to %dms.",
- (int)cbt->timeout_ms, max_time);
- cbt->timeout_ms = max_time;
- }
-
- if (max_time < INT32_MAX/2 && cbt->close_ms > 2*max_time) {
- log_info(LD_CIRC,
- "Circuit build measurement period of %dms is more than twice "
- "the maximum build time we have ever observed. Capping it to "
- "%dms.", (int)cbt->close_ms, 2*max_time);
- cbt->close_ms = 2*max_time;
- }
-
- cbt->have_computed_timeout = 1;
- return 1;
-}
-
-/**
- * Exposed function to compute a new timeout. Dispatches events and
- * also filters out extremely high timeout values.
- */
-void
-circuit_build_times_set_timeout(circuit_build_times_t *cbt)
-{
- long prev_timeout = tor_lround(cbt->timeout_ms/1000);
- double timeout_rate;
-
- /*
- * Just return if we aren't using adaptive timeouts
- */
- if (circuit_build_times_disabled())
- return;
-
- if (!circuit_build_times_set_timeout_worker(cbt))
- return;
-
- if (cbt->timeout_ms < circuit_build_times_min_timeout()) {
- log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms",
- cbt->timeout_ms, circuit_build_times_min_timeout());
- cbt->timeout_ms = circuit_build_times_min_timeout();
- if (cbt->close_ms < cbt->timeout_ms) {
- /* This shouldn't happen because of MAX() in timeout_worker above,
- * but doing it just in case */
- cbt->close_ms = circuit_build_times_initial_timeout();
- }
- }
-
- control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED);
-
- timeout_rate = circuit_build_times_timeout_rate(cbt);
-
- if (prev_timeout > tor_lround(cbt->timeout_ms/1000)) {
- log_info(LD_CIRC,
- "Based on %d circuit times, it looks like we don't need to "
- "wait so long for circuits to finish. We will now assume a "
- "circuit is too slow to use after waiting %ld seconds.",
- cbt->total_build_times,
- tor_lround(cbt->timeout_ms/1000));
- log_info(LD_CIRC,
- "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
- cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
- timeout_rate);
- } else if (prev_timeout < tor_lround(cbt->timeout_ms/1000)) {
- log_info(LD_CIRC,
- "Based on %d circuit times, it looks like we need to wait "
- "longer for circuits to finish. We will now assume a "
- "circuit is too slow to use after waiting %ld seconds.",
- cbt->total_build_times,
- tor_lround(cbt->timeout_ms/1000));
- log_info(LD_CIRC,
- "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
- cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
- timeout_rate);
- } else {
- log_info(LD_CIRC,
- "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f,"
- " r: %f) based on %d circuit times",
- tor_lround(cbt->timeout_ms/1000),
- cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate,
- cbt->total_build_times);
- }
+ return chan;
}
/** Iterate over values of circ_id, starting from conn-\>next_circ_id,
@@ -1680,28 +96,31 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
* Return it, or 0 if can't get a unique circ_id.
*/
static circid_t
-get_unique_circ_id_by_conn(or_connection_t *conn)
+get_unique_circ_id_by_chan(channel_t *chan)
{
circid_t test_circ_id;
circid_t attempts=0;
- circid_t high_bit;
+ circid_t high_bit, max_range;
+
+ tor_assert(chan);
- tor_assert(conn);
- if (conn->circ_id_type == CIRC_ID_TYPE_NEITHER) {
- log_warn(LD_BUG, "Trying to pick a circuit ID for a connection from "
+ if (chan->circ_id_type == CIRC_ID_TYPE_NEITHER) {
+ log_warn(LD_BUG,
+ "Trying to pick a circuit ID for a connection from "
"a client with no identity.");
return 0;
}
- high_bit = (conn->circ_id_type == CIRC_ID_TYPE_HIGHER) ? 1<<15 : 0;
+ max_range = (chan->wide_circ_ids) ? (1u<<31) : (1u<<15);
+ high_bit = (chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ? max_range : 0;
do {
- /* Sequentially iterate over test_circ_id=1...1<<15-1 until we find a
+ /* Sequentially iterate over test_circ_id=1...max_range until we find a
* circID such that (high_bit|test_circ_id) is not already used. */
- test_circ_id = conn->next_circ_id++;
- if (test_circ_id == 0 || test_circ_id >= 1<<15) {
+ test_circ_id = chan->next_circ_id++;
+ if (test_circ_id == 0 || test_circ_id >= max_range) {
test_circ_id = 1;
- conn->next_circ_id = 2;
+ chan->next_circ_id = 2;
}
- if (++attempts > 1<<15) {
+ if (++attempts > max_range) {
/* Make sure we don't loop forever if all circ_id's are used. This
* matters because it's an external DoS opportunity.
*/
@@ -1709,7 +128,7 @@ get_unique_circ_id_by_conn(or_connection_t *conn)
return 0;
}
test_circ_id |= high_bit;
- } while (circuit_id_in_use_on_orconn(test_circ_id, conn));
+ } while (circuit_id_in_use_on_channel(test_circ_id, chan));
return test_circ_id;
}
@@ -1736,8 +155,8 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names)
circ->build_state->is_internal ? "internal" : "exit",
circ->build_state->need_uptime ? " (high-uptime)" : "",
circ->build_state->desired_path_len,
- circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ",
- circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
+ circ->base_.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ",
+ circ->base_.state == CIRCUIT_STATE_OPEN ? "" :
(nickname?nickname:"*unnamed*"));
}
@@ -1888,9 +307,9 @@ onion_populate_cpath(origin_circuit_t *circ)
origin_circuit_t *
origin_circuit_init(uint8_t purpose, int flags)
{
- /* sets circ->p_circ_id and circ->p_conn */
+ /* sets circ->p_circ_id and circ->p_chan */
origin_circuit_t *circ = origin_circuit_new();
- circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OR_WAIT);
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_CHAN_WAIT);
circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
circ->build_state->onehop_tunnel =
((flags & CIRCLAUNCH_ONEHOP_TUNNEL) ? 1 : 0);
@@ -1900,7 +319,7 @@ origin_circuit_init(uint8_t purpose, int flags)
((flags & CIRCLAUNCH_NEED_CAPACITY) ? 1 : 0);
circ->build_state->is_internal =
((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0);
- circ->_base.purpose = purpose;
+ circ->base_.purpose = purpose;
return circ;
}
@@ -1942,7 +361,7 @@ int
circuit_handle_first_hop(origin_circuit_t *circ)
{
crypt_path_t *firsthop;
- or_connection_t *n_conn;
+ channel_t *n_chan;
int err_reason = 0;
const char *msg = NULL;
int should_launch = 0;
@@ -1952,29 +371,30 @@ circuit_handle_first_hop(origin_circuit_t *circ)
tor_assert(firsthop->extend_info);
/* now see if we're already connected to the first OR in 'route' */
- log_debug(LD_CIRC,"Looking for firsthop '%s:%u'",
- fmt_addr(&firsthop->extend_info->addr),
- firsthop->extend_info->port);
+ log_debug(LD_CIRC,"Looking for firsthop '%s'",
+ fmt_addrport(&firsthop->extend_info->addr,
+ firsthop->extend_info->port));
- n_conn = connection_or_get_for_extend(firsthop->extend_info->identity_digest,
- &firsthop->extend_info->addr,
- &msg,
- &should_launch);
+ n_chan = channel_get_for_extend(firsthop->extend_info->identity_digest,
+ &firsthop->extend_info->addr,
+ &msg,
+ &should_launch);
- if (!n_conn) {
+ if (!n_chan) {
/* not currently connected in a useful way. */
log_info(LD_CIRC, "Next router is %s: %s",
safe_str_client(extend_info_describe(firsthop->extend_info)),
msg?msg:"???");
- circ->_base.n_hop = extend_info_dup(firsthop->extend_info);
+ circ->base_.n_hop = extend_info_dup(firsthop->extend_info);
if (should_launch) {
if (circ->build_state->onehop_tunnel)
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
- n_conn = connection_or_connect(&firsthop->extend_info->addr,
- firsthop->extend_info->port,
- firsthop->extend_info->identity_digest);
- if (!n_conn) { /* connect failed, forget the whole thing */
+ n_chan = channel_connect_for_circuit(
+ &firsthop->extend_info->addr,
+ firsthop->extend_info->port,
+ firsthop->extend_info->identity_digest);
+ if (!n_chan) { /* connect failed, forget the whole thing */
log_info(LD_CIRC,"connect to firsthop failed. Closing.");
return -END_CIRC_REASON_CONNECTFAILED;
}
@@ -1982,13 +402,13 @@ circuit_handle_first_hop(origin_circuit_t *circ)
log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
/* return success. The onion/circuit/etc will be taken care of
- * automatically (may already have been) whenever n_conn reaches
+ * automatically (may already have been) whenever n_chan reaches
* OR_CONN_STATE_OPEN.
*/
return 0;
} else { /* it's already open. use it. */
- tor_assert(!circ->_base.n_hop);
- circ->_base.n_conn = n_conn;
+ tor_assert(!circ->base_.n_hop);
+ circ->base_.n_chan = n_chan;
log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
@@ -2004,48 +424,49 @@ circuit_handle_first_hop(origin_circuit_t *circ)
* Status is 1 if connect succeeded, or 0 if connect failed.
*/
void
-circuit_n_conn_done(or_connection_t *or_conn, int status)
+circuit_n_chan_done(channel_t *chan, int status)
{
smartlist_t *pending_circs;
int err_reason = 0;
- log_debug(LD_CIRC,"or_conn to %s/%s, status=%d",
- or_conn->nickname ? or_conn->nickname : "NULL",
- or_conn->_base.address, status);
+ tor_assert(chan);
+
+ log_debug(LD_CIRC,"chan to %s/%s, status=%d",
+ chan->nickname ? chan->nickname : "NULL",
+ channel_get_canonical_remote_descr(chan), status);
pending_circs = smartlist_new();
- circuit_get_all_pending_on_or_conn(pending_circs, or_conn);
+ circuit_get_all_pending_on_channel(pending_circs, chan);
SMARTLIST_FOREACH_BEGIN(pending_circs, circuit_t *, circ)
{
/* These checks are redundant wrt get_all_pending_on_or_conn, but I'm
* leaving them in in case it's possible for the status of a circuit to
* change as we're going down the list. */
- if (circ->marked_for_close || circ->n_conn || !circ->n_hop ||
- circ->state != CIRCUIT_STATE_OR_WAIT)
+ if (circ->marked_for_close || circ->n_chan || !circ->n_hop ||
+ circ->state != CIRCUIT_STATE_CHAN_WAIT)
continue;
if (tor_digest_is_zero(circ->n_hop->identity_digest)) {
/* Look at addr/port. This is an unkeyed connection. */
- if (!tor_addr_eq(&circ->n_hop->addr, &or_conn->_base.addr) ||
- circ->n_hop->port != or_conn->_base.port)
+ if (!channel_matches_extend_info(chan, circ->n_hop))
continue;
} else {
/* We expected a key. See if it's the right one. */
- if (tor_memneq(or_conn->identity_digest,
+ if (tor_memneq(chan->identity_digest,
circ->n_hop->identity_digest, DIGEST_LEN))
continue;
}
- if (!status) { /* or_conn failed; close circ */
- log_info(LD_CIRC,"or_conn failed. Closing circ.");
- circuit_mark_for_close(circ, END_CIRC_REASON_OR_CONN_CLOSED);
+ if (!status) { /* chan failed; close circ */
+ log_info(LD_CIRC,"Channel failed; closing circ.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED);
continue;
}
log_debug(LD_CIRC, "Found circ, sending create cell.");
/* circuit_deliver_create_cell will set n_circ_id and add us to
- * orconn_circuid_circuit_map, so we don't need to call
- * set_circid_orconn here. */
- circ->n_conn = or_conn;
+ * chan_circuid_circuit_map, so we don't need to call
+ * set_circid_chan here. */
+ circ->n_chan = chan;
extend_info_free(circ->n_hop);
circ->n_hop = NULL;
@@ -2060,14 +481,13 @@ circuit_n_conn_done(or_connection_t *or_conn, int status)
* died? */
}
} else {
- /* pull the create cell out of circ->onionskin, and send it */
- tor_assert(circ->n_conn_onionskin);
- if (circuit_deliver_create_cell(circ,CELL_CREATE,
- circ->n_conn_onionskin)<0) {
+ /* pull the create cell out of circ->n_chan_create_cell, and send it */
+ tor_assert(circ->n_chan_create_cell);
+ if (circuit_deliver_create_cell(circ, circ->n_chan_create_cell, 1)<0) {
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
continue;
}
- tor_free(circ->n_conn_onionskin);
+ tor_free(circ->n_chan_create_cell);
circuit_set_state(circ, CIRCUIT_STATE_OPEN);
}
}
@@ -2076,44 +496,63 @@ circuit_n_conn_done(or_connection_t *or_conn, int status)
smartlist_free(pending_circs);
}
-/** Find a new circid that isn't currently in use on the circ->n_conn
+/** Find a new circid that isn't currently in use on the circ->n_chan
* for the outgoing
- * circuit <b>circ</b>, and deliver a cell of type <b>cell_type</b>
- * (either CELL_CREATE or CELL_CREATE_FAST) with payload <b>payload</b>
- * to this circuit.
- * Return -1 if we failed to find a suitable circid, else return 0.
+ * circuit <b>circ</b>, and deliver the cell <b>create_cell</b> to this
+ * circuit. If <b>relayed</b> is true, this is a create cell somebody
+ * gave us via an EXTEND cell, so we shouldn't worry if we don't understand
+ * it. Return -1 if we failed to find a suitable circid, else return 0.
*/
static int
-circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
- const char *payload)
+circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell,
+ int relayed)
{
cell_t cell;
circid_t id;
+ int r;
tor_assert(circ);
- tor_assert(circ->n_conn);
- tor_assert(payload);
- tor_assert(cell_type == CELL_CREATE || cell_type == CELL_CREATE_FAST);
+ tor_assert(circ->n_chan);
+ tor_assert(create_cell);
+ tor_assert(create_cell->cell_type == CELL_CREATE ||
+ create_cell->cell_type == CELL_CREATE_FAST ||
+ create_cell->cell_type == CELL_CREATE2);
- id = get_unique_circ_id_by_conn(circ->n_conn);
+ id = get_unique_circ_id_by_chan(circ->n_chan);
if (!id) {
log_warn(LD_CIRC,"failed to get unique circID.");
return -1;
}
- log_debug(LD_CIRC,"Chosen circID %u.", id);
- circuit_set_n_circid_orconn(circ, id, circ->n_conn);
+ log_debug(LD_CIRC,"Chosen circID %u.", (unsigned)id);
+ circuit_set_n_circid_chan(circ, id, circ->n_chan);
memset(&cell, 0, sizeof(cell_t));
- cell.command = cell_type;
+ r = relayed ? create_cell_format_relayed(&cell, create_cell)
+ : create_cell_format(&cell, create_cell);
+ if (r < 0) {
+ log_warn(LD_CIRC,"Couldn't format create cell");
+ return -1;
+ }
cell.circ_id = circ->n_circ_id;
- memcpy(cell.payload, payload, ONIONSKIN_CHALLENGE_LEN);
- append_cell_to_circuit_queue(circ, circ->n_conn, &cell,
+ append_cell_to_circuit_queue(circ, circ->n_chan, &cell,
CELL_DIRECTION_OUT, 0);
if (CIRCUIT_IS_ORIGIN(circ)) {
+ /* Update began timestamp for circuits starting their first hop */
+ if (TO_ORIGIN_CIRCUIT(circ)->cpath->state == CPATH_STATE_CLOSED) {
+ if (circ->n_chan->state != CHANNEL_STATE_OPEN) {
+ log_warn(LD_CIRC,
+ "Got first hop for a circuit without an opened channel. "
+ "State: %s.", channel_state_to_string(circ->n_chan->state));
+ tor_fragile_assert();
+ }
+
+ tor_gettimeofday(&circ->timestamp_began);
+ }
+
/* mark it so it gets better rate limiting treatment. */
- circ->n_conn->client_used = time(NULL);
+ channel_timestamp_client(circ->n_chan);
}
return 0;
@@ -2185,6 +624,73 @@ circuit_timeout_want_to_count_circ(origin_circuit_t *circ)
&& circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN;
}
+#ifdef CURVE25519_ENABLED
+/** Return true if the ntor handshake is enabled in the configuration, or if
+ * it's been set to "auto" in the configuration and it's enabled in the
+ * consensus. */
+static int
+circuits_can_use_ntor(void)
+{
+ const or_options_t *options = get_options();
+ if (options->UseNTorHandshake != -1)
+ return options->UseNTorHandshake;
+ return networkstatus_get_param(NULL, "UseNTorHandshake", 0, 0, 1);
+}
+#endif
+
+/** Decide whether to use a TAP or ntor handshake for connecting to <b>ei</b>
+ * directly, and set *<b>cell_type_out</b> and *<b>handshake_type_out</b>
+ * accordingly. */
+static void
+circuit_pick_create_handshake(uint8_t *cell_type_out,
+ uint16_t *handshake_type_out,
+ const extend_info_t *ei)
+{
+#ifdef CURVE25519_ENABLED
+ if (!tor_mem_is_zero((const char*)ei->curve25519_onion_key.public_key,
+ CURVE25519_PUBKEY_LEN) &&
+ circuits_can_use_ntor()) {
+ *cell_type_out = CELL_CREATE2;
+ *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
+ return;
+ }
+#else
+ (void) ei;
+#endif
+
+ *cell_type_out = CELL_CREATE;
+ *handshake_type_out = ONION_HANDSHAKE_TYPE_TAP;
+}
+
+/** Decide whether to use a TAP or ntor handshake for connecting to <b>ei</b>
+ * directly, and set *<b>handshake_type_out</b> accordingly. Decide whether,
+ * in extending through <b>node</b> to do so, we should use an EXTEND2 or an
+ * EXTEND cell to do so, and set *<b>cell_type_out</b> and
+ * *<b>create_cell_type_out</b> accordingly. */
+static void
+circuit_pick_extend_handshake(uint8_t *cell_type_out,
+ uint8_t *create_cell_type_out,
+ uint16_t *handshake_type_out,
+ const node_t *node_prev,
+ const extend_info_t *ei)
+{
+ uint8_t t;
+ circuit_pick_create_handshake(&t, handshake_type_out, ei);
+ /* XXXX024 The check for whether the node has a curve25519 key is a bad
+ * proxy for whether it can do extend2 cells; once a version that
+ * handles extend2 cells is out, remove it. */
+ if (node_prev &&
+ *handshake_type_out != ONION_HANDSHAKE_TYPE_TAP &&
+ (node_has_curve25519_onion_key(node_prev) ||
+ (node_prev->rs && node_prev->rs->version_supports_extend2_cells))) {
+ *cell_type_out = RELAY_COMMAND_EXTEND2;
+ *create_cell_type_out = CELL_CREATE2;
+ } else {
+ *cell_type_out = RELAY_COMMAND_EXTEND;
+ *create_cell_type_out = CELL_CREATE;
+ }
+}
+
/** This is the backbone function for building circuits.
*
* If circ's first hop is closed, then we need to build a create
@@ -2200,49 +706,50 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
{
crypt_path_t *hop;
const node_t *node;
- char payload[2+4+DIGEST_LEN+ONIONSKIN_CHALLENGE_LEN];
- char *onionskin;
- size_t payload_len;
tor_assert(circ);
if (circ->cpath->state == CPATH_STATE_CLOSED) {
+ /* This is the first hop. */
+ create_cell_t cc;
int fast;
- uint8_t cell_type;
+ int len;
log_debug(LD_CIRC,"First skin; sending create cell.");
+ memset(&cc, 0, sizeof(cc));
if (circ->build_state->onehop_tunnel)
control_event_bootstrap(BOOTSTRAP_STATUS_ONEHOP_CREATE, 0);
else
control_event_bootstrap(BOOTSTRAP_STATUS_CIRCUIT_CREATE, 0);
- node = node_get_by_id(circ->_base.n_conn->identity_digest);
+ node = node_get_by_id(circ->base_.n_chan->identity_digest);
fast = should_use_create_fast_for_circuit(circ);
if (!fast) {
/* We are an OR and we know the right onion key: we should
- * send an old slow create cell.
+ * send a create cell.
*/
- cell_type = CELL_CREATE;
- if (onion_skin_create(circ->cpath->extend_info->onion_key,
- &(circ->cpath->dh_handshake_state),
- payload) < 0) {
- log_warn(LD_CIRC,"onion_skin_create (first hop) failed.");
- return - END_CIRC_REASON_INTERNAL;
- }
+ circuit_pick_create_handshake(&cc.cell_type, &cc.handshake_type,
+ circ->cpath->extend_info);
note_request("cell: create", 1);
} else {
/* We are not an OR, and we're building the first hop of a circuit to a
* new OR: we can be speedy and use CREATE_FAST to save an RSA operation
* and a DH operation. */
- cell_type = CELL_CREATE_FAST;
- memset(payload, 0, sizeof(payload));
- crypto_rand((char*) circ->cpath->fast_handshake_state,
- sizeof(circ->cpath->fast_handshake_state));
- memcpy(payload, circ->cpath->fast_handshake_state,
- sizeof(circ->cpath->fast_handshake_state));
+ cc.cell_type = CELL_CREATE_FAST;
+ cc.handshake_type = ONION_HANDSHAKE_TYPE_FAST;
note_request("cell: create fast", 1);
}
- if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload) < 0)
+ len = onion_skin_create(cc.handshake_type,
+ circ->cpath->extend_info,
+ &circ->cpath->handshake_state,
+ cc.onionskin);
+ if (len < 0) {
+ log_warn(LD_CIRC,"onion_skin_create (first hop) failed.");
+ return - END_CIRC_REASON_INTERNAL;
+ }
+ cc.handshake_len = len;
+
+ if (circuit_deliver_create_cell(TO_CIRCUIT(circ), &cc, 0) < 0)
return - END_CIRC_REASON_RESOURCELIMIT;
circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
@@ -2251,10 +758,13 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
fast ? "CREATE_FAST" : "CREATE",
node ? node_describe(node) : "<unnamed>");
} else {
+ extend_cell_t ec;
+ int len;
tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
- tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING);
+ tor_assert(circ->base_.state == CIRCUIT_STATE_BUILDING);
log_debug(LD_CIRC,"starting to send subsequent skin.");
hop = onion_next_hop_in_cpath(circ->cpath);
+ memset(&ec, 0, sizeof(ec));
if (!hop) {
/* done building the circuit. whew. */
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
@@ -2262,7 +772,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
struct timeval end;
long timediff;
tor_gettimeofday(&end);
- timediff = tv_mdiff(&circ->_base.timestamp_created, &end);
+ timediff = tv_mdiff(&circ->base_.timestamp_began, &end);
/*
* If the circuit build time is much greater than we would have cut
@@ -2272,8 +782,8 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
if (timediff < 0 || timediff > 2*circ_times.close_ms+1000) {
log_notice(LD_CIRC, "Strange value for circuit build time: %ldmsec. "
"Assuming clock jump. Purpose %d (%s)", timediff,
- circ->_base.purpose,
- circuit_purpose_to_string(circ->_base.purpose));
+ circ->base_.purpose,
+ circuit_purpose_to_string(circ->base_.purpose));
} else if (!circuit_build_times_disabled()) {
/* Only count circuit times if the network is live */
if (circuit_build_times_network_check_live(&circ_times)) {
@@ -2281,7 +791,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
circuit_build_times_set_timeout(&circ_times);
}
- if (circ->_base.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
circuit_build_times_network_circ_success(&circ_times);
}
}
@@ -2293,6 +803,10 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_STATUS, 0);
}
+ pathbias_count_build_success(circ);
+ circuit_rep_hist_note_result(circ);
+ circuit_has_opened(circ); /* do other actions as necessary */
+
if (!can_complete_circuit && !circ->build_state->onehop_tunnel) {
const or_options_t *options = get_options();
can_complete_circuit=1;
@@ -2309,13 +823,10 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
}
}
- pathbias_count_success(circ);
- circuit_rep_hist_note_result(circ);
- circuit_has_opened(circ); /* do other actions as necessary */
-
/* We're done with measurement circuits here. Just close them */
- if (circ->_base.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
+ if (circ->base_.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
+ }
return 0;
}
@@ -2324,29 +835,50 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
return - END_CIRC_REASON_INTERNAL;
}
- set_uint32(payload, tor_addr_to_ipv4n(&hop->extend_info->addr));
- set_uint16(payload+4, htons(hop->extend_info->port));
-
- onionskin = payload+2+4;
- memcpy(payload+2+4+ONIONSKIN_CHALLENGE_LEN,
- hop->extend_info->identity_digest, DIGEST_LEN);
- payload_len = 2+4+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN;
-
- if (onion_skin_create(hop->extend_info->onion_key,
- &(hop->dh_handshake_state), onionskin) < 0) {
+ {
+ const node_t *prev_node;
+ prev_node = node_get_by_id(hop->prev->extend_info->identity_digest);
+ circuit_pick_extend_handshake(&ec.cell_type,
+ &ec.create_cell.cell_type,
+ &ec.create_cell.handshake_type,
+ prev_node,
+ hop->extend_info);
+ }
+
+ tor_addr_copy(&ec.orport_ipv4.addr, &hop->extend_info->addr);
+ ec.orport_ipv4.port = hop->extend_info->port;
+ tor_addr_make_unspec(&ec.orport_ipv6.addr);
+ memcpy(ec.node_id, hop->extend_info->identity_digest, DIGEST_LEN);
+
+ len = onion_skin_create(ec.create_cell.handshake_type,
+ hop->extend_info,
+ &hop->handshake_state,
+ ec.create_cell.onionskin);
+ if (len < 0) {
log_warn(LD_CIRC,"onion_skin_create failed.");
return - END_CIRC_REASON_INTERNAL;
}
+ ec.create_cell.handshake_len = len;
log_info(LD_CIRC,"Sending extend relay cell.");
note_request("cell: extend", 1);
- /* send it to hop->prev, because it will transfer
- * it to a create cell and then send to hop */
- if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
- RELAY_COMMAND_EXTEND,
- payload, payload_len, hop->prev) < 0)
- return 0; /* circuit is closed */
+ {
+ uint8_t command = 0;
+ uint16_t payload_len=0;
+ uint8_t payload[RELAY_PAYLOAD_SIZE];
+ if (extend_cell_format(&command, &payload_len, payload, &ec)<0) {
+ log_warn(LD_CIRC,"Couldn't format extend cell");
+ return -END_CIRC_REASON_INTERNAL;
+ }
+ /* send it to hop->prev, because it will transfer
+ * it to a create cell and then send to hop */
+ if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
+ command,
+ (char*)payload, payload_len,
+ hop->prev) < 0)
+ return 0; /* circuit is closed */
+ }
hop->state = CPATH_STATE_AWAITING_KEYS;
}
return 0;
@@ -2369,7 +901,7 @@ circuit_note_clock_jumped(int seconds_elapsed)
control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s",
"CLOCK_JUMPED");
circuit_mark_all_unused_circs();
- circuit_expire_all_dirty_circs();
+ circuit_mark_all_dirty_circs_as_unusable();
}
/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion
@@ -2383,19 +915,15 @@ circuit_note_clock_jumped(int seconds_elapsed)
int
circuit_extend(cell_t *cell, circuit_t *circ)
{
- or_connection_t *n_conn;
+ channel_t *n_chan;
relay_header_t rh;
- char *onionskin;
- char *id_digest=NULL;
- uint32_t n_addr32;
- uint16_t n_port;
- tor_addr_t n_addr;
+ extend_cell_t ec;
const char *msg = NULL;
int should_launch = 0;
- if (circ->n_conn) {
+ if (circ->n_chan) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "n_conn already set. Bug/attack. Closing.");
+ "n_chan already set. Bug/attack. Closing.");
return -1;
}
if (circ->n_hop) {
@@ -2412,27 +940,21 @@ circuit_extend(cell_t *cell, circuit_t *circ)
relay_header_unpack(&rh, cell->payload);
- if (rh.length < 4+2+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN) {
+ if (extend_cell_parse(&ec, rh.command,
+ cell->payload+RELAY_HEADER_SIZE,
+ rh.length) < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Wrong length %d on extend cell. Closing circuit.",
- rh.length);
+ "Can't parse extend cell. Closing circuit.");
return -1;
}
- n_addr32 = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
- n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4));
- onionskin = (char*) cell->payload+RELAY_HEADER_SIZE+4+2;
- id_digest = (char*) cell->payload+RELAY_HEADER_SIZE+4+2+
- ONIONSKIN_CHALLENGE_LEN;
- tor_addr_from_ipv4h(&n_addr, n_addr32);
-
- if (!n_port || !n_addr32) {
+ if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend to zero destination port or addr.");
return -1;
}
- if (tor_addr_is_internal(&n_addr, 0) &&
+ if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) &&
!get_options()->ExtendAllowPrivateAddresses) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend to a private address");
@@ -2445,7 +967,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
* fingerprints -- a) because it opens the user up to a mitm attack,
* and b) because it lets an attacker force the relay to hold open a
* new TLS connection for each extend request. */
- if (tor_digest_is_zero(id_digest)) {
+ if (tor_digest_is_zero((const char*)ec.node_id)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend without specifying an id_digest.");
return -1;
@@ -2454,55 +976,64 @@ circuit_extend(cell_t *cell, circuit_t *circ)
/* Next, check if we're being asked to connect to the hop that the
* extend cell came from. There isn't any reason for that, and it can
* assist circular-path attacks. */
- if (tor_memeq(id_digest, TO_OR_CIRCUIT(circ)->p_conn->identity_digest,
- DIGEST_LEN)) {
+ if (tor_memeq(ec.node_id,
+ TO_OR_CIRCUIT(circ)->p_chan->identity_digest,
+ DIGEST_LEN)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Client asked me to extend back to the previous hop.");
return -1;
}
- n_conn = connection_or_get_for_extend(id_digest,
- &n_addr,
- &msg,
- &should_launch);
+ n_chan = channel_get_for_extend((const char*)ec.node_id,
+ &ec.orport_ipv4.addr,
+ &msg,
+ &should_launch);
- if (!n_conn) {
- log_debug(LD_CIRC|LD_OR,"Next router (%s:%d): %s",
- fmt_addr(&n_addr), (int)n_port, msg?msg:"????");
+ if (!n_chan) {
+ log_debug(LD_CIRC|LD_OR,"Next router (%s): %s",
+ fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port),
+ msg?msg:"????");
- circ->n_hop = extend_info_alloc(NULL /*nickname*/,
- id_digest,
- NULL /*onion_key*/,
- &n_addr, n_port);
+ circ->n_hop = extend_info_new(NULL /*nickname*/,
+ (const char*)ec.node_id,
+ NULL /*onion_key*/,
+ NULL /*curve25519_key*/,
+ &ec.orport_ipv4.addr,
+ ec.orport_ipv4.port);
- circ->n_conn_onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
- memcpy(circ->n_conn_onionskin, onionskin, ONIONSKIN_CHALLENGE_LEN);
- circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT);
+ circ->n_chan_create_cell = tor_memdup(&ec.create_cell,
+ sizeof(ec.create_cell));
+
+ circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
if (should_launch) {
/* we should try to open a connection */
- n_conn = connection_or_connect(&n_addr, n_port, id_digest);
- if (!n_conn) {
- log_info(LD_CIRC,"Launching n_conn failed. Closing circuit.");
+ n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr,
+ ec.orport_ipv4.port,
+ (const char*)ec.node_id);
+ if (!n_chan) {
+ log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
return 0;
}
log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
}
/* return success. The onion/circuit/etc will be taken care of
- * automatically (may already have been) whenever n_conn reaches
+ * automatically (may already have been) whenever n_chan reaches
* OR_CONN_STATE_OPEN.
*/
return 0;
}
tor_assert(!circ->n_hop); /* Connection is already established. */
- circ->n_conn = n_conn;
- log_debug(LD_CIRC,"n_conn is %s:%u",
- n_conn->_base.address,n_conn->_base.port);
+ circ->n_chan = n_chan;
+ log_debug(LD_CIRC,
+ "n_chan is %s",
+ channel_get_canonical_remote_descr(n_chan));
- if (circuit_deliver_create_cell(circ, CELL_CREATE, onionskin) < 0)
+ if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0)
return -1;
+
return 0;
}
@@ -2556,12 +1087,12 @@ circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data,
return 0;
}
-/** The minimum number of first hop completions before we start
+/** The minimum number of circuit attempts before we start
* thinking about warning about path bias and dropping guards */
static int
pathbias_get_min_circs(const or_options_t *options)
{
-#define DFLT_PATH_BIAS_MIN_CIRC 20
+#define DFLT_PATH_BIAS_MIN_CIRC 150
if (options->PathBiasCircThreshold >= 5)
return options->PathBiasCircThreshold;
else
@@ -2570,10 +1101,11 @@ pathbias_get_min_circs(const or_options_t *options)
5, INT32_MAX);
}
+/** The circuit success rate below which we issue a notice */
static double
pathbias_get_notice_rate(const or_options_t *options)
{
-#define DFLT_PATH_BIAS_NOTICE_PCT 40
+#define DFLT_PATH_BIAS_NOTICE_PCT 70
if (options->PathBiasNoticeRate >= 0.0)
return options->PathBiasNoticeRate;
else
@@ -2581,23 +1113,62 @@ pathbias_get_notice_rate(const or_options_t *options)
DFLT_PATH_BIAS_NOTICE_PCT, 0, 100)/100.0;
}
+/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */
+/** The circuit success rate below which we issue a warn */
static double
-pathbias_get_disable_rate(const or_options_t *options)
+pathbias_get_warn_rate(const or_options_t *options)
{
-// XXX: This needs tuning based on use + experimentation before we set it
-#define DFLT_PATH_BIAS_DISABLE_PCT 0
- if (options->PathBiasDisableRate >= 0.0)
- return options->PathBiasDisableRate;
+#define DFLT_PATH_BIAS_WARN_PCT 50
+ if (options->PathBiasWarnRate >= 0.0)
+ return options->PathBiasWarnRate;
else
- return networkstatus_get_param(NULL, "pb_disablepct",
- DFLT_PATH_BIAS_DISABLE_PCT, 0, 100)/100.0;
+ return networkstatus_get_param(NULL, "pb_warnpct",
+ DFLT_PATH_BIAS_WARN_PCT, 0, 100)/100.0;
}
+/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */
+/**
+ * The extreme rate is the rate at which we would drop the guard,
+ * if pb_dropguard is also set. Otherwise we just warn.
+ */
+double
+pathbias_get_extreme_rate(const or_options_t *options)
+{
+#define DFLT_PATH_BIAS_EXTREME_PCT 30
+ if (options->PathBiasExtremeRate >= 0.0)
+ return options->PathBiasExtremeRate;
+ else
+ return networkstatus_get_param(NULL, "pb_extremepct",
+ DFLT_PATH_BIAS_EXTREME_PCT, 0, 100)/100.0;
+}
+
+/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */
+/**
+ * If 1, we actually disable use of guards that fall below
+ * the extreme_pct.
+ */
+int
+pathbias_get_dropguards(const or_options_t *options)
+{
+#define DFLT_PATH_BIAS_DROP_GUARDS 0
+ if (options->PathBiasDropGuards >= 0)
+ return options->PathBiasDropGuards;
+ else
+ return networkstatus_get_param(NULL, "pb_dropguards",
+ DFLT_PATH_BIAS_DROP_GUARDS, 0, 1);
+}
+
+/**
+ * This is the number of circuits at which we scale our
+ * counts by mult_factor/scale_factor. Note, this count is
+ * not exact, as we only perform the scaling in the event
+ * of no integer truncation.
+ */
static int
pathbias_get_scale_threshold(const or_options_t *options)
{
-#define DFLT_PATH_BIAS_SCALE_THRESHOLD 200
- if (options->PathBiasScaleThreshold >= 2)
+#define DFLT_PATH_BIAS_SCALE_THRESHOLD 300
+ if (options->PathBiasScaleThreshold >= 10)
return options->PathBiasScaleThreshold;
else
return networkstatus_get_param(NULL, "pb_scalecircs",
@@ -2605,141 +1176,330 @@ pathbias_get_scale_threshold(const or_options_t *options)
INT32_MAX);
}
+/**
+ * Compute the path bias scaling ratio from the consensus
+ * parameters pb_multfactor/pb_scalefactor.
+ *
+ * Returns a value in (0, 1.0] which we multiply our pathbias
+ * counts with to scale them down.
+ */
+static double
+pathbias_get_scale_ratio(const or_options_t *options)
+{
+ /*
+ * The scale factor is the denominator for our scaling
+ * of circuit counts for our path bias window.
+ *
+ * Note that our use of doubles for the path bias state
+ * file means that powers of 2 work best here.
+ */
+ int denominator = networkstatus_get_param(NULL, "pb_scalefactor",
+ 2, 2, INT32_MAX);
+ (void) options;
+ /**
+ * The mult factor is the numerator for our scaling
+ * of circuit counts for our path bias window. It
+ * allows us to scale by fractions.
+ */
+ return networkstatus_get_param(NULL, "pb_multfactor",
+ 1, 1, denominator)/((double)denominator);
+}
+
+/** The minimum number of circuit usage attempts before we start
+ * thinking about warning about path use bias and dropping guards */
static int
-pathbias_get_scale_factor(const or_options_t *options)
+pathbias_get_min_use(const or_options_t *options)
+{
+#define DFLT_PATH_BIAS_MIN_USE 20
+ if (options->PathBiasUseThreshold >= 3)
+ return options->PathBiasUseThreshold;
+ else
+ return networkstatus_get_param(NULL, "pb_minuse",
+ DFLT_PATH_BIAS_MIN_USE,
+ 3, INT32_MAX);
+}
+
+/** The circuit use success rate below which we issue a notice */
+static double
+pathbias_get_notice_use_rate(const or_options_t *options)
{
-#define DFLT_PATH_BIAS_SCALE_FACTOR 4
- if (options->PathBiasScaleFactor >= 1)
- return options->PathBiasScaleFactor;
+#define DFLT_PATH_BIAS_NOTICE_USE_PCT 80
+ if (options->PathBiasNoticeUseRate >= 0.0)
+ return options->PathBiasNoticeUseRate;
else
- return networkstatus_get_param(NULL, "pb_scalefactor",
- DFLT_PATH_BIAS_SCALE_THRESHOLD, 1, INT32_MAX);
+ return networkstatus_get_param(NULL, "pb_noticeusepct",
+ DFLT_PATH_BIAS_NOTICE_USE_PCT,
+ 0, 100)/100.0;
}
-static const char *
+/**
+ * The extreme use rate is the rate at which we would drop the guard,
+ * if pb_dropguard is also set. Otherwise we just warn.
+ */
+double
+pathbias_get_extreme_use_rate(const or_options_t *options)
+{
+#define DFLT_PATH_BIAS_EXTREME_USE_PCT 60
+ if (options->PathBiasExtremeUseRate >= 0.0)
+ return options->PathBiasExtremeUseRate;
+ else
+ return networkstatus_get_param(NULL, "pb_extremeusepct",
+ DFLT_PATH_BIAS_EXTREME_USE_PCT,
+ 0, 100)/100.0;
+}
+
+/**
+ * This is the number of circuits at which we scale our
+ * use counts by mult_factor/scale_factor. Note, this count is
+ * not exact, as we only perform the scaling in the event
+ * of no integer truncation.
+ */
+static int
+pathbias_get_scale_use_threshold(const or_options_t *options)
+{
+#define DFLT_PATH_BIAS_SCALE_USE_THRESHOLD 100
+ if (options->PathBiasScaleUseThreshold >= 10)
+ return options->PathBiasScaleUseThreshold;
+ else
+ return networkstatus_get_param(NULL, "pb_scaleuse",
+ DFLT_PATH_BIAS_SCALE_USE_THRESHOLD,
+ 10, INT32_MAX);
+}
+
+/**
+ * Convert a Guard's path state to string.
+ */
+const char *
pathbias_state_to_string(path_state_t state)
{
switch (state) {
case PATH_STATE_NEW_CIRC:
return "new";
- case PATH_STATE_DID_FIRST_HOP:
- return "first hop";
- case PATH_STATE_SUCCEEDED:
- return "succeeded";
+ case PATH_STATE_BUILD_ATTEMPTED:
+ return "build attempted";
+ case PATH_STATE_BUILD_SUCCEEDED:
+ return "build succeeded";
+ case PATH_STATE_USE_ATTEMPTED:
+ return "use attempted";
+ case PATH_STATE_USE_SUCCEEDED:
+ return "use succeeded";
+ case PATH_STATE_USE_FAILED:
+ return "use failed";
+ case PATH_STATE_ALREADY_COUNTED:
+ return "already counted";
}
return "unknown";
}
/**
- * Check our circuit state to see if this is a successful first hop.
- * If so, record it in the current guard's path bias first_hop count.
+ * This function decides if a circuit has progressed far enough to count
+ * as a circuit "attempt". As long as end-to-end tagging is possible,
+ * we assume the adversary will use it over hop-to-hop failure. Therefore,
+ * we only need to account bias for the last hop. This should make us
+ * much more resilient to ambient circuit failure, and also make that
+ * failure easier to measure (we only need to measure Exit failure rates).
+ */
+static int
+pathbias_is_new_circ_attempt(origin_circuit_t *circ)
+{
+#define N2N_TAGGING_IS_POSSIBLE
+#ifdef N2N_TAGGING_IS_POSSIBLE
+ /* cpath is a circular list. We want circs with more than one hop,
+ * and the second hop must be waiting for keys still (it's just
+ * about to get them). */
+ return circ->cpath &&
+ circ->cpath->next != circ->cpath &&
+ circ->cpath->next->state == CPATH_STATE_AWAITING_KEYS;
+#else
+ /* If tagging attacks are no longer possible, we probably want to
+ * count bias from the first hop. However, one could argue that
+ * timing-based tagging is still more useful than per-hop failure.
+ * In which case, we'd never want to use this.
+ */
+ return circ->cpath &&
+ circ->cpath->state == CPATH_STATE_AWAITING_KEYS;
+#endif
+}
+
+/**
+ * Decide if the path bias code should count a circuit.
*
- * Also check for several potential error cases for bug #6475.
+ * @returns 1 if we should count it, 0 otherwise.
*/
static int
-pathbias_count_first_hop(origin_circuit_t *circ)
+pathbias_should_count(origin_circuit_t *circ)
{
-#define FIRST_HOP_NOTICE_INTERVAL (600)
- static ratelim_t first_hop_notice_limit =
- RATELIM_INIT(FIRST_HOP_NOTICE_INTERVAL);
+#define PATHBIAS_COUNT_INTERVAL (600)
+ static ratelim_t count_limit =
+ RATELIM_INIT(PATHBIAS_COUNT_INTERVAL);
char *rate_msg = NULL;
+ /* We can't do path bias accounting without entry guards.
+ * Testing and controller circuits also have no guards.
+ *
+ * We also don't count server-side rends, because their
+ * endpoint could be chosen maliciously.
+ * Similarly, we can't count client-side intro attempts,
+ * because clients can be manipulated into connecting to
+ * malicious intro points. */
+ if (get_options()->UseEntryGuards == 0 ||
+ circ->base_.purpose == CIRCUIT_PURPOSE_TESTING ||
+ circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER ||
+ circ->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND ||
+ circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED ||
+ (circ->base_.purpose >= CIRCUIT_PURPOSE_C_INTRODUCING &&
+ circ->base_.purpose <= CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)) {
+
+ /* Check to see if the shouldcount result has changed due to a
+ * unexpected purpose change that would affect our results.
+ *
+ * The reason we check the path state too here is because for the
+ * cannibalized versions of these purposes, we count them as successful
+ * before their purpose change.
+ */
+ if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_COUNTED
+ && circ->path_state != PATH_STATE_ALREADY_COUNTED) {
+ log_info(LD_BUG,
+ "Circuit %d is now being ignored despite being counted "
+ "in the past. Purpose is %s, path state is %s",
+ circ->global_identifier,
+ circuit_purpose_to_string(circ->base_.purpose),
+ pathbias_state_to_string(circ->path_state));
+ }
+ circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_IGNORED;
+ return 0;
+ }
+
/* Completely ignore one hop circuits */
if (circ->build_state->onehop_tunnel ||
circ->build_state->desired_path_len == 1) {
/* Check for inconsistency */
if (circ->build_state->desired_path_len != 1 ||
!circ->build_state->onehop_tunnel) {
- if ((rate_msg = rate_limit_log(&first_hop_notice_limit,
- approx_time()))) {
+ if ((rate_msg = rate_limit_log(&count_limit, approx_time()))) {
log_info(LD_BUG,
"One-hop circuit has length %d. Path state is %s. "
"Circuit is a %s currently %s.%s",
circ->build_state->desired_path_len,
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
tor_fragile_assert();
}
+
+ /* Check to see if the shouldcount result has changed due to a
+ * unexpected change that would affect our results */
+ if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_COUNTED) {
+ log_info(LD_BUG,
+ "One-hop circuit %d is now being ignored despite being counted "
+ "in the past. Purpose is %s, path state is %s",
+ circ->global_identifier,
+ circuit_purpose_to_string(circ->base_.purpose),
+ pathbias_state_to_string(circ->path_state));
+ }
+ circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_IGNORED;
return 0;
}
- if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) {
+ /* Check to see if the shouldcount result has changed due to a
+ * unexpected purpose change that would affect our results */
+ if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_IGNORED) {
+ log_info(LD_BUG,
+ "Circuit %d is now being counted despite being ignored "
+ "in the past. Purpose is %s, path state is %s",
+ circ->global_identifier,
+ circuit_purpose_to_string(circ->base_.purpose),
+ pathbias_state_to_string(circ->path_state));
+ }
+ circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_COUNTED;
+
+ return 1;
+}
+
+/**
+ * Check our circuit state to see if this is a successful circuit attempt.
+ * If so, record it in the current guard's path bias circ_attempt count.
+ *
+ * Also check for several potential error cases for bug #6475.
+ */
+static int
+pathbias_count_build_attempt(origin_circuit_t *circ)
+{
+#define CIRC_ATTEMPT_NOTICE_INTERVAL (600)
+ static ratelim_t circ_attempt_notice_limit =
+ RATELIM_INIT(CIRC_ATTEMPT_NOTICE_INTERVAL);
+ char *rate_msg = NULL;
+
+ if (!pathbias_should_count(circ)) {
+ return 0;
+ }
+
+ if (pathbias_is_new_circ_attempt(circ)) {
/* Help track down the real cause of bug #6475: */
- if (circ->has_opened && circ->path_state != PATH_STATE_DID_FIRST_HOP) {
- if ((rate_msg = rate_limit_log(&first_hop_notice_limit,
+ if (circ->has_opened && circ->path_state != PATH_STATE_BUILD_ATTEMPTED) {
+ if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit,
approx_time()))) {
log_info(LD_BUG,
"Opened circuit is in strange path state %s. "
"Circuit is a %s currently %s.%s",
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
}
- /* Don't count cannibalized circs for path bias */
+ /* Don't re-count cannibalized circs.. */
if (!circ->has_opened) {
- entry_guard_t *guard;
+ entry_guard_t *guard = NULL;
+
+ if (circ->cpath && circ->cpath->extend_info) {
+ guard = entry_guard_get_by_id_digest(
+ circ->cpath->extend_info->identity_digest);
+ } else if (circ->base_.n_chan) {
+ guard =
+ entry_guard_get_by_id_digest(circ->base_.n_chan->identity_digest);
+ }
- guard = entry_guard_get_by_id_digest(
- circ->_base.n_conn->identity_digest);
if (guard) {
if (circ->path_state == PATH_STATE_NEW_CIRC) {
- circ->path_state = PATH_STATE_DID_FIRST_HOP;
+ circ->path_state = PATH_STATE_BUILD_ATTEMPTED;
- if (entry_guard_inc_first_hop_count(guard) < 0) {
+ if (entry_guard_inc_circ_attempt_count(guard) < 0) {
/* Bogus guard; we already warned. */
return -END_CIRC_REASON_TORPROTOCOL;
}
} else {
- if ((rate_msg = rate_limit_log(&first_hop_notice_limit,
+ if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit,
approx_time()))) {
log_info(LD_BUG,
"Unopened circuit has strange path state %s. "
"Circuit is a %s currently %s.%s",
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
}
} else {
- if ((rate_msg = rate_limit_log(&first_hop_notice_limit,
+ if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit,
approx_time()))) {
- log_info(LD_BUG,
+ log_info(LD_CIRC,
"Unopened circuit has no known guard. "
"Circuit is a %s currently %s.%s",
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
}
}
- } else {
- /* Help track down the real cause of bug #6475: */
- if (circ->path_state == PATH_STATE_NEW_CIRC) {
- if ((rate_msg = rate_limit_log(&first_hop_notice_limit,
- approx_time()))) {
- log_info(LD_BUG,
- "A %s circuit is in cpath state %d (opened: %d). "
- "Circuit is a %s currently %s.%s",
- pathbias_state_to_string(circ->path_state),
- circ->cpath->state, circ->has_opened,
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
- rate_msg);
- tor_free(rate_msg);
- }
- }
}
return 0;
@@ -2753,48 +1513,34 @@ pathbias_count_first_hop(origin_circuit_t *circ)
* Also check for several potential error cases for bug #6475.
*/
static void
-pathbias_count_success(origin_circuit_t *circ)
+pathbias_count_build_success(origin_circuit_t *circ)
{
#define SUCCESS_NOTICE_INTERVAL (600)
static ratelim_t success_notice_limit =
RATELIM_INIT(SUCCESS_NOTICE_INTERVAL);
char *rate_msg = NULL;
+ entry_guard_t *guard = NULL;
- /* Ignore one hop circuits */
- if (circ->build_state->onehop_tunnel ||
- circ->build_state->desired_path_len == 1) {
- /* Check for consistency */
- if (circ->build_state->desired_path_len != 1 ||
- !circ->build_state->onehop_tunnel) {
- if ((rate_msg = rate_limit_log(&success_notice_limit,
- approx_time()))) {
- log_info(LD_BUG,
- "One-hop circuit has length %d. Path state is %s. "
- "Circuit is a %s currently %s.%s",
- circ->build_state->desired_path_len,
- pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
- rate_msg);
- tor_free(rate_msg);
- }
- tor_fragile_assert();
- }
+ if (!pathbias_should_count(circ)) {
return;
}
- /* Don't count cannibalized/reused circs for path bias */
+ /* Don't count cannibalized/reused circs for path bias
+ * "build" success, since they get counted under "use" success. */
if (!circ->has_opened) {
- entry_guard_t *guard =
- entry_guard_get_by_id_digest(circ->_base.n_conn->identity_digest);
+ if (circ->cpath && circ->cpath->extend_info) {
+ guard = entry_guard_get_by_id_digest(
+ circ->cpath->extend_info->identity_digest);
+ }
if (guard) {
- if (circ->path_state == PATH_STATE_DID_FIRST_HOP) {
- circ->path_state = PATH_STATE_SUCCEEDED;
- guard->circuit_successes++;
+ if (circ->path_state == PATH_STATE_BUILD_ATTEMPTED) {
+ circ->path_state = PATH_STATE_BUILD_SUCCEEDED;
+ guard->circ_successes++;
+ entry_guards_changed();
- log_info(LD_PROTOCOL, "Got success count %u/%u for guard %s=%s",
- guard->circuit_successes, guard->first_hops,
+ log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)",
+ guard->circ_successes, guard->circ_attempts,
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
} else {
if ((rate_msg = rate_limit_log(&success_notice_limit,
@@ -2803,41 +1549,44 @@ pathbias_count_success(origin_circuit_t *circ)
"Succeeded circuit is in strange path state %s. "
"Circuit is a %s currently %s.%s",
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
}
- if (guard->first_hops < guard->circuit_successes) {
- log_info(LD_BUG, "Unexpectedly high circuit_successes (%u/%u) "
- "for guard %s=%s",
- guard->circuit_successes, guard->first_hops,
+ if (guard->circ_attempts < guard->circ_successes) {
+ log_notice(LD_BUG, "Unexpectedly high successes counts (%f/%f) "
+ "for guard %s ($%s)",
+ guard->circ_successes, guard->circ_attempts,
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
}
- } else {
+ /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to
+ * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here.
+ * No need to log that case. */
+ } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
if ((rate_msg = rate_limit_log(&success_notice_limit,
approx_time()))) {
- log_info(LD_BUG,
+ log_info(LD_CIRC,
"Completed circuit has no known guard. "
"Circuit is a %s currently %s.%s",
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
}
} else {
- if (circ->path_state != PATH_STATE_SUCCEEDED) {
+ if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) {
if ((rate_msg = rate_limit_log(&success_notice_limit,
approx_time()))) {
log_info(LD_BUG,
"Opened circuit is in strange path state %s. "
"Circuit is a %s currently %s.%s",
pathbias_state_to_string(circ->path_state),
- circuit_purpose_to_string(circ->_base.purpose),
- circuit_state_to_string(circ->_base.state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state),
rate_msg);
tor_free(rate_msg);
}
@@ -2845,61 +1594,1012 @@ pathbias_count_success(origin_circuit_t *circ)
}
}
-/** Increment the number of times we successfully extended a circuit to
- * 'guard', first checking if the failure rate is high enough that we should
- * eliminate the guard. Return -1 if the guard looks no good; return 0 if the
- * guard looks fine. */
+/**
+ * Record an attempt to use a circuit. Changes the circuit's
+ * path state and update its guard's usage counter.
+ *
+ * Used for path bias usage accounting.
+ */
+void
+pathbias_count_use_attempt(origin_circuit_t *circ)
+{
+ entry_guard_t *guard;
+
+ if (!pathbias_should_count(circ)) {
+ return;
+ }
+
+ if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) {
+ log_notice(LD_BUG,
+ "Used circuit is in strange path state %s. "
+ "Circuit is a %s currently %s.",
+ pathbias_state_to_string(circ->path_state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state));
+ } else if (circ->path_state < PATH_STATE_USE_ATTEMPTED) {
+ guard = entry_guard_get_by_id_digest(
+ circ->cpath->extend_info->identity_digest);
+ if (guard) {
+ pathbias_measure_use_rate(guard);
+ pathbias_scale_use_rates(guard);
+ guard->use_attempts++;
+ entry_guards_changed();
+
+ log_debug(LD_CIRC,
+ "Marked circuit %d (%f/%f) as used for guard %s ($%s).",
+ circ->global_identifier,
+ guard->use_successes, guard->use_attempts,
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN));
+ }
+
+ circ->path_state = PATH_STATE_USE_ATTEMPTED;
+ } else {
+ /* Harmless but educational log message */
+ log_info(LD_CIRC,
+ "Used circuit %d is already in path state %s. "
+ "Circuit is a %s currently %s.",
+ circ->global_identifier,
+ pathbias_state_to_string(circ->path_state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state));
+ }
+
+ return;
+}
+
+/**
+ * Check the circuit's path state is appropriate and mark it as
+ * successfully used. Used for path bias usage accounting.
+ *
+ * We don't actually increment the guard's counters until
+ * pathbias_check_close(), because the circuit can still transition
+ * back to PATH_STATE_USE_ATTEMPTED if a stream fails later (this
+ * is done so we can probe the circuit for liveness at close).
+ */
+void
+pathbias_mark_use_success(origin_circuit_t *circ)
+{
+ if (!pathbias_should_count(circ)) {
+ return;
+ }
+
+ if (circ->path_state < PATH_STATE_USE_ATTEMPTED) {
+ log_notice(LD_BUG,
+ "Used circuit %d is in strange path state %s. "
+ "Circuit is a %s currently %s.",
+ circ->global_identifier,
+ pathbias_state_to_string(circ->path_state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state));
+
+ pathbias_count_use_attempt(circ);
+ }
+
+ /* We don't do any accounting at the guard until actual circuit close */
+ circ->path_state = PATH_STATE_USE_SUCCEEDED;
+
+ return;
+}
+
+/**
+ * If a stream ever detatches from a circuit in a retriable way,
+ * we need to mark this circuit as still needing either another
+ * successful stream, or in need of a probe.
+ *
+ * An adversary could let the first stream request succeed (ie the
+ * resolve), but then tag and timeout the remainder (via cell
+ * dropping), forcing them on new circuits.
+ *
+ * Rolling back the state will cause us to probe such circuits, which
+ * should lead to probe failures in the event of such tagging due to
+ * either unrecognized cells coming in while we wait for the probe,
+ * or the cipher state getting out of sync in the case of dropped cells.
+ */
+void
+pathbias_mark_use_rollback(origin_circuit_t *circ)
+{
+ if (circ->path_state == PATH_STATE_USE_SUCCEEDED) {
+ log_info(LD_CIRC,
+ "Rolling back pathbias use state to 'attempted' for detached "
+ "circuit %d", circ->global_identifier);
+ circ->path_state = PATH_STATE_USE_ATTEMPTED;
+ }
+}
+
+/**
+ * Actually count a circuit success towards a guard's usage counters
+ * if the path state is appropriate.
+ */
+static void
+pathbias_count_use_success(origin_circuit_t *circ)
+{
+ entry_guard_t *guard;
+
+ if (!pathbias_should_count(circ)) {
+ return;
+ }
+
+ if (circ->path_state != PATH_STATE_USE_SUCCEEDED) {
+ log_notice(LD_BUG,
+ "Successfully used circuit %d is in strange path state %s. "
+ "Circuit is a %s currently %s.",
+ circ->global_identifier,
+ pathbias_state_to_string(circ->path_state),
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state));
+ } else {
+ guard = entry_guard_get_by_id_digest(
+ circ->cpath->extend_info->identity_digest);
+ if (guard) {
+ guard->use_successes++;
+ entry_guards_changed();
+
+ if (guard->use_attempts < guard->use_successes) {
+ log_notice(LD_BUG, "Unexpectedly high use successes counts (%f/%f) "
+ "for guard %s=%s",
+ guard->use_successes, guard->use_attempts,
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN));
+ }
+
+ log_debug(LD_CIRC,
+ "Marked circuit %d (%f/%f) as used successfully for guard "
+ "%s ($%s).",
+ circ->global_identifier, guard->use_successes,
+ guard->use_attempts, guard->nickname,
+ hex_str(guard->identity, DIGEST_LEN));
+ }
+ }
+
+ return;
+}
+
+/**
+ * Send a probe down a circuit that the client attempted to use,
+ * but for which the stream timed out/failed. The probe is a
+ * RELAY_BEGIN cell with a 0.a.b.c destination address, which
+ * the exit will reject and reply back, echoing that address.
+ *
+ * The reason for such probes is because it is possible to bias
+ * a user's paths simply by causing timeouts, and these timeouts
+ * are not possible to differentiate from unresponsive servers.
+ *
+ * The probe is sent at the end of the circuit lifetime for two
+ * reasons: to prevent cryptographic taggers from being able to
+ * drop cells to cause timeouts, and to prevent easy recognition
+ * of probes before any real client traffic happens.
+ *
+ * Returns -1 if we couldn't probe, 0 otherwise.
+ */
+static int
+pathbias_send_usable_probe(circuit_t *circ)
+{
+ /* Based on connection_ap_handshake_send_begin() */
+ char payload[CELL_PAYLOAD_SIZE];
+ int payload_len;
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ crypt_path_t *cpath_layer = NULL;
+ char *probe_nonce = NULL;
+
+ tor_assert(ocirc);
+
+ cpath_layer = ocirc->cpath->prev;
+
+ if (cpath_layer->state != CPATH_STATE_OPEN) {
+ /* This can happen for cannibalized circuits. Their
+ * last hop isn't yet open */
+ log_info(LD_CIRC,
+ "Got pathbias probe request for unopened circuit %d. "
+ "Opened %d, len %d", ocirc->global_identifier,
+ ocirc->has_opened, ocirc->build_state->desired_path_len);
+ return -1;
+ }
+
+ /* We already went down this road. */
+ if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING &&
+ ocirc->pathbias_probe_id) {
+ log_info(LD_CIRC,
+ "Got pathbias probe request for circuit %d with "
+ "outstanding probe", ocirc->global_identifier);
+ return -1;
+ }
+
+ /* Can't probe if the channel isn't open */
+ if (circ->n_chan == NULL ||
+ (circ->n_chan->state != CHANNEL_STATE_OPEN
+ && circ->n_chan->state != CHANNEL_STATE_MAINT)) {
+ log_info(LD_CIRC,
+ "Skipping pathbias probe for circuit %d: Channel is not open.",
+ ocirc->global_identifier);
+ return -1;
+ }
+
+ circuit_change_purpose(circ, CIRCUIT_PURPOSE_PATH_BIAS_TESTING);
+
+ /* Update timestamp for when circuit_expire_building() should kill us */
+ tor_gettimeofday(&circ->timestamp_began);
+
+ /* Generate a random address for the nonce */
+ crypto_rand((char*)&ocirc->pathbias_probe_nonce,
+ sizeof(ocirc->pathbias_probe_nonce));
+ ocirc->pathbias_probe_nonce &= 0x00ffffff;
+ probe_nonce = tor_dup_ip(ocirc->pathbias_probe_nonce);
+
+ tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:25", probe_nonce);
+ payload_len = (int)strlen(payload)+1;
+
+ // XXX: need this? Can we assume ipv4 will always be supported?
+ // If not, how do we tell?
+ //if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) {
+ // set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags));
+ // payload_len += 4;
+ //}
+
+ /* Generate+Store stream id, make sure it's non-zero */
+ ocirc->pathbias_probe_id = get_unique_stream_id_by_circ(ocirc);
+
+ if (ocirc->pathbias_probe_id==0) {
+ log_warn(LD_CIRC,
+ "Ran out of stream IDs on circuit %u during "
+ "pathbias probe attempt.", ocirc->global_identifier);
+ tor_free(probe_nonce);
+ return -1;
+ }
+
+ log_info(LD_CIRC,
+ "Sending pathbias testing cell to %s:25 on stream %d for circ %d.",
+ probe_nonce, ocirc->pathbias_probe_id, ocirc->global_identifier);
+ tor_free(probe_nonce);
+
+ /* Send a test relay cell */
+ if (relay_send_command_from_edge(ocirc->pathbias_probe_id, circ,
+ RELAY_COMMAND_BEGIN, payload,
+ payload_len, cpath_layer) < 0) {
+ log_notice(LD_CIRC,
+ "Failed to send pathbias probe cell on circuit %d.",
+ ocirc->global_identifier);
+ return -1;
+ }
+
+ /* Mark it freshly dirty so it doesn't get expired in the meantime */
+ circ->timestamp_dirty = time(NULL);
+
+ return 0;
+}
+
+/**
+ * Check the response to a pathbias probe, to ensure the
+ * cell is recognized and the nonce and other probe
+ * characteristics are as expected.
+ *
+ * If the response is valid, return 0. Otherwise return < 0.
+ */
+int
+pathbias_check_probe_response(circuit_t *circ, const cell_t *cell)
+{
+ /* Based on connection_edge_process_relay_cell() */
+ relay_header_t rh;
+ int reason;
+ uint32_t ipv4_host;
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+
+ tor_assert(cell);
+ tor_assert(ocirc);
+ tor_assert(circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING);
+
+ relay_header_unpack(&rh, cell->payload);
+
+ reason = rh.length > 0 ?
+ get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC;
+
+ if (rh.command == RELAY_COMMAND_END &&
+ reason == END_STREAM_REASON_EXITPOLICY &&
+ ocirc->pathbias_probe_id == rh.stream_id) {
+
+ /* Check length+extract host: It is in network order after the reason code.
+ * See connection_edge_end(). */
+ if (rh.length < 9) { /* reason+ipv4+dns_ttl */
+ log_notice(LD_PROTOCOL,
+ "Short path bias probe response length field (%d).", rh.length);
+ return - END_CIRC_REASON_TORPROTOCOL;
+ }
+
+ ipv4_host = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
+
+ /* Check nonce */
+ if (ipv4_host == ocirc->pathbias_probe_nonce) {
+ pathbias_mark_use_success(ocirc);
+ circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
+ log_info(LD_CIRC,
+ "Got valid path bias probe back for circ %d, stream %d.",
+ ocirc->global_identifier, ocirc->pathbias_probe_id);
+ return 0;
+ } else {
+ log_notice(LD_CIRC,
+ "Got strange probe value 0x%x vs 0x%x back for circ %d, "
+ "stream %d.", ipv4_host, ocirc->pathbias_probe_nonce,
+ ocirc->global_identifier, ocirc->pathbias_probe_id);
+ return -1;
+ }
+ }
+ log_info(LD_CIRC,
+ "Got another cell back back on pathbias probe circuit %d: "
+ "Command: %d, Reason: %d, Stream-id: %d",
+ ocirc->global_identifier, rh.command, reason, rh.stream_id);
+ return -1;
+}
+
+/**
+ * Check if a circuit was used and/or closed successfully.
+ *
+ * If we attempted to use the circuit to carry a stream but failed
+ * for whatever reason, or if the circuit mysteriously died before
+ * we could attach any streams, record these two cases.
+ *
+ * If we *have* successfully used the circuit, or it appears to
+ * have been closed by us locally, count it as a success.
+ *
+ * Returns 0 if we're done making decisions with the circ,
+ * or -1 if we want to probe it first.
+ */
+int
+pathbias_check_close(origin_circuit_t *ocirc, int reason)
+{
+ circuit_t *circ = &ocirc->base_;
+
+ if (!pathbias_should_count(ocirc)) {
+ return 0;
+ }
+
+ switch (ocirc->path_state) {
+ /* If the circuit was closed after building, but before use, we need
+ * to ensure we were the ones who tried to close it (and not a remote
+ * actor). */
+ case PATH_STATE_BUILD_SUCCEEDED:
+ if (reason & END_CIRC_REASON_FLAG_REMOTE) {
+ /* Remote circ close reasons on an unused circuit all could be bias */
+ log_info(LD_CIRC,
+ "Circuit %d remote-closed without successful use for reason %d. "
+ "Circuit purpose %d currently %d,%s. Len %d.",
+ ocirc->global_identifier,
+ reason, circ->purpose, ocirc->has_opened,
+ circuit_state_to_string(circ->state),
+ ocirc->build_state->desired_path_len);
+ pathbias_count_collapse(ocirc);
+ } else if ((reason & ~END_CIRC_REASON_FLAG_REMOTE)
+ == END_CIRC_REASON_CHANNEL_CLOSED &&
+ circ->n_chan &&
+ circ->n_chan->reason_for_closing
+ != CHANNEL_CLOSE_REQUESTED) {
+ /* If we didn't close the channel ourselves, it could be bias */
+ /* XXX: Only count bias if the network is live?
+ * What about clock jumps/suspends? */
+ log_info(LD_CIRC,
+ "Circuit %d's channel closed without successful use for reason "
+ "%d, channel reason %d. Circuit purpose %d currently %d,%s. Len "
+ "%d.", ocirc->global_identifier,
+ reason, circ->n_chan->reason_for_closing,
+ circ->purpose, ocirc->has_opened,
+ circuit_state_to_string(circ->state),
+ ocirc->build_state->desired_path_len);
+ pathbias_count_collapse(ocirc);
+ } else {
+ pathbias_count_successful_close(ocirc);
+ }
+ break;
+
+ /* If we tried to use a circuit but failed, we should probe it to ensure
+ * it has not been tampered with. */
+ case PATH_STATE_USE_ATTEMPTED:
+ /* XXX: Only probe and/or count failure if the network is live?
+ * What about clock jumps/suspends? */
+ if (pathbias_send_usable_probe(circ) == 0)
+ return -1;
+ else
+ pathbias_count_use_failed(ocirc);
+
+ /* Any circuit where there were attempted streams but no successful
+ * streams could be bias */
+ log_info(LD_CIRC,
+ "Circuit %d closed without successful use for reason %d. "
+ "Circuit purpose %d currently %d,%s. Len %d.",
+ ocirc->global_identifier,
+ reason, circ->purpose, ocirc->has_opened,
+ circuit_state_to_string(circ->state),
+ ocirc->build_state->desired_path_len);
+ break;
+
+ case PATH_STATE_USE_SUCCEEDED:
+ pathbias_count_successful_close(ocirc);
+ pathbias_count_use_success(ocirc);
+ break;
+
+ case PATH_STATE_USE_FAILED:
+ pathbias_count_use_failed(ocirc);
+ break;
+
+ case PATH_STATE_NEW_CIRC:
+ case PATH_STATE_BUILD_ATTEMPTED:
+ case PATH_STATE_ALREADY_COUNTED:
+ default:
+ // Other states are uninteresting. No stats to count.
+ break;
+ }
+
+ ocirc->path_state = PATH_STATE_ALREADY_COUNTED;
+
+ return 0;
+}
+
+/**
+ * Count a successfully closed circuit.
+ */
+static void
+pathbias_count_successful_close(origin_circuit_t *circ)
+{
+ entry_guard_t *guard = NULL;
+ if (!pathbias_should_count(circ)) {
+ return;
+ }
+
+ if (circ->cpath && circ->cpath->extend_info) {
+ guard = entry_guard_get_by_id_digest(
+ circ->cpath->extend_info->identity_digest);
+ }
+
+ if (guard) {
+ /* In the long run: circuit_success ~= successful_circuit_close +
+ * circ_failure + stream_failure */
+ guard->successful_circuits_closed++;
+ entry_guards_changed();
+ } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
+ /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to
+ * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here.
+ * No need to log that case. */
+ log_info(LD_CIRC,
+ "Successfully closed circuit has no known guard. "
+ "Circuit is a %s currently %s",
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state));
+ }
+}
+
+/**
+ * Count a circuit that fails after it is built, but before it can
+ * carry any traffic.
+ *
+ * This is needed because there are ways to destroy a
+ * circuit after it has successfully completed. Right now, this is
+ * used for purely informational/debugging purposes.
+ */
+static void
+pathbias_count_collapse(origin_circuit_t *circ)
+{
+ entry_guard_t *guard = NULL;
+
+ if (!pathbias_should_count(circ)) {
+ return;
+ }
+
+ if (circ->cpath && circ->cpath->extend_info) {
+ guard = entry_guard_get_by_id_digest(
+ circ->cpath->extend_info->identity_digest);
+ }
+
+ if (guard) {
+ guard->collapsed_circuits++;
+ entry_guards_changed();
+ } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
+ /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to
+ * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here.
+ * No need to log that case. */
+ log_info(LD_CIRC,
+ "Destroyed circuit has no known guard. "
+ "Circuit is a %s currently %s",
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state));
+ }
+}
+
+/**
+ * Count a known failed circuit (because we could not probe it).
+ *
+ * This counter is informational.
+ */
+static void
+pathbias_count_use_failed(origin_circuit_t *circ)
+{
+ entry_guard_t *guard = NULL;
+ if (!pathbias_should_count(circ)) {
+ return;
+ }
+
+ if (circ->cpath && circ->cpath->extend_info) {
+ guard = entry_guard_get_by_id_digest(
+ circ->cpath->extend_info->identity_digest);
+ }
+
+ if (guard) {
+ guard->unusable_circuits++;
+ entry_guards_changed();
+ } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
+ /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to
+ * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here.
+ * No need to log that case. */
+ /* XXX note cut-and-paste code in this function compared to nearby
+ * functions. Would be nice to refactor. -RD */
+ log_info(LD_CIRC,
+ "Stream-failing circuit has no known guard. "
+ "Circuit is a %s currently %s",
+ circuit_purpose_to_string(circ->base_.purpose),
+ circuit_state_to_string(circ->base_.state));
+ }
+}
+
+/**
+ * Count timeouts for path bias log messages.
+ *
+ * These counts are purely informational.
+ */
+void
+pathbias_count_timeout(origin_circuit_t *circ)
+{
+ entry_guard_t *guard = NULL;
+
+ if (!pathbias_should_count(circ)) {
+ return;
+ }
+
+ /* For hidden service circs, they can actually be used
+ * successfully and then time out later (because
+ * the other side declines to use them). */
+ if (circ->path_state == PATH_STATE_USE_SUCCEEDED) {
+ return;
+ }
+
+ if (circ->cpath && circ->cpath->extend_info) {
+ guard = entry_guard_get_by_id_digest(
+ circ->cpath->extend_info->identity_digest);
+ }
+
+ if (guard) {
+ guard->timeouts++;
+ entry_guards_changed();
+ }
+}
+
+/**
+ * Helper function to count all of the currently opened circuits
+ * for a guard that are in a given path state range. The state
+ * range is inclusive on both ends.
+ */
static int
-entry_guard_inc_first_hop_count(entry_guard_t *guard)
+pathbias_count_circs_in_states(entry_guard_t *guard,
+ path_state_t from,
+ path_state_t to)
+{
+ circuit_t *circ;
+ int open_circuits = 0;
+
+ /* Count currently open circuits. Give them the benefit of the doubt. */
+ for (circ = global_circuitlist; circ; circ = circ->next) {
+ origin_circuit_t *ocirc = NULL;
+ if (!CIRCUIT_IS_ORIGIN(circ) || /* didn't originate here */
+ circ->marked_for_close) /* already counted */
+ continue;
+
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+
+ if (!ocirc->cpath || !ocirc->cpath->extend_info)
+ continue;
+
+ if (ocirc->path_state >= from &&
+ ocirc->path_state <= to &&
+ pathbias_should_count(ocirc) &&
+ fast_memeq(guard->identity,
+ ocirc->cpath->extend_info->identity_digest,
+ DIGEST_LEN)) {
+ log_debug(LD_CIRC, "Found opened circuit %d in path_state %s",
+ ocirc->global_identifier,
+ pathbias_state_to_string(ocirc->path_state));
+ open_circuits++;
+ }
+ }
+
+ return open_circuits;
+}
+
+/**
+ * Return the number of circuits counted as successfully closed for
+ * this guard.
+ *
+ * Also add in the currently open circuits to give them the benefit
+ * of the doubt.
+ */
+double
+pathbias_get_close_success_count(entry_guard_t *guard)
+{
+ return guard->successful_circuits_closed +
+ pathbias_count_circs_in_states(guard,
+ PATH_STATE_BUILD_SUCCEEDED,
+ PATH_STATE_USE_SUCCEEDED);
+}
+
+/**
+ * Return the number of circuits counted as successfully used
+ * this guard.
+ *
+ * Also add in the currently open circuits that we are attempting
+ * to use to give them the benefit of the doubt.
+ */
+double
+pathbias_get_use_success_count(entry_guard_t *guard)
+{
+ return guard->use_successes +
+ pathbias_count_circs_in_states(guard,
+ PATH_STATE_USE_ATTEMPTED,
+ PATH_STATE_USE_SUCCEEDED);
+}
+
+/**
+ * Check the path bias use rate against our consensus parameter limits.
+ *
+ * Emits a log message if the use success rates are too low.
+ *
+ * If pathbias_get_dropguards() is set, we also disable the use of
+ * very failure prone guards.
+ */
+static void
+pathbias_measure_use_rate(entry_guard_t *guard)
{
const or_options_t *options = get_options();
- entry_guards_changed();
+ if (guard->use_attempts > pathbias_get_min_use(options)) {
+ /* Note: We rely on the < comparison here to allow us to set a 0
+ * rate and disable the feature entirely. If refactoring, don't
+ * change to <= */
+ if (pathbias_get_use_success_count(guard)/guard->use_attempts
+ < pathbias_get_extreme_use_rate(options)) {
+ /* Dropping is currently disabled by default. */
+ if (pathbias_get_dropguards(options)) {
+ if (!guard->path_bias_disabled) {
+ log_warn(LD_CIRC,
+ "Your Guard %s ($%s) is failing to carry an extremely large "
+ "amount of stream on its circuits. "
+ "To avoid potential route manipulation attacks, Tor has "
+ "disabled use of this guard. "
+ "Use counts are %ld/%ld. Success counts are %ld/%ld. "
+ "%ld circuits completed, %ld were unusable, %ld collapsed, "
+ "and %ld timed out. "
+ "For reference, your timeout cutoff is %ld seconds.",
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN),
+ tor_lround(pathbias_get_use_success_count(guard)),
+ tor_lround(guard->use_attempts),
+ tor_lround(pathbias_get_close_success_count(guard)),
+ tor_lround(guard->circ_attempts),
+ tor_lround(guard->circ_successes),
+ tor_lround(guard->unusable_circuits),
+ tor_lround(guard->collapsed_circuits),
+ tor_lround(guard->timeouts),
+ tor_lround(circ_times.close_ms/1000));
+ guard->path_bias_disabled = 1;
+ guard->bad_since = approx_time();
+ entry_guards_changed();
+ return;
+ }
+ } else if (!guard->path_bias_use_extreme) {
+ guard->path_bias_use_extreme = 1;
+ log_warn(LD_CIRC,
+ "Your Guard %s ($%s) is failing to carry an extremely large "
+ "amount of streams on its circuits. "
+ "This could indicate a route manipulation attack, network "
+ "overload, bad local network connectivity, or a bug. "
+ "Use counts are %ld/%ld. Success counts are %ld/%ld. "
+ "%ld circuits completed, %ld were unusable, %ld collapsed, "
+ "and %ld timed out. "
+ "For reference, your timeout cutoff is %ld seconds.",
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN),
+ tor_lround(pathbias_get_use_success_count(guard)),
+ tor_lround(guard->use_attempts),
+ tor_lround(pathbias_get_close_success_count(guard)),
+ tor_lround(guard->circ_attempts),
+ tor_lround(guard->circ_successes),
+ tor_lround(guard->unusable_circuits),
+ tor_lround(guard->collapsed_circuits),
+ tor_lround(guard->timeouts),
+ tor_lround(circ_times.close_ms/1000));
+ }
+ } else if (pathbias_get_use_success_count(guard)/guard->use_attempts
+ < pathbias_get_notice_use_rate(options)) {
+ if (!guard->path_bias_use_noticed) {
+ guard->path_bias_use_noticed = 1;
+ log_notice(LD_CIRC,
+ "Your Guard %s ($%s) is failing to carry more streams on its "
+ "circuits than usual. "
+ "Most likely this means the Tor network is overloaded "
+ "or your network connection is poor. "
+ "Use counts are %ld/%ld. Success counts are %ld/%ld. "
+ "%ld circuits completed, %ld were unusable, %ld collapsed, "
+ "and %ld timed out. "
+ "For reference, your timeout cutoff is %ld seconds.",
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN),
+ tor_lround(pathbias_get_use_success_count(guard)),
+ tor_lround(guard->use_attempts),
+ tor_lround(pathbias_get_close_success_count(guard)),
+ tor_lround(guard->circ_attempts),
+ tor_lround(guard->circ_successes),
+ tor_lround(guard->unusable_circuits),
+ tor_lround(guard->collapsed_circuits),
+ tor_lround(guard->timeouts),
+ tor_lround(circ_times.close_ms/1000));
+ }
+ }
+ }
+}
- if (guard->first_hops > (unsigned)pathbias_get_min_circs(options)) {
+/**
+ * Check the path bias circuit close status rates against our consensus
+ * parameter limits.
+ *
+ * Emits a log message if the use success rates are too low.
+ *
+ * If pathbias_get_dropguards() is set, we also disable the use of
+ * very failure prone guards.
+ *
+ * XXX: This function shares similar log messages and checks to
+ * pathbias_measure_use_rate(). It may be possible to combine them
+ * eventually, especially if we can ever remove the need for 3
+ * levels of closure warns (if the overall circuit failure rate
+ * goes down with ntor). One way to do so would be to multiply
+ * the build rate with the use rate to get an idea of the total
+ * fraction of the total network paths the user is able to use.
+ * See ticket #8159.
+ */
+static void
+pathbias_measure_close_rate(entry_guard_t *guard)
+{
+ const or_options_t *options = get_options();
+
+ if (guard->circ_attempts > pathbias_get_min_circs(options)) {
/* Note: We rely on the < comparison here to allow us to set a 0
* rate and disable the feature entirely. If refactoring, don't
* change to <= */
- if (guard->circuit_successes/((double)guard->first_hops)
- < pathbias_get_disable_rate(options)) {
+ if (pathbias_get_close_success_count(guard)/guard->circ_attempts
+ < pathbias_get_extreme_rate(options)) {
+ /* Dropping is currently disabled by default. */
+ if (pathbias_get_dropguards(options)) {
+ if (!guard->path_bias_disabled) {
+ log_warn(LD_CIRC,
+ "Your Guard %s ($%s) is failing an extremely large "
+ "amount of circuits. "
+ "To avoid potential route manipulation attacks, Tor has "
+ "disabled use of this guard. "
+ "Success counts are %ld/%ld. Use counts are %ld/%ld. "
+ "%ld circuits completed, %ld were unusable, %ld collapsed, "
+ "and %ld timed out. "
+ "For reference, your timeout cutoff is %ld seconds.",
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN),
+ tor_lround(pathbias_get_close_success_count(guard)),
+ tor_lround(guard->circ_attempts),
+ tor_lround(pathbias_get_use_success_count(guard)),
+ tor_lround(guard->use_attempts),
+ tor_lround(guard->circ_successes),
+ tor_lround(guard->unusable_circuits),
+ tor_lround(guard->collapsed_circuits),
+ tor_lround(guard->timeouts),
+ tor_lround(circ_times.close_ms/1000));
+ guard->path_bias_disabled = 1;
+ guard->bad_since = approx_time();
+ entry_guards_changed();
+ return;
+ }
+ } else if (!guard->path_bias_extreme) {
+ guard->path_bias_extreme = 1;
+ log_warn(LD_CIRC,
+ "Your Guard %s ($%s) is failing an extremely large "
+ "amount of circuits. "
+ "This could indicate a route manipulation attack, "
+ "extreme network overload, or a bug. "
+ "Success counts are %ld/%ld. Use counts are %ld/%ld. "
+ "%ld circuits completed, %ld were unusable, %ld collapsed, "
+ "and %ld timed out. "
+ "For reference, your timeout cutoff is %ld seconds.",
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN),
+ tor_lround(pathbias_get_close_success_count(guard)),
+ tor_lround(guard->circ_attempts),
+ tor_lround(pathbias_get_use_success_count(guard)),
+ tor_lround(guard->use_attempts),
+ tor_lround(guard->circ_successes),
+ tor_lround(guard->unusable_circuits),
+ tor_lround(guard->collapsed_circuits),
+ tor_lround(guard->timeouts),
+ tor_lround(circ_times.close_ms/1000));
+ }
+ } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts
+ < pathbias_get_warn_rate(options)) {
+ if (!guard->path_bias_warned) {
+ guard->path_bias_warned = 1;
+ log_warn(LD_CIRC,
+ "Your Guard %s ($%s) is failing a very large "
+ "amount of circuits. "
+ "Most likely this means the Tor network is "
+ "overloaded, but it could also mean an attack against "
+ "you or potentially the guard itself. "
+ "Success counts are %ld/%ld. Use counts are %ld/%ld. "
+ "%ld circuits completed, %ld were unusable, %ld collapsed, "
+ "and %ld timed out. "
+ "For reference, your timeout cutoff is %ld seconds.",
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN),
+ tor_lround(pathbias_get_close_success_count(guard)),
+ tor_lround(guard->circ_attempts),
+ tor_lround(pathbias_get_use_success_count(guard)),
+ tor_lround(guard->use_attempts),
+ tor_lround(guard->circ_successes),
+ tor_lround(guard->unusable_circuits),
+ tor_lround(guard->collapsed_circuits),
+ tor_lround(guard->timeouts),
+ tor_lround(circ_times.close_ms/1000));
+ }
+ } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts
+ < pathbias_get_notice_rate(options)) {
+ if (!guard->path_bias_noticed) {
+ guard->path_bias_noticed = 1;
+ log_notice(LD_CIRC,
+ "Your Guard %s ($%s) is failing more circuits than "
+ "usual. "
+ "Most likely this means the Tor network is overloaded. "
+ "Success counts are %ld/%ld. Use counts are %ld/%ld. "
+ "%ld circuits completed, %ld were unusable, %ld collapsed, "
+ "and %ld timed out. "
+ "For reference, your timeout cutoff is %ld seconds.",
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN),
+ tor_lround(pathbias_get_close_success_count(guard)),
+ tor_lround(guard->circ_attempts),
+ tor_lround(pathbias_get_use_success_count(guard)),
+ tor_lround(guard->use_attempts),
+ tor_lround(guard->circ_successes),
+ tor_lround(guard->unusable_circuits),
+ tor_lround(guard->collapsed_circuits),
+ tor_lround(guard->timeouts),
+ tor_lround(circ_times.close_ms/1000));
+ }
+ }
+ }
+}
- log_info(LD_PROTOCOL,
- "Extremely low circuit success rate %u/%u for guard %s=%s. "
- "This might indicate an attack, or a bug.",
- guard->circuit_successes, guard->first_hops, guard->nickname,
- hex_str(guard->identity, DIGEST_LEN));
+/**
+ * This function scales the path bias use rates if we have
+ * more data than the scaling threshold. This allows us to
+ * be more sensitive to recent measurements.
+ *
+ * XXX: The attempt count transfer stuff here might be done
+ * better by keeping separate pending counters that get
+ * transfered at circuit close. See ticket #8160.
+ */
+static void
+pathbias_scale_close_rates(entry_guard_t *guard)
+{
+ const or_options_t *options = get_options();
- guard->path_bias_disabled = 1;
- guard->bad_since = approx_time();
- return -1;
- } else if (guard->circuit_successes/((double)guard->first_hops)
- < pathbias_get_notice_rate(options)
- && !guard->path_bias_notice) {
- guard->path_bias_notice = 1;
- log_info(LD_PROTOCOL,
- "Low circuit success rate %u/%u for guard %s=%s.",
- guard->circuit_successes, guard->first_hops, guard->nickname,
- hex_str(guard->identity, DIGEST_LEN));
+ /* If we get a ton of circuits, just scale everything down */
+ if (guard->circ_attempts > pathbias_get_scale_threshold(options)) {
+ double scale_ratio = pathbias_get_scale_ratio(options);
+ int opened_attempts = pathbias_count_circs_in_states(guard,
+ PATH_STATE_BUILD_ATTEMPTED, PATH_STATE_BUILD_ATTEMPTED);
+ int opened_built = pathbias_count_circs_in_states(guard,
+ PATH_STATE_BUILD_SUCCEEDED,
+ PATH_STATE_USE_FAILED);
+ /* Verify that the counts are sane before and after scaling */
+ int counts_are_sane = (guard->circ_attempts >= guard->circ_successes);
+
+ guard->circ_attempts -= (opened_attempts+opened_built);
+ guard->circ_successes -= opened_built;
+
+ guard->circ_attempts *= scale_ratio;
+ guard->circ_successes *= scale_ratio;
+ guard->timeouts *= scale_ratio;
+ guard->successful_circuits_closed *= scale_ratio;
+ guard->collapsed_circuits *= scale_ratio;
+ guard->unusable_circuits *= scale_ratio;
+
+ guard->circ_attempts += (opened_attempts+opened_built);
+ guard->circ_successes += opened_built;
+
+ entry_guards_changed();
+
+ log_info(LD_CIRC,
+ "Scaled pathbias counts to (%f,%f)/%f (%d/%d open) for guard "
+ "%s ($%s)",
+ guard->circ_successes, guard->successful_circuits_closed,
+ guard->circ_attempts, opened_built, opened_attempts,
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN));
+
+ /* Have the counts just become invalid by this scaling attempt? */
+ if (counts_are_sane && guard->circ_attempts < guard->circ_successes) {
+ log_notice(LD_BUG,
+ "Scaling has mangled pathbias counts to %f/%f (%d/%d open) "
+ "for guard %s ($%s)",
+ guard->circ_successes, guard->circ_attempts, opened_built,
+ opened_attempts, guard->nickname,
+ hex_str(guard->identity, DIGEST_LEN));
}
}
+}
+
+/**
+ * This function scales the path bias circuit close rates if we have
+ * more data than the scaling threshold. This allows us to be more
+ * sensitive to recent measurements.
+ *
+ * XXX: The attempt count transfer stuff here might be done
+ * better by keeping separate pending counters that get
+ * transfered at circuit close. See ticket #8160.
+ */
+void
+pathbias_scale_use_rates(entry_guard_t *guard)
+{
+ const or_options_t *options = get_options();
/* If we get a ton of circuits, just scale everything down */
- if (guard->first_hops > (unsigned)pathbias_get_scale_threshold(options)) {
- const int scale_factor = pathbias_get_scale_factor(options);
- guard->first_hops /= scale_factor;
- guard->circuit_successes /= scale_factor;
+ if (guard->use_attempts > pathbias_get_scale_use_threshold(options)) {
+ double scale_ratio = pathbias_get_scale_ratio(options);
+ int opened_attempts = pathbias_count_circs_in_states(guard,
+ PATH_STATE_USE_ATTEMPTED, PATH_STATE_USE_SUCCEEDED);
+ /* Verify that the counts are sane before and after scaling */
+ int counts_are_sane = (guard->use_attempts >= guard->use_successes);
+
+ guard->use_attempts -= opened_attempts;
+
+ guard->use_attempts *= scale_ratio;
+ guard->use_successes *= scale_ratio;
+
+ guard->use_attempts += opened_attempts;
+
+ log_info(LD_CIRC,
+ "Scaled pathbias use counts to %f/%f (%d open) for guard %s ($%s)",
+ guard->use_successes, guard->use_attempts, opened_attempts,
+ guard->nickname, hex_str(guard->identity, DIGEST_LEN));
+
+ /* Have the counts just become invalid by this scaling attempt? */
+ if (counts_are_sane && guard->use_attempts < guard->use_successes) {
+ log_notice(LD_BUG,
+ "Scaling has mangled pathbias usage counts to %f/%f "
+ "(%d open) for guard %s ($%s)",
+ guard->circ_successes, guard->circ_attempts,
+ opened_attempts, guard->nickname,
+ hex_str(guard->identity, DIGEST_LEN));
+ }
+
+ entry_guards_changed();
}
- guard->first_hops++;
- log_info(LD_PROTOCOL, "Got success count %u/%u for guard %s=%s",
- guard->circuit_successes, guard->first_hops, guard->nickname,
+}
+
+/** Increment the number of times we successfully extended a circuit to
+ * <b>guard</b>, first checking if the failure rate is high enough that
+ * we should eliminate the guard. Return -1 if the guard looks no good;
+ * return 0 if the guard looks fine.
+ */
+static int
+entry_guard_inc_circ_attempt_count(entry_guard_t *guard)
+{
+ entry_guards_changed();
+
+ pathbias_measure_close_rate(guard);
+
+ if (guard->path_bias_disabled)
+ return -1;
+
+ pathbias_scale_close_rates(guard);
+ guard->circ_attempts++;
+
+ log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)",
+ guard->circ_successes, guard->circ_attempts, guard->nickname,
hex_str(guard->identity, DIGEST_LEN));
return 0;
}
-/** A created or extended cell came back to us on the circuit, and it included
- * <b>reply</b> as its body. (If <b>reply_type</b> is CELL_CREATED, the body
- * contains (the second DH key, plus KH). If <b>reply_type</b> is
- * CELL_CREATED_FAST, the body contains a secret y and a hash H(x|y).)
+/** A "created" cell <b>reply</b> came back to us on circuit <b>circ</b>.
+ * (The body of <b>reply</b> varies depending on what sort of handshake
+ * this is.)
*
* Calculate the appropriate keys and digests, make sure KH is
* correct, and initialize this hop of the cpath.
@@ -2907,14 +2607,14 @@ entry_guard_inc_first_hop_count(entry_guard_t *guard)
* Return - reason if we want to mark circ for close, else return 0.
*/
int
-circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
- const uint8_t *reply)
+circuit_finish_handshake(origin_circuit_t *circ,
+ const created_cell_t *reply)
{
char keys[CPATH_KEY_MATERIAL_LEN];
crypt_path_t *hop;
int rv;
- if ((rv = pathbias_count_first_hop(circ)) < 0)
+ if ((rv = pathbias_count_build_attempt(circ)) < 0)
return rv;
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) {
@@ -2928,39 +2628,25 @@ circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
}
tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
- if (reply_type == CELL_CREATED && hop->dh_handshake_state) {
- if (onion_skin_client_handshake(hop->dh_handshake_state, (char*)reply,keys,
- DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
+ {
+ if (onion_skin_client_handshake(hop->handshake_state.tag,
+ &hop->handshake_state,
+ reply->reply, reply->handshake_len,
+ (uint8_t*)keys, sizeof(keys),
+ (uint8_t*)hop->rend_circ_nonce) < 0) {
log_warn(LD_CIRC,"onion_skin_client_handshake failed.");
return -END_CIRC_REASON_TORPROTOCOL;
}
- /* Remember hash of g^xy */
- memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN);
- } else if (reply_type == CELL_CREATED_FAST && !hop->dh_handshake_state) {
- if (fast_client_handshake(hop->fast_handshake_state, reply,
- (uint8_t*)keys,
- DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
- log_warn(LD_CIRC,"fast_client_handshake failed.");
- return -END_CIRC_REASON_TORPROTOCOL;
- }
- memcpy(hop->handshake_digest, reply+DIGEST_LEN, DIGEST_LEN);
- } else {
- log_warn(LD_PROTOCOL,"CREATED cell type did not match CREATE cell type.");
- return -END_CIRC_REASON_TORPROTOCOL;
}
- crypto_dh_free(hop->dh_handshake_state); /* don't need it anymore */
- hop->dh_handshake_state = NULL;
-
- memset(hop->fast_handshake_state, 0, sizeof(hop->fast_handshake_state));
+ onion_handshake_state_release(&hop->handshake_state);
if (circuit_init_cpath_crypto(hop, keys, 0)<0) {
return -END_CIRC_REASON_TORPROTOCOL;
}
hop->state = CPATH_STATE_OPEN;
- log_info(LD_CIRC,"Finished building %scircuit hop:",
- (reply_type == CELL_CREATED_FAST) ? "fast " : "");
+ log_info(LD_CIRC,"Finished building circuit hop:");
circuit_log_path(LOG_INFO,LD_CIRC,circ);
control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0);
@@ -2969,12 +2655,12 @@ circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
/** We received a relay truncated cell on circ.
*
- * Since we don't ask for truncates currently, getting a truncated
+ * Since we don't send truncates currently, getting a truncated
* means that a connection broke or an extend failed. For now,
- * just give up: for circ to close, and return 0.
+ * just give up: force circ to close, and return 0.
*/
int
-circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
+circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, int reason)
{
// crypt_path_t *victim;
// connection_t *stream;
@@ -2982,12 +2668,12 @@ circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
tor_assert(circ);
tor_assert(layer);
- /* XXX Since we don't ask for truncates currently, getting a truncated
+ /* XXX Since we don't send truncates currently, getting a truncated
* means that a connection broke or an extend failed. For now,
* just give up.
*/
circuit_mark_for_close(TO_CIRCUIT(circ),
- END_CIRC_REASON_FLAG_REMOTE|END_CIRC_REASON_OR_CONN_CLOSED);
+ END_CIRC_REASON_FLAG_REMOTE|reason);
return 0;
#if 0
@@ -3020,24 +2706,26 @@ circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
* cell back.
*/
int
-onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
- const char *keys)
+onionskin_answer(or_circuit_t *circ,
+ const created_cell_t *created_cell,
+ const char *keys,
+ const uint8_t *rend_circ_nonce)
{
cell_t cell;
crypt_path_t *tmp_cpath;
+ if (created_cell_format(&cell, created_cell) < 0) {
+ log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d)",
+ (int)created_cell->cell_type, (int)created_cell->handshake_len);
+ return -1;
+ }
+ cell.circ_id = circ->p_circ_id;
+
tmp_cpath = tor_malloc_zero(sizeof(crypt_path_t));
tmp_cpath->magic = CRYPT_PATH_MAGIC;
- memset(&cell, 0, sizeof(cell_t));
- cell.command = cell_type;
- cell.circ_id = circ->p_circ_id;
-
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
- memcpy(cell.payload, payload,
- cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2);
-
log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
(unsigned int)get_uint32(keys),
(unsigned int)get_uint32(keys+20));
@@ -3053,20 +2741,17 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
tmp_cpath->magic = 0;
tor_free(tmp_cpath);
- if (cell_type == CELL_CREATED)
- memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, DIGEST_LEN);
- else
- memcpy(circ->handshake_digest, cell.payload+DIGEST_LEN, DIGEST_LEN);
+ memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
- circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
+ circ->is_first_hop = (created_cell->cell_type == CELL_CREATED_FAST);
append_cell_to_circuit_queue(TO_CIRCUIT(circ),
- circ->p_conn, &cell, CELL_DIRECTION_IN, 0);
+ circ->p_chan, &cell, CELL_DIRECTION_IN, 0);
log_debug(LD_CIRC,"Finished sending '%s' cell.",
circ->is_first_hop ? "created_fast" : "created");
- if (!is_local_addr(&circ->p_conn->_base.addr) &&
- !connection_or_nonopen_was_started_here(circ->p_conn)) {
+ if (!channel_is_local(circ->p_chan) &&
+ !channel_is_outgoing(circ->p_chan)) {
/* record that we could process create cells from a non-local conn
* that we didn't initiate; presumably this means that create cells
* can reach us too. */
@@ -3076,15 +2761,18 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
return 0;
}
-/** Choose a length for a circuit of purpose <b>purpose</b>.
- * Default length is 3 + the number of endpoints that would give something
- * away. If the routerlist <b>routers</b> doesn't have enough routers
+/** Choose a length for a circuit of purpose <b>purpose</b>: three + the
+ * number of endpoints that would give something away about our destination.
+ *
+ * If the routerlist <b>nodes</b> doesn't have enough routers
* to handle the desired path length, return as large a path length as
* is feasible, except if it's less than 2, in which case return -1.
+ * XXX ^^ I think this behavior is a hold-over from back when we had only a
+ * few relays in the network, and certainly back before guards existed.
+ * We should very likely get rid of it. -RD
*/
static int
-new_route_len(uint8_t purpose, extend_info_t *exit,
- smartlist_t *nodes)
+new_route_len(uint8_t purpose, extend_info_t *exit, smartlist_t *nodes)
{
int num_acceptable_routers;
int routelen;
@@ -3149,7 +2837,7 @@ circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
enough = (smartlist_len(sl) == 0);
for (i = 0; i < smartlist_len(sl); ++i) {
port = smartlist_get(sl, i);
- if (smartlist_string_num_isin(LongLivedServices, *port))
+ if (smartlist_contains_int_as_string(LongLivedServices, *port))
*need_uptime = 1;
tor_free(port);
}
@@ -3268,7 +2956,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
n_supported[i] = -1;
continue;
}
- if (routerset_contains_node(options->_ExcludeExitNodesUnion, node)) {
+ if (routerset_contains_node(options->ExcludeExitNodesUnion_, node)) {
n_supported[i] = -1;
continue; /* user asked us not to use it, no matter what */
}
@@ -3285,7 +2973,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
* we'll retry later in this function with need_update and
* need_capacity set to 0. */
}
- if (!(node->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) {
+ if (!(node->is_valid || options->AllowInvalid_ & ALLOW_INVALID_EXIT)) {
/* if it's invalid and we don't want it */
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.",
@@ -3371,7 +3059,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
}
log_notice(LD_CIRC, "All routers are down or won't exit%s -- "
"choosing a doomed exit at random.",
- options->_ExcludeExitNodesUnion ? " or are Excluded" : "");
+ options->ExcludeExitNodesUnion_ ? " or are Excluded" : "");
}
supporting = smartlist_new();
needed_ports = circuit_get_unhandled_ports(time(NULL));
@@ -3410,7 +3098,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
log_warn(LD_CIRC,
"No specified %sexit routers seem to be running: "
"can't choose an exit.",
- options->_ExcludeExitNodesUnion ? "non-excluded " : "");
+ options->ExcludeExitNodesUnion_ ? "non-excluded " : "");
}
return NULL;
}
@@ -3438,14 +3126,14 @@ choose_good_exit_server(uint8_t purpose,
switch (purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
- if (options->_AllowInvalid & ALLOW_INVALID_MIDDLE)
+ if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE)
flags |= CRN_ALLOW_INVALID;
if (is_internal) /* pick it like a middle hop */
return router_choose_random_node(NULL, options->ExcludeNodes, flags);
else
return choose_good_exit_server_general(need_uptime,need_capacity);
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
- if (options->_AllowInvalid & ALLOW_INVALID_RENDEZVOUS)
+ if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS)
flags |= CRN_ALLOW_INVALID;
return router_choose_random_node(NULL, options->ExcludeNodes, flags);
}
@@ -3462,7 +3150,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
const or_options_t *options = get_options();
routerset_t *rs = options->ExcludeNodes;
const char *description;
- uint8_t purpose = circ->_base.purpose;
+ uint8_t purpose = circ->base_.purpose;
if (circ->build_state->onehop_tunnel)
return;
@@ -3482,7 +3170,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
if (circ->build_state->is_internal)
return;
description = "requested exit node";
- rs = options->_ExcludeExitNodesUnion;
+ rs = options->ExcludeExitNodesUnion_;
break;
case CIRCUIT_PURPOSE_C_INTRODUCING:
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
@@ -3499,7 +3187,7 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
description = "chosen rendezvous point";
break;
case CIRCUIT_PURPOSE_CONTROLLER:
- rs = options->_ExcludeExitNodesUnion;
+ rs = options->ExcludeExitNodesUnion_;
description = "controller-selected circuit target";
break;
}
@@ -3541,7 +3229,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel.");
state->desired_path_len = 1;
} else {
- int r = new_route_len(circ->_base.purpose, exit, nodelist_get_list());
+ int r = new_route_len(circ->base_.purpose, exit, nodelist_get_list());
if (r < 1) /* must be at least 1 */
return -1;
state->desired_path_len = r;
@@ -3554,7 +3242,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
exit = extend_info_dup(exit);
} else { /* we have to decide one */
const node_t *node =
- choose_good_exit_server(circ->_base.purpose, state->need_uptime,
+ choose_good_exit_server(circ->base_.purpose, state->need_uptime,
state->need_capacity, state->is_internal);
if (!node) {
log_warn(LD_CIRC,"failed to choose an exit server");
@@ -3597,6 +3285,9 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit)
{
int err_reason = 0;
warn_if_last_router_excluded(circ, exit);
+
+ tor_gettimeofday(&circ->base_.timestamp_began);
+
circuit_append_new_exit(circ, exit);
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
if ((err_reason = circuit_send_next_onion_skin(circ))<0) {
@@ -3605,6 +3296,9 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit)
circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason);
return -1;
}
+
+ // XXX: Should cannibalized circuits be dirty or not? Not easy to say..
+
return 0;
}
@@ -3675,8 +3369,8 @@ choose_good_middle_server(uint8_t purpose,
smartlist_t *excluded;
const or_options_t *options = get_options();
router_crn_flags_t flags = CRN_NEED_DESC;
- tor_assert(_CIRCUIT_PURPOSE_MIN <= purpose &&
- purpose <= _CIRCUIT_PURPOSE_MAX);
+ tor_assert(CIRCUIT_PURPOSE_MIN_ <= purpose &&
+ purpose <= CIRCUIT_PURPOSE_MAX_);
log_debug(LD_CIRC, "Contemplating intermediate hop: random choice.");
excluded = smartlist_new();
@@ -3693,7 +3387,7 @@ choose_good_middle_server(uint8_t purpose,
flags |= CRN_NEED_UPTIME;
if (state->need_capacity)
flags |= CRN_NEED_CAPACITY;
- if (options->_AllowInvalid & ALLOW_INVALID_MIDDLE)
+ if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE)
flags |= CRN_ALLOW_INVALID;
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
smartlist_free(excluded);
@@ -3708,7 +3402,8 @@ choose_good_middle_server(uint8_t purpose,
* If <b>state</b> is NULL, we're choosing a router to serve as an entry
* guard, not for any particular circuit.
*/
-static const node_t *
+/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */
+const node_t *
choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
{
const node_t *choice;
@@ -3740,8 +3435,9 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
});
}
/* and exclude current entry guards and their families, if applicable */
- if (options->UseEntryGuards && entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
+ /*XXXX025 use the using_as_guard flag to accomplish this.*/
+ if (options->UseEntryGuards) {
+ SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry,
{
if ((node = node_get_by_id(entry->identity))) {
nodelist_add_node_and_family(excluded, node);
@@ -3755,7 +3451,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
if (state->need_capacity)
flags |= CRN_NEED_CAPACITY;
}
- if (options->_AllowInvalid & ALLOW_INVALID_ENTRY)
+ if (options->AllowInvalid_ & ALLOW_INVALID_ENTRY)
flags |= CRN_ALLOW_INVALID;
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
@@ -3783,7 +3479,7 @@ onion_next_hop_in_cpath(crypt_path_t *cpath)
static int
onion_extend_cpath(origin_circuit_t *circ)
{
- uint8_t purpose = circ->_base.purpose;
+ uint8_t purpose = circ->base_.purpose;
cpath_build_state_t *state = circ->build_state;
int cur_len = circuit_get_cpath_len(circ);
extend_info_t *info = NULL;
@@ -3802,12 +3498,10 @@ onion_extend_cpath(origin_circuit_t *circ)
} else if (cur_len == 0) { /* picking first node */
const node_t *r = choose_good_entry_server(purpose, state);
if (r) {
- /* If we're extending to a bridge, use the preferred address
- rather than the primary, for potentially extending to an IPv6
- bridge. */
- int use_pref_addr = (r->ri != NULL &&
- r->ri->purpose == ROUTER_PURPOSE_BRIDGE);
- info = extend_info_from_node(r, use_pref_addr);
+ /* If we're a client, use the preferred address rather than the
+ primary address, for potentially connecting to an IPv6 OR
+ port. */
+ info = extend_info_from_node(r, server_mode(get_options()) == 0);
tor_assert(info);
}
} else {
@@ -3858,9 +3552,10 @@ onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice)
/** Allocate a new extend_info object based on the various arguments. */
extend_info_t *
-extend_info_alloc(const char *nickname, const char *digest,
- crypto_pk_t *onion_key,
- const tor_addr_t *addr, uint16_t port)
+extend_info_new(const char *nickname, const char *digest,
+ crypto_pk_t *onion_key,
+ const curve25519_public_key_t *curve25519_key,
+ const tor_addr_t *addr, uint16_t port)
{
extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t));
memcpy(info->identity_digest, digest, DIGEST_LEN);
@@ -3868,52 +3563,59 @@ extend_info_alloc(const char *nickname, const char *digest,
strlcpy(info->nickname, nickname, sizeof(info->nickname));
if (onion_key)
info->onion_key = crypto_pk_dup_key(onion_key);
+#ifdef CURVE25519_ENABLED
+ if (curve25519_key)
+ memcpy(&info->curve25519_onion_key, curve25519_key,
+ sizeof(curve25519_public_key_t));
+#else
+ (void)curve25519_key;
+#endif
tor_addr_copy(&info->addr, addr);
info->port = port;
return info;
}
-/** Allocate and return a new extend_info_t that can be used to build
- * a circuit to or through the router <b>r</b>. Use the primary
- * address of the router unless <b>for_direct_connect</b> is true, in
- * which case the preferred address is used instead. */
+/** Allocate and return a new extend_info that can be used to build a
+ * circuit to or through the node <b>node</b>. Use the primary address
+ * of the node (i.e. its IPv4 address) unless
+ * <b>for_direct_connect</b> is true, in which case the preferred
+ * address is used instead. May return NULL if there is not enough
+ * info about <b>node</b> to extend to it--for example, if there is no
+ * routerinfo_t or microdesc_t.
+ **/
extend_info_t *
-extend_info_from_router(const routerinfo_t *r, int for_direct_connect)
+extend_info_from_node(const node_t *node, int for_direct_connect)
{
tor_addr_port_t ap;
- tor_assert(r);
+
+ if (node->ri == NULL && (node->rs == NULL || node->md == NULL))
+ return NULL;
if (for_direct_connect)
- router_get_pref_orport(r, &ap);
+ node_get_pref_orport(node, &ap);
else
- router_get_prim_orport(r, &ap);
- return extend_info_alloc(r->nickname, r->cache_info.identity_digest,
- r->onion_pkey, &ap.addr, ap.port);
-}
+ node_get_prim_orport(node, &ap);
-/** Allocate and return a new extend_info that can be used to build a
- * circuit to or through the node <b>node</b>. Use the primary address
- * of the node unless <b>for_direct_connect</b> is true, in which case
- * the preferred address is used instead. May return NULL if there is
- * not enough info about <b>node</b> to extend to it--for example, if
- * there is no routerinfo_t or microdesc_t.
- **/
-extend_info_t *
-extend_info_from_node(const node_t *node, int for_direct_connect)
-{
- if (node->ri) {
- return extend_info_from_router(node->ri, for_direct_connect);
- } else if (node->rs && node->md) {
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, node->rs->addr);
- return extend_info_alloc(node->rs->nickname,
+ log_debug(LD_CIRC, "using %s for %s",
+ fmt_addrport(&ap.addr, ap.port),
+ node->ri ? node->ri->nickname : node->rs->nickname);
+
+ if (node->ri)
+ return extend_info_new(node->ri->nickname,
+ node->identity,
+ node->ri->onion_pkey,
+ node->ri->onion_curve25519_pkey,
+ &ap.addr,
+ ap.port);
+ else if (node->rs && node->md)
+ return extend_info_new(node->rs->nickname,
node->identity,
node->md->onion_pkey,
- &addr,
- node->rs->or_port);
- } else {
+ node->md->onion_curve25519_pkey,
+ &ap.addr,
+ ap.port);
+ else
return NULL;
- }
}
/** Release storage held by an extend_info_t struct. */
@@ -3966,2067 +3668,3 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
return state->chosen_exit->nickname;
}
-/** Check whether the entry guard <b>e</b> is usable, given the directory
- * authorities' opinion about the router (stored in <b>ri</b>) and the user's
- * configuration (in <b>options</b>). Set <b>e</b>-&gt;bad_since
- * accordingly. Return true iff the entry guard's status changes.
- *
- * If it's not usable, set *<b>reason</b> to a static string explaining why.
- */
-static int
-entry_guard_set_status(entry_guard_t *e, const node_t *node,
- time_t now, const or_options_t *options,
- const char **reason)
-{
- char buf[HEX_DIGEST_LEN+1];
- int changed = 0;
-
- *reason = NULL;
-
- /* Do we want to mark this guard as bad? */
- if (!node)
- *reason = "unlisted";
- else if (!node->is_running)
- *reason = "down";
- else if (options->UseBridges && (!node->ri ||
- node->ri->purpose != ROUTER_PURPOSE_BRIDGE))
- *reason = "not a bridge";
- else if (options->UseBridges && !node_is_a_configured_bridge(node))
- *reason = "not a configured bridge";
- else if (!options->UseBridges && !node->is_possible_guard &&
- !routerset_contains_node(options->EntryNodes,node))
- *reason = "not recommended as a guard";
- else if (routerset_contains_node(options->ExcludeNodes, node))
- *reason = "excluded";
- else if (e->path_bias_disabled)
- *reason = "path-biased";
-
- if (*reason && ! e->bad_since) {
- /* Router is newly bad. */
- base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
- log_info(LD_CIRC, "Entry guard %s (%s) is %s: marking as unusable.",
- e->nickname, buf, *reason);
-
- e->bad_since = now;
- control_event_guard(e->nickname, e->identity, "BAD");
- changed = 1;
- } else if (!*reason && e->bad_since) {
- /* There's nothing wrong with the router any more. */
- base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
- log_info(LD_CIRC, "Entry guard %s (%s) is no longer unusable: "
- "marking as ok.", e->nickname, buf);
-
- e->bad_since = 0;
- control_event_guard(e->nickname, e->identity, "GOOD");
- changed = 1;
- }
- return changed;
-}
-
-/** Return true iff enough time has passed since we last tried to connect
- * to the unreachable guard <b>e</b> that we're willing to try again. */
-static int
-entry_is_time_to_retry(entry_guard_t *e, time_t now)
-{
- long diff;
- if (e->last_attempted < e->unreachable_since)
- return 1;
- diff = now - e->unreachable_since;
- if (diff < 6*60*60)
- return now > (e->last_attempted + 60*60);
- else if (diff < 3*24*60*60)
- return now > (e->last_attempted + 4*60*60);
- else if (diff < 7*24*60*60)
- return now > (e->last_attempted + 18*60*60);
- else
- return now > (e->last_attempted + 36*60*60);
-}
-
-/** Return the node corresponding to <b>e</b>, if <b>e</b> is
- * working well enough that we are willing to use it as an entry
- * right now. (Else return NULL.) In particular, it must be
- * - Listed as either up or never yet contacted;
- * - Present in the routerlist;
- * - Listed as 'stable' or 'fast' by the current dirserver consensus,
- * if demanded by <b>need_uptime</b> or <b>need_capacity</b>
- * (unless it's a configured EntryNode);
- * - Allowed by our current ReachableORAddresses config option; and
- * - Currently thought to be reachable by us (unless <b>assume_reachable</b>
- * is true).
- *
- * If the answer is no, set *<b>msg</b> to an explanation of why.
- */
-static INLINE const node_t *
-entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity,
- int assume_reachable, const char **msg)
-{
- const node_t *node;
- const or_options_t *options = get_options();
- tor_assert(msg);
-
- if (e->path_bias_disabled) {
- *msg = "path-biased";
- return NULL;
- }
- if (e->bad_since) {
- *msg = "bad";
- return NULL;
- }
- /* no good if it's unreachable, unless assume_unreachable or can_retry. */
- if (!assume_reachable && !e->can_retry &&
- e->unreachable_since && !entry_is_time_to_retry(e, time(NULL))) {
- *msg = "unreachable";
- return NULL;
- }
- node = node_get_by_id(e->identity);
- if (!node || !node_has_descriptor(node)) {
- *msg = "no descriptor";
- return NULL;
- }
- if (get_options()->UseBridges) {
- if (node_get_purpose(node) != ROUTER_PURPOSE_BRIDGE) {
- *msg = "not a bridge";
- return NULL;
- }
- if (!node_is_a_configured_bridge(node)) {
- *msg = "not a configured bridge";
- return NULL;
- }
- } else { /* !get_options()->UseBridges */
- if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) {
- *msg = "not general-purpose";
- return NULL;
- }
- }
- if (routerset_contains_node(options->EntryNodes, node)) {
- /* they asked for it, they get it */
- need_uptime = need_capacity = 0;
- }
- if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
- *msg = "not fast/stable";
- return NULL;
- }
- if (!fascist_firewall_allows_node(node)) {
- *msg = "unreachable by config";
- return NULL;
- }
- return node;
-}
-
-/** Return the number of entry guards that we think are usable. */
-static int
-num_live_entry_guards(void)
-{
- int n = 0;
- const char *msg;
- if (! entry_guards)
- return 0;
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- {
- if (entry_is_live(entry, 0, 1, 0, &msg))
- ++n;
- });
- return n;
-}
-
-/** If <b>digest</b> matches the identity of any node in the
- * entry_guards list, return that node. Else return NULL. */
-static entry_guard_t *
-entry_guard_get_by_id_digest(const char *digest)
-{
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- if (tor_memeq(digest, entry->identity, DIGEST_LEN))
- return entry;
- );
- return NULL;
-}
-
-/** Dump a description of our list of entry guards to the log at level
- * <b>severity</b>. */
-static void
-log_entry_guards(int severity)
-{
- smartlist_t *elements = smartlist_new();
- char *s;
-
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e)
- {
- const char *msg = NULL;
- if (entry_is_live(e, 0, 1, 0, &msg))
- smartlist_add_asprintf(elements, "%s [%s] (up %s)",
- e->nickname,
- hex_str(e->identity, DIGEST_LEN),
- e->made_contact ? "made-contact" : "never-contacted");
- else
- smartlist_add_asprintf(elements, "%s [%s] (%s, %s)",
- e->nickname,
- hex_str(e->identity, DIGEST_LEN),
- msg,
- e->made_contact ? "made-contact" : "never-contacted");
- }
- SMARTLIST_FOREACH_END(e);
-
- s = smartlist_join_strings(elements, ",", 0, NULL);
- SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp));
- smartlist_free(elements);
- log_fn(severity,LD_CIRC,"%s",s);
- tor_free(s);
-}
-
-/** Called when one or more guards that we would previously have used for some
- * purpose are no longer in use because a higher-priority guard has become
- * usable again. */
-static void
-control_event_guard_deferred(void)
-{
- /* XXXX We don't actually have a good way to figure out _how many_ entries
- * are live for some purpose. We need an entry_is_even_slightly_live()
- * function for this to work right. NumEntryGuards isn't reliable: if we
- * need guards with weird properties, we can have more than that number
- * live.
- **/
-#if 0
- int n = 0;
- const char *msg;
- const or_options_t *options = get_options();
- if (!entry_guards)
- return;
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- {
- if (entry_is_live(entry, 0, 1, 0, &msg)) {
- if (n++ == options->NumEntryGuards) {
- control_event_guard(entry->nickname, entry->identity, "DEFERRED");
- return;
- }
- }
- });
-#endif
-}
-
-/** Add a new (preferably stable and fast) router to our
- * entry_guards list. Return a pointer to the router if we succeed,
- * or NULL if we can't find any more suitable entries.
- *
- * If <b>chosen</b> is defined, use that one, and if it's not
- * already in our entry_guards list, put it at the *beginning*.
- * Else, put the one we pick at the end of the list. */
-static const node_t *
-add_an_entry_guard(const node_t *chosen, int reset_status, int prepend)
-{
- const node_t *node;
- entry_guard_t *entry;
-
- if (chosen) {
- node = chosen;
- entry = entry_guard_get_by_id_digest(node->identity);
- if (entry) {
- if (reset_status) {
- entry->bad_since = 0;
- entry->can_retry = 1;
- }
- return NULL;
- }
- } else {
- node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL);
- if (!node)
- return NULL;
- }
- entry = tor_malloc_zero(sizeof(entry_guard_t));
- log_info(LD_CIRC, "Chose %s as new entry guard.",
- node_describe(node));
- strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname));
- memcpy(entry->identity, node->identity, DIGEST_LEN);
- /* Choose expiry time smudged over the past month. The goal here
- * is to a) spread out when Tor clients rotate their guards, so they
- * don't all select them on the same day, and b) avoid leaving a
- * precise timestamp in the state file about when we first picked
- * this guard. For details, see the Jan 2010 or-dev thread. */
- entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
- entry->chosen_by_version = tor_strdup(VERSION);
- if (prepend)
- smartlist_insert(entry_guards, 0, entry);
- else
- smartlist_add(entry_guards, entry);
- control_event_guard(entry->nickname, entry->identity, "NEW");
- control_event_guard_deferred();
- log_entry_guards(LOG_INFO);
- return node;
-}
-
-/** If the use of entry guards is configured, choose more entry guards
- * until we have enough in the list. */
-static void
-pick_entry_guards(const or_options_t *options)
-{
- int changed = 0;
-
- tor_assert(entry_guards);
-
- while (num_live_entry_guards() < options->NumEntryGuards) {
- if (!add_an_entry_guard(NULL, 0, 0))
- break;
- changed = 1;
- }
- if (changed)
- entry_guards_changed();
-}
-
-/** How long (in seconds) do we allow an entry guard to be nonfunctional,
- * unlisted, excluded, or otherwise nonusable before we give up on it? */
-#define ENTRY_GUARD_REMOVE_AFTER (30*24*60*60)
-
-/** Release all storage held by <b>e</b>. */
-static void
-entry_guard_free(entry_guard_t *e)
-{
- if (!e)
- return;
- tor_free(e->chosen_by_version);
- tor_free(e);
-}
-
-/** Remove any entry guard which was selected by an unknown version of Tor,
- * or which was selected by a version of Tor that's known to select
- * entry guards badly, or which was selected more 2 months ago. */
-/* XXXX The "obsolete guards" and "chosen long ago guards" things should
- * probably be different functions. */
-static int
-remove_obsolete_entry_guards(time_t now)
-{
- int changed = 0, i;
-
- for (i = 0; i < smartlist_len(entry_guards); ++i) {
- entry_guard_t *entry = smartlist_get(entry_guards, i);
- const char *ver = entry->chosen_by_version;
- const char *msg = NULL;
- tor_version_t v;
- int version_is_bad = 0, date_is_bad = 0;
- if (!ver) {
- msg = "does not say what version of Tor it was selected by";
- version_is_bad = 1;
- } else if (tor_version_parse(ver, &v)) {
- msg = "does not seem to be from any recognized version of Tor";
- version_is_bad = 1;
- } else {
- char *tor_ver = NULL;
- tor_asprintf(&tor_ver, "Tor %s", ver);
- if ((tor_version_as_new_as(tor_ver, "0.1.0.10-alpha") &&
- !tor_version_as_new_as(tor_ver, "0.1.2.16-dev")) ||
- (tor_version_as_new_as(tor_ver, "0.2.0.0-alpha") &&
- !tor_version_as_new_as(tor_ver, "0.2.0.6-alpha")) ||
- /* above are bug 440; below are bug 1217 */
- (tor_version_as_new_as(tor_ver, "0.2.1.3-alpha") &&
- !tor_version_as_new_as(tor_ver, "0.2.1.23")) ||
- (tor_version_as_new_as(tor_ver, "0.2.2.0-alpha") &&
- !tor_version_as_new_as(tor_ver, "0.2.2.7-alpha"))) {
- msg = "was selected without regard for guard bandwidth";
- version_is_bad = 1;
- }
- tor_free(tor_ver);
- }
- if (!version_is_bad && entry->chosen_on_date + 3600*24*60 < now) {
- /* It's been 2 months since the date listed in our state file. */
- msg = "was selected several months ago";
- date_is_bad = 1;
- }
-
- if (version_is_bad || date_is_bad) { /* we need to drop it */
- char dbuf[HEX_DIGEST_LEN+1];
- tor_assert(msg);
- base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
- log_fn(version_is_bad ? LOG_NOTICE : LOG_INFO, LD_CIRC,
- "Entry guard '%s' (%s) %s. (Version=%s.) Replacing it.",
- entry->nickname, dbuf, msg, ver?escaped(ver):"none");
- control_event_guard(entry->nickname, entry->identity, "DROPPED");
- entry_guard_free(entry);
- smartlist_del_keeporder(entry_guards, i--);
- log_entry_guards(LOG_INFO);
- changed = 1;
- }
- }
-
- return changed ? 1 : 0;
-}
-
-/** Remove all entry guards that have been down or unlisted for so
- * long that we don't think they'll come up again. Return 1 if we
- * removed any, or 0 if we did nothing. */
-static int
-remove_dead_entry_guards(time_t now)
-{
- char dbuf[HEX_DIGEST_LEN+1];
- char tbuf[ISO_TIME_LEN+1];
- int i;
- int changed = 0;
-
- for (i = 0; i < smartlist_len(entry_guards); ) {
- entry_guard_t *entry = smartlist_get(entry_guards, i);
- if (entry->bad_since &&
- ! entry->path_bias_disabled &&
- entry->bad_since + ENTRY_GUARD_REMOVE_AFTER < now) {
-
- base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
- format_local_iso_time(tbuf, entry->bad_since);
- log_info(LD_CIRC, "Entry guard '%s' (%s) has been down or unlisted "
- "since %s local time; removing.",
- entry->nickname, dbuf, tbuf);
- control_event_guard(entry->nickname, entry->identity, "DROPPED");
- entry_guard_free(entry);
- smartlist_del_keeporder(entry_guards, i);
- log_entry_guards(LOG_INFO);
- changed = 1;
- } else
- ++i;
- }
- return changed ? 1 : 0;
-}
-
-/** A new directory or router-status has arrived; update the down/listed
- * status of the entry guards.
- *
- * An entry is 'down' if the directory lists it as nonrunning.
- * An entry is 'unlisted' if the directory doesn't include it.
- *
- * Don't call this on startup; only on a fresh download. Otherwise we'll
- * think that things are unlisted.
- */
-void
-entry_guards_compute_status(const or_options_t *options, time_t now)
-{
- int changed = 0;
- digestmap_t *reasons;
-
- if (! entry_guards)
- return;
-
- if (options->EntryNodes) /* reshuffle the entry guard list if needed */
- entry_nodes_should_be_added();
-
- reasons = digestmap_new();
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry)
- {
- const node_t *r = node_get_by_id(entry->identity);
- const char *reason = NULL;
- if (entry_guard_set_status(entry, r, now, options, &reason))
- changed = 1;
-
- if (entry->bad_since)
- tor_assert(reason);
- if (reason)
- digestmap_set(reasons, entry->identity, (char*)reason);
- }
- SMARTLIST_FOREACH_END(entry);
-
- if (remove_dead_entry_guards(now))
- changed = 1;
- if (remove_obsolete_entry_guards(now))
- changed = 1;
-
- if (changed) {
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
- const char *reason = digestmap_get(reasons, entry->identity);
- const char *live_msg = "";
- const node_t *r = entry_is_live(entry, 0, 1, 0, &live_msg);
- log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.",
- entry->nickname,
- hex_str(entry->identity, DIGEST_LEN),
- entry->unreachable_since ? "unreachable" : "reachable",
- entry->bad_since ? "unusable" : "usable",
- reason ? ", ": "",
- reason ? reason : "",
- r ? "live" : "not live / ",
- r ? "" : live_msg);
- } SMARTLIST_FOREACH_END(entry);
- log_info(LD_CIRC, " (%d/%d entry guards are usable/new)",
- num_live_entry_guards(), smartlist_len(entry_guards));
- log_entry_guards(LOG_INFO);
- entry_guards_changed();
- }
-
- digestmap_free(reasons, NULL);
-}
-
-/** Called when a connection to an OR with the identity digest <b>digest</b>
- * is established (<b>succeeded</b>==1) or has failed (<b>succeeded</b>==0).
- * If the OR is an entry, change that entry's up/down status.
- * Return 0 normally, or -1 if we want to tear down the new connection.
- *
- * If <b>mark_relay_status</b>, also call router_set_status() on this
- * relay.
- *
- * XXX024 change succeeded and mark_relay_status into 'int flags'.
- */
-int
-entry_guard_register_connect_status(const char *digest, int succeeded,
- int mark_relay_status, time_t now)
-{
- int changed = 0;
- int refuse_conn = 0;
- int first_contact = 0;
- entry_guard_t *entry = NULL;
- int idx = -1;
- char buf[HEX_DIGEST_LEN+1];
-
- if (! entry_guards)
- return 0;
-
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- tor_assert(e);
- if (tor_memeq(e->identity, digest, DIGEST_LEN)) {
- entry = e;
- idx = e_sl_idx;
- break;
- }
- } SMARTLIST_FOREACH_END(e);
-
- if (!entry)
- return 0;
-
- base16_encode(buf, sizeof(buf), entry->identity, DIGEST_LEN);
-
- if (succeeded) {
- if (entry->unreachable_since) {
- log_info(LD_CIRC, "Entry guard '%s' (%s) is now reachable again. Good.",
- entry->nickname, buf);
- entry->can_retry = 0;
- entry->unreachable_since = 0;
- entry->last_attempted = now;
- control_event_guard(entry->nickname, entry->identity, "UP");
- changed = 1;
- }
- if (!entry->made_contact) {
- entry->made_contact = 1;
- first_contact = changed = 1;
- }
- } else { /* ! succeeded */
- if (!entry->made_contact) {
- /* We've never connected to this one. */
- log_info(LD_CIRC,
- "Connection to never-contacted entry guard '%s' (%s) failed. "
- "Removing from the list. %d/%d entry guards usable/new.",
- entry->nickname, buf,
- num_live_entry_guards()-1, smartlist_len(entry_guards)-1);
- control_event_guard(entry->nickname, entry->identity, "DROPPED");
- entry_guard_free(entry);
- smartlist_del_keeporder(entry_guards, idx);
- log_entry_guards(LOG_INFO);
- changed = 1;
- } else if (!entry->unreachable_since) {
- log_info(LD_CIRC, "Unable to connect to entry guard '%s' (%s). "
- "Marking as unreachable.", entry->nickname, buf);
- entry->unreachable_since = entry->last_attempted = now;
- control_event_guard(entry->nickname, entry->identity, "DOWN");
- changed = 1;
- entry->can_retry = 0; /* We gave it an early chance; no good. */
- } else {
- char tbuf[ISO_TIME_LEN+1];
- format_iso_time(tbuf, entry->unreachable_since);
- log_debug(LD_CIRC, "Failed to connect to unreachable entry guard "
- "'%s' (%s). It has been unreachable since %s.",
- entry->nickname, buf, tbuf);
- entry->last_attempted = now;
- entry->can_retry = 0; /* We gave it an early chance; no good. */
- }
- }
-
- /* if the caller asked us to, also update the is_running flags for this
- * relay */
- if (mark_relay_status)
- router_set_status(digest, succeeded);
-
- if (first_contact) {
- /* We've just added a new long-term entry guard. Perhaps the network just
- * came back? We should give our earlier entries another try too,
- * and close this connection so we don't use it before we've given
- * the others a shot. */
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- if (e == entry)
- break;
- if (e->made_contact) {
- const char *msg;
- const node_t *r = entry_is_live(e, 0, 1, 1, &msg);
- if (r && e->unreachable_since) {
- refuse_conn = 1;
- e->can_retry = 1;
- }
- }
- } SMARTLIST_FOREACH_END(e);
- if (refuse_conn) {
- log_info(LD_CIRC,
- "Connected to new entry guard '%s' (%s). Marking earlier "
- "entry guards up. %d/%d entry guards usable/new.",
- entry->nickname, buf,
- num_live_entry_guards(), smartlist_len(entry_guards));
- log_entry_guards(LOG_INFO);
- changed = 1;
- }
- }
-
- if (changed)
- entry_guards_changed();
- return refuse_conn ? -1 : 0;
-}
-
-/** When we try to choose an entry guard, should we parse and add
- * config's EntryNodes first? */
-static int should_add_entry_nodes = 0;
-
-/** Called when the value of EntryNodes changes in our configuration. */
-void
-entry_nodes_should_be_added(void)
-{
- log_info(LD_CIRC, "EntryNodes config option set. Putting configured "
- "relays at the front of the entry guard list.");
- should_add_entry_nodes = 1;
-}
-
-/** Adjust the entry guards list so that it only contains entries from
- * EntryNodes, adding new entries from EntryNodes to the list as needed. */
-static void
-entry_guards_set_from_config(const or_options_t *options)
-{
- smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps;
- smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list;
- tor_assert(entry_guards);
-
- should_add_entry_nodes = 0;
-
- if (!options->EntryNodes) {
- /* It's possible that a controller set EntryNodes, thus making
- * should_add_entry_nodes set, then cleared it again, all before the
- * call to choose_random_entry() that triggered us. If so, just return.
- */
- return;
- }
-
- {
- char *string = routerset_to_string(options->EntryNodes);
- log_info(LD_CIRC,"Adding configured EntryNodes '%s'.", string);
- tor_free(string);
- }
-
- entry_nodes = smartlist_new();
- worse_entry_nodes = smartlist_new();
- entry_fps = smartlist_new();
- old_entry_guards_on_list = smartlist_new();
- old_entry_guards_not_on_list = smartlist_new();
-
- /* Split entry guards into those on the list and those not. */
-
- routerset_get_all_nodes(entry_nodes, options->EntryNodes,
- options->ExcludeNodes, 0);
- SMARTLIST_FOREACH(entry_nodes, const node_t *,node,
- smartlist_add(entry_fps, (void*)node->identity));
-
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, {
- if (smartlist_digest_isin(entry_fps, e->identity))
- smartlist_add(old_entry_guards_on_list, e);
- else
- smartlist_add(old_entry_guards_not_on_list, e);
- });
-
- /* Remove all currently configured guard nodes, excluded nodes, unreachable
- * nodes, or non-Guard nodes from entry_nodes. */
- SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
- if (entry_guard_get_by_id_digest(node->identity)) {
- SMARTLIST_DEL_CURRENT(entry_nodes, node);
- continue;
- } else if (routerset_contains_node(options->ExcludeNodes, node)) {
- SMARTLIST_DEL_CURRENT(entry_nodes, node);
- continue;
- } else if (!fascist_firewall_allows_node(node)) {
- SMARTLIST_DEL_CURRENT(entry_nodes, node);
- continue;
- } else if (! node->is_possible_guard) {
- smartlist_add(worse_entry_nodes, (node_t*)node);
- SMARTLIST_DEL_CURRENT(entry_nodes, node);
- }
- } SMARTLIST_FOREACH_END(node);
-
- /* Now build the new entry_guards list. */
- smartlist_clear(entry_guards);
- /* First, the previously configured guards that are in EntryNodes. */
- smartlist_add_all(entry_guards, old_entry_guards_on_list);
- /* Next, scramble the rest of EntryNodes, putting the guards first. */
- smartlist_shuffle(entry_nodes);
- smartlist_shuffle(worse_entry_nodes);
- smartlist_add_all(entry_nodes, worse_entry_nodes);
-
- /* Next, the rest of EntryNodes */
- SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
- add_an_entry_guard(node, 0, 0);
- if (smartlist_len(entry_guards) > options->NumEntryGuards * 10)
- break;
- } SMARTLIST_FOREACH_END(node);
- log_notice(LD_GENERAL, "%d entries in guards", smartlist_len(entry_guards));
- /* Finally, free the remaining previously configured guards that are not in
- * EntryNodes. */
- SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
- entry_guard_free(e));
-
- smartlist_free(entry_nodes);
- smartlist_free(worse_entry_nodes);
- smartlist_free(entry_fps);
- smartlist_free(old_entry_guards_on_list);
- smartlist_free(old_entry_guards_not_on_list);
- entry_guards_changed();
-}
-
-/** Return 0 if we're fine adding arbitrary routers out of the
- * directory to our entry guard list, or return 1 if we have a
- * list already and we must stick to it.
- */
-int
-entry_list_is_constrained(const or_options_t *options)
-{
- if (options->EntryNodes)
- return 1;
- if (options->UseBridges)
- return 1;
- return 0;
-}
-
-/** Pick a live (up and listed) entry guard from entry_guards. If
- * <b>state</b> is non-NULL, this is for a specific circuit --
- * make sure not to pick this circuit's exit or any node in the
- * exit's family. If <b>state</b> is NULL, we're looking for a random
- * guard (likely a bridge). */
-const node_t *
-choose_random_entry(cpath_build_state_t *state)
-{
- const or_options_t *options = get_options();
- smartlist_t *live_entry_guards = smartlist_new();
- smartlist_t *exit_family = smartlist_new();
- const node_t *chosen_exit =
- state?build_state_get_exit_node(state) : NULL;
- const node_t *node = NULL;
- int need_uptime = state ? state->need_uptime : 0;
- int need_capacity = state ? state->need_capacity : 0;
- int preferred_min, consider_exit_family = 0;
-
- if (chosen_exit) {
- nodelist_add_node_and_family(exit_family, chosen_exit);
- consider_exit_family = 1;
- }
-
- if (!entry_guards)
- entry_guards = smartlist_new();
-
- if (should_add_entry_nodes)
- entry_guards_set_from_config(options);
-
- if (!entry_list_is_constrained(options) &&
- smartlist_len(entry_guards) < options->NumEntryGuards)
- pick_entry_guards(options);
-
- retry:
- smartlist_clear(live_entry_guards);
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
- const char *msg;
- node = entry_is_live(entry, need_uptime, need_capacity, 0, &msg);
- if (!node)
- continue; /* down, no point */
- if (node == chosen_exit)
- continue; /* don't pick the same node for entry and exit */
- if (consider_exit_family && smartlist_isin(exit_family, node))
- continue; /* avoid relays that are family members of our exit */
-#if 0 /* since EntryNodes is always strict now, this clause is moot */
- if (options->EntryNodes &&
- !routerset_contains_node(options->EntryNodes, node)) {
- /* We've come to the end of our preferred entry nodes. */
- if (smartlist_len(live_entry_guards))
- goto choose_and_finish; /* only choose from the ones we like */
- if (options->StrictNodes) {
- /* in theory this case should never happen, since
- * entry_guards_set_from_config() drops unwanted relays */
- tor_fragile_assert();
- } else {
- log_info(LD_CIRC,
- "No relays from EntryNodes available. Using others.");
- }
- }
-#endif
- smartlist_add(live_entry_guards, (void*)node);
- if (!entry->made_contact) {
- /* Always start with the first not-yet-contacted entry
- * guard. Otherwise we might add several new ones, pick
- * the second new one, and now we've expanded our entry
- * guard list without needing to. */
- goto choose_and_finish;
- }
- if (smartlist_len(live_entry_guards) >= options->NumEntryGuards)
- goto choose_and_finish; /* we have enough */
- } SMARTLIST_FOREACH_END(entry);
-
- if (entry_list_is_constrained(options)) {
- /* If we prefer the entry nodes we've got, and we have at least
- * one choice, that's great. Use it. */
- preferred_min = 1;
- } else {
- /* Try to have at least 2 choices available. This way we don't
- * get stuck with a single live-but-crummy entry and just keep
- * using him.
- * (We might get 2 live-but-crummy entry guards, but so be it.) */
- preferred_min = 2;
- }
-
- if (smartlist_len(live_entry_guards) < preferred_min) {
- if (!entry_list_is_constrained(options)) {
- /* still no? try adding a new entry then */
- /* XXX if guard doesn't imply fast and stable, then we need
- * to tell add_an_entry_guard below what we want, or it might
- * be a long time til we get it. -RD */
- node = add_an_entry_guard(NULL, 0, 0);
- if (node) {
- entry_guards_changed();
- /* XXX we start over here in case the new node we added shares
- * a family with our exit node. There's a chance that we'll just
- * load up on entry guards here, if the network we're using is
- * one big family. Perhaps we should teach add_an_entry_guard()
- * to understand nodes-to-avoid-if-possible? -RD */
- goto retry;
- }
- }
- if (!node && need_uptime) {
- need_uptime = 0; /* try without that requirement */
- goto retry;
- }
- if (!node && need_capacity) {
- /* still no? last attempt, try without requiring capacity */
- need_capacity = 0;
- goto retry;
- }
-#if 0
- /* Removing this retry logic: if we only allow one exit, and it is in the
- same family as all our entries, then we are just plain not going to win
- here. */
- if (!node && entry_list_is_constrained(options) && consider_exit_family) {
- /* still no? if we're using bridges or have strictentrynodes
- * set, and our chosen exit is in the same family as all our
- * bridges/entry guards, then be flexible about families. */
- consider_exit_family = 0;
- goto retry;
- }
-#endif
- /* live_entry_guards may be empty below. Oh well, we tried. */
- }
-
- choose_and_finish:
- if (entry_list_is_constrained(options)) {
- /* We need to weight by bandwidth, because our bridges or entryguards
- * were not already selected proportional to their bandwidth. */
- node = node_sl_choose_by_bandwidth(live_entry_guards, WEIGHT_FOR_GUARD);
- } else {
- /* We choose uniformly at random here, because choose_good_entry_server()
- * already weights its choices by bandwidth, so we don't want to
- * *double*-weight our guard selection. */
- node = smartlist_choose(live_entry_guards);
- }
- smartlist_free(live_entry_guards);
- smartlist_free(exit_family);
- return node;
-}
-
-/** Parse <b>state</b> and learn about the entry guards it describes.
- * If <b>set</b> is true, and there are no errors, replace the global
- * entry_list with what we find.
- * On success, return 0. On failure, alloc into *<b>msg</b> a string
- * describing the error, and return -1.
- */
-int
-entry_guards_parse_state(or_state_t *state, int set, char **msg)
-{
- entry_guard_t *node = NULL;
- smartlist_t *new_entry_guards = smartlist_new();
- config_line_t *line;
- time_t now = time(NULL);
- const char *state_version = state->TorVersion;
- digestmap_t *added_by = digestmap_new();
-
- *msg = NULL;
- for (line = state->EntryGuards; line; line = line->next) {
- if (!strcasecmp(line->key, "EntryGuard")) {
- smartlist_t *args = smartlist_new();
- node = tor_malloc_zero(sizeof(entry_guard_t));
- /* all entry guards on disk have been contacted */
- node->made_contact = 1;
- smartlist_add(new_entry_guards, node);
- smartlist_split_string(args, line->value, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- if (smartlist_len(args)<2) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Too few arguments to EntryGuard");
- } else if (!is_legal_nickname(smartlist_get(args,0))) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Bad nickname for EntryGuard");
- } else {
- strlcpy(node->nickname, smartlist_get(args,0), MAX_NICKNAME_LEN+1);
- if (base16_decode(node->identity, DIGEST_LEN, smartlist_get(args,1),
- strlen(smartlist_get(args,1)))<0) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Bad hex digest for EntryGuard");
- }
- }
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- if (*msg)
- break;
- } else if (!strcasecmp(line->key, "EntryGuardDownSince") ||
- !strcasecmp(line->key, "EntryGuardUnlistedSince")) {
- time_t when;
- time_t last_try = 0;
- if (!node) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "EntryGuardDownSince/UnlistedSince without EntryGuard");
- break;
- }
- if (parse_iso_time(line->value, &when)<0) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Bad time in EntryGuardDownSince/UnlistedSince");
- break;
- }
- if (when > now) {
- /* It's a bad idea to believe info in the future: you can wind
- * up with timeouts that aren't allowed to happen for years. */
- continue;
- }
- if (strlen(line->value) >= ISO_TIME_LEN+ISO_TIME_LEN+1) {
- /* ignore failure */
- (void) parse_iso_time(line->value+ISO_TIME_LEN+1, &last_try);
- }
- if (!strcasecmp(line->key, "EntryGuardDownSince")) {
- node->unreachable_since = when;
- node->last_attempted = last_try;
- } else {
- node->bad_since = when;
- }
- } else if (!strcasecmp(line->key, "EntryGuardAddedBy")) {
- char d[DIGEST_LEN];
- /* format is digest version date */
- if (strlen(line->value) < HEX_DIGEST_LEN+1+1+1+ISO_TIME_LEN) {
- log_warn(LD_BUG, "EntryGuardAddedBy line is not long enough.");
- continue;
- }
- if (base16_decode(d, sizeof(d), line->value, HEX_DIGEST_LEN)<0 ||
- line->value[HEX_DIGEST_LEN] != ' ') {
- log_warn(LD_BUG, "EntryGuardAddedBy line %s does not begin with "
- "hex digest", escaped(line->value));
- continue;
- }
- digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1));
- } else if (!strcasecmp(line->key, "EntryGuardPathBias")) {
- const or_options_t *options = get_options();
- unsigned hop_cnt, success_cnt;
-
- if (!node) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "EntryGuardPathBias without EntryGuard");
- break;
- }
-
- if (tor_sscanf(line->value, "%u %u", &success_cnt, &hop_cnt) != 2) {
- log_warn(LD_GENERAL, "Unable to parse guard path bias info: "
- "Misformated EntryGuardPathBias %s", escaped(line->value));
- continue;
- }
-
- node->first_hops = hop_cnt;
- node->circuit_successes = success_cnt;
- log_info(LD_GENERAL, "Read %u/%u path bias for node %s",
- node->circuit_successes, node->first_hops, node->nickname);
- /* Note: We rely on the < comparison here to allow us to set a 0
- * rate and disable the feature entirely. If refactoring, don't
- * change to <= */
- if (node->circuit_successes/((double)node->first_hops)
- < pathbias_get_disable_rate(options)) {
- node->path_bias_disabled = 1;
- log_info(LD_GENERAL,
- "Path bias is too high (%u/%u); disabling node %s",
- node->circuit_successes, node->first_hops, node->nickname);
- }
-
- } else {
- log_warn(LD_BUG, "Unexpected key %s", line->key);
- }
- }
-
- SMARTLIST_FOREACH_BEGIN(new_entry_guards, entry_guard_t *, e) {
- char *sp;
- char *val = digestmap_get(added_by, e->identity);
- if (val && (sp = strchr(val, ' '))) {
- time_t when;
- *sp++ = '\0';
- if (parse_iso_time(sp, &when)<0) {
- log_warn(LD_BUG, "Can't read time %s in EntryGuardAddedBy", sp);
- } else {
- e->chosen_by_version = tor_strdup(val);
- e->chosen_on_date = when;
- }
- } else {
- if (state_version) {
- e->chosen_by_version = tor_strdup(state_version);
- e->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
- }
- }
- if (e->path_bias_disabled && !e->bad_since)
- e->bad_since = time(NULL);
- }
- SMARTLIST_FOREACH_END(e);
-
- if (*msg || !set) {
- SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e,
- entry_guard_free(e));
- smartlist_free(new_entry_guards);
- } else { /* !err && set */
- if (entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
- entry_guard_free(e));
- smartlist_free(entry_guards);
- }
- entry_guards = new_entry_guards;
- entry_guards_dirty = 0;
- /* XXX024 hand new_entry_guards to this func, and move it up a
- * few lines, so we don't have to re-dirty it */
- if (remove_obsolete_entry_guards(now))
- entry_guards_dirty = 1;
- }
- digestmap_free(added_by, _tor_free);
- return *msg ? -1 : 0;
-}
-
-/** Our list of entry guards has changed, or some element of one
- * of our entry guards has changed. Write the changes to disk within
- * the next few minutes.
- */
-static void
-entry_guards_changed(void)
-{
- time_t when;
- entry_guards_dirty = 1;
-
- /* or_state_save() will call entry_guards_update_state(). */
- when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600;
- or_state_mark_dirty(get_or_state(), when);
-}
-
-/** If the entry guard info has not changed, do nothing and return.
- * Otherwise, free the EntryGuards piece of <b>state</b> and create
- * a new one out of the global entry_guards list, and then mark
- * <b>state</b> dirty so it will get saved to disk.
- */
-void
-entry_guards_update_state(or_state_t *state)
-{
- config_line_t **next, *line;
- if (! entry_guards_dirty)
- return;
-
- config_free_lines(state->EntryGuards);
- next = &state->EntryGuards;
- *next = NULL;
- if (!entry_guards)
- entry_guards = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- char dbuf[HEX_DIGEST_LEN+1];
- if (!e->made_contact)
- continue; /* don't write this one to disk */
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuard");
- base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN);
- tor_asprintf(&line->value, "%s %s", e->nickname, dbuf);
- next = &(line->next);
- if (e->unreachable_since) {
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardDownSince");
- line->value = tor_malloc(ISO_TIME_LEN+1+ISO_TIME_LEN+1);
- format_iso_time(line->value, e->unreachable_since);
- if (e->last_attempted) {
- line->value[ISO_TIME_LEN] = ' ';
- format_iso_time(line->value+ISO_TIME_LEN+1, e->last_attempted);
- }
- next = &(line->next);
- }
- if (e->bad_since) {
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardUnlistedSince");
- line->value = tor_malloc(ISO_TIME_LEN+1);
- format_iso_time(line->value, e->bad_since);
- next = &(line->next);
- }
- if (e->chosen_on_date && e->chosen_by_version &&
- !strchr(e->chosen_by_version, ' ')) {
- char d[HEX_DIGEST_LEN+1];
- char t[ISO_TIME_LEN+1];
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardAddedBy");
- base16_encode(d, sizeof(d), e->identity, DIGEST_LEN);
- format_iso_time(t, e->chosen_on_date);
- tor_asprintf(&line->value, "%s %s %s",
- d, e->chosen_by_version, t);
- next = &(line->next);
- }
- if (e->first_hops) {
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardPathBias");
- tor_asprintf(&line->value, "%u %u",
- e->circuit_successes, e->first_hops);
- next = &(line->next);
- }
-
- } SMARTLIST_FOREACH_END(e);
- if (!get_options()->AvoidDiskWrites)
- or_state_mark_dirty(get_or_state(), 0);
- entry_guards_dirty = 0;
-}
-
-/** If <b>question</b> is the string "entry-guards", then dump
- * to *<b>answer</b> a newly allocated string describing all of
- * the nodes in the global entry_guards list. See control-spec.txt
- * for details.
- * For backward compatibility, we also handle the string "helper-nodes".
- * */
-int
-getinfo_helper_entry_guards(control_connection_t *conn,
- const char *question, char **answer,
- const char **errmsg)
-{
- (void) conn;
- (void) errmsg;
-
- if (!strcmp(question,"entry-guards") ||
- !strcmp(question,"helper-nodes")) {
- smartlist_t *sl = smartlist_new();
- char tbuf[ISO_TIME_LEN+1];
- char nbuf[MAX_VERBOSE_NICKNAME_LEN+1];
- if (!entry_guards)
- entry_guards = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- const char *status = NULL;
- time_t when = 0;
- const node_t *node;
-
- if (!e->made_contact) {
- status = "never-connected";
- } else if (e->bad_since) {
- when = e->bad_since;
- status = "unusable";
- } else {
- status = "up";
- }
-
- node = node_get_by_id(e->identity);
- if (node) {
- node_get_verbose_nickname(node, nbuf);
- } else {
- nbuf[0] = '$';
- base16_encode(nbuf+1, sizeof(nbuf)-1, e->identity, DIGEST_LEN);
- /* e->nickname field is not very reliable if we don't know about
- * this router any longer; don't include it. */
- }
-
- if (when) {
- format_iso_time(tbuf, when);
- smartlist_add_asprintf(sl, "%s %s %s\n", nbuf, status, tbuf);
- } else {
- smartlist_add_asprintf(sl, "%s %s\n", nbuf, status);
- }
- } SMARTLIST_FOREACH_END(e);
- *answer = smartlist_join_strings(sl, "", 0, NULL);
- SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
- smartlist_free(sl);
- }
- return 0;
-}
-
-/** A list of configured bridges. Whenever we actually get a descriptor
- * for one, we add it as an entry guard. Note that the order of bridges
- * in this list does not necessarily correspond to the order of bridges
- * in the torrc. */
-static smartlist_t *bridge_list = NULL;
-
-/** Mark every entry of the bridge list to be removed on our next call to
- * sweep_bridge_list unless it has first been un-marked. */
-void
-mark_bridge_list(void)
-{
- if (!bridge_list)
- bridge_list = smartlist_new();
- SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b,
- b->marked_for_removal = 1);
-}
-
-/** Remove every entry of the bridge list that was marked with
- * mark_bridge_list if it has not subsequently been un-marked. */
-void
-sweep_bridge_list(void)
-{
- if (!bridge_list)
- bridge_list = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
- if (b->marked_for_removal) {
- SMARTLIST_DEL_CURRENT(bridge_list, b);
- bridge_free(b);
- }
- } SMARTLIST_FOREACH_END(b);
-}
-
-/** Initialize the bridge list to empty, creating it if needed. */
-static void
-clear_bridge_list(void)
-{
- if (!bridge_list)
- bridge_list = smartlist_new();
- SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, bridge_free(b));
- smartlist_clear(bridge_list);
-}
-
-/** Free the bridge <b>bridge</b>. */
-static void
-bridge_free(bridge_info_t *bridge)
-{
- if (!bridge)
- return;
-
- tor_free(bridge->transport_name);
- tor_free(bridge);
-}
-
-/** A list of pluggable transports found in torrc. */
-static smartlist_t *transport_list = NULL;
-
-/** Mark every entry of the transport list to be removed on our next call to
- * sweep_transport_list unless it has first been un-marked. */
-void
-mark_transport_list(void)
-{
- if (!transport_list)
- transport_list = smartlist_new();
- SMARTLIST_FOREACH(transport_list, transport_t *, t,
- t->marked_for_removal = 1);
-}
-
-/** Remove every entry of the transport list that was marked with
- * mark_transport_list if it has not subsequently been un-marked. */
-void
-sweep_transport_list(void)
-{
- if (!transport_list)
- transport_list = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, t) {
- if (t->marked_for_removal) {
- SMARTLIST_DEL_CURRENT(transport_list, t);
- transport_free(t);
- }
- } SMARTLIST_FOREACH_END(t);
-}
-
-/** Initialize the pluggable transports list to empty, creating it if
- * needed. */
-void
-clear_transport_list(void)
-{
- if (!transport_list)
- transport_list = smartlist_new();
- SMARTLIST_FOREACH(transport_list, transport_t *, t, transport_free(t));
- smartlist_clear(transport_list);
-}
-
-/** Free the pluggable transport struct <b>transport</b>. */
-void
-transport_free(transport_t *transport)
-{
- if (!transport)
- return;
-
- tor_free(transport->name);
- tor_free(transport);
-}
-
-/** Returns the transport in our transport list that has the name <b>name</b>.
- * Else returns NULL. */
-transport_t *
-transport_get_by_name(const char *name)
-{
- tor_assert(name);
-
- if (!transport_list)
- return NULL;
-
- SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, transport) {
- if (!strcmp(transport->name, name))
- return transport;
- } SMARTLIST_FOREACH_END(transport);
-
- return NULL;
-}
-
-/** Returns a transport_t struct for a transport proxy supporting the
- protocol <b>name</b> listening at <b>addr</b>:<b>port</b> using
- SOCKS version <b>socks_ver</b>. */
-transport_t *
-transport_new(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver)
-{
- transport_t *t = tor_malloc_zero(sizeof(transport_t));
-
- tor_addr_copy(&t->addr, addr);
- t->port = port;
- t->name = tor_strdup(name);
- t->socks_version = socks_ver;
-
- return t;
-}
-
-/** Resolve any conflicts that the insertion of transport <b>t</b>
- * might cause.
- * Return 0 if <b>t</b> is OK and should be registered, 1 if there is
- * a transport identical to <b>t</b> already registered and -1 if
- * <b>t</b> cannot be added due to conflicts. */
-static int
-transport_resolve_conflicts(transport_t *t)
-{
- /* This is how we resolve transport conflicts:
-
- If there is already a transport with the same name and addrport,
- we either have duplicate torrc lines OR we are here post-HUP and
- this transport was here pre-HUP as well. In any case, mark the
- old transport so that it doesn't get removed and ignore the new
- one. Our caller has to free the new transport so we return '1' to
- signify this.
-
- If there is already a transport with the same name but different
- addrport:
- * if it's marked for removal, it means that it either has a lower
- priority than 't' in torrc (otherwise the mark would have been
- cleared by the paragraph above), or it doesn't exist at all in
- the post-HUP torrc. We destroy the old transport and register 't'.
- * if it's *not* marked for removal, it means that it was newly
- added in the post-HUP torrc or that it's of higher priority, in
- this case we ignore 't'. */
- transport_t *t_tmp = transport_get_by_name(t->name);
- if (t_tmp) { /* same name */
- if (tor_addr_eq(&t->addr, &t_tmp->addr) && (t->port == t_tmp->port)) {
- /* same name *and* addrport */
- t_tmp->marked_for_removal = 0;
- return 1;
- } else { /* same name but different addrport */
- char *new_transport_addr = tor_strdup(fmt_addr(&t->addr));
- if (t_tmp->marked_for_removal) { /* marked for removal */
- log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' "
- "but there was already a transport marked for deletion at "
- "'%s:%u'. We deleted the old transport and registered the "
- "new one.", t->name, new_transport_addr, t->port,
- fmt_addr(&t_tmp->addr), t_tmp->port);
- smartlist_remove(transport_list, t_tmp);
- transport_free(t_tmp);
- tor_free(new_transport_addr);
- } else { /* *not* marked for removal */
- log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' "
- "but the same transport already exists at '%s:%u'. "
- "Skipping.", t->name, new_transport_addr, t->port,
- fmt_addr(&t_tmp->addr), t_tmp->port);
- tor_free(new_transport_addr);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-/** Add transport <b>t</b> to the internal list of pluggable
- * transports.
- * Returns 0 if the transport was added correctly, 1 if the same
- * transport was already registered (in this case the caller must
- * free the transport) and -1 if there was an error. */
-int
-transport_add(transport_t *t)
-{
- int r;
- tor_assert(t);
-
- r = transport_resolve_conflicts(t);
-
- switch (r) {
- case 0: /* should register transport */
- if (!transport_list)
- transport_list = smartlist_new();
- smartlist_add(transport_list, t);
- return 0;
- default: /* let our caller know the return code */
- return r;
- }
-}
-
-/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>.
- * <b>name</b> is set to the name of the protocol this proxy uses.
- * <b>socks_ver</b> is set to the SOCKS version of the proxy. */
-int
-transport_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver)
-{
- transport_t *t = transport_new(addr, port, name, socks_ver);
-
- int r = transport_add(t);
-
- switch (r) {
- case -1:
- default:
- log_notice(LD_GENERAL, "Could not add transport %s at %s:%u. Skipping.",
- t->name, fmt_addr(&t->addr), t->port);
- transport_free(t);
- return -1;
- case 1:
- log_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.",
- t->name, fmt_addr(&t->addr), t->port);
- transport_free(t); /* falling */
- return 0;
- case 0:
- log_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.",
- t->name, fmt_addr(&t->addr), t->port);
- return 0;
- }
-}
-
-/** Return a bridge pointer if <b>ri</b> is one of our known bridges
- * (either by comparing keys if possible, else by comparing addr/port).
- * Else return NULL. */
-static bridge_info_t *
-get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr,
- uint16_t port,
- const char *digest)
-{
- if (!bridge_list)
- return NULL;
- SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
- {
- if (tor_digest_is_zero(bridge->identity) &&
- !tor_addr_compare(&bridge->addr, addr, CMP_EXACT) &&
- bridge->port == port)
- return bridge;
- if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN))
- return bridge;
- }
- SMARTLIST_FOREACH_END(bridge);
- return NULL;
-}
-
-/** Wrapper around get_configured_bridge_by_addr_port_digest() to look
- * it up via router descriptor <b>ri</b>. */
-static bridge_info_t *
-get_configured_bridge_by_routerinfo(const routerinfo_t *ri)
-{
- tor_addr_port_t ap;
-
- router_get_pref_orport(ri, &ap);
- return get_configured_bridge_by_addr_port_digest(&ap.addr, ap.port,
- ri->cache_info.identity_digest);
-}
-
-/** Return 1 if <b>ri</b> is one of our known bridges, else 0. */
-int
-routerinfo_is_a_configured_bridge(const routerinfo_t *ri)
-{
- return get_configured_bridge_by_routerinfo(ri) ? 1 : 0;
-}
-
-/** Return 1 if <b>node</b> is one of our configured bridges, else 0. */
-int
-node_is_a_configured_bridge(const node_t *node)
-{
- int retval = 0; /* Negative. */
- smartlist_t *orports = NULL;
-
- if (!node)
- goto out;
-
- orports = node_get_all_orports(node);
- if (orports == NULL)
- goto out;
-
- SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, orport) {
- if (get_configured_bridge_by_addr_port_digest(&orport->addr, orport->port,
- node->identity) != NULL) {
- retval = 1;
- goto out;
- }
- } SMARTLIST_FOREACH_END(orport);
-
- out:
- if (orports != NULL) {
- SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p));
- smartlist_free(orports);
- orports = NULL;
- }
- return retval;
-}
-
-/** We made a connection to a router at <b>addr</b>:<b>port</b>
- * without knowing its digest. Its digest turned out to be <b>digest</b>.
- * If it was a bridge, and we still don't know its digest, record it.
- */
-void
-learned_router_identity(const tor_addr_t *addr, uint16_t port,
- const char *digest)
-{
- bridge_info_t *bridge =
- get_configured_bridge_by_addr_port_digest(addr, port, digest);
- if (bridge && tor_digest_is_zero(bridge->identity)) {
- memcpy(bridge->identity, digest, DIGEST_LEN);
- log_notice(LD_DIR, "Learned fingerprint %s for bridge %s:%d",
- hex_str(digest, DIGEST_LEN), fmt_addr(addr), port);
- }
-}
-
-/** Return true if <b>bridge</b> has the same identity digest as
- * <b>digest</b>. If <b>digest</b> is NULL, it matches
- * bridges with unspecified identity digests. */
-static int
-bridge_has_digest(const bridge_info_t *bridge, const char *digest)
-{
- if (digest)
- return tor_memeq(digest, bridge->identity, DIGEST_LEN);
- else
- return tor_digest_is_zero(bridge->identity);
-}
-
-/** We are about to add a new bridge at <b>addr</b>:<b>port</b>, with optional
- * <b>digest</b> and <b>transport_name</b>. Mark for removal any previously
- * existing bridge with the same address and port, and warn the user as
- * appropriate.
- */
-static void
-bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
- const char *digest, const char *transport_name)
-{
- /* Iterate the already-registered bridge list:
-
- If you find a bridge with the same adress and port, mark it for
- removal. It doesn't make sense to have two active bridges with
- the same IP:PORT. If the bridge in question has a different
- digest or transport than <b>digest</b>/<b>transport_name</b>,
- it's probably a misconfiguration and we should warn the user.
- */
- SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) {
- if (bridge->marked_for_removal)
- continue;
-
- if (tor_addr_eq(&bridge->addr, addr) && (bridge->port == port)) {
-
- bridge->marked_for_removal = 1;
-
- if (!bridge_has_digest(bridge, digest) ||
- strcmp_opt(bridge->transport_name, transport_name)) {
- /* warn the user */
- char *bridge_description_new, *bridge_description_old;
- tor_asprintf(&bridge_description_new, "%s:%u:%s:%s",
- fmt_addr(addr), port,
- digest ? hex_str(digest, DIGEST_LEN) : "",
- transport_name ? transport_name : "");
- tor_asprintf(&bridge_description_old, "%s:%u:%s:%s",
- fmt_addr(&bridge->addr), bridge->port,
- tor_digest_is_zero(bridge->identity) ?
- "" : hex_str(bridge->identity,DIGEST_LEN),
- bridge->transport_name ? bridge->transport_name : "");
-
- log_warn(LD_GENERAL,"Tried to add bridge '%s', but we found a conflict"
- " with the already registered bridge '%s'. We will discard"
- " the old bridge and keep '%s'. If this is not what you"
- " wanted, please change your configuration file accordingly.",
- bridge_description_new, bridge_description_old,
- bridge_description_new);
-
- tor_free(bridge_description_new);
- tor_free(bridge_description_old);
- }
- }
- } SMARTLIST_FOREACH_END(bridge);
-}
-
-/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
- * is set, it tells us the identity key too. If we already had the
- * bridge in our list, unmark it, and don't actually add anything new.
- * If <b>transport_name</b> is non-NULL - the bridge is associated with a
- * pluggable transport - we assign the transport to the bridge. */
-void
-bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *digest, const char *transport_name)
-{
- bridge_info_t *b;
-
- bridge_resolve_conflicts(addr, port, digest, transport_name);
-
- b = tor_malloc_zero(sizeof(bridge_info_t));
- tor_addr_copy(&b->addr, addr);
- b->port = port;
- if (digest)
- memcpy(b->identity, digest, DIGEST_LEN);
- if (transport_name)
- b->transport_name = tor_strdup(transport_name);
- b->fetch_status.schedule = DL_SCHED_BRIDGE;
- if (!bridge_list)
- bridge_list = smartlist_new();
-
- smartlist_add(bridge_list, b);
-}
-
-/** Return true iff <b>routerset</b> contains the bridge <b>bridge</b>. */
-static int
-routerset_contains_bridge(const routerset_t *routerset,
- const bridge_info_t *bridge)
-{
- int result;
- extend_info_t *extinfo;
- tor_assert(bridge);
- if (!routerset)
- return 0;
-
- extinfo = extend_info_alloc(
- NULL, bridge->identity, NULL, &bridge->addr, bridge->port);
- result = routerset_contains_extendinfo(routerset, extinfo);
- extend_info_free(extinfo);
- return result;
-}
-
-/** If <b>digest</b> is one of our known bridges, return it. */
-static bridge_info_t *
-find_bridge_by_digest(const char *digest)
-{
- SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge,
- {
- if (tor_memeq(bridge->identity, digest, DIGEST_LEN))
- return bridge;
- });
- return NULL;
-}
-
-/* DOCDOC find_transport_name_by_bridge_addrport */
-const char *
-find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port)
-{
- if (!bridge_list)
- return NULL;
-
- SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
- if (tor_addr_eq(&bridge->addr, addr) &&
- (bridge->port == port))
- return bridge->transport_name;
- } SMARTLIST_FOREACH_END(bridge);
-
- return NULL;
-}
-
-/** If <b>addr</b> and <b>port</b> match the address and port of a
- * bridge of ours that uses pluggable transports, place its transport
- * in <b>transport</b>.
- *
- * Return 0 on success (found a transport, or found a bridge with no
- * transport, or found no bridge); return -1 if we should be using a
- * transport, but the transport could not be found.
- */
-int
-find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
- const transport_t **transport)
-{
- *transport = NULL;
- if (!bridge_list)
- return 0;
-
- SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
- if (tor_addr_eq(&bridge->addr, addr) &&
- (bridge->port == port)) { /* bridge matched */
- if (bridge->transport_name) { /* it also uses pluggable transports */
- *transport = transport_get_by_name(bridge->transport_name);
- if (*transport == NULL) { /* it uses pluggable transports, but
- the transport could not be found! */
- return -1;
- }
- return 0;
- } else { /* bridge matched, but it doesn't use transports. */
- break;
- }
- }
- } SMARTLIST_FOREACH_END(bridge);
-
- *transport = NULL;
- return 0;
-}
-
-/** We need to ask <b>bridge</b> for its server descriptor. */
-static void
-launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
-{
- char *address;
- const or_options_t *options = get_options();
-
- if (connection_get_by_type_addr_port_purpose(
- CONN_TYPE_DIR, &bridge->addr, bridge->port,
- DIR_PURPOSE_FETCH_SERVERDESC))
- return; /* it's already on the way */
-
- if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
- download_status_mark_impossible(&bridge->fetch_status);
- log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
- safe_str_client(fmt_addr(&bridge->addr)));
- return;
- }
-
- address = tor_dup_addr(&bridge->addr);
-
- directory_initiate_command(address, &bridge->addr,
- bridge->port, 0,
- 0, /* does not matter */
- 1, bridge->identity,
- DIR_PURPOSE_FETCH_SERVERDESC,
- ROUTER_PURPOSE_BRIDGE,
- 0, "authority.z", NULL, 0, 0);
- tor_free(address);
-}
-
-/** Fetching the bridge descriptor from the bridge authority returned a
- * "not found". Fall back to trying a direct fetch. */
-void
-retry_bridge_descriptor_fetch_directly(const char *digest)
-{
- bridge_info_t *bridge = find_bridge_by_digest(digest);
- if (!bridge)
- return; /* not found? oh well. */
-
- launch_direct_bridge_descriptor_fetch(bridge);
-}
-
-/** For each bridge in our list for which we don't currently have a
- * descriptor, fetch a new copy of its descriptor -- either directly
- * from the bridge or via a bridge authority. */
-void
-fetch_bridge_descriptors(const or_options_t *options, time_t now)
-{
- int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO);
- int ask_bridge_directly;
- int can_use_bridge_authority;
-
- if (!bridge_list)
- return;
-
- /* If we still have unconfigured managed proxies, don't go and
- connect to a bridge. */
- if (pt_proxies_configuration_pending())
- return;
-
- SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
- {
- if (!download_status_is_ready(&bridge->fetch_status, now,
- IMPOSSIBLE_TO_DOWNLOAD))
- continue; /* don't bother, no need to retry yet */
- if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
- download_status_mark_impossible(&bridge->fetch_status);
- log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
- safe_str_client(fmt_addr(&bridge->addr)));
- continue;
- }
-
- /* schedule another fetch as if this one will fail, in case it does */
- download_status_failed(&bridge->fetch_status, 0);
-
- can_use_bridge_authority = !tor_digest_is_zero(bridge->identity) &&
- num_bridge_auths;
- ask_bridge_directly = !can_use_bridge_authority ||
- !options->UpdateBridgesFromAuthority;
- log_debug(LD_DIR, "ask_bridge_directly=%d (%d, %d, %d)",
- ask_bridge_directly, tor_digest_is_zero(bridge->identity),
- !options->UpdateBridgesFromAuthority, !num_bridge_auths);
-
- if (ask_bridge_directly &&
- !fascist_firewall_allows_address_or(&bridge->addr, bridge->port)) {
- log_notice(LD_DIR, "Bridge at '%s:%d' isn't reachable by our "
- "firewall policy. %s.", fmt_addr(&bridge->addr),
- bridge->port,
- can_use_bridge_authority ?
- "Asking bridge authority instead" : "Skipping");
- if (can_use_bridge_authority)
- ask_bridge_directly = 0;
- else
- continue;
- }
-
- if (ask_bridge_directly) {
- /* we need to ask the bridge itself for its descriptor. */
- launch_direct_bridge_descriptor_fetch(bridge);
- } else {
- /* We have a digest and we want to ask an authority. We could
- * combine all the requests into one, but that may give more
- * hints to the bridge authority than we want to give. */
- char resource[10 + HEX_DIGEST_LEN];
- memcpy(resource, "fp/", 3);
- base16_encode(resource+3, HEX_DIGEST_LEN+1,
- bridge->identity, DIGEST_LEN);
- memcpy(resource+3+HEX_DIGEST_LEN, ".z", 3);
- log_info(LD_DIR, "Fetching bridge info '%s' from bridge authority.",
- resource);
- directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,
- ROUTER_PURPOSE_BRIDGE, resource, 0);
- }
- }
- SMARTLIST_FOREACH_END(bridge);
-}
-
-/** If our <b>bridge</b> is configured to be a different address than
- * the bridge gives in <b>node</b>, rewrite the routerinfo
- * we received to use the address we meant to use. Now we handle
- * multihomed bridges better.
- */
-static void
-rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
-{
- /* XXXX move this function. */
- /* XXXX overridden addresses should really live in the node_t, so that the
- * routerinfo_t and the microdesc_t can be immutable. But we can only
- * do that safely if we know that no function that connects to an OR
- * does so through an address from any source other than node_get_addr().
- */
- tor_addr_t addr;
-
- if (node->ri) {
- routerinfo_t *ri = node->ri;
- tor_addr_from_ipv4h(&addr, ri->addr);
-
- if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
- bridge->port == ri->or_port) ||
- (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) &&
- bridge->port == ri->ipv6_orport)) {
- /* they match, so no need to do anything */
- } else {
- if (tor_addr_family(&bridge->addr) == AF_INET) {
- ri->addr = tor_addr_to_ipv4h(&bridge->addr);
- tor_free(ri->address);
- ri->address = tor_dup_ip(ri->addr);
- ri->or_port = bridge->port;
- log_info(LD_DIR,
- "Adjusted bridge routerinfo for '%s' to match configured "
- "address %s:%d.",
- ri->nickname, ri->address, ri->or_port);
- } else if (tor_addr_family(&bridge->addr) == AF_INET6) {
- tor_addr_copy(&ri->ipv6_addr, &bridge->addr);
- ri->ipv6_orport = bridge->port;
- log_info(LD_DIR,
- "Adjusted bridge routerinfo for '%s' to match configured "
- "address %s:%d.",
- ri->nickname, fmt_addr(&ri->ipv6_addr), ri->ipv6_orport);
- } else {
- log_err(LD_BUG, "Address family not supported: %d.",
- tor_addr_family(&bridge->addr));
- return;
- }
- }
-
- /* Indicate that we prefer connecting to this bridge over the
- protocol that the bridge address indicates. Last bridge
- descriptor handled wins. */
- ri->ipv6_preferred = tor_addr_family(&bridge->addr) == AF_INET6;
-
- /* XXXipv6 we lack support for falling back to another address for
- the same relay, warn the user */
- if (!tor_addr_is_null(&ri->ipv6_addr)) {
- tor_addr_port_t ap;
- router_get_pref_orport(ri, &ap);
- log_notice(LD_CONFIG,
- "Bridge '%s' has both an IPv4 and an IPv6 address. "
- "Will prefer using its %s address (%s:%d).",
- ri->nickname,
- ri->ipv6_preferred ? "IPv6" : "IPv4",
- fmt_addr(&ap.addr), ap.port);
- }
- }
- if (node->rs) {
- routerstatus_t *rs = node->rs;
- tor_addr_from_ipv4h(&addr, rs->addr);
-
- if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
- bridge->port == rs->or_port) {
- /* they match, so no need to do anything */
- } else {
- rs->addr = tor_addr_to_ipv4h(&bridge->addr);
- rs->or_port = bridge->port;
- log_info(LD_DIR,
- "Adjusted bridge routerstatus for '%s' to match "
- "configured address %s:%d.",
- rs->nickname, fmt_addr(&bridge->addr), rs->or_port);
- }
- }
-}
-
-/** We just learned a descriptor for a bridge. See if that
- * digest is in our entry guard list, and add it if not. */
-void
-learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
-{
- tor_assert(ri);
- tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE);
- if (get_options()->UseBridges) {
- int first = !any_bridge_descriptors_known();
- bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri);
- time_t now = time(NULL);
- router_set_status(ri->cache_info.identity_digest, 1);
-
- if (bridge) { /* if we actually want to use this one */
- node_t *node;
- /* it's here; schedule its re-fetch for a long time from now. */
- if (!from_cache)
- download_status_reset(&bridge->fetch_status);
-
- node = node_get_mutable_by_id(ri->cache_info.identity_digest);
- tor_assert(node);
- rewrite_node_address_for_bridge(bridge, node);
- add_an_entry_guard(node, 1, 1);
-
- log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname,
- from_cache ? "cached" : "fresh", router_describe(ri));
- /* set entry->made_contact so if it goes down we don't drop it from
- * our entry node list */
- entry_guard_register_connect_status(ri->cache_info.identity_digest,
- 1, 0, now);
- if (first)
- routerlist_retry_directory_downloads(now);
- }
- }
-}
-
-/** Return 1 if any of our entry guards have descriptors that
- * are marked with purpose 'bridge' and are running. Else return 0.
- *
- * We use this function to decide if we're ready to start building
- * circuits through our bridges, or if we need to wait until the
- * directory "server/authority" requests finish. */
-int
-any_bridge_descriptors_known(void)
-{
- tor_assert(get_options()->UseBridges);
- return choose_random_entry(NULL)!=NULL ? 1 : 0;
-}
-
-/** Return 1 if there are any directory conns fetching bridge descriptors
- * that aren't marked for close. We use this to guess if we should tell
- * the controller that we have a problem. */
-int
-any_pending_bridge_descriptor_fetches(void)
-{
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
- if (conn->type == CONN_TYPE_DIR &&
- conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
- TO_DIR_CONN(conn)->router_purpose == ROUTER_PURPOSE_BRIDGE &&
- !conn->marked_for_close &&
- conn->linked &&
- conn->linked_conn && !conn->linked_conn->marked_for_close) {
- log_debug(LD_DIR, "found one: %s", conn->address);
- return 1;
- }
- } SMARTLIST_FOREACH_END(conn);
- return 0;
-}
-
-/** Return 1 if we have at least one descriptor for an entry guard
- * (bridge or member of EntryNodes) and all descriptors we know are
- * down. Else return 0. If <b>act</b> is 1, then mark the down guards
- * up; else just observe and report. */
-static int
-entries_retry_helper(const or_options_t *options, int act)
-{
- const node_t *node;
- int any_known = 0;
- int any_running = 0;
- int need_bridges = options->UseBridges != 0;
- if (!entry_guards)
- entry_guards = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- node = node_get_by_id(e->identity);
- if (node && node_has_descriptor(node) &&
- node_is_bridge(node) == need_bridges) {
- any_known = 1;
- if (node->is_running)
- any_running = 1; /* some entry is both known and running */
- else if (act) {
- /* Mark all current connections to this OR as unhealthy, since
- * otherwise there could be one that started 30 seconds
- * ago, and in 30 seconds it will time out, causing us to mark
- * the node down and undermine the retry attempt. We mark even
- * the established conns, since if the network just came back
- * we'll want to attach circuits to fresh conns. */
- connection_or_set_bad_connections(node->identity, 1);
-
- /* mark this entry node for retry */
- router_set_status(node->identity, 1);
- e->can_retry = 1;
- e->bad_since = 0;
- }
- }
- } SMARTLIST_FOREACH_END(e);
- log_debug(LD_DIR, "%d: any_known %d, any_running %d",
- act, any_known, any_running);
- return any_known && !any_running;
-}
-
-/** Do we know any descriptors for our bridges / entrynodes, and are
- * all the ones we have descriptors for down? */
-int
-entries_known_but_down(const or_options_t *options)
-{
- tor_assert(entry_list_is_constrained(options));
- return entries_retry_helper(options, 0);
-}
-
-/** Mark all down known bridges / entrynodes up. */
-void
-entries_retry_all(const or_options_t *options)
-{
- tor_assert(entry_list_is_constrained(options));
- entries_retry_helper(options, 1);
-}
-
-/** Return true if we've ever had a bridge running a Tor version that can't
- * provide microdescriptors to us. In that case fall back to asking for
- * full descriptors. Eventually all bridges will support microdescriptors
- * and we can take this check out; see bug 4013. */
-int
-any_bridges_dont_support_microdescriptors(void)
-{
- const node_t *node;
- static int ever_answered_yes = 0;
- if (!get_options()->UseBridges || !entry_guards)
- return 0;
- if (ever_answered_yes)
- return 1; /* if we ever answer 'yes', always answer 'yes' */
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- node = node_get_by_id(e->identity);
- if (node && node->ri &&
- node_is_bridge(node) && node_is_a_configured_bridge(node) &&
- !tor_version_supports_microdescriptors(node->ri->platform)) {
- /* This is one of our current bridges, and we know enough about
- * it to know that it won't be able to answer our microdescriptor
- * questions. */
- ever_answered_yes = 1;
- return 1;
- }
- } SMARTLIST_FOREACH_END(e);
- return 0;
-}
-
-/** Release all storage held by the list of entry guards and related
- * memory structs. */
-void
-entry_guards_free_all(void)
-{
- if (entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
- entry_guard_free(e));
- smartlist_free(entry_guards);
- entry_guards = NULL;
- }
- clear_bridge_list();
- clear_transport_list();
- smartlist_free(bridge_list);
- smartlist_free(transport_list);
- bridge_list = NULL;
- transport_list = NULL;
-}
-
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index fc6ca65fc..a3091707e 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,36 +9,20 @@
* \brief Header file for circuitbuild.c.
**/
-#ifndef _TOR_CIRCUITBUILD_H
-#define _TOR_CIRCUITBUILD_H
-
-/** Represents a pluggable transport proxy used by a bridge. */
-typedef struct {
- /** SOCKS version: One of PROXY_SOCKS4, PROXY_SOCKS5. */
- int socks_version;
- /** Name of pluggable transport protocol */
- char *name;
- /** Address of proxy */
- tor_addr_t addr;
- /** Port of proxy */
- uint16_t port;
- /** Boolean: We are re-parsing our transport list, and we are going to remove
- * this one if we don't find it in the list of configured transports. */
- unsigned marked_for_removal : 1;
-} transport_t;
+#ifndef TOR_CIRCUITBUILD_H
+#define TOR_CIRCUITBUILD_H
char *circuit_list_path(origin_circuit_t *circ, int verbose);
char *circuit_list_path_for_controller(origin_circuit_t *circ);
void circuit_log_path(int severity, unsigned int domain,
origin_circuit_t *circ);
void circuit_rep_hist_note_result(origin_circuit_t *circ);
-int circuit_build_times_disabled(void);
origin_circuit_t *origin_circuit_init(uint8_t purpose, int flags);
origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
extend_info_t *exit,
int flags);
int circuit_handle_first_hop(origin_circuit_t *circ);
-void circuit_n_conn_done(or_connection_t *or_conn, int status);
+void circuit_n_chan_done(channel_t *chan, int status);
int inform_testing_reachability(void);
int circuit_timeout_want_to_count_circ(origin_circuit_t *circ);
int circuit_send_next_onion_skin(origin_circuit_t *circ);
@@ -46,127 +30,43 @@ void circuit_note_clock_jumped(int seconds_elapsed);
int circuit_extend(cell_t *cell, circuit_t *circ);
int circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data,
int reverse);
-int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type,
- const uint8_t *reply);
-int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer);
-int onionskin_answer(or_circuit_t *circ, uint8_t cell_type,
- const char *payload, const char *keys);
+struct created_cell_t;
+int circuit_finish_handshake(origin_circuit_t *circ,
+ const struct created_cell_t *created_cell);
+int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer,
+ int reason);
+int onionskin_answer(or_circuit_t *circ,
+ const struct created_cell_t *created_cell,
+ const char *keys,
+ const uint8_t *rend_circ_nonce);
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
int *need_capacity);
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
-extend_info_t *extend_info_alloc(const char *nickname, const char *digest,
- crypto_pk_t *onion_key,
- const tor_addr_t *addr, uint16_t port);
-extend_info_t *extend_info_from_router(const routerinfo_t *r,
- int for_direct_connect);
-extend_info_t *extend_info_from_node(const node_t *node,
- int for_direct_connect);
+extend_info_t *extend_info_new(const char *nickname, const char *digest,
+ crypto_pk_t *onion_key,
+ const curve25519_public_key_t *curve25519_key,
+ const tor_addr_t *addr, uint16_t port);
+extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
extend_info_t *extend_info_dup(extend_info_t *info);
void extend_info_free(extend_info_t *info);
const node_t *build_state_get_exit_node(cpath_build_state_t *state);
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
-void entry_guards_compute_status(const or_options_t *options, time_t now);
-int entry_guard_register_connect_status(const char *digest, int succeeded,
- int mark_relay_status, time_t now);
-void entry_nodes_should_be_added(void);
-int entry_list_is_constrained(const or_options_t *options);
-const node_t *choose_random_entry(cpath_build_state_t *state);
-int entry_guards_parse_state(or_state_t *state, int set, char **msg);
-void entry_guards_update_state(or_state_t *state);
-int getinfo_helper_entry_guards(control_connection_t *conn,
- const char *question, char **answer,
- const char **errmsg);
-
-void mark_bridge_list(void);
-void sweep_bridge_list(void);
-void mark_transport_list(void);
-void sweep_transport_list(void);
-
-int routerinfo_is_a_configured_bridge(const routerinfo_t *ri);
-int node_is_a_configured_bridge(const node_t *node);
-void learned_router_identity(const tor_addr_t *addr, uint16_t port,
- const char *digest);
-void bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *digest,
- const char *transport_name);
-void retry_bridge_descriptor_fetch_directly(const char *digest);
-void fetch_bridge_descriptors(const or_options_t *options, time_t now);
-void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);
-int any_bridge_descriptors_known(void);
-int any_pending_bridge_descriptor_fetches(void);
-int entries_known_but_down(const or_options_t *options);
-void entries_retry_all(const or_options_t *options);
-
-int any_bridges_dont_support_microdescriptors(void);
-
-void entry_guards_free_all(void);
-
-extern circuit_build_times_t circ_times;
-int circuit_build_times_enough_to_compute(circuit_build_times_t *cbt);
-void circuit_build_times_update_state(circuit_build_times_t *cbt,
- or_state_t *state);
-int circuit_build_times_parse_state(circuit_build_times_t *cbt,
- or_state_t *state);
-void circuit_build_times_count_timeout(circuit_build_times_t *cbt,
- int did_onehop);
-int circuit_build_times_count_close(circuit_build_times_t *cbt,
- int did_onehop, time_t start_time);
-void circuit_build_times_set_timeout(circuit_build_times_t *cbt);
-int circuit_build_times_add_time(circuit_build_times_t *cbt,
- build_time_t time);
-int circuit_build_times_needs_circuits(circuit_build_times_t *cbt);
-
-int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt);
-void circuit_build_times_init(circuit_build_times_t *cbt);
-void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
-void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
- networkstatus_t *ns);
-double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
-double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
-
-#ifdef CIRCUIT_PRIVATE
-double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
- double quantile);
-build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt,
- double q_lo, double q_hi);
-void circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
- double quantile, double time_ms);
-int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
-double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
-void circuitbuild_running_unit_tests(void);
-void circuit_build_times_reset(circuit_build_times_t *cbt);
-
-/* Network liveness functions */
-int circuit_build_times_network_check_changed(circuit_build_times_t *cbt);
-#endif
-
-/* Network liveness functions */
-void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
-int circuit_build_times_network_check_live(circuit_build_times_t *cbt);
-void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
-
-/* DOCDOC circuit_build_times_get_bw_scale */
-int circuit_build_times_get_bw_scale(networkstatus_t *ns);
-
-void clear_transport_list(void);
-int transport_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver);
-int transport_add(transport_t *t);
-void transport_free(transport_t *transport);
-transport_t *transport_new(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver);
-
-/* DOCDOC find_transport_name_by_bridge_addrport */
-const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr,
- uint16_t port);
-
-int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
- const transport_t **transport);
-transport_t *transport_get_by_name(const char *name);
+const node_t *choose_good_entry_server(uint8_t purpose,
+ cpath_build_state_t *state);
+double pathbias_get_extreme_rate(const or_options_t *options);
+double pathbias_get_extreme_use_rate(const or_options_t *options);
+int pathbias_get_dropguards(const or_options_t *options);
+void pathbias_count_timeout(origin_circuit_t *circ);
+int pathbias_check_close(origin_circuit_t *circ, int reason);
+int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell);
+void pathbias_count_use_attempt(origin_circuit_t *circ);
+void pathbias_mark_use_success(origin_circuit_t *circ);
+void pathbias_mark_use_rollback(origin_circuit_t *circ);
+const char *pathbias_state_to_string(path_state_t state);
#endif
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 6250c11d2..b0e24a5fe 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -1,7 +1,7 @@
/* Copyright 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,9 +10,11 @@
**/
#include "or.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
+#include "circuitstats.h"
#include "connection.h"
#include "config.h"
#include "connection_edge.h"
@@ -21,11 +23,14 @@
#include "networkstatus.h"
#include "nodelist.h"
#include "onion.h"
+#include "onion_fast.h"
+#include "policies.h"
#include "relay.h"
#include "rendclient.h"
#include "rendcommon.h"
#include "rephist.h"
#include "routerlist.h"
+#include "routerset.h"
#include "ht.h"
/********* START VARIABLES **********/
@@ -33,8 +38,8 @@
/** A global list of all circuits at this hop. */
circuit_t *global_circuitlist=NULL;
-/** A list of all the circuits in CIRCUIT_STATE_OR_WAIT. */
-static smartlist_t *circuits_pending_or_conns=NULL;
+/** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */
+static smartlist_t *circuits_pending_chans = NULL;
static void circuit_free(circuit_t *circ);
static void circuit_free_cpath(crypt_path_t *cpath);
@@ -43,154 +48,190 @@ static void cpath_ref_decref(crypt_path_reference_t *cpath_ref);
/********* END VARIABLES ************/
-/** A map from OR connection and circuit ID to circuit. (Lookup performance is
+/** A map from channel and circuit ID to circuit. (Lookup performance is
* very important here, since we need to do it every time a cell arrives.) */
-typedef struct orconn_circid_circuit_map_t {
- HT_ENTRY(orconn_circid_circuit_map_t) node;
- or_connection_t *or_conn;
+typedef struct chan_circid_circuit_map_t {
+ HT_ENTRY(chan_circid_circuit_map_t) node;
+ channel_t *chan;
circid_t circ_id;
circuit_t *circuit;
-} orconn_circid_circuit_map_t;
+} chan_circid_circuit_map_t;
-/** Helper for hash tables: compare the OR connection and circuit ID for a and
+/** Helper for hash tables: compare the channel and circuit ID for a and
* b, and return less than, equal to, or greater than zero appropriately.
*/
static INLINE int
-_orconn_circid_entries_eq(orconn_circid_circuit_map_t *a,
- orconn_circid_circuit_map_t *b)
+chan_circid_entries_eq_(chan_circid_circuit_map_t *a,
+ chan_circid_circuit_map_t *b)
{
- return a->or_conn == b->or_conn && a->circ_id == b->circ_id;
+ return a->chan == b->chan && a->circ_id == b->circ_id;
}
/** Helper: return a hash based on circuit ID and the pointer value of
- * or_conn in <b>a</b>. */
+ * chan in <b>a</b>. */
static INLINE unsigned int
-_orconn_circid_entry_hash(orconn_circid_circuit_map_t *a)
+chan_circid_entry_hash_(chan_circid_circuit_map_t *a)
{
- return (((unsigned)a->circ_id)<<8) ^ (unsigned)(uintptr_t)(a->or_conn);
+ return ((unsigned)a->circ_id) ^ (unsigned)(uintptr_t)(a->chan);
}
-/** Map from [orconn,circid] to circuit. */
-static HT_HEAD(orconn_circid_map, orconn_circid_circuit_map_t)
- orconn_circid_circuit_map = HT_INITIALIZER();
-HT_PROTOTYPE(orconn_circid_map, orconn_circid_circuit_map_t, node,
- _orconn_circid_entry_hash, _orconn_circid_entries_eq)
-HT_GENERATE(orconn_circid_map, orconn_circid_circuit_map_t, node,
- _orconn_circid_entry_hash, _orconn_circid_entries_eq, 0.6,
+/** Map from [chan,circid] to circuit. */
+static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t)
+ chan_circid_map = HT_INITIALIZER();
+HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node,
+ chan_circid_entry_hash_, chan_circid_entries_eq_)
+HT_GENERATE(chan_circid_map, chan_circid_circuit_map_t, node,
+ chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6,
malloc, realloc, free)
-/** The most recently returned entry from circuit_get_by_circid_orconn;
+/** The most recently returned entry from circuit_get_by_circid_chan;
* used to improve performance when many cells arrive in a row from the
* same circuit.
*/
-orconn_circid_circuit_map_t *_last_circid_orconn_ent = NULL;
+chan_circid_circuit_map_t *_last_circid_chan_ent = NULL;
-/** Implementation helper for circuit_set_{p,n}_circid_orconn: A circuit ID
- * and/or or_connection for circ has just changed from <b>old_conn, old_id</b>
- * to <b>conn, id</b>. Adjust the conn,circid map as appropriate, removing
+/** Implementation helper for circuit_set_{p,n}_circid_channel: A circuit ID
+ * and/or channel for circ has just changed from <b>old_chan, old_id</b>
+ * to <b>chan, id</b>. Adjust the chan,circid map as appropriate, removing
* the old entry (if any) and adding a new one. */
static void
-circuit_set_circid_orconn_helper(circuit_t *circ, int direction,
- circid_t id,
- or_connection_t *conn)
+circuit_set_circid_chan_helper(circuit_t *circ, int direction,
+ circid_t id,
+ channel_t *chan)
{
- orconn_circid_circuit_map_t search;
- orconn_circid_circuit_map_t *found;
- or_connection_t *old_conn, **conn_ptr;
+ chan_circid_circuit_map_t search;
+ chan_circid_circuit_map_t *found;
+ channel_t *old_chan, **chan_ptr;
circid_t old_id, *circid_ptr;
- int was_active, make_active;
+ int make_active, attached = 0;
if (direction == CELL_DIRECTION_OUT) {
- conn_ptr = &circ->n_conn;
+ chan_ptr = &circ->n_chan;
circid_ptr = &circ->n_circ_id;
- was_active = circ->next_active_on_n_conn != NULL;
- make_active = circ->n_conn_cells.n > 0;
+ make_active = circ->n_chan_cells.n > 0;
} else {
or_circuit_t *c = TO_OR_CIRCUIT(circ);
- conn_ptr = &c->p_conn;
+ chan_ptr = &c->p_chan;
circid_ptr = &c->p_circ_id;
- was_active = c->next_active_on_p_conn != NULL;
- make_active = c->p_conn_cells.n > 0;
+ make_active = c->p_chan_cells.n > 0;
}
- old_conn = *conn_ptr;
+ old_chan = *chan_ptr;
old_id = *circid_ptr;
- if (id == old_id && conn == old_conn)
+ if (id == old_id && chan == old_chan)
return;
- if (_last_circid_orconn_ent &&
- ((old_id == _last_circid_orconn_ent->circ_id &&
- old_conn == _last_circid_orconn_ent->or_conn) ||
- (id == _last_circid_orconn_ent->circ_id &&
- conn == _last_circid_orconn_ent->or_conn))) {
- _last_circid_orconn_ent = NULL;
+ if (_last_circid_chan_ent &&
+ ((old_id == _last_circid_chan_ent->circ_id &&
+ old_chan == _last_circid_chan_ent->chan) ||
+ (id == _last_circid_chan_ent->circ_id &&
+ chan == _last_circid_chan_ent->chan))) {
+ _last_circid_chan_ent = NULL;
}
- if (old_conn) { /* we may need to remove it from the conn-circid map */
- tor_assert(old_conn->_base.magic == OR_CONNECTION_MAGIC);
+ if (old_chan) {
+ /*
+ * If we're changing channels or ID and had an old channel and a non
+ * zero old ID and weren't marked for close (i.e., we should have been
+ * attached), detach the circuit. ID changes require this because
+ * circuitmux hashes on (channel_id, circuit_id).
+ */
+ if (old_id != 0 && (old_chan != chan || old_id != id) &&
+ !(circ->marked_for_close)) {
+ tor_assert(old_chan->cmux);
+ circuitmux_detach_circuit(old_chan->cmux, circ);
+ }
+
+ /* we may need to remove it from the conn-circid map */
search.circ_id = old_id;
- search.or_conn = old_conn;
- found = HT_REMOVE(orconn_circid_map, &orconn_circid_circuit_map, &search);
+ search.chan = old_chan;
+ found = HT_REMOVE(chan_circid_map, &chan_circid_map, &search);
if (found) {
tor_free(found);
- --old_conn->n_circuits;
+ if (direction == CELL_DIRECTION_OUT) {
+ /* One fewer circuits use old_chan as n_chan */
+ --(old_chan->num_n_circuits);
+ } else {
+ /* One fewer circuits use old_chan as p_chan */
+ --(old_chan->num_p_circuits);
+ }
}
- if (was_active && old_conn != conn)
- make_circuit_inactive_on_conn(circ,old_conn);
}
/* Change the values only after we have possibly made the circuit inactive
- * on the previous conn. */
- *conn_ptr = conn;
+ * on the previous chan. */
+ *chan_ptr = chan;
*circid_ptr = id;
- if (conn == NULL)
+ if (chan == NULL)
return;
/* now add the new one to the conn-circid map */
search.circ_id = id;
- search.or_conn = conn;
- found = HT_FIND(orconn_circid_map, &orconn_circid_circuit_map, &search);
+ search.chan = chan;
+ found = HT_FIND(chan_circid_map, &chan_circid_map, &search);
if (found) {
found->circuit = circ;
} else {
- found = tor_malloc_zero(sizeof(orconn_circid_circuit_map_t));
+ found = tor_malloc_zero(sizeof(chan_circid_circuit_map_t));
found->circ_id = id;
- found->or_conn = conn;
+ found->chan = chan;
found->circuit = circ;
- HT_INSERT(orconn_circid_map, &orconn_circid_circuit_map, found);
+ HT_INSERT(chan_circid_map, &chan_circid_map, found);
+ }
+
+ /*
+ * Attach to the circuitmux if we're changing channels or IDs and
+ * have a new channel and ID to use and the circuit is not marked for
+ * close.
+ */
+ if (chan && id != 0 && (old_chan != chan || old_id != id) &&
+ !(circ->marked_for_close)) {
+ tor_assert(chan->cmux);
+ circuitmux_attach_circuit(chan->cmux, circ, direction);
+ attached = 1;
}
- if (make_active && old_conn != conn)
- make_circuit_active_on_conn(circ,conn);
- ++conn->n_circuits;
+ /*
+ * This is a no-op if we have no cells, but if we do it marks us active to
+ * the circuitmux
+ */
+ if (make_active && attached)
+ update_circuit_on_cmux(circ, direction);
+
+ /* Adjust circuit counts on new channel */
+ if (direction == CELL_DIRECTION_OUT) {
+ ++chan->num_n_circuits;
+ } else {
+ ++chan->num_p_circuits;
+ }
}
/** Set the p_conn field of a circuit <b>circ</b>, along
* with the corresponding circuit ID, and add the circuit as appropriate
- * to the (orconn,id)-\>circuit map. */
+ * to the (chan,id)-\>circuit map. */
void
-circuit_set_p_circid_orconn(or_circuit_t *circ, circid_t id,
- or_connection_t *conn)
+circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id,
+ channel_t *chan)
{
- circuit_set_circid_orconn_helper(TO_CIRCUIT(circ), CELL_DIRECTION_IN,
- id, conn);
+ circuit_set_circid_chan_helper(TO_CIRCUIT(circ), CELL_DIRECTION_IN,
+ id, chan);
- if (conn)
- tor_assert(bool_eq(circ->p_conn_cells.n, circ->next_active_on_p_conn));
+ if (chan)
+ tor_assert(bool_eq(circ->p_chan_cells.n, circ->next_active_on_p_chan));
}
/** Set the n_conn field of a circuit <b>circ</b>, along
* with the corresponding circuit ID, and add the circuit as appropriate
- * to the (orconn,id)-\>circuit map. */
+ * to the (chan,id)-\>circuit map. */
void
-circuit_set_n_circid_orconn(circuit_t *circ, circid_t id,
- or_connection_t *conn)
+circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
+ channel_t *chan)
{
- circuit_set_circid_orconn_helper(circ, CELL_DIRECTION_OUT, id, conn);
+ circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan);
- if (conn)
- tor_assert(bool_eq(circ->n_conn_cells.n, circ->next_active_on_n_conn));
+ if (chan)
+ tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan));
}
/** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
@@ -201,18 +242,18 @@ circuit_set_state(circuit_t *circ, uint8_t state)
tor_assert(circ);
if (state == circ->state)
return;
- if (!circuits_pending_or_conns)
- circuits_pending_or_conns = smartlist_new();
- if (circ->state == CIRCUIT_STATE_OR_WAIT) {
+ if (!circuits_pending_chans)
+ circuits_pending_chans = smartlist_new();
+ if (circ->state == CIRCUIT_STATE_CHAN_WAIT) {
/* remove from waiting-circuit list. */
- smartlist_remove(circuits_pending_or_conns, circ);
+ smartlist_remove(circuits_pending_chans, circ);
}
- if (state == CIRCUIT_STATE_OR_WAIT) {
+ if (state == CIRCUIT_STATE_CHAN_WAIT) {
/* add to waiting-circuit list. */
- smartlist_add(circuits_pending_or_conns, circ);
+ smartlist_add(circuits_pending_chans, circ);
}
if (state == CIRCUIT_STATE_OPEN)
- tor_assert(!circ->n_conn_onionskin);
+ tor_assert(!circ->n_chan_create_cell);
circ->state = state;
}
@@ -231,51 +272,53 @@ circuit_add(circuit_t *circ)
}
}
-/** Append to <b>out</b> all circuits in state OR_WAIT waiting for
+/** Append to <b>out</b> all circuits in state CHAN_WAIT waiting for
* the given connection. */
void
-circuit_get_all_pending_on_or_conn(smartlist_t *out, or_connection_t *or_conn)
+circuit_get_all_pending_on_channel(smartlist_t *out, channel_t *chan)
{
tor_assert(out);
- tor_assert(or_conn);
+ tor_assert(chan);
- if (!circuits_pending_or_conns)
+ if (!circuits_pending_chans)
return;
- SMARTLIST_FOREACH_BEGIN(circuits_pending_or_conns, circuit_t *, circ) {
+ SMARTLIST_FOREACH_BEGIN(circuits_pending_chans, circuit_t *, circ) {
if (circ->marked_for_close)
continue;
if (!circ->n_hop)
continue;
- tor_assert(circ->state == CIRCUIT_STATE_OR_WAIT);
+ tor_assert(circ->state == CIRCUIT_STATE_CHAN_WAIT);
if (tor_digest_is_zero(circ->n_hop->identity_digest)) {
/* Look at addr/port. This is an unkeyed connection. */
- if (!tor_addr_eq(&circ->n_hop->addr, &or_conn->_base.addr) ||
- circ->n_hop->port != or_conn->_base.port)
+ if (!channel_matches_extend_info(chan, circ->n_hop))
continue;
} else {
/* We expected a key. See if it's the right one. */
- if (tor_memneq(or_conn->identity_digest,
- circ->n_hop->identity_digest, DIGEST_LEN))
+ if (tor_memneq(chan->identity_digest,
+ circ->n_hop->identity_digest, DIGEST_LEN))
continue;
}
smartlist_add(out, circ);
} SMARTLIST_FOREACH_END(circ);
}
-/** Return the number of circuits in state OR_WAIT, waiting for the given
- * connection. */
+/** Return the number of circuits in state CHAN_WAIT, waiting for the given
+ * channel. */
int
-circuit_count_pending_on_or_conn(or_connection_t *or_conn)
+circuit_count_pending_on_channel(channel_t *chan)
{
int cnt;
smartlist_t *sl = smartlist_new();
- circuit_get_all_pending_on_or_conn(sl, or_conn);
+
+ tor_assert(chan);
+
+ circuit_get_all_pending_on_channel(sl, chan);
cnt = smartlist_len(sl);
smartlist_free(sl);
log_debug(LD_CIRC,"or_conn to %s at %s, %d pending circs",
- or_conn->nickname ? or_conn->nickname : "NULL",
- or_conn->_base.address,
+ chan->nickname ? chan->nickname : "NULL",
+ channel_get_canonical_remote_descr(chan),
cnt);
return cnt;
}
@@ -310,7 +353,7 @@ circuit_close_all_marked(void)
/** Return the head of the global linked list of circuits. */
circuit_t *
-_circuit_get_global_list(void)
+circuit_get_global_list_(void)
{
return global_circuitlist;
}
@@ -323,7 +366,7 @@ circuit_state_to_string(int state)
switch (state) {
case CIRCUIT_STATE_BUILDING: return "doing handshakes";
case CIRCUIT_STATE_ONIONSKIN_PENDING: return "processing the onion";
- case CIRCUIT_STATE_OR_WAIT: return "connecting to server";
+ case CIRCUIT_STATE_CHAN_WAIT: return "connecting to server";
case CIRCUIT_STATE_OPEN: return "open";
default:
log_warn(LD_BUG, "Unknown circuit state %d", state);
@@ -372,6 +415,8 @@ circuit_purpose_to_controller_string(uint8_t purpose)
return "MEASURE_TIMEOUT";
case CIRCUIT_PURPOSE_CONTROLLER:
return "CONTROLLER";
+ case CIRCUIT_PURPOSE_PATH_BIAS_TESTING:
+ return "PATH_BIAS_TESTING";
default:
tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose);
@@ -399,6 +444,7 @@ circuit_purpose_to_controller_hs_state_string(uint8_t purpose)
case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT:
case CIRCUIT_PURPOSE_TESTING:
case CIRCUIT_PURPOSE_CONTROLLER:
+ case CIRCUIT_PURPOSE_PATH_BIAS_TESTING:
return NULL;
case CIRCUIT_PURPOSE_INTRO_POINT:
@@ -486,6 +532,9 @@ circuit_purpose_to_string(uint8_t purpose)
case CIRCUIT_PURPOSE_CONTROLLER:
return "Circuit made by controller";
+ case CIRCUIT_PURPOSE_PATH_BIAS_TESTING:
+ return "Path-bias testing circuit";
+
default:
tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose);
return buf;
@@ -514,15 +563,14 @@ init_circuit_base(circuit_t *circ)
{
tor_gettimeofday(&circ->timestamp_created);
+ // Gets reset when we send CREATE_FAST.
+ // circuit_expire_building() expects these to be equal
+ // until the orconn is built.
+ circ->timestamp_began = circ->timestamp_created;
+
circ->package_window = circuit_initial_package_window();
circ->deliver_window = CIRCWINDOW_START;
- /* Initialize the cell_ewma_t structure */
- circ->n_cell_ewma.last_adjusted_tick = cell_ewma_get_tick();
- circ->n_cell_ewma.cell_count = 0.0;
- circ->n_cell_ewma.heap_index = -1;
- circ->n_cell_ewma.is_for_p_conn = 0;
-
circuit_add(circ);
}
@@ -538,7 +586,7 @@ origin_circuit_new(void)
static uint32_t n_circuits_allocated = 1;
circ = tor_malloc_zero(sizeof(origin_circuit_t));
- circ->_base.magic = ORIGIN_CIRCUIT_MAGIC;
+ circ->base_.magic = ORIGIN_CIRCUIT_MAGIC;
circ->next_stream_id = crypto_rand_int(1<<16);
circ->global_identifier = n_circuits_allocated++;
@@ -555,31 +603,21 @@ origin_circuit_new(void)
/** Allocate a new or_circuit_t, connected to <b>p_conn</b> as
* <b>p_circ_id</b>. If <b>p_conn</b> is NULL, the circuit is unattached. */
or_circuit_t *
-or_circuit_new(circid_t p_circ_id, or_connection_t *p_conn)
+or_circuit_new(circid_t p_circ_id, channel_t *p_chan)
{
/* CircIDs */
or_circuit_t *circ;
circ = tor_malloc_zero(sizeof(or_circuit_t));
- circ->_base.magic = OR_CIRCUIT_MAGIC;
+ circ->base_.magic = OR_CIRCUIT_MAGIC;
- if (p_conn)
- circuit_set_p_circid_orconn(circ, p_circ_id, p_conn);
+ if (p_chan)
+ circuit_set_p_circid_chan(circ, p_circ_id, p_chan);
circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT;
init_circuit_base(TO_CIRCUIT(circ));
- /* Initialize the cell_ewma_t structure */
-
- /* Initialize the cell counts to 0 */
- circ->p_cell_ewma.cell_count = 0.0;
- circ->p_cell_ewma.last_adjusted_tick = cell_ewma_get_tick();
- circ->p_cell_ewma.is_for_p_conn = 1;
-
- /* It's not in any heap yet. */
- circ->p_cell_ewma.heap_index = -1;
-
return circ;
}
@@ -619,6 +657,7 @@ circuit_free(circuit_t *circ)
memwipe(ocirc->socks_password, 0x06, ocirc->socks_password_len);
tor_free(ocirc->socks_password);
}
+ addr_policy_list_free(ocirc->prepend_policy);
} else {
or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
/* Remember cell statistics for this circuit before deallocating. */
@@ -635,27 +674,27 @@ circuit_free(circuit_t *circ)
if (ocirc->rend_splice) {
or_circuit_t *other = ocirc->rend_splice;
- tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC);
+ tor_assert(other->base_.magic == OR_CIRCUIT_MAGIC);
other->rend_splice = NULL;
}
/* remove from map. */
- circuit_set_p_circid_orconn(ocirc, 0, NULL);
+ circuit_set_p_circid_chan(ocirc, 0, NULL);
/* Clear cell queue _after_ removing it from the map. Otherwise our
* "active" checks will be violated. */
- cell_queue_clear(&ocirc->p_conn_cells);
+ cell_queue_clear(&ocirc->p_chan_cells);
}
extend_info_free(circ->n_hop);
- tor_free(circ->n_conn_onionskin);
+ tor_free(circ->n_chan_create_cell);
/* Remove from map. */
- circuit_set_n_circid_orconn(circ, 0, NULL);
+ circuit_set_n_circid_chan(circ, 0, NULL);
/* Clear cell queue _after_ removing it from the map. Otherwise our
* "active" checks will be violated. */
- cell_queue_clear(&circ->n_conn_cells);
+ cell_queue_clear(&circ->n_chan_cells);
memwipe(mem, 0xAA, memlen); /* poison memory */
tor_free(mem);
@@ -701,10 +740,10 @@ circuit_free_all(void)
global_circuitlist = next;
}
- smartlist_free(circuits_pending_or_conns);
- circuits_pending_or_conns = NULL;
+ smartlist_free(circuits_pending_chans);
+ circuits_pending_chans = NULL;
- HT_CLEAR(orconn_circid_map, &orconn_circid_circuit_map);
+ HT_CLEAR(chan_circid_map, &chan_circid_map);
}
/** Deallocate space associated with the cpath node <b>victim</b>. */
@@ -718,7 +757,8 @@ circuit_free_cpath_node(crypt_path_t *victim)
crypto_cipher_free(victim->b_crypto);
crypto_digest_free(victim->f_digest);
crypto_digest_free(victim->b_digest);
- crypto_dh_free(victim->dh_handshake_state);
+ onion_handshake_state_release(&victim->handshake_state);
+ crypto_dh_free(victim->rend_dh_handshake_state);
extend_info_free(victim->extend_info);
memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */
@@ -741,14 +781,18 @@ cpath_ref_decref(crypt_path_reference_t *cpath_ref)
* of information about circuit <b>circ</b>.
*/
static void
-circuit_dump_details(int severity, circuit_t *circ, int conn_array_index,
- const char *type, int this_circid, int other_circid)
+circuit_dump_conn_details(int severity,
+ circuit_t *circ,
+ int conn_array_index,
+ const char *type,
+ circid_t this_circid,
+ circid_t other_circid)
{
- log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
- "state %d (%s), born %ld:",
- conn_array_index, type, this_circid, other_circid, circ->state,
- circuit_state_to_string(circ->state),
- (long)circ->timestamp_created.tv_sec);
+ tor_log(severity, LD_CIRC, "Conn %d has %s circuit: circID %u "
+ "(other side %u), state %d (%s), born %ld:",
+ conn_array_index, type, (unsigned)this_circid, (unsigned)other_circid,
+ circ->state, circuit_state_to_string(circ->state),
+ (long)circ->timestamp_began.tv_sec);
if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ));
}
@@ -763,50 +807,101 @@ circuit_dump_by_conn(connection_t *conn, int severity)
circuit_t *circ;
edge_connection_t *tmpconn;
- for (circ=global_circuitlist;circ;circ = circ->next) {
+ for (circ = global_circuitlist; circ; circ = circ->next) {
circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
- if (circ->marked_for_close)
+
+ if (circ->marked_for_close) {
continue;
+ }
- if (! CIRCUIT_IS_ORIGIN(circ))
+ if (!CIRCUIT_IS_ORIGIN(circ)) {
p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
- if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn &&
- TO_CONN(TO_OR_CIRCUIT(circ)->p_conn) == conn)
- circuit_dump_details(severity, circ, conn->conn_array_index, "App-ward",
- p_circ_id, n_circ_id);
if (CIRCUIT_IS_ORIGIN(circ)) {
for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (TO_CONN(tmpconn) == conn) {
- circuit_dump_details(severity, circ, conn->conn_array_index,
- "App-ward", p_circ_id, n_circ_id);
+ circuit_dump_conn_details(severity, circ, conn->conn_array_index,
+ "App-ward", p_circ_id, n_circ_id);
}
}
}
- if (circ->n_conn && TO_CONN(circ->n_conn) == conn)
- circuit_dump_details(severity, circ, conn->conn_array_index, "Exit-ward",
- n_circ_id, p_circ_id);
+
if (! CIRCUIT_IS_ORIGIN(circ)) {
for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (TO_CONN(tmpconn) == conn) {
- circuit_dump_details(severity, circ, conn->conn_array_index,
- "Exit-ward", n_circ_id, p_circ_id);
+ circuit_dump_conn_details(severity, circ, conn->conn_array_index,
+ "Exit-ward", n_circ_id, p_circ_id);
}
}
}
- if (!circ->n_conn && circ->n_hop &&
- tor_addr_eq(&circ->n_hop->addr, &conn->addr) &&
- circ->n_hop->port == conn->port &&
- conn->type == CONN_TYPE_OR &&
- tor_memeq(TO_OR_CONN(conn)->identity_digest,
- circ->n_hop->identity_digest, DIGEST_LEN)) {
- circuit_dump_details(severity, circ, conn->conn_array_index,
- (circ->state == CIRCUIT_STATE_OPEN &&
- !CIRCUIT_IS_ORIGIN(circ)) ?
- "Endpoint" : "Pending",
- n_circ_id, p_circ_id);
+ }
+}
+
+/** A helper function for circuit_dump_by_chan() below. Log a bunch
+ * of information about circuit <b>circ</b>.
+ */
+static void
+circuit_dump_chan_details(int severity,
+ circuit_t *circ,
+ channel_t *chan,
+ const char *type,
+ circid_t this_circid,
+ circid_t other_circid)
+{
+ tor_log(severity, LD_CIRC, "Conn %p has %s circuit: circID %u "
+ "(other side %u), state %d (%s), born %ld:",
+ chan, type, (unsigned)this_circid, (unsigned)other_circid, circ->state,
+ circuit_state_to_string(circ->state),
+ (long)circ->timestamp_began.tv_sec);
+ if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
+ circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ));
+ }
+}
+
+/** Log, at severity <b>severity</b>, information about each circuit
+ * that is connected to <b>chan</b>.
+ */
+void
+circuit_dump_by_chan(channel_t *chan, int severity)
+{
+ circuit_t *circ;
+
+ tor_assert(chan);
+
+ for (circ = global_circuitlist; circ; circ = circ->next) {
+ circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
+
+ if (circ->marked_for_close) {
+ continue;
+ }
+
+ if (!CIRCUIT_IS_ORIGIN(circ)) {
+ p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
+
+ if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_chan &&
+ TO_OR_CIRCUIT(circ)->p_chan == chan) {
+ circuit_dump_chan_details(severity, circ, chan, "App-ward",
+ p_circ_id, n_circ_id);
+ }
+
+ if (circ->n_chan && circ->n_chan == chan) {
+ circuit_dump_chan_details(severity, circ, chan, "Exit-ward",
+ n_circ_id, p_circ_id);
+ }
+
+ if (!circ->n_chan && circ->n_hop &&
+ channel_matches_extend_info(chan, circ->n_hop) &&
+ tor_memeq(chan->identity_digest,
+ circ->n_hop->identity_digest, DIGEST_LEN)) {
+ circuit_dump_chan_details(severity, circ, chan,
+ (circ->state == CIRCUIT_STATE_OPEN &&
+ !CIRCUIT_IS_ORIGIN(circ)) ?
+ "Endpoint" : "Pending",
+ n_circ_id, p_circ_id);
}
}
}
@@ -831,27 +926,39 @@ circuit_get_by_global_id(uint32_t id)
/** Return a circ such that:
* - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
- * - circ is attached to <b>conn</b>, either as p_conn or n_conn.
+ * - circ is attached to <b>chan</b>, either as p_chan or n_chan.
* Return NULL if no such circuit exists.
*/
static INLINE circuit_t *
-circuit_get_by_circid_orconn_impl(circid_t circ_id, or_connection_t *conn)
+circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan)
{
- orconn_circid_circuit_map_t search;
- orconn_circid_circuit_map_t *found;
+ chan_circid_circuit_map_t search;
+ chan_circid_circuit_map_t *found;
- if (_last_circid_orconn_ent &&
- circ_id == _last_circid_orconn_ent->circ_id &&
- conn == _last_circid_orconn_ent->or_conn) {
- found = _last_circid_orconn_ent;
+ if (_last_circid_chan_ent &&
+ circ_id == _last_circid_chan_ent->circ_id &&
+ chan == _last_circid_chan_ent->chan) {
+ found = _last_circid_chan_ent;
} else {
search.circ_id = circ_id;
- search.or_conn = conn;
- found = HT_FIND(orconn_circid_map, &orconn_circid_circuit_map, &search);
- _last_circid_orconn_ent = found;
+ search.chan = chan;
+ found = HT_FIND(chan_circid_map, &chan_circid_map, &search);
+ _last_circid_chan_ent = found;
}
- if (found && found->circuit)
+ if (found && found->circuit) {
+ log_debug(LD_CIRC,
+ "circuit_get_by_circid_channel_impl() returning circuit %p for"
+ " circ_id %u, channel ID " U64_FORMAT " (%p)",
+ found->circuit, (unsigned)circ_id,
+ U64_PRINTF_ARG(chan->global_identifier), chan);
return found->circuit;
+ }
+
+ log_debug(LD_CIRC,
+ "circuit_get_by_circid_channel_impl() found nothing for"
+ " circ_id %u, channel ID " U64_FORMAT " (%p)",
+ (unsigned)circ_id,
+ U64_PRINTF_ARG(chan->global_identifier), chan);
return NULL;
/* The rest of this checks for bugs. Disabled by default. */
@@ -861,15 +968,15 @@ circuit_get_by_circid_orconn_impl(circid_t circ_id, or_connection_t *conn)
for (circ=global_circuitlist;circ;circ = circ->next) {
if (! CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
- if (or_circ->p_conn == conn && or_circ->p_circ_id == circ_id) {
+ if (or_circ->p_chan == chan && or_circ->p_circ_id == circ_id) {
log_warn(LD_BUG,
- "circuit matches p_conn, but not in hash table (Bug!)");
+ "circuit matches p_chan, but not in hash table (Bug!)");
return circ;
}
}
- if (circ->n_conn == conn && circ->n_circ_id == circ_id) {
+ if (circ->n_chan == chan && circ->n_circ_id == circ_id) {
log_warn(LD_BUG,
- "circuit matches n_conn, but not in hash table (Bug!)");
+ "circuit matches n_chan, but not in hash table (Bug!)");
return circ;
}
}
@@ -879,26 +986,38 @@ circuit_get_by_circid_orconn_impl(circid_t circ_id, or_connection_t *conn)
/** Return a circ such that:
* - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
- * - circ is attached to <b>conn</b>, either as p_conn or n_conn.
+ * - circ is attached to <b>chan</b>, either as p_chan or n_chan.
* - circ is not marked for close.
* Return NULL if no such circuit exists.
*/
circuit_t *
-circuit_get_by_circid_orconn(circid_t circ_id, or_connection_t *conn)
+circuit_get_by_circid_channel(circid_t circ_id, channel_t *chan)
{
- circuit_t *circ = circuit_get_by_circid_orconn_impl(circ_id, conn);
+ circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan);
if (!circ || circ->marked_for_close)
return NULL;
else
return circ;
}
+/** Return a circ such that:
+ * - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
+ * - circ is attached to <b>chan</b>, either as p_chan or n_chan.
+ * Return NULL if no such circuit exists.
+ */
+circuit_t *
+circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
+ channel_t *chan)
+{
+ return circuit_get_by_circid_channel_impl(circ_id, chan);
+}
+
/** Return true iff the circuit ID <b>circ_id</b> is currently used by a
- * circuit, marked or not, on <b>conn</b>. */
+ * circuit, marked or not, on <b>chan</b>. */
int
-circuit_id_in_use_on_orconn(circid_t circ_id, or_connection_t *conn)
+circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan)
{
- return circuit_get_by_circid_orconn_impl(circ_id, conn) != NULL;
+ return circuit_get_by_circid_channel_impl(circ_id, chan) != NULL;
}
/** Return the circuit that a given edge connection is using. */
@@ -915,27 +1034,32 @@ circuit_get_by_edge_conn(edge_connection_t *conn)
return circ;
}
-/** For each circuit that has <b>conn</b> as n_conn or p_conn, unlink the
- * circuit from the orconn,circid map, and mark it for close if it hasn't
+/** For each circuit that has <b>chan</b> as n_chan or p_chan, unlink the
+ * circuit from the chan,circid map, and mark it for close if it hasn't
* been marked already.
*/
void
-circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason)
+circuit_unlink_all_from_channel(channel_t *chan, int reason)
{
circuit_t *circ;
- connection_or_unlink_all_active_circs(conn);
+ channel_unlink_all_circuits(chan);
for (circ = global_circuitlist; circ; circ = circ->next) {
int mark = 0;
- if (circ->n_conn == conn) {
- circuit_set_n_circid_orconn(circ, 0, NULL);
- mark = 1;
+ if (circ->n_chan == chan) {
+ circuit_set_n_circid_chan(circ, 0, NULL);
+ mark = 1;
+
+ /* If we didn't request this closure, pass the remote
+ * bit to mark_for_close. */
+ if (chan->reason_for_closing != CHANNEL_CLOSE_REQUESTED)
+ reason |= END_CIRC_REASON_FLAG_REMOTE;
}
if (! CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
- if (or_circ->p_conn == conn) {
- circuit_set_p_circid_orconn(or_circ, 0, NULL);
+ if (or_circ->p_chan == chan) {
+ circuit_set_p_circid_chan(or_circ, 0, NULL);
mark = 1;
}
}
@@ -1059,7 +1183,7 @@ origin_circuit_t *
circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
int flags)
{
- circuit_t *_circ;
+ circuit_t *circ_;
origin_circuit_t *best=NULL;
int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0;
int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0;
@@ -1075,16 +1199,17 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
"capacity %d, internal %d",
purpose, need_uptime, need_capacity, internal);
- for (_circ=global_circuitlist; _circ; _circ = _circ->next) {
- if (CIRCUIT_IS_ORIGIN(_circ) &&
- _circ->state == CIRCUIT_STATE_OPEN &&
- !_circ->marked_for_close &&
- _circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
- !_circ->timestamp_dirty) {
- origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(_circ);
+ for (circ_=global_circuitlist; circ_; circ_ = circ_->next) {
+ if (CIRCUIT_IS_ORIGIN(circ_) &&
+ circ_->state == CIRCUIT_STATE_OPEN &&
+ !circ_->marked_for_close &&
+ circ_->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
+ !circ_->timestamp_dirty) {
+ origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(circ_);
if ((!need_uptime || circ->build_state->need_uptime) &&
(!need_capacity || circ->build_state->need_capacity) &&
(internal == circ->build_state->is_internal) &&
+ !circ->unusable_for_new_conns &&
circ->remaining_relay_early_cells &&
circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN &&
!circ->build_state->onehop_tunnel &&
@@ -1180,20 +1305,17 @@ circuit_mark_all_unused_circs(void)
* This is useful for letting the user change pseudonyms, so new
* streams will not be linkable to old streams.
*/
-/* XXX024 this is a bad name for what this function does */
void
-circuit_expire_all_dirty_circs(void)
+circuit_mark_all_dirty_circs_as_unusable(void)
{
circuit_t *circ;
- const or_options_t *options = get_options();
for (circ=global_circuitlist; circ; circ = circ->next) {
if (CIRCUIT_IS_ORIGIN(circ) &&
!circ->marked_for_close &&
- circ->timestamp_dirty)
- /* XXXX024 This is a screwed-up way to say "This is too dirty
- * for new circuits. */
- circ->timestamp_dirty -= options->MaxCircuitDirtiness;
+ circ->timestamp_dirty) {
+ mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
+ }
}
}
@@ -1215,7 +1337,7 @@ circuit_expire_all_dirty_circs(void)
* rendezvous stream), then mark the other circuit to close as well.
*/
void
-_circuit_mark_for_close(circuit_t *circ, int reason, int line,
+circuit_mark_for_close_(circuit_t *circ, int reason, int line,
const char *file)
{
int orig_reason = reason; /* Passed to the controller */
@@ -1224,7 +1346,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
tor_assert(file);
if (circ->marked_for_close) {
- log(LOG_WARN,LD_BUG,
+ log_warn(LD_BUG,
"Duplicate call to circuit_mark_for_close at %s:%d"
" (first at %s:%d)", file, line,
circ->marked_for_close_file, circ->marked_for_close);
@@ -1238,7 +1360,13 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
}
reason = END_CIRC_REASON_NONE;
}
+
if (CIRCUIT_IS_ORIGIN(circ)) {
+ if (pathbias_check_close(TO_ORIGIN_CIRCUIT(circ), reason) == -1) {
+ /* Don't close it yet, we need to test it first */
+ return;
+ }
+
/* We don't send reasons when closing circuits at the origin. */
reason = END_CIRC_REASON_NONE;
}
@@ -1246,7 +1374,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
if (reason & END_CIRC_REASON_FLAG_REMOTE)
reason &= ~END_CIRC_REASON_FLAG_REMOTE;
- if (reason < _END_CIRC_REASON_MIN || reason > _END_CIRC_REASON_MAX) {
+ if (reason < END_CIRC_REASON_MIN_ || reason > END_CIRC_REASON_MAX_) {
if (!(orig_reason & END_CIRC_REASON_FLAG_REMOTE))
log_warn(LD_BUG, "Reason %d out of range at %s:%d", reason, file, line);
reason = END_CIRC_REASON_NONE;
@@ -1266,9 +1394,9 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
circuit_rep_hist_note_result(ocirc);
}
}
- if (circ->state == CIRCUIT_STATE_OR_WAIT) {
- if (circuits_pending_or_conns)
- smartlist_remove(circuits_pending_or_conns, circ);
+ if (circ->state == CIRCUIT_STATE_CHAN_WAIT) {
+ if (circuits_pending_chans)
+ smartlist_remove(circuits_pending_chans, circ);
}
if (CIRCUIT_IS_ORIGIN(circ)) {
control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
@@ -1305,9 +1433,15 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
INTRO_POINT_FAILURE_UNREACHABLE);
}
}
- if (circ->n_conn) {
- circuit_clear_cell_queue(circ, circ->n_conn);
- connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
+ if (circ->n_chan) {
+ circuit_clear_cell_queue(circ, circ->n_chan);
+ /* Only send destroy if the channel isn't closing anyway */
+ if (!(circ->n_chan->state == CHANNEL_STATE_CLOSING ||
+ circ->n_chan->state == CHANNEL_STATE_CLOSED ||
+ circ->n_chan->state == CHANNEL_STATE_ERROR)) {
+ channel_send_destroy(circ->n_circ_id, circ->n_chan, reason);
+ }
+ circuitmux_detach_circuit(circ->n_chan->cmux, circ);
}
if (! CIRCUIT_IS_ORIGIN(circ)) {
@@ -1320,7 +1454,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
while (or_circ->resolving_streams) {
conn = or_circ->resolving_streams;
or_circ->resolving_streams = conn->next_stream;
- if (!conn->_base.marked_for_close) {
+ if (!conn->base_.marked_for_close) {
/* The client will see a DESTROY, and infer that the connections
* are closing because the circuit is getting torn down. No need
* to send an end cell. */
@@ -1332,9 +1466,15 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
conn->on_circuit = NULL;
}
- if (or_circ->p_conn) {
- circuit_clear_cell_queue(circ, or_circ->p_conn);
- connection_or_send_destroy(or_circ->p_circ_id, or_circ->p_conn, reason);
+ if (or_circ->p_chan) {
+ circuit_clear_cell_queue(circ, or_circ->p_chan);
+ /* Only send destroy if the channel isn't closing anyway */
+ if (!(or_circ->p_chan->state == CHANNEL_STATE_CLOSING ||
+ or_circ->p_chan->state == CHANNEL_STATE_CLOSED ||
+ or_circ->p_chan->state == CHANNEL_STATE_ERROR)) {
+ channel_send_destroy(or_circ->p_circ_id, or_circ->p_chan, reason);
+ }
+ circuitmux_detach_circuit(or_circ->p_chan->cmux, circ);
}
} else {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
@@ -1350,7 +1490,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
if (!CIRCUIT_IS_ORIGIN(circ)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
if (or_circ->rend_splice) {
- if (!or_circ->rend_splice->_base.marked_for_close) {
+ if (!or_circ->rend_splice->base_.marked_for_close) {
/* do this after marking this circuit, to avoid infinite recursion. */
circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason);
}
@@ -1368,18 +1508,20 @@ marked_circuit_free_cells(circuit_t *circ)
log_warn(LD_BUG, "Called on non-marked circuit");
return;
}
- cell_queue_clear(&circ->n_conn_cells);
+ cell_queue_clear(&circ->n_chan_cells);
if (! CIRCUIT_IS_ORIGIN(circ))
- cell_queue_clear(& TO_OR_CIRCUIT(circ)->p_conn_cells);
+ cell_queue_clear(& TO_OR_CIRCUIT(circ)->p_chan_cells);
}
/** Return the number of cells used by the circuit <b>c</b>'s cell queues. */
static size_t
n_cells_in_circ_queues(const circuit_t *c)
{
- size_t n = c->n_conn_cells.n;
- if (! CIRCUIT_IS_ORIGIN(c))
- n += TO_OR_CIRCUIT((circuit_t*)c)->p_conn_cells.n;
+ size_t n = c->n_chan_cells.n;
+ if (! CIRCUIT_IS_ORIGIN(c)) {
+ circuit_t *cc = (circuit_t *) c;
+ n += TO_OR_CIRCUIT(cc)->p_chan_cells.n;
+ }
return n;
}
@@ -1395,13 +1537,13 @@ static uint32_t
circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
{
uint32_t age = 0;
- if (c->n_conn_cells.head)
- age = now - c->n_conn_cells.head->inserted_time;
+ if (c->n_chan_cells.head)
+ age = now - c->n_chan_cells.head->inserted_time;
if (! CIRCUIT_IS_ORIGIN(c)) {
const or_circuit_t *orcirc = TO_OR_CIRCUIT((circuit_t*)c);
- if (orcirc->p_conn_cells.head) {
- uint32_t age2 = now - orcirc->p_conn_cells.head->inserted_time;
+ if (orcirc->p_chan_cells.head) {
+ uint32_t age2 = now - orcirc->p_chan_cells.head->inserted_time;
if (age2 > age)
return age2;
}
@@ -1514,7 +1656,8 @@ assert_cpath_layer_ok(const crypt_path_t *cp)
tor_assert(cp->b_crypto);
/* fall through */
case CPATH_STATE_CLOSED:
- tor_assert(!cp->dh_handshake_state);
+ /*XXXX Assert that there's no handshake_state either. */
+ tor_assert(!cp->rend_dh_handshake_state);
break;
case CPATH_STATE_AWAITING_KEYS:
/* tor_assert(cp->dh_handshake_state); */
@@ -1562,8 +1705,8 @@ assert_circuit_ok(const circuit_t *c)
tor_assert(c);
tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC);
- tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN &&
- c->purpose <= _CIRCUIT_PURPOSE_MAX);
+ tor_assert(c->purpose >= CIRCUIT_PURPOSE_MIN_ &&
+ c->purpose <= CIRCUIT_PURPOSE_MAX_);
{
/* Having a separate variable for this pleases GCC 4.2 in ways I hope I
@@ -1575,33 +1718,33 @@ assert_circuit_ok(const circuit_t *c)
or_circ = TO_OR_CIRCUIT(nonconst_circ);
}
- if (c->n_conn) {
+ if (c->n_chan) {
tor_assert(!c->n_hop);
if (c->n_circ_id) {
/* We use the _impl variant here to make sure we don't fail on marked
* circuits, which would not be returned by the regular function. */
- circuit_t *c2 = circuit_get_by_circid_orconn_impl(c->n_circ_id,
- c->n_conn);
+ circuit_t *c2 = circuit_get_by_circid_channel_impl(c->n_circ_id,
+ c->n_chan);
tor_assert(c == c2);
}
}
- if (or_circ && or_circ->p_conn) {
+ if (or_circ && or_circ->p_chan) {
if (or_circ->p_circ_id) {
/* ibid */
- circuit_t *c2 = circuit_get_by_circid_orconn_impl(or_circ->p_circ_id,
- or_circ->p_conn);
+ circuit_t *c2 = circuit_get_by_circid_channel_impl(or_circ->p_circ_id,
+ or_circ->p_chan);
tor_assert(c == c2);
}
}
if (or_circ)
for (conn = or_circ->n_streams; conn; conn = conn->next_stream)
- tor_assert(conn->_base.type == CONN_TYPE_EXIT);
+ tor_assert(conn->base_.type == CONN_TYPE_EXIT);
tor_assert(c->deliver_window >= 0);
tor_assert(c->package_window >= 0);
if (c->state == CIRCUIT_STATE_OPEN) {
- tor_assert(!c->n_conn_onionskin);
+ tor_assert(!c->n_chan_create_cell);
if (or_circ) {
tor_assert(or_circ->n_crypto);
tor_assert(or_circ->p_crypto);
@@ -1609,12 +1752,12 @@ assert_circuit_ok(const circuit_t *c)
tor_assert(or_circ->p_digest);
}
}
- if (c->state == CIRCUIT_STATE_OR_WAIT && !c->marked_for_close) {
- tor_assert(circuits_pending_or_conns &&
- smartlist_isin(circuits_pending_or_conns, c));
+ if (c->state == CIRCUIT_STATE_CHAN_WAIT && !c->marked_for_close) {
+ tor_assert(circuits_pending_chans &&
+ smartlist_contains(circuits_pending_chans, c));
} else {
- tor_assert(!circuits_pending_or_conns ||
- !smartlist_isin(circuits_pending_or_conns, c));
+ tor_assert(!circuits_pending_chans ||
+ !smartlist_contains(circuits_pending_chans, c));
}
if (origin_circ && origin_circ->cpath) {
assert_cpath_ok(origin_circ->cpath);
diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h
index 44f0c1fe3..874f68cd2 100644
--- a/src/or/circuitlist.h
+++ b/src/or/circuitlist.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,29 +9,33 @@
* \brief Header file for circuitlist.c.
**/
-#ifndef _TOR_CIRCUITLIST_H
-#define _TOR_CIRCUITLIST_H
+#ifndef TOR_CIRCUITLIST_H
+#define TOR_CIRCUITLIST_H
-circuit_t * _circuit_get_global_list(void);
+circuit_t * circuit_get_global_list_(void);
const char *circuit_state_to_string(int state);
const char *circuit_purpose_to_controller_string(uint8_t purpose);
const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose);
const char *circuit_purpose_to_string(uint8_t purpose);
void circuit_dump_by_conn(connection_t *conn, int severity);
-void circuit_set_p_circid_orconn(or_circuit_t *circ, circid_t id,
- or_connection_t *conn);
-void circuit_set_n_circid_orconn(circuit_t *circ, circid_t id,
- or_connection_t *conn);
+void circuit_dump_by_chan(channel_t *chan, int severity);
+void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id,
+ channel_t *chan);
+void circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
+ channel_t *chan);
void circuit_set_state(circuit_t *circ, uint8_t state);
void circuit_close_all_marked(void);
int32_t circuit_initial_package_window(void);
origin_circuit_t *origin_circuit_new(void);
-or_circuit_t *or_circuit_new(circid_t p_circ_id, or_connection_t *p_conn);
-circuit_t *circuit_get_by_circid_orconn(circid_t circ_id,
- or_connection_t *conn);
-int circuit_id_in_use_on_orconn(circid_t circ_id, or_connection_t *conn);
+or_circuit_t *or_circuit_new(circid_t p_circ_id, channel_t *p_chan);
+circuit_t *circuit_get_by_circid_channel(circid_t circ_id,
+ channel_t *chan);
+circuit_t *
+circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
+ channel_t *chan);
+int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan);
circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn);
-void circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason);
+void circuit_unlink_all_from_channel(channel_t *chan, int reason);
origin_circuit_t *circuit_get_by_global_id(uint32_t id);
origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data(
const rend_data_t *rend_data);
@@ -42,17 +46,17 @@ or_circuit_t *circuit_get_intro_point(const char *digest);
origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
extend_info_t *info, int flags);
void circuit_mark_all_unused_circs(void);
-void circuit_expire_all_dirty_circs(void);
-void _circuit_mark_for_close(circuit_t *circ, int reason,
+void circuit_mark_all_dirty_circs_as_unusable(void);
+void circuit_mark_for_close_(circuit_t *circ, int reason,
int line, const char *file);
int circuit_get_cpath_len(origin_circuit_t *circ);
crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum);
-void circuit_get_all_pending_on_or_conn(smartlist_t *out,
- or_connection_t *or_conn);
-int circuit_count_pending_on_or_conn(or_connection_t *or_conn);
+void circuit_get_all_pending_on_channel(smartlist_t *out,
+ channel_t *chan);
+int circuit_count_pending_on_channel(channel_t *chan);
#define circuit_mark_for_close(c, reason) \
- _circuit_mark_for_close((c), (reason), __LINE__, _SHORT_FILE_)
+ circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__)
void assert_cpath_layer_ok(const crypt_path_t *cp);
void assert_circuit_ok(const circuit_t *c);
diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c
new file mode 100644
index 000000000..545cfd065
--- /dev/null
+++ b/src/or/circuitmux.c
@@ -0,0 +1,1745 @@
+/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitmux.c
+ * \brief Circuit mux/cell selection abstraction
+ **/
+
+#include "or.h"
+#include "channel.h"
+#include "circuitlist.h"
+#include "circuitmux.h"
+
+/*
+ * Private typedefs for circuitmux.c
+ */
+
+/*
+ * Map of muxinfos for circuitmux_t to use; struct is defined below (name
+ * of struct must match HT_HEAD line).
+ */
+typedef struct chanid_circid_muxinfo_map chanid_circid_muxinfo_map_t;
+
+/*
+ * Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to
+ * break the hash table code).
+ */
+typedef struct chanid_circid_muxinfo_t chanid_circid_muxinfo_t;
+
+/*
+ * Anything the mux wants to store per-circuit in the map; right now just
+ * a count of queued cells.
+ */
+
+typedef struct circuit_muxinfo_s circuit_muxinfo_t;
+
+/*
+ * Structures for circuitmux.c
+ */
+
+/*
+ * A circuitmux is a collection of circuits; it tracks which subset
+ * of the attached circuits are 'active' (i.e., have cells available
+ * to transmit) and how many cells on each. It expoes three distinct
+ * interfaces to other components:
+ *
+ * To channels, which each have a circuitmux_t, the supported operations
+ * are:
+ *
+ * circuitmux_get_first_active_circuit():
+ *
+ * Pick one of the circuitmux's active circuits to send cells from.
+ *
+ * circuitmux_notify_xmit_cells():
+ *
+ * Notify the circuitmux that cells have been sent on a circuit.
+ *
+ * To circuits, the exposed operations are:
+ *
+ * circuitmux_attach_circuit():
+ *
+ * Attach a circuit to the circuitmux; this will allocate any policy-
+ * specific data wanted for this circuit and add it to the active
+ * circuits list if it has queued cells.
+ *
+ * circuitmux_detach_circuit():
+ *
+ * Detach a circuit from the circuitmux, freeing associated structures.
+ *
+ * circuitmux_clear_num_cells():
+ *
+ * Clear the circuitmux's cell counter for this circuit.
+ *
+ * circuitmux_set_num_cells():
+ *
+ * Set the circuitmux's cell counter for this circuit.
+ *
+ * See circuitmux.h for the circuitmux_policy_t data structure, which contains
+ * a table of function pointers implementing a circuit selection policy, and
+ * circuitmux_ewma.c for an example of a circuitmux policy. Circuitmux
+ * policies can be manipulated with:
+ *
+ * circuitmux_get_policy():
+ *
+ * Return the current policy for a circuitmux_t, if any.
+ *
+ * circuitmux_clear_policy():
+ *
+ * Remove a policy installed on a circuitmux_t, freeing all associated
+ * data. The circuitmux will revert to the built-in round-robin behavior.
+ *
+ * circuitmux_set_policy():
+ *
+ * Install a policy on a circuitmux_t; the appropriate callbacks will be
+ * made to attach all existing circuits to the new policy.
+ *
+ */
+
+struct circuitmux_s {
+ /* Keep count of attached, active circuits */
+ unsigned int n_circuits, n_active_circuits;
+
+ /* Total number of queued cells on all circuits */
+ unsigned int n_cells;
+
+ /*
+ * Map from (channel ID, circuit ID) pairs to circuit_muxinfo_t
+ */
+ chanid_circid_muxinfo_map_t *chanid_circid_map;
+
+ /*
+ * Double-linked ring of circuits with queued cells waiting for room to
+ * free up on this connection's outbuf. Every time we pull cells from
+ * a circuit, we advance this pointer to the next circuit in the ring.
+ */
+ struct circuit_t *active_circuits_head, *active_circuits_tail;
+
+ /*
+ * Circuitmux policy; if this is non-NULL, it can override the built-
+ * in round-robin active circuits behavior. This is how EWMA works in
+ * the new circuitmux_t world.
+ */
+ const circuitmux_policy_t *policy;
+
+ /* Policy-specific data */
+ circuitmux_policy_data_t *policy_data;
+};
+
+/*
+ * This struct holds whatever we want to store per attached circuit on a
+ * circuitmux_t; right now, just the count of queued cells and the direction.
+ */
+
+struct circuit_muxinfo_s {
+ /* Count of cells on this circuit at last update */
+ unsigned int cell_count;
+ /* Direction of flow */
+ cell_direction_t direction;
+ /* Policy-specific data */
+ circuitmux_policy_circ_data_t *policy_data;
+ /* Mark bit for consistency checker */
+ unsigned int mark:1;
+};
+
+/*
+ * A map from channel ID and circuit ID to a circuit_muxinfo_t for that
+ * circuit.
+ */
+
+struct chanid_circid_muxinfo_t {
+ HT_ENTRY(chanid_circid_muxinfo_t) node;
+ uint64_t chan_id;
+ circid_t circ_id;
+ circuit_muxinfo_t muxinfo;
+};
+
+/*
+ * Internal-use #defines
+ */
+
+#ifdef CMUX_PARANOIA
+#define circuitmux_assert_okay_paranoid(cmux) \
+ circuitmux_assert_okay(cmux)
+#else
+#define circuitmux_assert_okay_paranoid(cmux)
+#endif
+
+/*
+ * Static function declarations
+ */
+
+static INLINE int
+chanid_circid_entries_eq(chanid_circid_muxinfo_t *a,
+ chanid_circid_muxinfo_t *b);
+static INLINE unsigned int
+chanid_circid_entry_hash(chanid_circid_muxinfo_t *a);
+static chanid_circid_muxinfo_t *
+circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ);
+static void
+circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction);
+static void
+circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction);
+static INLINE void
+circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction);
+static INLINE circuit_t **
+circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
+static INLINE circuit_t **
+circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
+static void circuitmux_assert_okay_pass_one(circuitmux_t *cmux);
+static void circuitmux_assert_okay_pass_two(circuitmux_t *cmux);
+static void circuitmux_assert_okay_pass_three(circuitmux_t *cmux);
+
+/* Function definitions */
+
+/**
+ * Linked list helpers
+ */
+
+/**
+ * Move an active circuit to the tail of the cmux's active circuits list;
+ * used by circuitmux_notify_xmit_cells().
+ */
+
+static INLINE void
+circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction)
+{
+ circuit_t **next_p = NULL, **prev_p = NULL;
+ circuit_t **next_prev = NULL, **prev_next = NULL;
+ circuit_t **tail_next = NULL;
+ or_circuit_t *or_circ = NULL;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ circuitmux_assert_okay_paranoid(cmux);
+
+ /* Figure out our next_p and prev_p for this cmux/direction */
+ if (direction) {
+ if (direction == CELL_DIRECTION_OUT) {
+ tor_assert(circ->n_mux == cmux);
+ next_p = &(circ->next_active_on_n_chan);
+ prev_p = &(circ->prev_active_on_n_chan);
+ } else {
+ or_circ = TO_OR_CIRCUIT(circ);
+ tor_assert(or_circ->p_mux == cmux);
+ next_p = &(or_circ->next_active_on_p_chan);
+ prev_p = &(or_circ->prev_active_on_p_chan);
+ }
+ } else {
+ if (circ->n_mux == cmux) {
+ next_p = &(circ->next_active_on_n_chan);
+ prev_p = &(circ->prev_active_on_n_chan);
+ direction = CELL_DIRECTION_OUT;
+ } else {
+ or_circ = TO_OR_CIRCUIT(circ);
+ tor_assert(or_circ->p_mux == cmux);
+ next_p = &(or_circ->next_active_on_p_chan);
+ prev_p = &(or_circ->prev_active_on_p_chan);
+ direction = CELL_DIRECTION_IN;
+ }
+ }
+ tor_assert(next_p);
+ tor_assert(prev_p);
+
+ /* Check if this really is an active circuit */
+ if ((*next_p == NULL && *prev_p == NULL) &&
+ !(circ == cmux->active_circuits_head ||
+ circ == cmux->active_circuits_tail)) {
+ /* Not active, no-op */
+ return;
+ }
+
+ /* Check if this is already the tail */
+ if (circ == cmux->active_circuits_tail) return;
+
+ /* Okay, we have to move it; figure out next_prev and prev_next */
+ if (*next_p) next_prev = circuitmux_prev_active_circ_p(cmux, *next_p);
+ if (*prev_p) prev_next = circuitmux_next_active_circ_p(cmux, *prev_p);
+ /* Adjust the previous node's next pointer, if any */
+ if (prev_next) *prev_next = *next_p;
+ /* Otherwise, we were the head */
+ else cmux->active_circuits_head = *next_p;
+ /* Adjust the next node's previous pointer, if any */
+ if (next_prev) *next_prev = *prev_p;
+ /* We're out of the list; now re-attach at the tail */
+ /* Adjust our next and prev pointers */
+ *next_p = NULL;
+ *prev_p = cmux->active_circuits_tail;
+ /* Set the next pointer of the tail, or the head if none */
+ if (cmux->active_circuits_tail) {
+ tail_next = circuitmux_next_active_circ_p(cmux,
+ cmux->active_circuits_tail);
+ *tail_next = circ;
+ } else {
+ cmux->active_circuits_head = circ;
+ }
+ /* Set the tail to this circuit */
+ cmux->active_circuits_tail = circ;
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+static INLINE circuit_t **
+circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
+{
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ if (circ->n_mux == cmux) return &(circ->next_active_on_n_chan);
+ else {
+ tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
+ return &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
+ }
+}
+
+static INLINE circuit_t **
+circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
+{
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ if (circ->n_mux == cmux) return &(circ->prev_active_on_n_chan);
+ else {
+ tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
+ return &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
+ }
+}
+
+/**
+ * Helper for chanid_circid_cell_count_map_t hash table: compare the channel
+ * ID and circuit ID for a and b, and return less than, equal to, or greater
+ * than zero appropriately.
+ */
+
+static INLINE int
+chanid_circid_entries_eq(chanid_circid_muxinfo_t *a,
+ chanid_circid_muxinfo_t *b)
+{
+ return a->chan_id == b->chan_id && a->circ_id == b->circ_id;
+}
+
+/**
+ * Helper: return a hash based on circuit ID and channel ID in a.
+ */
+
+static INLINE unsigned int
+chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
+{
+ return (((unsigned int)(a->circ_id) << 8) ^
+ ((unsigned int)((a->chan_id >> 32) & 0xffffffff)) ^
+ ((unsigned int)(a->chan_id & 0xffffffff)));
+}
+
+/* Declare the struct chanid_circid_muxinfo_map type */
+HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t);
+
+/* Emit a bunch of hash table stuff */
+HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
+ chanid_circid_entry_hash, chanid_circid_entries_eq);
+HT_GENERATE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
+ chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6,
+ malloc, realloc, free);
+
+/*
+ * Circuitmux alloc/free functions
+ */
+
+/**
+ * Allocate a new circuitmux_t
+ */
+
+circuitmux_t *
+circuitmux_alloc(void)
+{
+ circuitmux_t *rv = NULL;
+
+ rv = tor_malloc_zero(sizeof(*rv));
+ rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map)));
+ HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
+
+ return rv;
+}
+
+/**
+ * Detach all circuits from a circuitmux (use before circuitmux_free())
+ */
+
+void
+circuitmux_detach_all_circuits(circuitmux_t *cmux)
+{
+ chanid_circid_muxinfo_t **i = NULL, *to_remove;
+ channel_t *chan = NULL;
+ circuit_t *circ = NULL;
+
+ tor_assert(cmux);
+ /*
+ * Don't circuitmux_assert_okay_paranoid() here; this gets called when
+ * channels are being freed and have already been unregistered, so
+ * the channel ID lookups it does will fail.
+ */
+
+ i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+ while (i) {
+ to_remove = *i;
+ if (to_remove) {
+ /* Find a channel and circuit */
+ chan = channel_find_by_global_id(to_remove->chan_id);
+ if (chan) {
+ circ =
+ circuit_get_by_circid_channel_even_if_marked(to_remove->circ_id,
+ chan);
+ if (circ) {
+ /* Clear the circuit's mux for this direction */
+ if (to_remove->muxinfo.direction == CELL_DIRECTION_OUT) {
+ /*
+ * Update active_circuits et al.; this does policy notifies, so
+ * comes before freeing policy data
+ */
+
+ if (to_remove->muxinfo.cell_count > 0) {
+ circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_OUT);
+ }
+
+ /* Clear n_mux */
+ circ->n_mux = NULL;
+ } else if (circ->magic == OR_CIRCUIT_MAGIC) {
+ /*
+ * Update active_circuits et al.; this does policy notifies, so
+ * comes before freeing policy data
+ */
+
+ if (to_remove->muxinfo.cell_count > 0) {
+ circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_IN);
+ }
+
+ /*
+ * It has a sensible p_chan and direction == CELL_DIRECTION_IN,
+ * so clear p_mux.
+ */
+ TO_OR_CIRCUIT(circ)->p_mux = NULL;
+ } else {
+ /* Complain and move on */
+ log_warn(LD_CIRC,
+ "Circuit %u/channel " U64_FORMAT " had direction == "
+ "CELL_DIRECTION_IN, but isn't an or_circuit_t",
+ (unsigned)to_remove->circ_id,
+ U64_PRINTF_ARG(to_remove->chan_id));
+ }
+
+ /* Free policy-specific data if we have it */
+ if (to_remove->muxinfo.policy_data) {
+ /*
+ * If we have policy data, assert that we have the means to
+ * free it
+ */
+ tor_assert(cmux->policy);
+ tor_assert(cmux->policy->free_circ_data);
+ /* Call free_circ_data() */
+ cmux->policy->free_circ_data(cmux,
+ cmux->policy_data,
+ circ,
+ to_remove->muxinfo.policy_data);
+ to_remove->muxinfo.policy_data = NULL;
+ }
+ } else {
+ /* Complain and move on */
+ log_warn(LD_CIRC,
+ "Couldn't find circuit %u (for channel " U64_FORMAT ")",
+ (unsigned)to_remove->circ_id,
+ U64_PRINTF_ARG(to_remove->chan_id));
+ }
+ } else {
+ /* Complain and move on */
+ log_warn(LD_CIRC,
+ "Couldn't find channel " U64_FORMAT " (for circuit id %u)",
+ U64_PRINTF_ARG(to_remove->chan_id),
+ (unsigned)to_remove->circ_id);
+ }
+
+ /* Assert that we don't have un-freed policy data for this circuit */
+ tor_assert(to_remove->muxinfo.policy_data == NULL);
+ }
+
+ i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
+
+ /* Free it */
+ tor_free(to_remove);
+ }
+
+ cmux->n_circuits = 0;
+ cmux->n_active_circuits = 0;
+ cmux->n_cells = 0;
+}
+
+/**
+ * Free a circuitmux_t; the circuits must be detached first with
+ * circuitmux_detach_all_circuits().
+ */
+
+void
+circuitmux_free(circuitmux_t *cmux)
+{
+ if (!cmux) return;
+
+ tor_assert(cmux->n_circuits == 0);
+ tor_assert(cmux->n_active_circuits == 0);
+
+ /*
+ * Free policy-specific data if we have any; we don't
+ * need to do circuitmux_set_policy(cmux, NULL) to cover
+ * the circuits because they would have been handled in
+ * circuitmux_detach_all_circuits() before this was
+ * called.
+ */
+ if (cmux->policy && cmux->policy->free_cmux_data) {
+ if (cmux->policy_data) {
+ cmux->policy->free_cmux_data(cmux, cmux->policy_data);
+ cmux->policy_data = NULL;
+ }
+ } else tor_assert(cmux->policy_data == NULL);
+
+ if (cmux->chanid_circid_map) {
+ HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+ tor_free(cmux->chanid_circid_map);
+ }
+
+ tor_free(cmux);
+}
+
+/*
+ * Circuitmux policy control functions
+ */
+
+/**
+ * Remove any policy installed on cmux; all policy data will be freed and
+ * cmux behavior will revert to the built-in round-robin active_circuits
+ * mechanism.
+ */
+
+void
+circuitmux_clear_policy(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ /* Internally, this is just setting policy to NULL */
+ if (cmux->policy) {
+ circuitmux_set_policy(cmux, NULL);
+ }
+}
+
+/**
+ * Return the policy currently installed on a circuitmux_t
+ */
+
+const circuitmux_policy_t *
+circuitmux_get_policy(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ return cmux->policy;
+}
+
+/**
+ * Set policy; allocate for new policy, detach all circuits from old policy
+ * if any, attach them to new policy, and free old policy data.
+ */
+
+void
+circuitmux_set_policy(circuitmux_t *cmux,
+ const circuitmux_policy_t *pol)
+{
+ const circuitmux_policy_t *old_pol = NULL, *new_pol = NULL;
+ circuitmux_policy_data_t *old_pol_data = NULL, *new_pol_data = NULL;
+ chanid_circid_muxinfo_t **i = NULL;
+ channel_t *chan = NULL;
+ uint64_t last_chan_id_searched = 0;
+ circuit_t *circ = NULL;
+
+ tor_assert(cmux);
+
+ /* Set up variables */
+ old_pol = cmux->policy;
+ old_pol_data = cmux->policy_data;
+ new_pol = pol;
+
+ /* Check if this is the trivial case */
+ if (old_pol == new_pol) return;
+
+ /* Allocate data for new policy, if any */
+ if (new_pol && new_pol->alloc_cmux_data) {
+ /*
+ * If alloc_cmux_data is not null, then we expect to get some policy
+ * data. Assert that we also have free_cmux_data so we can free it
+ * when the time comes, and allocate it.
+ */
+ tor_assert(new_pol->free_cmux_data);
+ new_pol_data = new_pol->alloc_cmux_data(cmux);
+ tor_assert(new_pol_data);
+ }
+
+ /* Install new policy and new policy data on cmux */
+ cmux->policy = new_pol;
+ cmux->policy_data = new_pol_data;
+
+ /* Iterate over all circuits, attaching/detaching each one */
+ i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+ while (i) {
+ /* Assert that this entry isn't NULL */
+ tor_assert(*i);
+
+ /*
+ * Get the channel; since normal case is all circuits on the mux share a
+ * channel, we cache last_chan_id_searched
+ */
+ if (!chan || last_chan_id_searched != (*i)->chan_id) {
+ chan = channel_find_by_global_id((*i)->chan_id);
+ last_chan_id_searched = (*i)->chan_id;
+ }
+ tor_assert(chan);
+
+ /* Get the circuit */
+ circ = circuit_get_by_circid_channel_even_if_marked((*i)->circ_id, chan);
+ tor_assert(circ);
+
+ /* Need to tell old policy it becomes inactive (i.e., it is active) ? */
+ if (old_pol && old_pol->notify_circ_inactive &&
+ (*i)->muxinfo.cell_count > 0) {
+ old_pol->notify_circ_inactive(cmux, old_pol_data, circ,
+ (*i)->muxinfo.policy_data);
+ }
+
+ /* Need to free old policy data? */
+ if ((*i)->muxinfo.policy_data) {
+ /* Assert that we have the means to free it if we have policy data */
+ tor_assert(old_pol);
+ tor_assert(old_pol->free_circ_data);
+ /* Free it */
+ old_pol->free_circ_data(cmux, old_pol_data, circ,
+ (*i)->muxinfo.policy_data);
+ (*i)->muxinfo.policy_data = NULL;
+ }
+
+ /* Need to allocate new policy data? */
+ if (new_pol && new_pol->alloc_circ_data) {
+ /*
+ * If alloc_circ_data is not null, we expect to get some per-circuit
+ * policy data. Assert that we also have free_circ_data so we can
+ * free it when the time comes, and allocate it.
+ */
+ tor_assert(new_pol->free_circ_data);
+ (*i)->muxinfo.policy_data =
+ new_pol->alloc_circ_data(cmux, new_pol_data, circ,
+ (*i)->muxinfo.direction,
+ (*i)->muxinfo.cell_count);
+ }
+
+ /* Need to make active on new policy? */
+ if (new_pol && new_pol->notify_circ_active &&
+ (*i)->muxinfo.cell_count > 0) {
+ new_pol->notify_circ_active(cmux, new_pol_data, circ,
+ (*i)->muxinfo.policy_data);
+ }
+
+ /* Advance to next circuit map entry */
+ i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
+ }
+
+ /* Free data for old policy, if any */
+ if (old_pol_data) {
+ /*
+ * If we had old policy data, we should have an old policy and a free
+ * function for it.
+ */
+ tor_assert(old_pol);
+ tor_assert(old_pol->free_cmux_data);
+ old_pol->free_cmux_data(cmux, old_pol_data);
+ old_pol_data = NULL;
+ }
+}
+
+/*
+ * Circuitmux/circuit attachment status inquiry functions
+ */
+
+/**
+ * Query the direction of an attached circuit
+ */
+
+cell_direction_t
+circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+
+ /* Try to find a map entry */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+
+ /*
+ * This function should only be called on attached circuits; assert that
+ * we had a map entry.
+ */
+ tor_assert(hashent);
+
+ /* Return the direction from the map entry */
+ return hashent->muxinfo.direction;
+}
+
+/**
+ * Find an entry in the cmux's map for this circuit or return NULL if there
+ * is none.
+ */
+
+static chanid_circid_muxinfo_t *
+circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t search, *hashent = NULL;
+
+ /* Sanity-check parameters */
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+ tor_assert(circ);
+
+ /* Check if we have n_chan */
+ if (circ->n_chan) {
+ /* Okay, let's see if it's attached for n_chan/n_circ_id */
+ search.chan_id = circ->n_chan->global_identifier;
+ search.circ_id = circ->n_circ_id;
+
+ /* Query */
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+ }
+
+ /* Found something? */
+ if (hashent) {
+ /*
+ * Assert that the direction makes sense for a hashent we found by
+ * n_chan/n_circ_id before we return it.
+ */
+ tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_OUT);
+ } else {
+ /* Not there, have we got a p_chan/p_circ_id to try? */
+ if (circ->magic == OR_CIRCUIT_MAGIC) {
+ search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ /* Check for p_chan */
+ if (TO_OR_CIRCUIT(circ)->p_chan) {
+ search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
+ /* Okay, search for that */
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+ /* Find anything? */
+ if (hashent) {
+ /* Assert that the direction makes sense before we return it */
+ tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_IN);
+ }
+ }
+ }
+ }
+
+ /* Okay, hashent is it if it was there */
+ return hashent;
+}
+
+/**
+ * Query whether a circuit is attached to a circuitmux
+ */
+
+int
+circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+
+ /* Look if it's in the circuit map */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+
+ return (hashent != NULL);
+}
+
+/**
+ * Query whether a circuit is active on a circuitmux
+ */
+
+int
+circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+ int is_active = 0;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ /* Look if it's in the circuit map */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ if (hashent) {
+ /* Check the number of cells on this circuit */
+ is_active = (hashent->muxinfo.cell_count > 0);
+ }
+ /* else not attached, so not active */
+
+ return is_active;
+}
+
+/**
+ * Query number of available cells for a circuit on a circuitmux
+ */
+
+unsigned int
+circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+ unsigned int n_cells = 0;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ /* Look if it's in the circuit map */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ if (hashent) {
+ /* Just get the cell count for this circuit */
+ n_cells = hashent->muxinfo.cell_count;
+ }
+ /* else not attached, so 0 cells */
+
+ return n_cells;
+}
+
+/**
+ * Query total number of available cells on a circuitmux
+ */
+
+unsigned int
+circuitmux_num_cells(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ return cmux->n_cells;
+}
+
+/**
+ * Query total number of circuits active on a circuitmux
+ */
+
+unsigned int
+circuitmux_num_active_circuits(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ return cmux->n_active_circuits;
+}
+
+/**
+ * Query total number of circuits attached to a circuitmux
+ */
+
+unsigned int
+circuitmux_num_circuits(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ return cmux->n_circuits;
+}
+
+/*
+ * Functions for circuit code to call to update circuit status
+ */
+
+/**
+ * Attach a circuit to a circuitmux, for the specified direction.
+ */
+
+void
+circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction)
+{
+ channel_t *chan = NULL;
+ uint64_t channel_id;
+ circid_t circ_id;
+ chanid_circid_muxinfo_t search, *hashent = NULL;
+ unsigned int cell_count;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ tor_assert(direction == CELL_DIRECTION_IN ||
+ direction == CELL_DIRECTION_OUT);
+ circuitmux_assert_okay_paranoid(cmux);
+
+ /*
+ * Figure out which channel we're using, and get the circuit's current
+ * cell count and circuit ID; assert that the circuit is not already
+ * attached to another mux.
+ */
+ if (direction == CELL_DIRECTION_OUT) {
+ /* It's n_chan */
+ chan = circ->n_chan;
+ cell_count = circ->n_chan_cells.n;
+ circ_id = circ->n_circ_id;
+ } else {
+ /* We want p_chan */
+ chan = TO_OR_CIRCUIT(circ)->p_chan;
+ cell_count = TO_OR_CIRCUIT(circ)->p_chan_cells.n;
+ circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
+ /* Assert that we did get a channel */
+ tor_assert(chan);
+ /* Assert that the circuit ID is sensible */
+ tor_assert(circ_id != 0);
+
+ /* Get the channel ID */
+ channel_id = chan->global_identifier;
+
+ /* See if we already have this one */
+ search.chan_id = channel_id;
+ search.circ_id = circ_id;
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+
+ if (hashent) {
+ /*
+ * This circuit was already attached to this cmux; make sure the
+ * directions match and update the cell count and active circuit count.
+ */
+ log_info(LD_CIRC,
+ "Circuit %u on channel " U64_FORMAT " was already attached to "
+ "cmux %p (trying to attach to %p)",
+ (unsigned)circ_id, U64_PRINTF_ARG(channel_id),
+ ((direction == CELL_DIRECTION_OUT) ?
+ circ->n_mux : TO_OR_CIRCUIT(circ)->p_mux),
+ cmux);
+
+ /*
+ * The mux pointer on this circuit and the direction in result should
+ * match; otherwise assert.
+ */
+ if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == cmux);
+ else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
+ tor_assert(hashent->muxinfo.direction == direction);
+
+ /*
+ * Looks okay; just update the cell count and active circuits if we must
+ */
+ if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
+ --(cmux->n_active_circuits);
+ circuitmux_make_circuit_inactive(cmux, circ, direction);
+ } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
+ ++(cmux->n_active_circuits);
+ circuitmux_make_circuit_active(cmux, circ, direction);
+ }
+ cmux->n_cells -= hashent->muxinfo.cell_count;
+ cmux->n_cells += cell_count;
+ hashent->muxinfo.cell_count = cell_count;
+ } else {
+ /*
+ * New circuit; add an entry and update the circuit/active circuit
+ * counts.
+ */
+ log_debug(LD_CIRC,
+ "Attaching circuit %u on channel " U64_FORMAT " to cmux %p",
+ (unsigned)circ_id, U64_PRINTF_ARG(channel_id), cmux);
+
+ /*
+ * Assert that the circuit doesn't already have a mux for this
+ * direction.
+ */
+ if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == NULL);
+ else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == NULL);
+
+ /* Insert it in the map */
+ hashent = tor_malloc_zero(sizeof(*hashent));
+ hashent->chan_id = channel_id;
+ hashent->circ_id = circ_id;
+ hashent->muxinfo.cell_count = cell_count;
+ hashent->muxinfo.direction = direction;
+ /* Allocate policy specific circuit data if we need it */
+ if (cmux->policy && cmux->policy->alloc_circ_data) {
+ /* Assert that we have the means to free policy-specific data */
+ tor_assert(cmux->policy->free_circ_data);
+ /* Allocate it */
+ hashent->muxinfo.policy_data =
+ cmux->policy->alloc_circ_data(cmux,
+ cmux->policy_data,
+ circ,
+ direction,
+ cell_count);
+ /* If we wanted policy data, it's an error not to get any */
+ tor_assert(hashent->muxinfo.policy_data);
+ }
+ HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ hashent);
+
+ /* Set the circuit's mux for this direction */
+ if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux;
+ else TO_OR_CIRCUIT(circ)->p_mux = cmux;
+
+ /* Make sure the next/prev pointers are NULL */
+ if (direction == CELL_DIRECTION_OUT) {
+ circ->next_active_on_n_chan = NULL;
+ circ->prev_active_on_n_chan = NULL;
+ } else {
+ TO_OR_CIRCUIT(circ)->next_active_on_p_chan = NULL;
+ TO_OR_CIRCUIT(circ)->prev_active_on_p_chan = NULL;
+ }
+
+ /* Update counters */
+ ++(cmux->n_circuits);
+ if (cell_count > 0) {
+ ++(cmux->n_active_circuits);
+ circuitmux_make_circuit_active(cmux, circ, direction);
+ }
+ cmux->n_cells += cell_count;
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/**
+ * Detach a circuit from a circuitmux and update all counters as needed;
+ * no-op if not attached.
+ */
+
+void
+circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
+{
+ chanid_circid_muxinfo_t search, *hashent = NULL;
+ /*
+ * Use this to keep track of whether we found it for n_chan or
+ * p_chan for consistency checking.
+ */
+ cell_direction_t last_searched_direction;
+
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+ tor_assert(circ);
+ circuitmux_assert_okay_paranoid(cmux);
+
+ /* See if we have it for n_chan/n_circ_id */
+ if (circ->n_chan) {
+ search.chan_id = circ->n_chan->global_identifier;
+ search.circ_id = circ->n_circ_id;
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+ last_searched_direction = CELL_DIRECTION_OUT;
+ }
+
+ /* Got one? If not, see if it's an or_circuit_t and try p_chan/p_circ_id */
+ if (!hashent) {
+ if (circ->magic == OR_CIRCUIT_MAGIC) {
+ search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ if (TO_OR_CIRCUIT(circ)->p_chan) {
+ search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
+ hashent = HT_FIND(chanid_circid_muxinfo_map,
+ cmux->chanid_circid_map,
+ &search);
+ last_searched_direction = CELL_DIRECTION_IN;
+ }
+ }
+ }
+
+ /*
+ * If hashent isn't NULL, we have a circuit to detach; don't remove it from
+ * the map until later of circuitmux_make_circuit_inactive() breaks.
+ */
+ if (hashent) {
+ /* Update counters */
+ --(cmux->n_circuits);
+ if (hashent->muxinfo.cell_count > 0) {
+ --(cmux->n_active_circuits);
+ /* This does policy notifies, so comes before freeing policy data */
+ circuitmux_make_circuit_inactive(cmux, circ, last_searched_direction);
+ }
+ cmux->n_cells -= hashent->muxinfo.cell_count;
+
+ /* Free policy-specific data if we have it */
+ if (hashent->muxinfo.policy_data) {
+ /* If we have policy data, assert that we have the means to free it */
+ tor_assert(cmux->policy);
+ tor_assert(cmux->policy->free_circ_data);
+ /* Call free_circ_data() */
+ cmux->policy->free_circ_data(cmux,
+ cmux->policy_data,
+ circ,
+ hashent->muxinfo.policy_data);
+ hashent->muxinfo.policy_data = NULL;
+ }
+
+ /* Consistency check: the direction must match the direction searched */
+ tor_assert(last_searched_direction == hashent->muxinfo.direction);
+ /* Clear the circuit's mux for this direction */
+ if (last_searched_direction == CELL_DIRECTION_OUT) circ->n_mux = NULL;
+ else TO_OR_CIRCUIT(circ)->p_mux = NULL;
+
+ /* Now remove it from the map */
+ HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent);
+
+ /* Free the hash entry */
+ tor_free(hashent);
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/**
+ * Make a circuit active; update active list and policy-specific info, but
+ * we don't mess with the counters or hash table here.
+ */
+
+static void
+circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction)
+{
+ circuit_t **next_active = NULL, **prev_active = NULL, **next_prev = NULL;
+ circuitmux_t *circuit_cmux = NULL;
+ chanid_circid_muxinfo_t *hashent = NULL;
+ channel_t *chan = NULL;
+ circid_t circ_id;
+ int already_active;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ tor_assert(direction == CELL_DIRECTION_OUT ||
+ direction == CELL_DIRECTION_IN);
+ /*
+ * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
+ * already got changed and we have to update the list for it to be consistent
+ * again.
+ */
+
+ /* Get the right set of active list links for this direction */
+ if (direction == CELL_DIRECTION_OUT) {
+ next_active = &(circ->next_active_on_n_chan);
+ prev_active = &(circ->prev_active_on_n_chan);
+ circuit_cmux = circ->n_mux;
+ chan = circ->n_chan;
+ circ_id = circ->n_circ_id;
+ } else {
+ next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
+ prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
+ circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
+ chan = TO_OR_CIRCUIT(circ)->p_chan;
+ circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
+
+ /* Assert that it is attached to this mux and a channel */
+ tor_assert(cmux == circuit_cmux);
+ tor_assert(chan != NULL);
+
+ /*
+ * Check if the circuit really was inactive; if it's active, at least one
+ * of the next_active and prev_active pointers will not be NULL, or this
+ * circuit will be either the head or tail of the list for this cmux.
+ */
+ already_active = (*prev_active != NULL || *next_active != NULL ||
+ cmux->active_circuits_head == circ ||
+ cmux->active_circuits_tail == circ);
+
+ /* If we're already active, log a warning and finish */
+ if (already_active) {
+ log_warn(LD_CIRC,
+ "Circuit %u on channel " U64_FORMAT " was already active",
+ (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier));
+ return;
+ }
+
+ /*
+ * This is going at the head of the list; if the old head is not NULL,
+ * then its prev pointer should point to this.
+ */
+ *next_active = cmux->active_circuits_head; /* Next is old head */
+ *prev_active = NULL; /* Prev is NULL (this will be the head) */
+ if (cmux->active_circuits_head) {
+ /* The list had an old head; update its prev pointer */
+ next_prev =
+ circuitmux_prev_active_circ_p(cmux, cmux->active_circuits_head);
+ tor_assert(next_prev);
+ *next_prev = circ;
+ } else {
+ /* The list was empty; this becomes the tail as well */
+ cmux->active_circuits_tail = circ;
+ }
+ /* This becomes the new head of the list */
+ cmux->active_circuits_head = circ;
+
+ /* Policy-specific notification */
+ if (cmux->policy &&
+ cmux->policy->notify_circ_active) {
+ /* Okay, we need to check the circuit for policy data now */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ /* We should have found something */
+ tor_assert(hashent);
+ /* Notify */
+ cmux->policy->notify_circ_active(cmux, cmux->policy_data,
+ circ, hashent->muxinfo.policy_data);
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/**
+ * Make a circuit inactive; update active list and policy-specific info, but
+ * we don't mess with the counters or hash table here.
+ */
+
+static void
+circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction)
+{
+ circuit_t **next_active = NULL, **prev_active = NULL;
+ circuit_t **next_prev = NULL, **prev_next = NULL;
+ circuitmux_t *circuit_cmux = NULL;
+ chanid_circid_muxinfo_t *hashent = NULL;
+ channel_t *chan = NULL;
+ circid_t circ_id;
+ int already_inactive;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ tor_assert(direction == CELL_DIRECTION_OUT ||
+ direction == CELL_DIRECTION_IN);
+ /*
+ * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
+ * already got changed and we have to update the list for it to be consistent
+ * again.
+ */
+
+ /* Get the right set of active list links for this direction */
+ if (direction == CELL_DIRECTION_OUT) {
+ next_active = &(circ->next_active_on_n_chan);
+ prev_active = &(circ->prev_active_on_n_chan);
+ circuit_cmux = circ->n_mux;
+ chan = circ->n_chan;
+ circ_id = circ->n_circ_id;
+ } else {
+ next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
+ prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
+ circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
+ chan = TO_OR_CIRCUIT(circ)->p_chan;
+ circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+ }
+
+ /* Assert that it is attached to this mux and a channel */
+ tor_assert(cmux == circuit_cmux);
+ tor_assert(chan != NULL);
+
+ /*
+ * Check if the circuit really was active; if it's inactive, the
+ * next_active and prev_active pointers will be NULL and this circuit
+ * will not be the head or tail of the list for this cmux.
+ */
+ already_inactive = (*prev_active == NULL && *next_active == NULL &&
+ cmux->active_circuits_head != circ &&
+ cmux->active_circuits_tail != circ);
+
+ /* If we're already inactive, log a warning and finish */
+ if (already_inactive) {
+ log_warn(LD_CIRC,
+ "Circuit %d on channel " U64_FORMAT " was already inactive",
+ (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier));
+ return;
+ }
+
+ /* Remove from the list; first get next_prev and prev_next */
+ if (*next_active) {
+ /*
+ * If there's a next circuit, its previous circuit becomes this
+ * circuit's previous circuit.
+ */
+ next_prev = circuitmux_prev_active_circ_p(cmux, *next_active);
+ } else {
+ /* Else, the tail becomes this circuit's previous circuit */
+ next_prev = &(cmux->active_circuits_tail);
+ }
+
+ /* Got next_prev, now prev_next */
+ if (*prev_active) {
+ /*
+ * If there's a previous circuit, its next circuit becomes this circuit's
+ * next circuit.
+ */
+ prev_next = circuitmux_next_active_circ_p(cmux, *prev_active);
+ } else {
+ /* Else, the head becomes this circuit's next circuit */
+ prev_next = &(cmux->active_circuits_head);
+ }
+
+ /* Assert that we got sensible values for the next/prev pointers */
+ tor_assert(next_prev != NULL);
+ tor_assert(prev_next != NULL);
+
+ /* Update the next/prev pointers - this removes circ from the list */
+ *next_prev = *prev_active;
+ *prev_next = *next_active;
+
+ /* Now null out prev_active/next_active */
+ *prev_active = NULL;
+ *next_active = NULL;
+
+ /* Policy-specific notification */
+ if (cmux->policy &&
+ cmux->policy->notify_circ_inactive) {
+ /* Okay, we need to check the circuit for policy data now */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ /* We should have found something */
+ tor_assert(hashent);
+ /* Notify */
+ cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
+ circ, hashent->muxinfo.policy_data);
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/**
+ * Clear the cell counter for a circuit on a circuitmux
+ */
+
+void
+circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
+{
+ /* This is the same as setting the cell count to zero */
+ circuitmux_set_num_cells(cmux, circ, 0);
+}
+
+/**
+ * Set the cell counter for a circuit on a circuitmux
+ */
+
+void
+circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
+ unsigned int n_cells)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+
+ circuitmux_assert_okay_paranoid(cmux);
+
+ /* Search for this circuit's entry */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ /* Assert that we found one */
+ tor_assert(hashent);
+
+ /* Update cmux cell counter */
+ cmux->n_cells -= hashent->muxinfo.cell_count;
+ cmux->n_cells += n_cells;
+
+ /* Do we need to notify a cmux policy? */
+ if (cmux->policy && cmux->policy->notify_set_n_cells) {
+ /* Call notify_set_n_cells */
+ cmux->policy->notify_set_n_cells(cmux,
+ cmux->policy_data,
+ circ,
+ hashent->muxinfo.policy_data,
+ n_cells);
+ }
+
+ /*
+ * Update cmux active circuit counter: is the old cell count > 0 and the
+ * new cell count == 0 ?
+ */
+ if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
+ --(cmux->n_active_circuits);
+ hashent->muxinfo.cell_count = n_cells;
+ circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
+ /* Is the old cell count == 0 and the new cell count > 0 ? */
+ } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
+ ++(cmux->n_active_circuits);
+ hashent->muxinfo.cell_count = n_cells;
+ circuitmux_make_circuit_active(cmux, circ, hashent->muxinfo.direction);
+ } else {
+ /*
+ * Update the entry cell count like this so we can put a
+ * circuitmux_assert_okay_paranoid inside make_circuit_(in)active() too.
+ */
+ hashent->muxinfo.cell_count = n_cells;
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/*
+ * Functions for channel code to call to get a circuit to transmit from or
+ * notify that cells have been transmitted.
+ */
+
+/**
+ * Pick a circuit to send from, using the active circuits list or a
+ * circuitmux policy if one is available. This is called from channel.c.
+ */
+
+circuit_t *
+circuitmux_get_first_active_circuit(circuitmux_t *cmux)
+{
+ circuit_t *circ = NULL;
+
+ tor_assert(cmux);
+
+ if (cmux->n_active_circuits > 0) {
+ /* We also must have a cell available for this to be the case */
+ tor_assert(cmux->n_cells > 0);
+ /* Do we have a policy-provided circuit selector? */
+ if (cmux->policy && cmux->policy->pick_active_circuit) {
+ circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
+ }
+ /* Fall back on the head of the active circuits list */
+ if (!circ) {
+ tor_assert(cmux->active_circuits_head);
+ circ = cmux->active_circuits_head;
+ }
+ } else tor_assert(cmux->n_cells == 0);
+
+ return circ;
+}
+
+/**
+ * Notify the circuitmux that cells have been sent on a circuit; this
+ * is called from channel.c.
+ */
+
+void
+circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
+ unsigned int n_cells)
+{
+ chanid_circid_muxinfo_t *hashent = NULL;
+ int becomes_inactive = 0;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ circuitmux_assert_okay_paranoid(cmux);
+
+ if (n_cells == 0) return;
+
+ /*
+ * To handle this, we have to:
+ *
+ * 1.) Adjust the circuit's cell counter in the cmux hash table
+ * 2.) Move the circuit to the tail of the active_circuits linked list
+ * for this cmux, or make the circuit inactive if the cell count
+ * went to zero.
+ * 3.) Call cmux->policy->notify_xmit_cells(), if any
+ */
+
+ /* Find the hash entry */
+ hashent = circuitmux_find_map_entry(cmux, circ);
+ /* Assert that we found one */
+ tor_assert(hashent);
+
+ /* Adjust the cell counter and assert that we had that many cells to send */
+ tor_assert(n_cells <= hashent->muxinfo.cell_count);
+ hashent->muxinfo.cell_count -= n_cells;
+ /* Do we need to make the circuit inactive? */
+ if (hashent->muxinfo.cell_count == 0) becomes_inactive = 1;
+ /* Adjust the mux cell counter */
+ cmux->n_cells -= n_cells;
+
+ /* If we aren't making it inactive later, move it to the tail of the list */
+ if (!becomes_inactive) {
+ circuitmux_move_active_circ_to_tail(cmux, circ,
+ hashent->muxinfo.direction);
+ }
+
+ /*
+ * We call notify_xmit_cells() before making the circuit inactive if needed,
+ * so the policy can always count on this coming in on an active circuit.
+ */
+ if (cmux->policy && cmux->policy->notify_xmit_cells) {
+ cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ,
+ hashent->muxinfo.policy_data,
+ n_cells);
+ }
+
+ /*
+ * Now make the circuit inactive if needed; this will call the policy's
+ * notify_circ_inactive() if present.
+ */
+ if (becomes_inactive) {
+ --(cmux->n_active_circuits);
+ circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
+ }
+
+ circuitmux_assert_okay_paranoid(cmux);
+}
+
+/*
+ * Circuitmux consistency checking assertions
+ */
+
+/**
+ * Check that circuitmux data structures are consistent and fail with an
+ * assert if not.
+ */
+
+void
+circuitmux_assert_okay(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ /*
+ * Pass 1: iterate the hash table; for each entry:
+ * a) Check that the circuit has this cmux for n_mux or p_mux
+ * b) If the cell_count is > 0, set the mark bit; otherwise clear it
+ * c) Also check activeness (cell_count > 0 should be active)
+ * d) Count the number of circuits, active circuits and queued cells
+ * and at the end check that they match the counters in the cmux.
+ *
+ * Pass 2: iterate the active circuits list; for each entry,
+ * make sure the circuit is attached to this mux and appears
+ * in the hash table. Make sure the mark bit is 1, and clear
+ * it in the hash table entry. Consistency-check the linked
+ * list pointers.
+ *
+ * Pass 3: iterate the hash table again; assert if any active circuits
+ * (mark bit set to 1) are discovered that weren't cleared in pass 2
+ * (don't appear in the linked list).
+ */
+
+ circuitmux_assert_okay_pass_one(cmux);
+ circuitmux_assert_okay_pass_two(cmux);
+ circuitmux_assert_okay_pass_three(cmux);
+}
+
+/**
+ * Do the first pass of circuitmux_assert_okay(); see the comment in that
+ * function.
+ */
+
+static void
+circuitmux_assert_okay_pass_one(circuitmux_t *cmux)
+{
+ chanid_circid_muxinfo_t **i = NULL;
+ uint64_t chan_id;
+ channel_t *chan;
+ circid_t circ_id;
+ circuit_t *circ;
+ or_circuit_t *or_circ;
+ unsigned int circ_is_active;
+ circuit_t **next_p, **prev_p;
+ unsigned int n_circuits, n_active_circuits, n_cells;
+
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+
+ /* Reset the counters */
+ n_circuits = n_active_circuits = n_cells = 0;
+ /* Start iterating the hash table */
+ i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+ while (i) {
+ /* Assert that the hash table entry isn't null */
+ tor_assert(*i);
+
+ /* Get the channel and circuit id */
+ chan_id = (*i)->chan_id;
+ circ_id = (*i)->circ_id;
+
+ /* Find the channel and circuit, assert that they exist */
+ chan = channel_find_by_global_id(chan_id);
+ tor_assert(chan);
+ circ = circuit_get_by_circid_channel_even_if_marked(circ_id, chan);
+ tor_assert(circ);
+ /* Clear the circ_is_active bit to start */
+ circ_is_active = 0;
+
+ /* Assert that we know which direction this is going */
+ tor_assert((*i)->muxinfo.direction == CELL_DIRECTION_OUT ||
+ (*i)->muxinfo.direction == CELL_DIRECTION_IN);
+
+ if ((*i)->muxinfo.direction == CELL_DIRECTION_OUT) {
+ /* We should be n_mux on this circuit */
+ tor_assert(cmux == circ->n_mux);
+ tor_assert(chan == circ->n_chan);
+ /* Get next and prev for next test */
+ next_p = &(circ->next_active_on_n_chan);
+ prev_p = &(circ->prev_active_on_n_chan);
+ } else {
+ /* This should be an or_circuit_t and we should be p_mux */
+ or_circ = TO_OR_CIRCUIT(circ);
+ tor_assert(cmux == or_circ->p_mux);
+ tor_assert(chan == or_circ->p_chan);
+ /* Get next and prev for next test */
+ next_p = &(or_circ->next_active_on_p_chan);
+ prev_p = &(or_circ->prev_active_on_p_chan);
+ }
+
+ /*
+ * Should this circuit be active? I.e., does the mux know about > 0
+ * cells on it?
+ */
+ circ_is_active = ((*i)->muxinfo.cell_count > 0);
+
+ /* It should be in the linked list iff it's active */
+ if (circ_is_active) {
+ /* Either we have a next link or we are the tail */
+ tor_assert(*next_p || (circ == cmux->active_circuits_tail));
+ /* Either we have a prev link or we are the head */
+ tor_assert(*prev_p || (circ == cmux->active_circuits_head));
+ /* Increment the active circuits counter */
+ ++n_active_circuits;
+ } else {
+ /* Shouldn't be in list, so no next or prev link */
+ tor_assert(!(*next_p));
+ tor_assert(!(*prev_p));
+ /* And can't be head or tail */
+ tor_assert(circ != cmux->active_circuits_head);
+ tor_assert(circ != cmux->active_circuits_tail);
+ }
+
+ /* Increment the circuits counter */
+ ++n_circuits;
+ /* Adjust the cell counter */
+ n_cells += (*i)->muxinfo.cell_count;
+
+ /* Set the mark bit to circ_is_active */
+ (*i)->muxinfo.mark = circ_is_active;
+
+ /* Advance to the next entry */
+ i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
+ }
+
+ /* Now check the counters */
+ tor_assert(n_cells == cmux->n_cells);
+ tor_assert(n_circuits == cmux->n_circuits);
+ tor_assert(n_active_circuits == cmux->n_active_circuits);
+}
+
+/**
+ * Do the second pass of circuitmux_assert_okay(); see the comment in that
+ * function.
+ */
+
+static void
+circuitmux_assert_okay_pass_two(circuitmux_t *cmux)
+{
+ circuit_t *curr_circ, *prev_circ = NULL, *next_circ;
+ or_circuit_t *curr_or_circ;
+ uint64_t curr_chan_id;
+ circid_t curr_circ_id;
+ circuit_t **next_p, **prev_p;
+ channel_t *chan;
+ unsigned int n_active_circuits = 0;
+ cell_direction_t direction;
+ chanid_circid_muxinfo_t search, *hashent = NULL;
+
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+
+ /*
+ * Walk the linked list of active circuits in cmux; keep track of the
+ * previous circuit seen for consistency checking purposes. Count them
+ * to make sure the number in the linked list matches
+ * cmux->n_active_circuits.
+ */
+ curr_circ = cmux->active_circuits_head;
+ while (curr_circ) {
+ /* Reset some things */
+ chan = NULL;
+ curr_or_circ = NULL;
+ next_circ = NULL;
+ next_p = prev_p = NULL;
+ direction = 0;
+
+ /* Figure out if this is n_mux or p_mux */
+ if (cmux == curr_circ->n_mux) {
+ /* Get next_p and prev_p */
+ next_p = &(curr_circ->next_active_on_n_chan);
+ prev_p = &(curr_circ->prev_active_on_n_chan);
+ /* Get the channel */
+ chan = curr_circ->n_chan;
+ /* Get the circuit id */
+ curr_circ_id = curr_circ->n_circ_id;
+ /* Remember the direction */
+ direction = CELL_DIRECTION_OUT;
+ } else {
+ /* We must be p_mux and this must be an or_circuit_t */
+ curr_or_circ = TO_OR_CIRCUIT(curr_circ);
+ tor_assert(cmux == curr_or_circ->p_mux);
+ /* Get next_p and prev_p */
+ next_p = &(curr_or_circ->next_active_on_p_chan);
+ prev_p = &(curr_or_circ->prev_active_on_p_chan);
+ /* Get the channel */
+ chan = curr_or_circ->p_chan;
+ /* Get the circuit id */
+ curr_circ_id = curr_or_circ->p_circ_id;
+ /* Remember the direction */
+ direction = CELL_DIRECTION_IN;
+ }
+
+ /* Assert that we got a channel and get the channel ID */
+ tor_assert(chan);
+ curr_chan_id = chan->global_identifier;
+
+ /* Assert that prev_p points to last circuit we saw */
+ tor_assert(*prev_p == prev_circ);
+ /* If that's NULL, assert that we are the head */
+ if (!(*prev_p)) tor_assert(curr_circ == cmux->active_circuits_head);
+
+ /* Get the next circuit */
+ next_circ = *next_p;
+ /* If it's NULL, assert that we are the tail */
+ if (!(*next_p)) tor_assert(curr_circ == cmux->active_circuits_tail);
+
+ /* Now find the hash table entry for this circuit */
+ search.chan_id = curr_chan_id;
+ search.circ_id = curr_circ_id;
+ hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
+ &search);
+
+ /* Assert that we have one */
+ tor_assert(hashent);
+
+ /* Assert that the direction matches */
+ tor_assert(direction == hashent->muxinfo.direction);
+
+ /* Assert that the hash entry got marked in pass one */
+ tor_assert(hashent->muxinfo.mark);
+
+ /* Clear the mark */
+ hashent->muxinfo.mark = 0;
+
+ /* Increment the counter */
+ ++n_active_circuits;
+
+ /* Advance to the next active circuit and update prev_circ */
+ prev_circ = curr_circ;
+ curr_circ = next_circ;
+ }
+
+ /* Assert that the counter matches the cmux */
+ tor_assert(n_active_circuits == cmux->n_active_circuits);
+}
+
+/**
+ * Do the third pass of circuitmux_assert_okay(); see the comment in that
+ * function.
+ */
+
+static void
+circuitmux_assert_okay_pass_three(circuitmux_t *cmux)
+{
+ chanid_circid_muxinfo_t **i = NULL;
+
+ tor_assert(cmux);
+ tor_assert(cmux->chanid_circid_map);
+
+ /* Start iterating the hash table */
+ i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
+
+ /* Advance through each entry */
+ while (i) {
+ /* Assert that it isn't null */
+ tor_assert(*i);
+
+ /*
+ * Assert that this entry is not marked - i.e., that either we didn't
+ * think it should be active in pass one or we saw it in the active
+ * circuits linked list.
+ */
+ tor_assert(!((*i)->muxinfo.mark));
+
+ /* Advance to the next entry */
+ i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
+ }
+}
+
diff --git a/src/or/circuitmux.h b/src/or/circuitmux.h
new file mode 100644
index 000000000..25644ffab
--- /dev/null
+++ b/src/or/circuitmux.h
@@ -0,0 +1,136 @@
+/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitmux.h
+ * \brief Header file for circuitmux.c
+ **/
+
+#ifndef TOR_CIRCUITMUX_H
+#define TOR_CIRCUITMUX_H
+
+#include "or.h"
+
+typedef struct circuitmux_policy_s circuitmux_policy_t;
+typedef struct circuitmux_policy_data_s circuitmux_policy_data_t;
+typedef struct circuitmux_policy_circ_data_s circuitmux_policy_circ_data_t;
+
+struct circuitmux_policy_s {
+ /* Allocate cmux-wide policy-specific data */
+ circuitmux_policy_data_t * (*alloc_cmux_data)(circuitmux_t *cmux);
+ /* Free cmux-wide policy-specific data */
+ void (*free_cmux_data)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data);
+ /* Allocate circuit policy-specific data for a newly attached circuit */
+ circuitmux_policy_circ_data_t *
+ (*alloc_circ_data)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ cell_direction_t direction,
+ unsigned int cell_count);
+ /* Free circuit policy-specific data */
+ void (*free_circ_data)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+ /* Notify that a circuit has become active/inactive */
+ void (*notify_circ_active)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+ void (*notify_circ_inactive)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+ /* Notify of arriving/transmitted cells on a circuit */
+ void (*notify_set_n_cells)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data,
+ unsigned int n_cells);
+ void (*notify_xmit_cells)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data,
+ unsigned int n_cells);
+ /* Choose a circuit */
+ circuit_t * (*pick_active_circuit)(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data);
+};
+
+/*
+ * Circuitmux policy implementations can subclass this to store circuitmux-
+ * wide data; it just has the magic number in the base struct.
+ */
+
+struct circuitmux_policy_data_s {
+ uint32_t magic;
+};
+
+/*
+ * Circuitmux policy implementations can subclass this to store circuit-
+ * specific data; it just has the magic number in the base struct.
+ */
+
+struct circuitmux_policy_circ_data_s {
+ uint32_t magic;
+};
+
+/*
+ * Upcast #defines for the above types
+ */
+
+/**
+ * Convert a circuitmux_policy_data_t subtype to a circuitmux_policy_data_t.
+ */
+
+#define TO_CMUX_POL_DATA(x) (&((x)->base_))
+
+/**
+ * Convert a circuitmux_policy_circ_data_t subtype to a
+ * circuitmux_policy_circ_data_t.
+ */
+
+#define TO_CMUX_POL_CIRC_DATA(x) (&((x)->base_))
+
+/* Consistency check */
+void circuitmux_assert_okay(circuitmux_t *cmux);
+
+/* Create/destroy */
+circuitmux_t * circuitmux_alloc(void);
+void circuitmux_detach_all_circuits(circuitmux_t *cmux);
+void circuitmux_free(circuitmux_t *cmux);
+
+/* Policy control */
+void circuitmux_clear_policy(circuitmux_t *cmux);
+const circuitmux_policy_t * circuitmux_get_policy(circuitmux_t *cmux);
+void circuitmux_set_policy(circuitmux_t *cmux,
+ const circuitmux_policy_t *pol);
+
+/* Status inquiries */
+cell_direction_t circuitmux_attached_circuit_direction(
+ circuitmux_t *cmux,
+ circuit_t *circ);
+int circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ);
+int circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ);
+unsigned int circuitmux_num_cells_for_circuit(circuitmux_t *cmux,
+ circuit_t *circ);
+unsigned int circuitmux_num_cells(circuitmux_t *cmux);
+unsigned int circuitmux_num_circuits(circuitmux_t *cmux);
+unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux);
+
+/* Channel interface */
+circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux);
+void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
+ unsigned int n_cells);
+
+/* Circuit interface */
+void circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction);
+void circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ);
+void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ);
+void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
+ unsigned int n_cells);
+
+#endif /* TOR_CIRCUITMUX_H */
+
diff --git a/src/or/circuitmux_ewma.c b/src/or/circuitmux_ewma.c
new file mode 100644
index 000000000..3f37d7b9a
--- /dev/null
+++ b/src/or/circuitmux_ewma.c
@@ -0,0 +1,684 @@
+/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitmux_ewma.c
+ * \brief EWMA circuit selection as a circuitmux_t policy
+ **/
+
+#define TOR_CIRCUITMUX_EWMA_C_
+
+#include <math.h>
+
+#include "or.h"
+#include "circuitmux.h"
+#include "circuitmux_ewma.h"
+#include "networkstatus.h"
+
+/*** EWMA parameter #defines ***/
+
+/** How long does a tick last (seconds)? */
+#define EWMA_TICK_LEN 10
+
+/** The default per-tick scale factor, if it hasn't been overridden by a
+ * consensus or a configuration setting. zero means "disabled". */
+#define EWMA_DEFAULT_HALFLIFE 0.0
+
+/*** Some useful constant #defines ***/
+
+/*DOCDOC*/
+#define EPSILON 0.00001
+/*DOCDOC*/
+#define LOG_ONEHALF -0.69314718055994529
+
+/*** EWMA structures ***/
+
+typedef struct cell_ewma_s cell_ewma_t;
+typedef struct ewma_policy_data_s ewma_policy_data_t;
+typedef struct ewma_policy_circ_data_s ewma_policy_circ_data_t;
+
+/**
+ * The cell_ewma_t structure keeps track of how many cells a circuit has
+ * transferred recently. It keeps an EWMA (exponentially weighted moving
+ * average) of the number of cells flushed from the circuit queue onto a
+ * connection in channel_flush_from_first_active_circuit().
+ */
+
+struct cell_ewma_s {
+ /** The last 'tick' at which we recalibrated cell_count.
+ *
+ * A cell sent at exactly the start of this tick has weight 1.0. Cells sent
+ * since the start of this tick have weight greater than 1.0; ones sent
+ * earlier have less weight. */
+ unsigned int last_adjusted_tick;
+ /** The EWMA of the cell count. */
+ double cell_count;
+ /** True iff this is the cell count for a circuit's previous
+ * channel. */
+ unsigned int is_for_p_chan : 1;
+ /** The position of the circuit within the OR connection's priority
+ * queue. */
+ int heap_index;
+};
+
+struct ewma_policy_data_s {
+ circuitmux_policy_data_t base_;
+
+ /**
+ * Priority queue of cell_ewma_t for circuits with queued cells waiting
+ * for room to free up on the channel that owns this circuitmux. Kept
+ * in heap order according to EWMA. This was formerly in channel_t, and
+ * in or_connection_t before that.
+ */
+ smartlist_t *active_circuit_pqueue;
+
+ /**
+ * The tick on which the cell_ewma_ts in active_circuit_pqueue last had
+ * their ewma values rescaled. This was formerly in channel_t, and in
+ * or_connection_t before that.
+ */
+ unsigned int active_circuit_pqueue_last_recalibrated;
+};
+
+struct ewma_policy_circ_data_s {
+ circuitmux_policy_circ_data_t base_;
+
+ /**
+ * The EWMA count for the number of cells flushed from this circuit
+ * onto this circuitmux. Used to determine which circuit to flush
+ * from next. This was formerly in circuit_t and or_circuit_t.
+ */
+ cell_ewma_t cell_ewma;
+
+ /**
+ * Pointer back to the circuit_t this is for; since we're separating
+ * out circuit selection policy like this, we can't attach cell_ewma_t
+ * to the circuit_t any more, so we can't use SUBTYPE_P directly to a
+ * circuit_t like before; instead get it here.
+ */
+ circuit_t *circ;
+};
+
+#define EWMA_POL_DATA_MAGIC 0x2fd8b16aU
+#define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U
+
+/*** Downcasts for the above types ***/
+
+static ewma_policy_data_t *
+TO_EWMA_POL_DATA(circuitmux_policy_data_t *);
+
+static ewma_policy_circ_data_t *
+TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *);
+
+/**
+ * Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert
+ * if the cast is impossible.
+ */
+
+static INLINE ewma_policy_data_t *
+TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol)
+{
+ if (!pol) return NULL;
+ else {
+ tor_assert(pol->magic == EWMA_POL_DATA_MAGIC);
+ return DOWNCAST(ewma_policy_data_t, pol);
+ }
+}
+
+/**
+ * Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t
+ * and assert if the cast is impossible.
+ */
+
+static INLINE ewma_policy_circ_data_t *
+TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol)
+{
+ if (!pol) return NULL;
+ else {
+ tor_assert(pol->magic == EWMA_POL_CIRC_DATA_MAGIC);
+ return DOWNCAST(ewma_policy_circ_data_t, pol);
+ }
+}
+
+/*** Static declarations for circuitmux_ewma.c ***/
+
+static void add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma);
+static int compare_cell_ewma_counts(const void *p1, const void *p2);
+static unsigned cell_ewma_tick_from_timeval(const struct timeval *now,
+ double *remainder_out);
+static circuit_t * cell_ewma_to_circuit(cell_ewma_t *ewma);
+static INLINE double get_scale_factor(unsigned from_tick, unsigned to_tick);
+static cell_ewma_t * pop_first_cell_ewma(ewma_policy_data_t *pol);
+static void remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma);
+static void scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick);
+static void scale_active_circuits(ewma_policy_data_t *pol,
+ unsigned cur_tick);
+
+/*** Circuitmux policy methods ***/
+
+static circuitmux_policy_data_t * ewma_alloc_cmux_data(circuitmux_t *cmux);
+static void ewma_free_cmux_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data);
+static circuitmux_policy_circ_data_t *
+ewma_alloc_circ_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data,
+ circuit_t *circ, cell_direction_t direction,
+ unsigned int cell_count);
+static void
+ewma_free_circ_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+static void
+ewma_notify_circ_active(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+static void
+ewma_notify_circ_inactive(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data);
+static void
+ewma_notify_xmit_cells(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data,
+ unsigned int n_cells);
+static circuit_t *
+ewma_pick_active_circuit(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data);
+
+/*** EWMA global variables ***/
+
+/** The per-tick scale factor to be used when computing cell-count EWMA
+ * values. (A cell sent N ticks before the start of the current tick
+ * has value ewma_scale_factor ** N.)
+ */
+static double ewma_scale_factor = 0.1;
+/* DOCDOC ewma_enabled */
+static int ewma_enabled = 0;
+
+/*** EWMA circuitmux_policy_t method table ***/
+
+circuitmux_policy_t ewma_policy = {
+ /*.alloc_cmux_data =*/ ewma_alloc_cmux_data,
+ /*.free_cmux_data =*/ ewma_free_cmux_data,
+ /*.alloc_circ_data =*/ ewma_alloc_circ_data,
+ /*.free_circ_data =*/ ewma_free_circ_data,
+ /*.notify_circ_active =*/ ewma_notify_circ_active,
+ /*.notify_circ_inactive =*/ ewma_notify_circ_inactive,
+ /*.notify_set_n_cells =*/ NULL, /* EWMA doesn't need this */
+ /*.notify_xmit_cells =*/ ewma_notify_xmit_cells,
+ /*.pick_active_circuit =*/ ewma_pick_active_circuit
+};
+
+/*** EWMA method implementations using the below EWMA helper functions ***/
+
+/**
+ * Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t;
+ * this is called when setting the policy on a circuitmux_t to ewma_policy.
+ */
+
+static circuitmux_policy_data_t *
+ewma_alloc_cmux_data(circuitmux_t *cmux)
+{
+ ewma_policy_data_t *pol = NULL;
+
+ tor_assert(cmux);
+
+ pol = tor_malloc_zero(sizeof(*pol));
+ pol->base_.magic = EWMA_POL_DATA_MAGIC;
+ pol->active_circuit_pqueue = smartlist_new();
+ pol->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick();
+
+ return TO_CMUX_POL_DATA(pol);
+}
+
+/**
+ * Free an ewma_policy_data_t allocated with ewma_alloc_cmux_data()
+ */
+
+static void
+ewma_free_cmux_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data)
+{
+ ewma_policy_data_t *pol = NULL;
+
+ tor_assert(cmux);
+ if (!pol_data) return;
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+
+ smartlist_free(pol->active_circuit_pqueue);
+ tor_free(pol);
+}
+
+/**
+ * Allocate an ewma_policy_circ_data_t and upcast it to a
+ * circuitmux_policy_data_t; this is called when attaching a circuit to a
+ * circuitmux_t with ewma_policy.
+ */
+
+static circuitmux_policy_circ_data_t *
+ewma_alloc_circ_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ cell_direction_t direction,
+ unsigned int cell_count)
+{
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+ tor_assert(circ);
+ tor_assert(direction == CELL_DIRECTION_OUT ||
+ direction == CELL_DIRECTION_IN);
+ /* Shut the compiler up */
+ tor_assert(cell_count == cell_count);
+
+ cdata = tor_malloc_zero(sizeof(*cdata));
+ cdata->base_.magic = EWMA_POL_CIRC_DATA_MAGIC;
+ cdata->circ = circ;
+
+ /*
+ * Initialize the cell_ewma_t structure (formerly in
+ * init_circuit_base())
+ */
+ cdata->cell_ewma.last_adjusted_tick = cell_ewma_get_tick();
+ cdata->cell_ewma.cell_count = 0.0;
+ cdata->cell_ewma.heap_index = -1;
+ if (direction == CELL_DIRECTION_IN) {
+ cdata->cell_ewma.is_for_p_chan = 1;
+ } else {
+ cdata->cell_ewma.is_for_p_chan = 0;
+ }
+
+ return TO_CMUX_POL_CIRC_DATA(cdata);
+}
+
+/**
+ * Free an ewma_policy_circ_data_t allocated with ewma_alloc_circ_data()
+ */
+
+static void
+ewma_free_circ_data(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data)
+
+{
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(cmux);
+ tor_assert(circ);
+ tor_assert(pol_data);
+
+ if (!pol_circ_data) return;
+
+ cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
+
+ tor_free(cdata);
+}
+
+/**
+ * Handle circuit activation; this inserts the circuit's cell_ewma into
+ * the active_circuits_pqueue.
+ */
+
+static void
+ewma_notify_circ_active(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data)
+{
+ ewma_policy_data_t *pol = NULL;
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+ tor_assert(circ);
+ tor_assert(pol_circ_data);
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+ cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
+
+ add_cell_ewma(pol, &(cdata->cell_ewma));
+}
+
+/**
+ * Handle circuit deactivation; this removes the circuit's cell_ewma from
+ * the active_circuits_pqueue.
+ */
+
+static void
+ewma_notify_circ_inactive(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data)
+{
+ ewma_policy_data_t *pol = NULL;
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+ tor_assert(circ);
+ tor_assert(pol_circ_data);
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+ cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
+
+ remove_cell_ewma(pol, &(cdata->cell_ewma));
+}
+
+/**
+ * Update cell_ewma for this circuit after we've sent some cells, and
+ * remove/reinsert it in the queue. This used to be done (brokenly,
+ * see bug 6816) in channel_flush_from_first_active_circuit().
+ */
+
+static void
+ewma_notify_xmit_cells(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data,
+ circuit_t *circ,
+ circuitmux_policy_circ_data_t *pol_circ_data,
+ unsigned int n_cells)
+{
+ ewma_policy_data_t *pol = NULL;
+ ewma_policy_circ_data_t *cdata = NULL;
+ unsigned int tick;
+ double fractional_tick, ewma_increment;
+ /* The current (hi-res) time */
+ struct timeval now_hires;
+ cell_ewma_t *cell_ewma, *tmp;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+ tor_assert(circ);
+ tor_assert(pol_circ_data);
+ tor_assert(n_cells > 0);
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+ cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
+
+ /* Rescale the EWMAs if needed */
+ tor_gettimeofday_cached(&now_hires);
+ tick = cell_ewma_tick_from_timeval(&now_hires, &fractional_tick);
+
+ if (tick != pol->active_circuit_pqueue_last_recalibrated) {
+ scale_active_circuits(pol, tick);
+ }
+
+ /* How much do we adjust the cell count in cell_ewma by? */
+ ewma_increment =
+ ((double)(n_cells)) * pow(ewma_scale_factor, -fractional_tick);
+
+ /* Do the adjustment */
+ cell_ewma = &(cdata->cell_ewma);
+ cell_ewma->cell_count += ewma_increment;
+
+ /*
+ * Since we just sent on this circuit, it should be at the head of
+ * the queue. Pop the head, assert that it matches, then re-add.
+ */
+ tmp = pop_first_cell_ewma(pol);
+ tor_assert(tmp == cell_ewma);
+ add_cell_ewma(pol, cell_ewma);
+}
+
+/**
+ * Pick the preferred circuit to send from; this will be the one with
+ * the lowest EWMA value in the priority queue. This used to be done
+ * in channel_flush_from_first_active_circuit().
+ */
+
+static circuit_t *
+ewma_pick_active_circuit(circuitmux_t *cmux,
+ circuitmux_policy_data_t *pol_data)
+{
+ ewma_policy_data_t *pol = NULL;
+ circuit_t *circ = NULL;
+ cell_ewma_t *cell_ewma = NULL;
+
+ tor_assert(cmux);
+ tor_assert(pol_data);
+
+ pol = TO_EWMA_POL_DATA(pol_data);
+
+ if (smartlist_len(pol->active_circuit_pqueue) > 0) {
+ /* Get the head of the queue */
+ cell_ewma = smartlist_get(pol->active_circuit_pqueue, 0);
+ circ = cell_ewma_to_circuit(cell_ewma);
+ }
+
+ return circ;
+}
+
+/** Helper for sorting cell_ewma_t values in their priority queue. */
+static int
+compare_cell_ewma_counts(const void *p1, const void *p2)
+{
+ const cell_ewma_t *e1 = p1, *e2 = p2;
+
+ if (e1->cell_count < e2->cell_count)
+ return -1;
+ else if (e1->cell_count > e2->cell_count)
+ return 1;
+ else
+ return 0;
+}
+
+/** Given a cell_ewma_t, return a pointer to the circuit containing it. */
+static circuit_t *
+cell_ewma_to_circuit(cell_ewma_t *ewma)
+{
+ ewma_policy_circ_data_t *cdata = NULL;
+
+ tor_assert(ewma);
+ cdata = SUBTYPE_P(ewma, ewma_policy_circ_data_t, cell_ewma);
+ tor_assert(cdata);
+
+ return cdata->circ;
+}
+
+/* ==== Functions for scaling cell_ewma_t ====
+
+ When choosing which cells to relay first, we favor circuits that have been
+ quiet recently. This gives better latency on connections that aren't
+ pushing lots of data, and makes the network feel more interactive.
+
+ Conceptually, we take an exponentially weighted mean average of the number
+ of cells a circuit has sent, and allow active circuits (those with cells to
+ relay) to send cells in reverse order of their exponentially-weighted mean
+ average (EWMA) cell count. [That is, a cell sent N seconds ago 'counts'
+ F^N times as much as a cell sent now, for 0<F<1.0, and we favor the
+ circuit that has sent the fewest cells]
+
+ If 'double' had infinite precision, we could do this simply by counting a
+ cell sent at startup as having weight 1.0, and a cell sent N seconds later
+ as having weight F^-N. This way, we would never need to re-scale
+ any already-sent cells.
+
+ To prevent double from overflowing, we could count a cell sent now as
+ having weight 1.0 and a cell sent N seconds ago as having weight F^N.
+ This, however, would mean we'd need to re-scale *ALL* old circuits every
+ time we wanted to send a cell.
+
+ So as a compromise, we divide time into 'ticks' (currently, 10-second
+ increments) and say that a cell sent at the start of a current tick is
+ worth 1.0, a cell sent N seconds before the start of the current tick is
+ worth F^N, and a cell sent N seconds after the start of the current tick is
+ worth F^-N. This way we don't overflow, and we don't need to constantly
+ rescale.
+ */
+
+/** Given a timeval <b>now</b>, compute the cell_ewma tick in which it occurs
+ * and the fraction of the tick that has elapsed between the start of the tick
+ * and <b>now</b>. Return the former and store the latter in
+ * *<b>remainder_out</b>.
+ *
+ * These tick values are not meant to be shared between Tor instances, or used
+ * for other purposes. */
+
+static unsigned
+cell_ewma_tick_from_timeval(const struct timeval *now,
+ double *remainder_out)
+{
+ unsigned res = (unsigned) (now->tv_sec / EWMA_TICK_LEN);
+ /* rem */
+ double rem = (now->tv_sec % EWMA_TICK_LEN) +
+ ((double)(now->tv_usec)) / 1.0e6;
+ *remainder_out = rem / EWMA_TICK_LEN;
+ return res;
+}
+
+/** Tell the caller whether ewma_enabled is set */
+int
+cell_ewma_enabled(void)
+{
+ return ewma_enabled;
+}
+
+/** Compute and return the current cell_ewma tick. */
+unsigned int
+cell_ewma_get_tick(void)
+{
+ return ((unsigned)approx_time() / EWMA_TICK_LEN);
+}
+
+/** Adjust the global cell scale factor based on <b>options</b> */
+void
+cell_ewma_set_scale_factor(const or_options_t *options,
+ const networkstatus_t *consensus)
+{
+ int32_t halflife_ms;
+ double halflife;
+ const char *source;
+ if (options && options->CircuitPriorityHalflife >= -EPSILON) {
+ halflife = options->CircuitPriorityHalflife;
+ source = "CircuitPriorityHalflife in configuration";
+ } else if (consensus && (halflife_ms = networkstatus_get_param(
+ consensus, "CircuitPriorityHalflifeMsec",
+ -1, -1, INT32_MAX)) >= 0) {
+ halflife = ((double)halflife_ms)/1000.0;
+ source = "CircuitPriorityHalflifeMsec in consensus";
+ } else {
+ halflife = EWMA_DEFAULT_HALFLIFE;
+ source = "Default value";
+ }
+
+ if (halflife <= EPSILON) {
+ /* The cell EWMA algorithm is disabled. */
+ ewma_scale_factor = 0.1;
+ ewma_enabled = 0;
+ log_info(LD_OR,
+ "Disabled cell_ewma algorithm because of value in %s",
+ source);
+ } else {
+ /* convert halflife into halflife-per-tick. */
+ halflife /= EWMA_TICK_LEN;
+ /* compute per-tick scale factor. */
+ ewma_scale_factor = exp( LOG_ONEHALF / halflife );
+ ewma_enabled = 1;
+ log_info(LD_OR,
+ "Enabled cell_ewma algorithm because of value in %s; "
+ "scale factor is %f per %d seconds",
+ source, ewma_scale_factor, EWMA_TICK_LEN);
+ }
+}
+
+/** Return the multiplier necessary to convert the value of a cell sent in
+ * 'from_tick' to one sent in 'to_tick'. */
+static INLINE double
+get_scale_factor(unsigned from_tick, unsigned to_tick)
+{
+ /* This math can wrap around, but that's okay: unsigned overflow is
+ well-defined */
+ int diff = (int)(to_tick - from_tick);
+ return pow(ewma_scale_factor, diff);
+}
+
+/** Adjust the cell count of <b>ewma</b> so that it is scaled with respect to
+ * <b>cur_tick</b> */
+static void
+scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick)
+{
+ double factor = get_scale_factor(ewma->last_adjusted_tick, cur_tick);
+ ewma->cell_count *= factor;
+ ewma->last_adjusted_tick = cur_tick;
+}
+
+/** Adjust the cell count of every active circuit on <b>chan</b> so
+ * that they are scaled with respect to <b>cur_tick</b> */
+static void
+scale_active_circuits(ewma_policy_data_t *pol, unsigned cur_tick)
+{
+ double factor;
+
+ tor_assert(pol);
+ tor_assert(pol->active_circuit_pqueue);
+
+ factor =
+ get_scale_factor(
+ pol->active_circuit_pqueue_last_recalibrated,
+ cur_tick);
+ /** Ordinarily it isn't okay to change the value of an element in a heap,
+ * but it's okay here, since we are preserving the order. */
+ SMARTLIST_FOREACH_BEGIN(
+ pol->active_circuit_pqueue,
+ cell_ewma_t *, e) {
+ tor_assert(e->last_adjusted_tick ==
+ pol->active_circuit_pqueue_last_recalibrated);
+ e->cell_count *= factor;
+ e->last_adjusted_tick = cur_tick;
+ } SMARTLIST_FOREACH_END(e);
+ pol->active_circuit_pqueue_last_recalibrated = cur_tick;
+}
+
+/** Rescale <b>ewma</b> to the same scale as <b>pol</b>, and add it to
+ * <b>pol</b>'s priority queue of active circuits */
+static void
+add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma)
+{
+ tor_assert(pol);
+ tor_assert(pol->active_circuit_pqueue);
+ tor_assert(ewma);
+ tor_assert(ewma->heap_index == -1);
+
+ scale_single_cell_ewma(
+ ewma,
+ pol->active_circuit_pqueue_last_recalibrated);
+
+ smartlist_pqueue_add(pol->active_circuit_pqueue,
+ compare_cell_ewma_counts,
+ STRUCT_OFFSET(cell_ewma_t, heap_index),
+ ewma);
+}
+
+/** Remove <b>ewma</b> from <b>pol</b>'s priority queue of active circuits */
+static void
+remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma)
+{
+ tor_assert(pol);
+ tor_assert(pol->active_circuit_pqueue);
+ tor_assert(ewma);
+ tor_assert(ewma->heap_index != -1);
+
+ smartlist_pqueue_remove(pol->active_circuit_pqueue,
+ compare_cell_ewma_counts,
+ STRUCT_OFFSET(cell_ewma_t, heap_index),
+ ewma);
+}
+
+/** Remove and return the first cell_ewma_t from pol's priority queue of
+ * active circuits. Requires that the priority queue is nonempty. */
+static cell_ewma_t *
+pop_first_cell_ewma(ewma_policy_data_t *pol)
+{
+ tor_assert(pol);
+ tor_assert(pol->active_circuit_pqueue);
+
+ return smartlist_pqueue_pop(pol->active_circuit_pqueue,
+ compare_cell_ewma_counts,
+ STRUCT_OFFSET(cell_ewma_t, heap_index));
+}
+
diff --git a/src/or/circuitmux_ewma.h b/src/or/circuitmux_ewma.h
new file mode 100644
index 000000000..a512745c7
--- /dev/null
+++ b/src/or/circuitmux_ewma.h
@@ -0,0 +1,29 @@
+/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitmux_ewma.h
+ * \brief Header file for circuitmux_ewma.c
+ **/
+
+#ifndef TOR_CIRCUITMUX_EWMA_H
+#define TOR_CIRCUITMUX_EWMA_H
+
+#include "or.h"
+#include "circuitmux.h"
+
+/* Everything but circuitmux_ewma.c should see this extern */
+#ifndef TOR_CIRCUITMUX_EWMA_C_
+
+extern circuitmux_policy_t ewma_policy;
+
+#endif /* !(TOR_CIRCUITMUX_EWMA_C_) */
+
+/* Externally visible EWMA functions */
+int cell_ewma_enabled(void);
+unsigned int cell_ewma_get_tick(void);
+void cell_ewma_set_scale_factor(const or_options_t *options,
+ const networkstatus_t *consensus);
+
+#endif /* TOR_CIRCUITMUX_EWMA_H */
+
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
new file mode 100644
index 000000000..1d7812bf2
--- /dev/null
+++ b/src/or/circuitstats.c
@@ -0,0 +1,1556 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CIRCUITSTATS_PRIVATE
+
+#include "or.h"
+#include "circuitbuild.h"
+#include "circuitstats.h"
+#include "config.h"
+#include "confparse.h"
+#include "control.h"
+#include "networkstatus.h"
+#include "statefile.h"
+
+#undef log
+#include <math.h>
+
+#define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2))
+
+/** Global list of circuit build times */
+// XXXX: Add this as a member for entry_guard_t instead of global?
+// Then we could do per-guard statistics, as guards are likely to
+// vary in their own latency. The downside of this is that guards
+// can change frequently, so we'd be building a lot more circuits
+// most likely.
+/* XXXX024 Make this static; add accessor functions. */
+circuit_build_times_t circ_times;
+
+/** If set, we're running the unit tests: we should avoid clobbering
+ * our state file or accessing get_options() or get_or_state() */
+static int unit_tests = 0;
+
+/**
+ * This function decides if CBT learning should be disabled. It returns
+ * true if one or more of the following four conditions are met:
+ *
+ * 1. If the cbtdisabled consensus parameter is set.
+ * 2. If the torrc option LearnCircuitBuildTimeout is false.
+ * 3. If we are a directory authority
+ * 4. If we fail to write circuit build time history to our state file.
+ */
+int
+circuit_build_times_disabled(void)
+{
+ if (unit_tests) {
+ return 0;
+ } else {
+ int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled",
+ 0, 0, 1);
+ int config_disabled = !get_options()->LearnCircuitBuildTimeout;
+ int dirauth_disabled = get_options()->AuthoritativeDir;
+ int state_disabled = did_last_state_file_write_fail() ? 1 : 0;
+
+ if (consensus_disabled || config_disabled || dirauth_disabled ||
+ state_disabled) {
+ log_debug(LD_CIRC,
+ "CircuitBuildTime learning is disabled. "
+ "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d",
+ consensus_disabled, config_disabled, dirauth_disabled,
+ state_disabled);
+ return 1;
+ } else {
+ log_debug(LD_CIRC,
+ "CircuitBuildTime learning is not disabled. "
+ "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d",
+ consensus_disabled, config_disabled, dirauth_disabled,
+ state_disabled);
+ return 0;
+ }
+ }
+}
+
+/**
+ * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter.
+ *
+ * Effect: When this many timeouts happen in the last 'cbtrecentcount'
+ * circuit attempts, the client should discard all of its history and
+ * begin learning a fresh timeout value.
+ */
+static int32_t
+circuit_build_times_max_timeouts(void)
+{
+ int32_t cbt_maxtimeouts;
+
+ cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts",
+ CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT,
+ CBT_MIN_MAX_RECENT_TIMEOUT_COUNT,
+ CBT_MAX_MAX_RECENT_TIMEOUT_COUNT);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is"
+ " %d",
+ cbt_maxtimeouts);
+ }
+
+ return cbt_maxtimeouts;
+}
+
+/**
+ * Retrieve and bounds-check the cbtnummodes consensus paramter.
+ *
+ * Effect: This value governs how many modes to use in the weighted
+ * average calculation of Pareto parameter Xm. A value of 3 introduces
+ * some bias (2-5% of CDF) under ideal conditions, but allows for better
+ * performance in the event that a client chooses guard nodes of radically
+ * different performance characteristics.
+ */
+static int32_t
+circuit_build_times_default_num_xm_modes(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbtnummodes",
+ CBT_DEFAULT_NUM_XM_MODES,
+ CBT_MIN_NUM_XM_MODES,
+ CBT_MAX_NUM_XM_MODES);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_default_num_xm_modes() called, cbtnummodes"
+ " is %d",
+ num);
+ }
+
+ return num;
+}
+
+/**
+ * Retrieve and bounds-check the cbtmincircs consensus paramter.
+ *
+ * Effect: This is the minimum number of circuits to build before
+ * computing a timeout.
+ */
+static int32_t
+circuit_build_times_min_circs_to_observe(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbtmincircs",
+ CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE,
+ CBT_MIN_MIN_CIRCUITS_TO_OBSERVE,
+ CBT_MAX_MIN_CIRCUITS_TO_OBSERVE);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_min_circs_to_observe() called, cbtmincircs"
+ " is %d",
+ num);
+ }
+
+ return num;
+}
+
+/** Return true iff <b>cbt</b> has recorded enough build times that we
+ * want to start acting on the timeout it implies. */
+int
+circuit_build_times_enough_to_compute(circuit_build_times_t *cbt)
+{
+ return cbt->total_build_times >= circuit_build_times_min_circs_to_observe();
+}
+
+/**
+ * Retrieve and bounds-check the cbtquantile consensus paramter.
+ *
+ * Effect: This is the position on the quantile curve to use to set the
+ * timeout value. It is a percent (10-99).
+ */
+double
+circuit_build_times_quantile_cutoff(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbtquantile",
+ CBT_DEFAULT_QUANTILE_CUTOFF,
+ CBT_MIN_QUANTILE_CUTOFF,
+ CBT_MAX_QUANTILE_CUTOFF);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_quantile_cutoff() called, cbtquantile"
+ " is %d",
+ num);
+ }
+
+ return num/100.0;
+}
+
+/**
+ * Retrieve and bounds-check the cbtclosequantile consensus paramter.
+ *
+ * Effect: This is the position on the quantile curve to use to set the
+ * timeout value to use to actually close circuits. It is a percent
+ * (0-99).
+ */
+static double
+circuit_build_times_close_quantile(void)
+{
+ int32_t param;
+ /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */
+ int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff());
+ param = networkstatus_get_param(NULL, "cbtclosequantile",
+ CBT_DEFAULT_CLOSE_QUANTILE,
+ CBT_MIN_CLOSE_QUANTILE,
+ CBT_MAX_CLOSE_QUANTILE);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_close_quantile() called, cbtclosequantile"
+ " is %d", param);
+ }
+
+ if (param < min) {
+ log_warn(LD_DIR, "Consensus parameter cbtclosequantile is "
+ "too small, raising to %d", min);
+ param = min;
+ }
+ return param / 100.0;
+}
+
+/**
+ * Retrieve and bounds-check the cbttestfreq consensus paramter.
+ *
+ * Effect: Describes how often in seconds to build a test circuit to
+ * gather timeout values. Only applies if less than 'cbtmincircs'
+ * have been recorded.
+ */
+static int32_t
+circuit_build_times_test_frequency(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbttestfreq",
+ CBT_DEFAULT_TEST_FREQUENCY,
+ CBT_MIN_TEST_FREQUENCY,
+ CBT_MAX_TEST_FREQUENCY);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_test_frequency() called, cbttestfreq is %d",
+ num);
+ }
+
+ return num;
+}
+
+/**
+ * Retrieve and bounds-check the cbtmintimeout consensus parameter.
+ *
+ * Effect: This is the minimum allowed timeout value in milliseconds.
+ * The minimum is to prevent rounding to 0 (we only check once
+ * per second).
+ */
+static int32_t
+circuit_build_times_min_timeout(void)
+{
+ int32_t num = networkstatus_get_param(NULL, "cbtmintimeout",
+ CBT_DEFAULT_TIMEOUT_MIN_VALUE,
+ CBT_MIN_TIMEOUT_MIN_VALUE,
+ CBT_MAX_TIMEOUT_MIN_VALUE);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_min_timeout() called, cbtmintimeout is %d",
+ num);
+ }
+
+ return num;
+}
+
+/**
+ * Retrieve and bounds-check the cbtinitialtimeout consensus paramter.
+ *
+ * Effect: This is the timeout value to use before computing a timeout,
+ * in milliseconds.
+ */
+int32_t
+circuit_build_times_initial_timeout(void)
+{
+ int32_t min = circuit_build_times_min_timeout();
+ int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout",
+ CBT_DEFAULT_TIMEOUT_INITIAL_VALUE,
+ CBT_MIN_TIMEOUT_INITIAL_VALUE,
+ CBT_MAX_TIMEOUT_INITIAL_VALUE);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_initial_timeout() called, "
+ "cbtinitialtimeout is %d",
+ param);
+ }
+
+ if (param < min) {
+ log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, "
+ "raising to %d", min);
+ param = min;
+ }
+ return param;
+}
+
+/**
+ * Retrieve and bounds-check the cbtrecentcount consensus paramter.
+ *
+ * Effect: This is the number of circuit build times to keep track of
+ * for deciding if we hit cbtmaxtimeouts and need to reset our state
+ * and learn a new timeout.
+ */
+static int32_t
+circuit_build_times_recent_circuit_count(networkstatus_t *ns)
+{
+ int32_t num;
+ num = networkstatus_get_param(ns, "cbtrecentcount",
+ CBT_DEFAULT_RECENT_CIRCUITS,
+ CBT_MIN_RECENT_CIRCUITS,
+ CBT_MAX_RECENT_CIRCUITS);
+
+ if (!(get_options()->LearnCircuitBuildTimeout)) {
+ log_debug(LD_BUG,
+ "circuit_build_times_recent_circuit_count() called, "
+ "cbtrecentcount is %d",
+ num);
+ }
+
+ return num;
+}
+
+/**
+ * This function is called when we get a consensus update.
+ *
+ * It checks to see if we have changed any consensus parameters
+ * that require reallocation or discard of previous stats.
+ */
+void
+circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
+ networkstatus_t *ns)
+{
+ int32_t num;
+
+ /*
+ * First check if we're doing adaptive timeouts at all; nothing to
+ * update if we aren't.
+ */
+
+ if (!circuit_build_times_disabled()) {
+ num = circuit_build_times_recent_circuit_count(ns);
+
+ if (num > 0) {
+ if (num != cbt->liveness.num_recent_circs) {
+ int8_t *recent_circs;
+ log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many "
+ "circuits we must track to detect network failures from %d "
+ "to %d.", cbt->liveness.num_recent_circs, num);
+
+ tor_assert(cbt->liveness.timeouts_after_firsthop ||
+ cbt->liveness.num_recent_circs == 0);
+
+ /*
+ * Technically this is a circular array that we are reallocating
+ * and memcopying. However, since it only consists of either 1s
+ * or 0s, and is only used in a statistical test to determine when
+ * we should discard our history after a sufficient number of 1's
+ * have been reached, it is fine if order is not preserved or
+ * elements are lost.
+ *
+ * cbtrecentcount should only be changing in cases of severe network
+ * distress anyway, so memory correctness here is paramount over
+ * doing acrobatics to preserve the array.
+ */
+ recent_circs = tor_malloc_zero(sizeof(int8_t)*num);
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop,
+ sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs));
+ }
+
+ // Adjust the index if it needs it.
+ if (num < cbt->liveness.num_recent_circs) {
+ cbt->liveness.after_firsthop_idx = MIN(num-1,
+ cbt->liveness.after_firsthop_idx);
+ }
+
+ tor_free(cbt->liveness.timeouts_after_firsthop);
+ cbt->liveness.timeouts_after_firsthop = recent_circs;
+ cbt->liveness.num_recent_circs = num;
+ }
+ /* else no change, nothing to do */
+ } else { /* num == 0 */
+ /*
+ * Weird. This probably shouldn't happen, so log a warning, but try
+ * to do something sensible anyway.
+ */
+
+ log_warn(LD_CIRC,
+ "The cbtrecentcircs consensus parameter came back zero! "
+ "This disables adaptive timeouts since we can't keep track of "
+ "any recent circuits.");
+
+ circuit_build_times_free_timeouts(cbt);
+ }
+ } else {
+ /*
+ * Adaptive timeouts are disabled; this might be because of the
+ * LearnCircuitBuildTimes config parameter, and hence permanent, or
+ * the cbtdisabled consensus parameter, so it may be a new condition.
+ * Treat it like getting num == 0 above and free the circuit history
+ * if we have any.
+ */
+
+ circuit_build_times_free_timeouts(cbt);
+ }
+}
+
+/**
+ * Return the initial default or configured timeout in milliseconds
+ */
+static double
+circuit_build_times_get_initial_timeout(void)
+{
+ double timeout;
+
+ /*
+ * Check if we have LearnCircuitBuildTimeout, and if we don't,
+ * always use CircuitBuildTimeout, no questions asked.
+ */
+ if (!unit_tests && get_options()->CircuitBuildTimeout) {
+ timeout = get_options()->CircuitBuildTimeout*1000;
+ if (get_options()->LearnCircuitBuildTimeout &&
+ timeout < circuit_build_times_min_timeout()) {
+ log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds",
+ circuit_build_times_min_timeout()/1000);
+ timeout = circuit_build_times_min_timeout();
+ }
+ } else {
+ timeout = circuit_build_times_initial_timeout();
+ }
+
+ return timeout;
+}
+
+/**
+ * Reset the build time state.
+ *
+ * Leave estimated parameters, timeout and network liveness intact
+ * for future use.
+ */
+void
+circuit_build_times_reset(circuit_build_times_t *cbt)
+{
+ memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times));
+ cbt->total_build_times = 0;
+ cbt->build_times_idx = 0;
+ cbt->have_computed_timeout = 0;
+}
+
+/**
+ * Initialize the buildtimes structure for first use.
+ *
+ * Sets the initial timeout values based on either the config setting,
+ * the consensus param, or the default (CBT_DEFAULT_TIMEOUT_INITIAL_VALUE).
+ */
+void
+circuit_build_times_init(circuit_build_times_t *cbt)
+{
+ memset(cbt, 0, sizeof(*cbt));
+ /*
+ * Check if we really are using adaptive timeouts, and don't keep
+ * track of this stuff if not.
+ */
+ if (!circuit_build_times_disabled()) {
+ cbt->liveness.num_recent_circs =
+ circuit_build_times_recent_circuit_count(NULL);
+ cbt->liveness.timeouts_after_firsthop =
+ tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs);
+ } else {
+ cbt->liveness.num_recent_circs = 0;
+ cbt->liveness.timeouts_after_firsthop = NULL;
+ }
+ cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout();
+ control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
+}
+
+/**
+ * Free the saved timeouts, if the cbtdisabled consensus parameter got turned
+ * on or something.
+ */
+
+void
+circuit_build_times_free_timeouts(circuit_build_times_t *cbt)
+{
+ if (!cbt) return;
+
+ if (cbt->liveness.timeouts_after_firsthop) {
+ tor_free(cbt->liveness.timeouts_after_firsthop);
+ }
+
+ cbt->liveness.num_recent_circs = 0;
+}
+
+#if 0
+/**
+ * Rewind our build time history by n positions.
+ */
+static void
+circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
+{
+ int i = 0;
+
+ cbt->build_times_idx -= n;
+ cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE;
+
+ for (i = 0; i < n; i++) {
+ cbt->circuit_build_times[(i+cbt->build_times_idx)
+ %CBT_NCIRCUITS_TO_OBSERVE]=0;
+ }
+
+ if (cbt->total_build_times > n) {
+ cbt->total_build_times -= n;
+ } else {
+ cbt->total_build_times = 0;
+ }
+
+ log_info(LD_CIRC,
+ "Rewound history by %d places. Current index: %d. "
+ "Total: %d", n, cbt->build_times_idx, cbt->total_build_times);
+}
+#endif
+
+/**
+ * Add a new build time value <b>time</b> to the set of build times. Time
+ * units are milliseconds.
+ *
+ * circuit_build_times <b>cbt</b> is a circular array, so loop around when
+ * array is full.
+ */
+int
+circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
+{
+ if (time <= 0 || time > CBT_BUILD_TIME_MAX) {
+ log_warn(LD_BUG, "Circuit build time is too large (%u)."
+ "This is probably a bug.", time);
+ tor_fragile_assert();
+ return -1;
+ }
+
+ log_debug(LD_CIRC, "Adding circuit build time %u", time);
+
+ cbt->circuit_build_times[cbt->build_times_idx] = time;
+ cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE;
+ if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
+ cbt->total_build_times++;
+
+ if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) {
+ /* Save state every n circuit builds */
+ if (!unit_tests && !get_options()->AvoidDiskWrites)
+ or_state_mark_dirty(get_or_state(), 0);
+ }
+
+ return 0;
+}
+
+/**
+ * Return maximum circuit build time
+ */
+static build_time_t
+circuit_build_times_max(circuit_build_times_t *cbt)
+{
+ int i = 0;
+ build_time_t max_build_time = 0;
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] > max_build_time
+ && cbt->circuit_build_times[i] != CBT_BUILD_ABANDONED)
+ max_build_time = cbt->circuit_build_times[i];
+ }
+ return max_build_time;
+}
+
+#if 0
+/** Return minimum circuit build time */
+build_time_t
+circuit_build_times_min(circuit_build_times_t *cbt)
+{
+ int i = 0;
+ build_time_t min_build_time = CBT_BUILD_TIME_MAX;
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */
+ cbt->circuit_build_times[i] < min_build_time)
+ min_build_time = cbt->circuit_build_times[i];
+ }
+ if (min_build_time == CBT_BUILD_TIME_MAX) {
+ log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!");
+ }
+ return min_build_time;
+}
+#endif
+
+/**
+ * Calculate and return a histogram for the set of build times.
+ *
+ * Returns an allocated array of histrogram bins representing
+ * the frequency of index*CBT_BIN_WIDTH millisecond
+ * build times. Also outputs the number of bins in nbins.
+ *
+ * The return value must be freed by the caller.
+ */
+static uint32_t *
+circuit_build_times_create_histogram(circuit_build_times_t *cbt,
+ build_time_t *nbins)
+{
+ uint32_t *histogram;
+ build_time_t max_build_time = circuit_build_times_max(cbt);
+ int i, c;
+
+ *nbins = 1 + (max_build_time / CBT_BIN_WIDTH);
+ histogram = tor_malloc_zero(*nbins * sizeof(build_time_t));
+
+ // calculate histogram
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] == 0
+ || cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED)
+ continue; /* 0 <-> uninitialized */
+
+ c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH);
+ histogram[c]++;
+ }
+
+ return histogram;
+}
+
+/**
+ * Return the Pareto start-of-curve parameter Xm.
+ *
+ * Because we are not a true Pareto curve, we compute this as the
+ * weighted average of the N most frequent build time bins. N is either
+ * 1 if we don't have enough circuit build time data collected, or
+ * determined by the consensus parameter cbtnummodes (default 3).
+ */
+static build_time_t
+circuit_build_times_get_xm(circuit_build_times_t *cbt)
+{
+ build_time_t i, nbins;
+ build_time_t *nth_max_bin;
+ int32_t bin_counts=0;
+ build_time_t ret = 0;
+ uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins);
+ int n=0;
+ int num_modes = circuit_build_times_default_num_xm_modes();
+
+ tor_assert(nbins > 0);
+ tor_assert(num_modes > 0);
+
+ // Only use one mode if < 1000 buildtimes. Not enough data
+ // for multiple.
+ if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
+ num_modes = 1;
+
+ nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t));
+
+ /* Determine the N most common build times */
+ for (i = 0; i < nbins; i++) {
+ if (histogram[i] >= histogram[nth_max_bin[0]]) {
+ nth_max_bin[0] = i;
+ }
+
+ for (n = 1; n < num_modes; n++) {
+ if (histogram[i] >= histogram[nth_max_bin[n]] &&
+ (!histogram[nth_max_bin[n-1]]
+ || histogram[i] < histogram[nth_max_bin[n-1]])) {
+ nth_max_bin[n] = i;
+ }
+ }
+ }
+
+ for (n = 0; n < num_modes; n++) {
+ bin_counts += histogram[nth_max_bin[n]];
+ ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]];
+ log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]),
+ histogram[nth_max_bin[n]]);
+ }
+
+ /* The following assert is safe, because we don't get called when we
+ * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */
+ tor_assert(bin_counts > 0);
+
+ ret /= bin_counts;
+ tor_free(histogram);
+ tor_free(nth_max_bin);
+
+ return ret;
+}
+
+/**
+ * Output a histogram of current circuit build times to
+ * the or_state_t state structure.
+ */
+void
+circuit_build_times_update_state(circuit_build_times_t *cbt,
+ or_state_t *state)
+{
+ uint32_t *histogram;
+ build_time_t i = 0;
+ build_time_t nbins = 0;
+ config_line_t **next, *line;
+
+ histogram = circuit_build_times_create_histogram(cbt, &nbins);
+ // write to state
+ config_free_lines(state->BuildtimeHistogram);
+ next = &state->BuildtimeHistogram;
+ *next = NULL;
+
+ state->TotalBuildTimes = cbt->total_build_times;
+ state->CircuitBuildAbandonedCount = 0;
+
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED)
+ state->CircuitBuildAbandonedCount++;
+ }
+
+ for (i = 0; i < nbins; i++) {
+ // compress the histogram by skipping the blanks
+ if (histogram[i] == 0) continue;
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("CircuitBuildTimeBin");
+ tor_asprintf(&line->value, "%d %d",
+ CBT_BIN_TO_MS(i), histogram[i]);
+ next = &(line->next);
+ }
+
+ if (!unit_tests) {
+ if (!get_options()->AvoidDiskWrites)
+ or_state_mark_dirty(get_or_state(), 0);
+ }
+
+ tor_free(histogram);
+}
+
+/**
+ * Shuffle the build times array.
+ *
+ * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+ */
+static void
+circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
+ build_time_t *raw_times,
+ uint32_t num_times)
+{
+ uint32_t n = num_times;
+ if (num_times > CBT_NCIRCUITS_TO_OBSERVE) {
+ log_notice(LD_CIRC, "The number of circuit times that this Tor version "
+ "uses to calculate build times is less than the number stored "
+ "in your state file. Decreasing the circuit time history from "
+ "%lu to %d.", (unsigned long)num_times,
+ CBT_NCIRCUITS_TO_OBSERVE);
+ }
+
+ if (n > INT_MAX-1) {
+ log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build "
+ "observations in your state file. That's far too many; probably "
+ "there's a bug here.", (unsigned long)n);
+ n = INT_MAX-1;
+ }
+
+ /* This code can only be run on a compact array */
+ while (n-- > 1) {
+ int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */
+ build_time_t tmp = raw_times[k];
+ raw_times[k] = raw_times[n];
+ raw_times[n] = tmp;
+ }
+
+ /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE
+ * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */
+ for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) {
+ circuit_build_times_add_time(cbt, raw_times[n]);
+ }
+}
+
+/**
+ * Filter old synthetic timeouts that were created before the
+ * new right-censored Pareto calculation was deployed.
+ *
+ * Once all clients before 0.2.1.13-alpha are gone, this code
+ * will be unused.
+ */
+static int
+circuit_build_times_filter_timeouts(circuit_build_times_t *cbt)
+{
+ int num_filtered=0, i=0;
+ double timeout_rate = 0;
+ build_time_t max_timeout = 0;
+
+ timeout_rate = circuit_build_times_timeout_rate(cbt);
+ max_timeout = (build_time_t)cbt->close_ms;
+
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] > max_timeout) {
+ build_time_t replaced = cbt->circuit_build_times[i];
+ num_filtered++;
+ cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED;
+
+ log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced,
+ cbt->circuit_build_times[i]);
+ }
+ }
+
+ log_info(LD_CIRC,
+ "We had %d timeouts out of %d build times, "
+ "and filtered %d above the max of %u",
+ (int)(cbt->total_build_times*timeout_rate),
+ cbt->total_build_times, num_filtered, max_timeout);
+
+ return num_filtered;
+}
+
+/**
+ * Load histogram from <b>state</b>, shuffling the resulting array
+ * after we do so. Use this result to estimate parameters and
+ * calculate the timeout.
+ *
+ * Return -1 on error.
+ */
+int
+circuit_build_times_parse_state(circuit_build_times_t *cbt,
+ or_state_t *state)
+{
+ int tot_values = 0;
+ uint32_t loaded_cnt = 0, N = 0;
+ config_line_t *line;
+ unsigned int i;
+ build_time_t *loaded_times;
+ int err = 0;
+ circuit_build_times_init(cbt);
+
+ if (circuit_build_times_disabled()) {
+ return 0;
+ }
+
+ /* build_time_t 0 means uninitialized */
+ loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes);
+
+ for (line = state->BuildtimeHistogram; line; line = line->next) {
+ smartlist_t *args = smartlist_new();
+ smartlist_split_string(args, line->value, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ if (smartlist_len(args) < 2) {
+ log_warn(LD_GENERAL, "Unable to parse circuit build times: "
+ "Too few arguments to CircuitBuildTime");
+ err = 1;
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ break;
+ } else {
+ const char *ms_str = smartlist_get(args,0);
+ const char *count_str = smartlist_get(args,1);
+ uint32_t count, k;
+ build_time_t ms;
+ int ok;
+ ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0,
+ CBT_BUILD_TIME_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_GENERAL, "Unable to parse circuit build times: "
+ "Unparsable bin number");
+ err = 1;
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ break;
+ }
+ count = (uint32_t)tor_parse_ulong(count_str, 0, 0,
+ UINT32_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_GENERAL, "Unable to parse circuit build times: "
+ "Unparsable bin count");
+ err = 1;
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ break;
+ }
+
+ if (loaded_cnt+count+state->CircuitBuildAbandonedCount
+ > state->TotalBuildTimes) {
+ log_warn(LD_CIRC,
+ "Too many build times in state file. "
+ "Stopping short before %d",
+ loaded_cnt+count);
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ break;
+ }
+
+ for (k = 0; k < count; k++) {
+ loaded_times[loaded_cnt++] = ms;
+ }
+ N++;
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ }
+ }
+
+ log_info(LD_CIRC,
+ "Adding %d timeouts.", state->CircuitBuildAbandonedCount);
+ for (i=0; i < state->CircuitBuildAbandonedCount; i++) {
+ loaded_times[loaded_cnt++] = CBT_BUILD_ABANDONED;
+ }
+
+ if (loaded_cnt != state->TotalBuildTimes) {
+ log_warn(LD_CIRC,
+ "Corrupt state file? Build times count mismatch. "
+ "Read %d times, but file says %d", loaded_cnt,
+ state->TotalBuildTimes);
+ err = 1;
+ circuit_build_times_reset(cbt);
+ goto done;
+ }
+
+ circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt);
+
+ /* Verify that we didn't overwrite any indexes */
+ for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (!cbt->circuit_build_times[i])
+ break;
+ tot_values++;
+ }
+ log_info(LD_CIRC,
+ "Loaded %d/%d values from %d lines in circuit time histogram",
+ tot_values, cbt->total_build_times, N);
+
+ if (cbt->total_build_times != tot_values
+ || cbt->total_build_times > CBT_NCIRCUITS_TO_OBSERVE) {
+ log_warn(LD_CIRC,
+ "Corrupt state file? Shuffled build times mismatch. "
+ "Read %d times, but file says %d", tot_values,
+ state->TotalBuildTimes);
+ err = 1;
+ circuit_build_times_reset(cbt);
+ goto done;
+ }
+
+ circuit_build_times_set_timeout(cbt);
+
+ if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) {
+ circuit_build_times_filter_timeouts(cbt);
+ }
+
+ done:
+ tor_free(loaded_times);
+ return err ? -1 : 0;
+}
+
+/**
+ * Estimates the Xm and Alpha parameters using
+ * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation
+ *
+ * The notable difference is that we use mode instead of min to estimate Xm.
+ * This is because our distribution is frechet-like. We claim this is
+ * an acceptable approximation because we are only concerned with the
+ * accuracy of the CDF of the tail.
+ */
+int
+circuit_build_times_update_alpha(circuit_build_times_t *cbt)
+{
+ build_time_t *x=cbt->circuit_build_times;
+ double a = 0;
+ int n=0,i=0,abandoned_count=0;
+ build_time_t max_time=0;
+
+ /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */
+ /* We sort of cheat here and make our samples slightly more pareto-like
+ * and less frechet-like. */
+ cbt->Xm = circuit_build_times_get_xm(cbt);
+
+ tor_assert(cbt->Xm > 0);
+
+ for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (!x[i]) {
+ continue;
+ }
+
+ if (x[i] < cbt->Xm) {
+ a += tor_mathlog(cbt->Xm);
+ } else if (x[i] == CBT_BUILD_ABANDONED) {
+ abandoned_count++;
+ } else {
+ a += tor_mathlog(x[i]);
+ if (x[i] > max_time)
+ max_time = x[i];
+ }
+ n++;
+ }
+
+ /*
+ * We are erring and asserting here because this can only happen
+ * in codepaths other than startup. The startup state parsing code
+ * performs this same check, and resets state if it hits it. If we
+ * hit it at runtime, something serious has gone wrong.
+ */
+ if (n!=cbt->total_build_times) {
+ log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n,
+ cbt->total_build_times);
+ }
+ tor_assert(n==cbt->total_build_times);
+
+ if (max_time <= 0) {
+ /* This can happen if Xm is actually the *maximum* value in the set.
+ * It can also happen if we've abandoned every single circuit somehow.
+ * In either case, tell the caller not to compute a new build timeout. */
+ log_warn(LD_BUG,
+ "Could not determine largest build time (%d). "
+ "Xm is %dms and we've abandoned %d out of %d circuits.", max_time,
+ cbt->Xm, abandoned_count, n);
+ return 0;
+ }
+
+ a += abandoned_count*tor_mathlog(max_time);
+
+ a -= n*tor_mathlog(cbt->Xm);
+ // Estimator comes from Eq #4 in:
+ // "Bayesian estimation based on trimmed samples from Pareto populations"
+ // by Arturo J. Fernández. We are right-censored only.
+ a = (n-abandoned_count)/a;
+
+ cbt->alpha = a;
+
+ return 1;
+}
+
+/**
+ * This is the Pareto Quantile Function. It calculates the point x
+ * in the distribution such that F(x) = quantile (ie quantile*100%
+ * of the mass of the density function is below x on the curve).
+ *
+ * We use it to calculate the timeout and also to generate synthetic
+ * values of time for circuits that timeout before completion.
+ *
+ * See http://en.wikipedia.org/wiki/Quantile_function,
+ * http://en.wikipedia.org/wiki/Inverse_transform_sampling and
+ * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_
+ * random_sample_from_Pareto_distribution
+ * That's right. I'll cite wikipedia all day long.
+ *
+ * Return value is in milliseconds.
+ */
+double
+circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
+ double quantile)
+{
+ double ret;
+ tor_assert(quantile >= 0);
+ tor_assert(1.0-quantile > 0);
+ tor_assert(cbt->Xm > 0);
+
+ ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha);
+ if (ret > INT32_MAX) {
+ ret = INT32_MAX;
+ }
+ tor_assert(ret > 0);
+ return ret;
+}
+
+/** Pareto CDF */
+double
+circuit_build_times_cdf(circuit_build_times_t *cbt, double x)
+{
+ double ret;
+ tor_assert(cbt->Xm > 0);
+ ret = 1.0-pow(cbt->Xm/x,cbt->alpha);
+ tor_assert(0 <= ret && ret <= 1.0);
+ return ret;
+}
+
+/**
+ * Generate a synthetic time using our distribution parameters.
+ *
+ * The return value will be within the [q_lo, q_hi) quantile points
+ * on the CDF.
+ */
+build_time_t
+circuit_build_times_generate_sample(circuit_build_times_t *cbt,
+ double q_lo, double q_hi)
+{
+ double randval = crypto_rand_double();
+ build_time_t ret;
+ double u;
+
+ /* Generate between [q_lo, q_hi) */
+ /*XXXX This is what nextafter is supposed to be for; we should use it on the
+ * platforms that support it. */
+ q_hi -= 1.0/(INT32_MAX);
+
+ tor_assert(q_lo >= 0);
+ tor_assert(q_hi < 1);
+ tor_assert(q_lo < q_hi);
+
+ u = q_lo + (q_hi-q_lo)*randval;
+
+ tor_assert(0 <= u && u < 1.0);
+ /* circuit_build_times_calculate_timeout returns <= INT32_MAX */
+ ret = (build_time_t)
+ tor_lround(circuit_build_times_calculate_timeout(cbt, u));
+ tor_assert(ret > 0);
+ return ret;
+}
+
+/**
+ * Estimate an initial alpha parameter by solving the quantile
+ * function with a quantile point and a specific timeout value.
+ */
+void
+circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
+ double quantile, double timeout_ms)
+{
+ // Q(u) = Xm/((1-u)^(1/a))
+ // Q(0.8) = Xm/((1-0.8))^(1/a)) = CircBuildTimeout
+ // CircBuildTimeout = Xm/((1-0.8))^(1/a))
+ // CircBuildTimeout = Xm*((1-0.8))^(-1/a))
+ // ln(CircBuildTimeout) = ln(Xm)+ln(((1-0.8)))*(-1/a)
+ // -ln(1-0.8)/(ln(CircBuildTimeout)-ln(Xm))=a
+ tor_assert(quantile >= 0);
+ tor_assert(cbt->Xm > 0);
+ cbt->alpha = tor_mathlog(1.0-quantile)/
+ (tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms));
+ tor_assert(cbt->alpha > 0);
+}
+
+/**
+ * Returns true if we need circuits to be built
+ */
+int
+circuit_build_times_needs_circuits(circuit_build_times_t *cbt)
+{
+ /* Return true if < MIN_CIRCUITS_TO_OBSERVE */
+ return !circuit_build_times_enough_to_compute(cbt);
+}
+
+/**
+ * Returns true if we should build a timeout test circuit
+ * right now.
+ */
+int
+circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt)
+{
+ return circuit_build_times_needs_circuits(cbt) &&
+ approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency();
+}
+
+/**
+ * Called to indicate that the network showed some signs of liveness,
+ * i.e. we received a cell.
+ *
+ * This is used by circuit_build_times_network_check_live() to decide
+ * if we should record the circuit build timeout or not.
+ *
+ * This function is called every time we receive a cell. Avoid
+ * syscalls, events, and other high-intensity work.
+ */
+void
+circuit_build_times_network_is_live(circuit_build_times_t *cbt)
+{
+ time_t now = approx_time();
+ if (cbt->liveness.nonlive_timeouts > 0) {
+ log_notice(LD_CIRC,
+ "Tor now sees network activity. Restoring circuit build "
+ "timeout recording. Network was down for %d seconds "
+ "during %d circuit attempts.",
+ (int)(now - cbt->liveness.network_last_live),
+ cbt->liveness.nonlive_timeouts);
+ }
+ cbt->liveness.network_last_live = now;
+ cbt->liveness.nonlive_timeouts = 0;
+}
+
+/**
+ * Called to indicate that we completed a circuit. Because this circuit
+ * succeeded, it doesn't count as a timeout-after-the-first-hop.
+ *
+ * This is used by circuit_build_times_network_check_changed() to determine
+ * if we had too many recent timeouts and need to reset our learned timeout
+ * to something higher.
+ */
+void
+circuit_build_times_network_circ_success(circuit_build_times_t *cbt)
+{
+ /* Check for NULLness because we might not be using adaptive timeouts */
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]
+ = 0;
+ cbt->liveness.after_firsthop_idx++;
+ cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
+ }
+}
+
+/**
+ * A circuit just timed out. If it failed after the first hop, record it
+ * in our history for later deciding if the network speed has changed.
+ *
+ * This is used by circuit_build_times_network_check_changed() to determine
+ * if we had too many recent timeouts and need to reset our learned timeout
+ * to something higher.
+ */
+static void
+circuit_build_times_network_timeout(circuit_build_times_t *cbt,
+ int did_onehop)
+{
+ /* Check for NULLness because we might not be using adaptive timeouts */
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ if (did_onehop) {
+ cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]
+ = 1;
+ cbt->liveness.after_firsthop_idx++;
+ cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
+ }
+ }
+}
+
+/**
+ * A circuit was just forcibly closed. If there has been no recent network
+ * activity at all, but this circuit was launched back when we thought the
+ * network was live, increment the number of "nonlive" circuit timeouts.
+ *
+ * This is used by circuit_build_times_network_check_live() to decide
+ * if we should record the circuit build timeout or not.
+ */
+static void
+circuit_build_times_network_close(circuit_build_times_t *cbt,
+ int did_onehop, time_t start_time)
+{
+ time_t now = time(NULL);
+ /*
+ * Check if this is a timeout that was for a circuit that spent its
+ * entire existence during a time where we have had no network activity.
+ */
+ if (cbt->liveness.network_last_live < start_time) {
+ if (did_onehop) {
+ char last_live_buf[ISO_TIME_LEN+1];
+ char start_time_buf[ISO_TIME_LEN+1];
+ char now_buf[ISO_TIME_LEN+1];
+ format_local_iso_time(last_live_buf, cbt->liveness.network_last_live);
+ format_local_iso_time(start_time_buf, start_time);
+ format_local_iso_time(now_buf, now);
+ log_notice(LD_CIRC,
+ "A circuit somehow completed a hop while the network was "
+ "not live. The network was last live at %s, but the circuit "
+ "launched at %s. It's now %s. This could mean your clock "
+ "changed.", last_live_buf, start_time_buf, now_buf);
+ }
+ cbt->liveness.nonlive_timeouts++;
+ if (cbt->liveness.nonlive_timeouts == 1) {
+ log_notice(LD_CIRC,
+ "Tor has not observed any network activity for the past %d "
+ "seconds. Disabling circuit build timeout recording.",
+ (int)(now - cbt->liveness.network_last_live));
+ } else {
+ log_info(LD_CIRC,
+ "Got non-live timeout. Current count is: %d",
+ cbt->liveness.nonlive_timeouts);
+ }
+ }
+}
+
+/**
+ * When the network is not live, we do not record circuit build times.
+ *
+ * The network is considered not live if there has been at least one
+ * circuit build that began and ended (had its close_ms measurement
+ * period expire) since we last received a cell.
+ *
+ * Also has the side effect of rewinding the circuit time history
+ * in the case of recent liveness changes.
+ */
+int
+circuit_build_times_network_check_live(circuit_build_times_t *cbt)
+{
+ if (cbt->liveness.nonlive_timeouts > 0) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Returns true if we have seen more than MAX_RECENT_TIMEOUT_COUNT of
+ * the past RECENT_CIRCUITS time out after the first hop. Used to detect
+ * if the network connection has changed significantly, and if so,
+ * resets our circuit build timeout to the default.
+ *
+ * Also resets the entire timeout history in this case and causes us
+ * to restart the process of building test circuits and estimating a
+ * new timeout.
+ */
+int
+circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
+{
+ int total_build_times = cbt->total_build_times;
+ int timeout_count=0;
+ int i;
+
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ /* how many of our recent circuits made it to the first hop but then
+ * timed out? */
+ for (i = 0; i < cbt->liveness.num_recent_circs; i++) {
+ timeout_count += cbt->liveness.timeouts_after_firsthop[i];
+ }
+ }
+
+ /* If 80% of our recent circuits are timing out after the first hop,
+ * we need to re-estimate a new initial alpha and timeout. */
+ if (timeout_count < circuit_build_times_max_timeouts()) {
+ return 0;
+ }
+
+ circuit_build_times_reset(cbt);
+ if (cbt->liveness.timeouts_after_firsthop &&
+ cbt->liveness.num_recent_circs > 0) {
+ memset(cbt->liveness.timeouts_after_firsthop, 0,
+ sizeof(*cbt->liveness.timeouts_after_firsthop)*
+ cbt->liveness.num_recent_circs);
+ }
+ cbt->liveness.after_firsthop_idx = 0;
+
+ /* Check to see if this has happened before. If so, double the timeout
+ * to give people on abysmally bad network connections a shot at access */
+ if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) {
+ if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) {
+ log_warn(LD_CIRC, "Insanely large circuit build timeout value. "
+ "(timeout = %fmsec, close = %fmsec)",
+ cbt->timeout_ms, cbt->close_ms);
+ } else {
+ cbt->timeout_ms *= 2;
+ cbt->close_ms *= 2;
+ }
+ } else {
+ cbt->close_ms = cbt->timeout_ms
+ = circuit_build_times_get_initial_timeout();
+ }
+
+ control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
+
+ log_notice(LD_CIRC,
+ "Your network connection speed appears to have changed. Resetting "
+ "timeout to %lds after %d timeouts and %d buildtimes.",
+ tor_lround(cbt->timeout_ms/1000), timeout_count,
+ total_build_times);
+
+ return 1;
+}
+
+/**
+ * Count the number of timeouts in a set of cbt data.
+ */
+double
+circuit_build_times_timeout_rate(const circuit_build_times_t *cbt)
+{
+ int i=0,timeouts=0;
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] >= cbt->timeout_ms) {
+ timeouts++;
+ }
+ }
+
+ if (!cbt->total_build_times)
+ return 0;
+
+ return ((double)timeouts)/cbt->total_build_times;
+}
+
+/**
+ * Count the number of closed circuits in a set of cbt data.
+ */
+double
+circuit_build_times_close_rate(const circuit_build_times_t *cbt)
+{
+ int i=0,closed=0;
+ for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
+ if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) {
+ closed++;
+ }
+ }
+
+ if (!cbt->total_build_times)
+ return 0;
+
+ return ((double)closed)/cbt->total_build_times;
+}
+
+/**
+ * Store a timeout as a synthetic value.
+ *
+ * Returns true if the store was successful and we should possibly
+ * update our timeout estimate.
+ */
+int
+circuit_build_times_count_close(circuit_build_times_t *cbt,
+ int did_onehop,
+ time_t start_time)
+{
+ if (circuit_build_times_disabled()) {
+ cbt->close_ms = cbt->timeout_ms
+ = circuit_build_times_get_initial_timeout();
+ return 0;
+ }
+
+ /* Record this force-close to help determine if the network is dead */
+ circuit_build_times_network_close(cbt, did_onehop, start_time);
+
+ /* Only count timeouts if network is live.. */
+ if (!circuit_build_times_network_check_live(cbt)) {
+ return 0;
+ }
+
+ circuit_build_times_add_time(cbt, CBT_BUILD_ABANDONED);
+ return 1;
+}
+
+/**
+ * Update timeout counts to determine if we need to expire
+ * our build time history due to excessive timeouts.
+ *
+ * We do not record any actual time values at this stage;
+ * we are only interested in recording the fact that a timeout
+ * happened. We record the time values via
+ * circuit_build_times_count_close() and circuit_build_times_add_time().
+ */
+void
+circuit_build_times_count_timeout(circuit_build_times_t *cbt,
+ int did_onehop)
+{
+ if (circuit_build_times_disabled()) {
+ cbt->close_ms = cbt->timeout_ms
+ = circuit_build_times_get_initial_timeout();
+ return;
+ }
+
+ /* Register the fact that a timeout just occurred. */
+ circuit_build_times_network_timeout(cbt, did_onehop);
+
+ /* If there are a ton of timeouts, we should reset
+ * the circuit build timeout. */
+ circuit_build_times_network_check_changed(cbt);
+}
+
+/**
+ * Estimate a new timeout based on history and set our timeout
+ * variable accordingly.
+ */
+static int
+circuit_build_times_set_timeout_worker(circuit_build_times_t *cbt)
+{
+ build_time_t max_time;
+ if (!circuit_build_times_enough_to_compute(cbt))
+ return 0;
+
+ if (!circuit_build_times_update_alpha(cbt))
+ return 0;
+
+ cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt,
+ circuit_build_times_quantile_cutoff());
+
+ cbt->close_ms = circuit_build_times_calculate_timeout(cbt,
+ circuit_build_times_close_quantile());
+
+ max_time = circuit_build_times_max(cbt);
+
+ if (cbt->timeout_ms > max_time) {
+ log_info(LD_CIRC,
+ "Circuit build timeout of %dms is beyond the maximum build "
+ "time we have ever observed. Capping it to %dms.",
+ (int)cbt->timeout_ms, max_time);
+ cbt->timeout_ms = max_time;
+ }
+
+ if (max_time < INT32_MAX/2 && cbt->close_ms > 2*max_time) {
+ log_info(LD_CIRC,
+ "Circuit build measurement period of %dms is more than twice "
+ "the maximum build time we have ever observed. Capping it to "
+ "%dms.", (int)cbt->close_ms, 2*max_time);
+ cbt->close_ms = 2*max_time;
+ }
+
+ /* Sometimes really fast guard nodes give us such a steep curve
+ * that this ends up being not that much greater than timeout_ms.
+ * Make it be at least 1 min to handle this case. */
+ cbt->close_ms = MAX(cbt->close_ms, circuit_build_times_initial_timeout());
+
+ cbt->have_computed_timeout = 1;
+ return 1;
+}
+
+/**
+ * Exposed function to compute a new timeout. Dispatches events and
+ * also filters out extremely high timeout values.
+ */
+void
+circuit_build_times_set_timeout(circuit_build_times_t *cbt)
+{
+ long prev_timeout = tor_lround(cbt->timeout_ms/1000);
+ double timeout_rate;
+
+ /*
+ * Just return if we aren't using adaptive timeouts
+ */
+ if (circuit_build_times_disabled())
+ return;
+
+ if (!circuit_build_times_set_timeout_worker(cbt))
+ return;
+
+ if (cbt->timeout_ms < circuit_build_times_min_timeout()) {
+ log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms",
+ cbt->timeout_ms, circuit_build_times_min_timeout());
+ cbt->timeout_ms = circuit_build_times_min_timeout();
+ if (cbt->close_ms < cbt->timeout_ms) {
+ /* This shouldn't happen because of MAX() in timeout_worker above,
+ * but doing it just in case */
+ cbt->close_ms = circuit_build_times_initial_timeout();
+ }
+ }
+
+ control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED);
+
+ timeout_rate = circuit_build_times_timeout_rate(cbt);
+
+ if (prev_timeout > tor_lround(cbt->timeout_ms/1000)) {
+ log_info(LD_CIRC,
+ "Based on %d circuit times, it looks like we don't need to "
+ "wait so long for circuits to finish. We will now assume a "
+ "circuit is too slow to use after waiting %ld seconds.",
+ cbt->total_build_times,
+ tor_lround(cbt->timeout_ms/1000));
+ log_info(LD_CIRC,
+ "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
+ cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
+ timeout_rate);
+ } else if (prev_timeout < tor_lround(cbt->timeout_ms/1000)) {
+ log_info(LD_CIRC,
+ "Based on %d circuit times, it looks like we need to wait "
+ "longer for circuits to finish. We will now assume a "
+ "circuit is too slow to use after waiting %ld seconds.",
+ cbt->total_build_times,
+ tor_lround(cbt->timeout_ms/1000));
+ log_info(LD_CIRC,
+ "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f",
+ cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha,
+ timeout_rate);
+ } else {
+ log_info(LD_CIRC,
+ "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f,"
+ " r: %f) based on %d circuit times",
+ tor_lround(cbt->timeout_ms/1000),
+ cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate,
+ cbt->total_build_times);
+ }
+}
+/** Make a note that we're running unit tests (rather than running Tor
+ * itself), so we avoid clobbering our state file. */
+void
+circuitbuild_running_unit_tests(void)
+{
+ unit_tests = 1;
+}
+
diff --git a/src/or/circuitstats.h b/src/or/circuitstats.h
new file mode 100644
index 000000000..87dce99f4
--- /dev/null
+++ b/src/or/circuitstats.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file circuitstats.h
+ * \brief Header file for circuitstats.c
+ **/
+
+#ifndef TOR_CIRCUITSTATS_H
+#define TOR_CIRCUITSTATS_H
+
+extern circuit_build_times_t circ_times;
+
+int circuit_build_times_disabled(void);
+int circuit_build_times_enough_to_compute(circuit_build_times_t *cbt);
+void circuit_build_times_update_state(circuit_build_times_t *cbt,
+ or_state_t *state);
+int circuit_build_times_parse_state(circuit_build_times_t *cbt,
+ or_state_t *state);
+void circuit_build_times_count_timeout(circuit_build_times_t *cbt,
+ int did_onehop);
+int circuit_build_times_count_close(circuit_build_times_t *cbt,
+ int did_onehop, time_t start_time);
+void circuit_build_times_set_timeout(circuit_build_times_t *cbt);
+int circuit_build_times_add_time(circuit_build_times_t *cbt,
+ build_time_t time);
+int circuit_build_times_needs_circuits(circuit_build_times_t *cbt);
+
+int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt);
+void circuit_build_times_init(circuit_build_times_t *cbt);
+void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
+void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
+ networkstatus_t *ns);
+double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
+double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
+
+#ifdef CIRCUITSTATS_PRIVATE
+double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
+ double quantile);
+build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt,
+ double q_lo, double q_hi);
+void circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
+ double quantile, double time_ms);
+int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
+double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
+void circuitbuild_running_unit_tests(void);
+void circuit_build_times_reset(circuit_build_times_t *cbt);
+
+/* Network liveness functions */
+int circuit_build_times_network_check_changed(circuit_build_times_t *cbt);
+#endif
+
+/* Network liveness functions */
+void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
+int circuit_build_times_network_check_live(circuit_build_times_t *cbt);
+void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
+
+/* DOCDOC circuit_build_times_get_bw_scale */
+int circuit_build_times_get_bw_scale(networkstatus_t *ns);
+
+#endif
+
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index ade4224fe..598469198 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,13 +10,17 @@
**/
#include "or.h"
+#include "addressmap.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitstats.h"
#include "circuituse.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "control.h"
+#include "entrynodes.h"
#include "nodelist.h"
#include "networkstatus.h"
#include "policies.h"
@@ -53,7 +57,7 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
tor_assert(conn);
tor_assert(conn->socks_request);
- if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_conn))
+ if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_chan))
return 0; /* ignore non-open circs */
if (circ->marked_for_close)
return 0;
@@ -81,10 +85,14 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
}
if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
- purpose == CIRCUIT_PURPOSE_C_REND_JOINED)
+ purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
if (circ->timestamp_dirty &&
circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now)
return 0;
+ }
+
+ if (origin_circ->unusable_for_new_conns)
+ return 0;
/* decide if this circ is suitable for this conn */
@@ -101,6 +109,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
return 0;
if (purpose == CIRCUIT_PURPOSE_C_GENERAL) {
+ tor_addr_t addr;
+ const int family = tor_addr_parse(&addr, conn->socks_request->address);
if (!exitnode && !build_state->onehop_tunnel) {
log_debug(LD_CIRC,"Not considering circuit with unknown router.");
return 0; /* this circuit is screwed and doesn't know it yet,
@@ -121,9 +131,7 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
return 0; /* this is a circuit to somewhere else */
if (tor_digest_is_zero(digest)) {
/* we don't know the digest; have to compare addr:port */
- tor_addr_t addr;
- int r = tor_addr_parse(&addr, conn->socks_request->address);
- if (r < 0 ||
+ if (family < 0 ||
!tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
build_state->chosen_exit->port != conn->socks_request->port)
return 0;
@@ -135,6 +143,13 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
return 0;
}
}
+ if (origin_circ->prepend_policy && family != -1) {
+ int r = compare_tor_addr_to_addr_policy(&addr,
+ conn->socks_request->port,
+ origin_circ->prepend_policy);
+ if (r == ADDR_POLICY_REJECTED)
+ return 0;
+ }
if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) {
/* can't exit from this router */
return 0;
@@ -172,6 +187,13 @@ circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob,
const uint8_t purpose = ENTRY_TO_CONN(conn)->purpose;
int a_bits, b_bits;
+ /* If one of the circuits was allowed to live due to relaxing its timeout,
+ * it is definitely worse (it's probably a much slower path). */
+ if (oa->relaxed_timeout && !ob->relaxed_timeout)
+ return 0; /* ob is better. It's not relaxed. */
+ if (!oa->relaxed_timeout && ob->relaxed_timeout)
+ return 1; /* oa is better. It's not relaxed. */
+
switch (purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
/* if it's used but less dirty it's best;
@@ -183,7 +205,7 @@ circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob,
return 1;
} else {
if (a->timestamp_dirty ||
- timercmp(&a->timestamp_created, &b->timestamp_created, >))
+ timercmp(&a->timestamp_began, &b->timestamp_began, >))
return 1;
if (ob->build_state->is_internal)
/* XXX023 what the heck is this internal thing doing here. I
@@ -269,17 +291,19 @@ circuit_get_best(const entry_connection_t *conn,
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
origin_circ = TO_ORIGIN_CIRCUIT(circ);
- if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose,
- need_uptime,need_internal,now.tv_sec))
- continue;
+ /* Log an info message if we're going to launch a new intro circ in
+ * parallel */
if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT &&
- !must_be_open && circ->state != CIRCUIT_STATE_OPEN &&
- tv_mdiff(&now, &circ->timestamp_created) > circ_times.timeout_ms) {
- intro_going_on_but_too_old = 1;
- continue;
+ !must_be_open && origin_circ->hs_circ_has_timed_out) {
+ intro_going_on_but_too_old = 1;
+ continue;
}
+ if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose,
+ need_uptime,need_internal,now.tv_sec))
+ continue;
+
/* now this is an acceptable circ to hand back. but that doesn't
* mean it's the *best* circ to hand back. try to decide.
*/
@@ -356,13 +380,38 @@ circuit_expire_building(void)
* circuit_build_times_get_initial_timeout() if we haven't computed
* custom timeouts yet */
struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff,
- cannibalize_cutoff, close_cutoff, extremely_old_cutoff,
- hs_extremely_old_cutoff;
+ close_cutoff, extremely_old_cutoff, hs_extremely_old_cutoff,
+ cannibalized_cutoff, c_intro_cutoff, s_intro_cutoff, stream_cutoff;
const or_options_t *options = get_options();
struct timeval now;
cpath_build_state_t *build_state;
+ int any_opened_circs = 0;
tor_gettimeofday(&now);
+
+ /* Check to see if we have any opened circuits. If we don't,
+ * we want to be more lenient with timeouts, in case the
+ * user has relocated and/or changed network connections.
+ * See bug #3443. */
+ while (next_circ) {
+ if (!CIRCUIT_IS_ORIGIN(next_circ) || /* didn't originate here */
+ next_circ->marked_for_close) { /* don't mess with marked circs */
+ next_circ = next_circ->next;
+ continue;
+ }
+
+ if (TO_ORIGIN_CIRCUIT(next_circ)->has_opened &&
+ next_circ->state == CIRCUIT_STATE_OPEN &&
+ TO_ORIGIN_CIRCUIT(next_circ)->build_state &&
+ TO_ORIGIN_CIRCUIT(next_circ)->build_state->desired_path_len
+ == DEFAULT_ROUTE_LEN) {
+ any_opened_circs = 1;
+ break;
+ }
+ next_circ = next_circ->next;
+ }
+ next_circ = global_circuitlist;
+
#define SET_CUTOFF(target, msec) do { \
long ms = tor_lround(msec); \
struct timeval diff; \
@@ -371,10 +420,60 @@ circuit_expire_building(void)
timersub(&now, &diff, &target); \
} while (0)
+ /**
+ * Because circuit build timeout is calculated only based on 3 hop
+ * general purpose circuit construction, we need to scale the timeout
+ * to make it properly apply to longer circuits, and circuits of
+ * certain usage types. The following diagram illustrates how we
+ * derive the scaling below. In short, we calculate the number
+ * of times our telescoping-based circuit construction causes cells
+ * to traverse each link for the circuit purpose types in question,
+ * and then assume each link is equivalent.
+ *
+ * OP --a--> A --b--> B --c--> C
+ * OP --a--> A --b--> B --c--> C --d--> D
+ *
+ * Let h = a = b = c = d
+ *
+ * Three hops (general_cutoff)
+ * RTTs = 3a + 2b + c
+ * RTTs = 6h
+ * Cannibalized:
+ * RTTs = a+b+c+d
+ * RTTs = 4h
+ * Four hops:
+ * RTTs = 4a + 3b + 2c + d
+ * RTTs = 10h
+ * Client INTRODUCE1+ACK: // XXX: correct?
+ * RTTs = 5a + 4b + 3c + 2d
+ * RTTs = 14h
+ * Server intro:
+ * RTTs = 4a + 3b + 2c
+ * RTTs = 9h
+ */
SET_CUTOFF(general_cutoff, circ_times.timeout_ms);
SET_CUTOFF(begindir_cutoff, circ_times.timeout_ms);
- SET_CUTOFF(fourhop_cutoff, circ_times.timeout_ms * (4/3.0));
- SET_CUTOFF(cannibalize_cutoff, circ_times.timeout_ms / 2.0);
+
+ /* > 3hop circs seem to have a 1.0 second delay on their cannibalized
+ * 4th hop. */
+ SET_CUTOFF(fourhop_cutoff, circ_times.timeout_ms * (10/6.0) + 1000);
+
+ /* CIRCUIT_PURPOSE_C_ESTABLISH_REND behaves more like a RELAY cell.
+ * Use the stream cutoff (more or less). */
+ SET_CUTOFF(stream_cutoff, MAX(options->CircuitStreamTimeout,15)*1000 + 1000);
+
+ /* Be lenient with cannibalized circs. They already survived the official
+ * CBT, and they're usually not performance-critical. */
+ SET_CUTOFF(cannibalized_cutoff,
+ MAX(circ_times.close_ms*(4/6.0),
+ options->CircuitStreamTimeout * 1000) + 1000);
+
+ /* Intro circs have an extra round trip (and are also 4 hops long) */
+ SET_CUTOFF(c_intro_cutoff, circ_times.timeout_ms * (14/6.0) + 1000);
+
+ /* Server intro circs have an extra round trip */
+ SET_CUTOFF(s_intro_cutoff, circ_times.timeout_ms * (9/6.0) + 1000);
+
SET_CUTOFF(close_cutoff, circ_times.close_ms);
SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000);
@@ -387,28 +486,95 @@ circuit_expire_building(void)
victim = next_circ;
next_circ = next_circ->next;
if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */
- victim->marked_for_close) /* don't mess with marked circs */
+ victim->marked_for_close) /* don't mess with marked circs */
+ continue;
+
+ /* If we haven't yet started the first hop, it means we don't have
+ * any orconns available, and thus have not started counting time yet
+ * for this circuit. See circuit_deliver_create_cell() and uses of
+ * timestamp_began.
+ *
+ * Continue to wait in this case. The ORConn should timeout
+ * independently and kill us then.
+ */
+ if (TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_CLOSED) {
continue;
+ }
build_state = TO_ORIGIN_CIRCUIT(victim)->build_state;
if (build_state && build_state->onehop_tunnel)
cutoff = begindir_cutoff;
- else if (build_state && build_state->desired_path_len == 4
- && !TO_ORIGIN_CIRCUIT(victim)->has_opened)
- cutoff = fourhop_cutoff;
- else if (TO_ORIGIN_CIRCUIT(victim)->has_opened)
- cutoff = cannibalize_cutoff;
else if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
cutoff = close_cutoff;
+ else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
+ victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
+ cutoff = c_intro_cutoff;
+ else if (victim->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
+ cutoff = s_intro_cutoff;
+ else if (victim->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND)
+ cutoff = stream_cutoff;
+ else if (victim->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
+ cutoff = close_cutoff;
+ else if (TO_ORIGIN_CIRCUIT(victim)->has_opened &&
+ victim->state != CIRCUIT_STATE_OPEN)
+ cutoff = cannibalized_cutoff;
+ else if (build_state && build_state->desired_path_len >= 4)
+ cutoff = fourhop_cutoff;
else
cutoff = general_cutoff;
if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)
cutoff = hs_extremely_old_cutoff;
- if (timercmp(&victim->timestamp_created, &cutoff, >))
+ if (timercmp(&victim->timestamp_began, &cutoff, >))
continue; /* it's still young, leave it alone */
+ /* We need to double-check the opened state here because
+ * we don't want to consider opened 1-hop dircon circuits for
+ * deciding when to relax the timeout, but we *do* want to relax
+ * those circuits too if nothing else is opened *and* they still
+ * aren't either. */
+ if (!any_opened_circs && victim->state != CIRCUIT_STATE_OPEN) {
+ /* It's still young enough that we wouldn't close it, right? */
+ if (timercmp(&victim->timestamp_began, &close_cutoff, >)) {
+ if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) {
+ int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath->state
+ == CPATH_STATE_OPEN;
+ log_info(LD_CIRC,
+ "No circuits are opened. Relaxing timeout for circuit %d "
+ "(a %s %d-hop circuit in state %s with channel state %s). "
+ "%d guards are live.",
+ TO_ORIGIN_CIRCUIT(victim)->global_identifier,
+ circuit_purpose_to_string(victim->purpose),
+ TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len,
+ circuit_state_to_string(victim->state),
+ channel_state_to_string(victim->n_chan->state),
+ num_live_entry_guards(0));
+
+ /* We count the timeout here for CBT, because technically this
+ * was a timeout, and the timeout value needs to reset if we
+ * see enough of them. Note this means we also need to avoid
+ * double-counting below, too. */
+ circuit_build_times_count_timeout(&circ_times, first_hop_succeeded);
+ TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout = 1;
+ }
+ continue;
+ } else {
+ static ratelim_t relax_timeout_limit = RATELIM_INIT(3600);
+ log_fn_ratelim(&relax_timeout_limit, LOG_NOTICE, LD_CIRC,
+ "No circuits are opened. Relaxed timeout for circuit %d "
+ "(a %s %d-hop circuit in state %s with channel state %s) to "
+ "%ldms. However, it appears the circuit has timed out "
+ "anyway. %d guards are live.",
+ TO_ORIGIN_CIRCUIT(victim)->global_identifier,
+ circuit_purpose_to_string(victim->purpose),
+ TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len,
+ circuit_state_to_string(victim->state),
+ channel_state_to_string(victim->n_chan->state),
+ (long)circ_times.close_ms, num_live_entry_guards(0));
+ }
+ }
+
#if 0
/* some debug logs, to help track bugs */
if (victim->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING &&
@@ -436,8 +602,6 @@ circuit_expire_building(void)
default: /* most open circuits can be left alone. */
continue; /* yes, continue inside a switch refers to the nearest
* enclosing loop. C is smart. */
- case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
- case CIRCUIT_PURPOSE_C_INTRODUCING:
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
break; /* too old, need to die */
case CIRCUIT_PURPOSE_C_REND_READY:
@@ -449,6 +613,19 @@ circuit_expire_building(void)
victim->timestamp_dirty > cutoff.tv_sec)
continue;
break;
+ case CIRCUIT_PURPOSE_PATH_BIAS_TESTING:
+ /* Open path bias testing circuits are given a long
+ * time to complete the test, but not forever */
+ TO_ORIGIN_CIRCUIT(victim)->path_state = PATH_STATE_USE_FAILED;
+ break;
+ case CIRCUIT_PURPOSE_C_INTRODUCING:
+ /* We keep old introducing circuits around for
+ * a while in parallel, and they can end up "opened".
+ * We decide below if we're going to mark them timed
+ * out and eventually close them.
+ */
+ break;
+ case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
/* rend and intro circs become dirty each time they
@@ -485,9 +662,12 @@ circuit_expire_building(void)
/* Record this failure to check for too many timeouts
* in a row. This function does not record a time value yet
* (we do that later); it only counts the fact that we did
- * have a timeout. */
- circuit_build_times_count_timeout(&circ_times,
- first_hop_succeeded);
+ * have a timeout. We also want to avoid double-counting
+ * already "relaxed" circuits, which are counted above. */
+ if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) {
+ circuit_build_times_count_timeout(&circ_times,
+ first_hop_succeeded);
+ }
continue;
}
@@ -496,11 +676,11 @@ circuit_expire_building(void)
* it off at, we probably had a suspend event along this codepath,
* and we should discard the value.
*/
- if (timercmp(&victim->timestamp_created, &extremely_old_cutoff, <)) {
+ if (timercmp(&victim->timestamp_began, &extremely_old_cutoff, <)) {
log_notice(LD_CIRC,
"Extremely large value for circuit build timeout: %lds. "
"Assuming clock jump. Purpose %d (%s)",
- (long)(now.tv_sec - victim->timestamp_created.tv_sec),
+ (long)(now.tv_sec - victim->timestamp_began.tv_sec),
victim->purpose,
circuit_purpose_to_string(victim->purpose));
} else if (circuit_build_times_count_close(&circ_times,
@@ -534,12 +714,15 @@ circuit_expire_building(void)
if (TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath ==
NULL)
break;
+ /* fallthrough! */
+ case CIRCUIT_PURPOSE_C_INTRODUCING:
+ /* connection_ap_handshake_attach_circuit() will relaunch for us */
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
/* If we have reached this line, we want to spare the circ for now. */
- log_info(LD_CIRC,"Marking circ %d (state %d:%s, purpose %d) "
+ log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) "
"as timed-out HS circ",
- victim->n_circ_id,
+ (unsigned)victim->n_circ_id,
victim->state, circuit_state_to_string(victim->state),
victim->purpose);
TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
@@ -555,9 +738,9 @@ circuit_expire_building(void)
if (!(options->CloseHSServiceRendCircuitsImmediatelyOnTimeout) &&
!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) &&
victim->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) {
- log_info(LD_CIRC,"Marking circ %d (state %d:%s, purpose %d) "
+ log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) "
"as timed-out HS circ; relaunching rendezvous attempt.",
- victim->n_circ_id,
+ (unsigned)victim->n_circ_id,
victim->state, circuit_state_to_string(victim->state),
victim->purpose);
TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
@@ -565,22 +748,33 @@ circuit_expire_building(void)
continue;
}
- if (victim->n_conn)
- log_info(LD_CIRC,"Abandoning circ %s:%d:%d (state %d:%s, purpose %d)",
- victim->n_conn->_base.address, victim->n_conn->_base.port,
- victim->n_circ_id,
+ if (victim->n_chan)
+ log_info(LD_CIRC,
+ "Abandoning circ %u %s:%d (state %d,%d:%s, purpose %d, "
+ "len %d)", TO_ORIGIN_CIRCUIT(victim)->global_identifier,
+ channel_get_canonical_remote_descr(victim->n_chan),
+ (unsigned)victim->n_circ_id,
+ TO_ORIGIN_CIRCUIT(victim)->has_opened,
victim->state, circuit_state_to_string(victim->state),
- victim->purpose);
+ victim->purpose,
+ TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len);
else
- log_info(LD_CIRC,"Abandoning circ %d (state %d:%s, purpose %d)",
- victim->n_circ_id, victim->state,
- circuit_state_to_string(victim->state), victim->purpose);
+ log_info(LD_CIRC,
+ "Abandoning circ %u %d (state %d,%d:%s, purpose %d, len %d)",
+ TO_ORIGIN_CIRCUIT(victim)->global_identifier,
+ (unsigned)victim->n_circ_id,
+ TO_ORIGIN_CIRCUIT(victim)->has_opened,
+ victim->state,
+ circuit_state_to_string(victim->state), victim->purpose,
+ TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len);
circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim));
if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
circuit_mark_for_close(victim, END_CIRC_REASON_MEASUREMENT_EXPIRED);
else
circuit_mark_for_close(victim, END_CIRC_REASON_TIMEOUT);
+
+ pathbias_count_timeout(TO_ORIGIN_CIRCUIT(victim));
}
}
@@ -620,7 +814,8 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
const node_t *exitnode;
int num=0;
time_t now = time(NULL);
- int need_uptime = smartlist_string_num_isin(get_options()->LongLivedPorts,
+ int need_uptime = smartlist_contains_int_as_string(
+ get_options()->LongLivedPorts,
conn ? conn->socks_request->port : port);
for (circ=global_circuitlist;circ;circ = circ->next) {
@@ -629,9 +824,12 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
(!circ->timestamp_dirty ||
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) {
- cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
+ cpath_build_state_t *build_state = origin_circ->build_state;
if (build_state->is_internal || build_state->onehop_tunnel)
continue;
+ if (origin_circ->unusable_for_new_conns)
+ continue;
exitnode = build_state_get_exit_node(build_state);
if (exitnode && (!need_uptime || build_state->need_uptime)) {
@@ -673,6 +871,7 @@ circuit_predict_and_launch_new(void)
/* First, count how many of each type of circuit we have already. */
for (circ=global_circuitlist;circ;circ = circ->next) {
cpath_build_state_t *build_state;
+ origin_circuit_t *origin_circ;
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
if (circ->marked_for_close)
@@ -681,7 +880,10 @@ circuit_predict_and_launch_new(void)
continue; /* only count clean circs */
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
continue; /* only pay attention to general-purpose circs */
- build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ origin_circ = TO_ORIGIN_CIRCUIT(circ);
+ if (origin_circ->unusable_for_new_conns)
+ continue;
+ build_state = origin_circ->build_state;
if (build_state->onehop_tunnel)
continue;
num++;
@@ -787,7 +989,7 @@ circuit_build_needed_circs(time_t now)
circ = circuit_get_youngest_clean_open(CIRCUIT_PURPOSE_C_GENERAL);
if (get_options()->RunTesting &&
circ &&
- circ->timestamp_created.tv_sec + TESTING_CIRCUIT_INTERVAL < now) {
+ circ->timestamp_began.tv_sec + TESTING_CIRCUIT_INTERVAL < now) {
log_fn(LOG_INFO,"Creating a new testing circuit.");
circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, 0);
}
@@ -808,7 +1010,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
tor_assert(circ);
tor_assert(conn);
- if (conn->_base.type == CONN_TYPE_AP) {
+ if (conn->base_.type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
entry_conn->may_use_optimistic_data = 0;
}
@@ -901,13 +1103,17 @@ circuit_expire_old_circuits_clientside(void)
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness <
now.tv_sec &&
!TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) {
- log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %ld sec ago, "
+ log_debug(LD_CIRC, "Closing n_circ_id %u (dirty %ld sec ago, "
"purpose %d)",
- circ->n_circ_id, (long)(now.tv_sec - circ->timestamp_dirty),
+ (unsigned)circ->n_circ_id,
+ (long)(now.tv_sec - circ->timestamp_dirty),
circ->purpose);
- circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
+ /* Don't do this magic for testing circuits. Their death is governed
+ * by circuit_expire_building */
+ if (circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
+ circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
} else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) {
- if (timercmp(&circ->timestamp_created, &cutoff, <)) {
+ if (timercmp(&circ->timestamp_began, &cutoff, <)) {
if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT ||
circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -917,7 +1123,7 @@ circuit_expire_old_circuits_clientside(void)
circ->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) {
log_debug(LD_CIRC,
"Closing circuit that has been unused for %ld msec.",
- tv_mdiff(&circ->timestamp_created, &now));
+ tv_mdiff(&circ->timestamp_began, &now));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
} else if (!TO_ORIGIN_CIRCUIT(circ)->is_ancient) {
/* Server-side rend joined circuits can end up really old, because
@@ -931,7 +1137,7 @@ circuit_expire_old_circuits_clientside(void)
"Ancient non-dirty circuit %d is still around after "
"%ld milliseconds. Purpose: %d (%s)",
TO_ORIGIN_CIRCUIT(circ)->global_identifier,
- tv_mdiff(&circ->timestamp_created, &now),
+ tv_mdiff(&circ->timestamp_began, &now),
circ->purpose,
circuit_purpose_to_string(circ->purpose));
TO_ORIGIN_CIRCUIT(circ)->is_ancient = 1;
@@ -977,13 +1183,13 @@ circuit_expire_old_circuits_serverside(time_t now)
/* If the circuit has been idle for too long, and there are no streams
* on it, and it ends here, and it used a create_fast, mark it for close.
*/
- if (or_circ->is_first_hop && !circ->n_conn &&
+ if (or_circ->is_first_hop && !circ->n_chan &&
!or_circ->n_streams && !or_circ->resolving_streams &&
- or_circ->p_conn &&
- or_circ->p_conn->timestamp_last_added_nonpadding <= cutoff) {
- log_info(LD_CIRC, "Closing circ_id %d (empty %d secs ago)",
- or_circ->p_circ_id,
- (int)(now - or_circ->p_conn->timestamp_last_added_nonpadding));
+ or_circ->p_chan &&
+ channel_when_last_xmit(or_circ->p_chan) <= cutoff) {
+ log_info(LD_CIRC, "Closing circ_id %u (empty %d secs ago)",
+ (unsigned)or_circ->p_circ_id,
+ (int)(now - channel_when_last_xmit(or_circ->p_chan)));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
}
}
@@ -1125,7 +1331,7 @@ static int
circuit_try_clearing_isolation_state(origin_circuit_t *circ)
{
if (/* The circuit may have become non-open if it was cannibalized.*/
- circ->_base.state == CIRCUIT_STATE_OPEN &&
+ circ->base_.state == CIRCUIT_STATE_OPEN &&
/* If !isolation_values_set, there is nothing to clear. */
circ->isolation_values_set &&
/* It's not legal to clear a circuit's isolation info if it's ever had
@@ -1163,6 +1369,7 @@ circuit_try_attaching_streams(origin_circuit_t *circ)
void
circuit_build_failed(origin_circuit_t *circ)
{
+ channel_t *n_chan = NULL;
/* we should examine circ and see if it failed because of
* the last hop or an earlier hop. then use this info below.
*/
@@ -1179,11 +1386,12 @@ circuit_build_failed(origin_circuit_t *circ)
/* We failed at the first hop. If there's an OR connection
* to blame, blame it. Also, avoid this relay for a while, and
* fail any one-hop directory fetches destined for it. */
- const char *n_conn_id = circ->cpath->extend_info->identity_digest;
+ const char *n_chan_id = circ->cpath->extend_info->identity_digest;
int already_marked = 0;
- if (circ->_base.n_conn) {
- or_connection_t *n_conn = circ->_base.n_conn;
- if (n_conn->is_bad_for_new_circs) {
+ if (circ->base_.n_chan) {
+ n_chan = circ->base_.n_chan;
+
+ if (n_chan->is_bad_for_new_circs) {
/* We only want to blame this router when a fresh healthy
* connection fails. So don't mark this router as newly failed,
* since maybe this was just an old circuit attempt that's
@@ -1195,22 +1403,22 @@ circuit_build_failed(origin_circuit_t *circ)
}
log_info(LD_OR,
"Our circuit failed to get a response from the first hop "
- "(%s:%d). I'm going to try to rotate to a better connection.",
- n_conn->_base.address, n_conn->_base.port);
- n_conn->is_bad_for_new_circs = 1;
+ "(%s). I'm going to try to rotate to a better connection.",
+ channel_get_canonical_remote_descr(n_chan));
+ n_chan->is_bad_for_new_circs = 1;
} else {
log_info(LD_OR,
"Our circuit died before the first hop with no connection");
}
- if (n_conn_id && !already_marked) {
- entry_guard_register_connect_status(n_conn_id, 0, 1, time(NULL));
+ if (n_chan_id && !already_marked) {
+ entry_guard_register_connect_status(n_chan_id, 0, 1, time(NULL));
/* if there are any one-hop streams waiting on this circuit, fail
* them now so they can retry elsewhere. */
- connection_ap_fail_onehop(n_conn_id, circ->build_state);
+ connection_ap_fail_onehop(n_chan_id, circ->build_state);
}
}
- switch (circ->_base.purpose) {
+ switch (circ->base_.purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
/* If we never built the circuit, note it as a failure. */
circuit_increment_failure_count();
@@ -1225,7 +1433,7 @@ circuit_build_failed(origin_circuit_t *circ)
break;
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
/* at Bob, waiting for introductions */
- if (circ->_base.state != CIRCUIT_STATE_OPEN) {
+ if (circ->base_.state != CIRCUIT_STATE_OPEN) {
circuit_increment_failure_count();
}
/* no need to care here, because bob will rebuild intro
@@ -1309,21 +1517,46 @@ circuit_launch_by_extend_info(uint8_t purpose,
* internal circs rather than exit circs? -RD */
circ = circuit_find_to_cannibalize(purpose, extend_info, flags);
if (circ) {
- uint8_t old_purpose = circ->_base.purpose;
- struct timeval old_timestamp_created;
+ uint8_t old_purpose = circ->base_.purpose;
+ struct timeval old_timestamp_began;
log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d (%s)",
build_state_get_exit_nickname(circ->build_state), purpose,
circuit_purpose_to_string(purpose));
+ if ((purpose == CIRCUIT_PURPOSE_S_CONNECT_REND ||
+ purpose == CIRCUIT_PURPOSE_C_INTRODUCING) &&
+ circ->path_state == PATH_STATE_BUILD_SUCCEEDED) {
+ /* Path bias: Cannibalized rends pre-emptively count as a
+ * successfully built but unused closed circuit. We don't
+ * wait until the extend (or the close) because the rend
+ * point could be malicious.
+ *
+ * Same deal goes for client side introductions. Clients
+ * can be manipulated to connect repeatedly to them
+ * (especially web clients).
+ *
+ * If we decide to probe the initial portion of these circs,
+ * (up to the adversary's final hop), we need to remove this,
+ * or somehow mark the circuit with a special path state.
+ */
+
+ /* This must be called before the purpose change */
+ pathbias_check_close(circ, END_CIRC_REASON_FINISHED);
+ }
+
circuit_change_purpose(TO_CIRCUIT(circ), purpose);
- /* reset the birth date of this circ, else expire_building
+ /* Reset the start date of this circ, else expire_building
* will see it and think it's been trying to build since it
- * began. */
- tor_gettimeofday(&circ->_base.timestamp_created);
+ * began.
+ *
+ * Technically, the code should reset this when the
+ * create cell is finally sent, but we're close enough
+ * here. */
+ tor_gettimeofday(&circ->base_.timestamp_began);
control_event_circuit_cannibalized(circ, old_purpose,
- &old_timestamp_created);
+ &old_timestamp_began);
switch (purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
@@ -1412,7 +1645,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
want_onehop = conn->want_onehop;
need_uptime = !conn->want_onehop && !conn->use_begindir &&
- smartlist_string_num_isin(options->LongLivedPorts,
+ smartlist_contains_int_as_string(options->LongLivedPorts,
conn->socks_request->port);
if (desired_circuit_purpose != CIRCUIT_PURPOSE_C_GENERAL)
@@ -1513,8 +1746,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
if ((m = rate_limit_log(&delay_limit, approx_time()))) {
log_notice(LD_APP, "We'd like to launch a circuit to handle a "
"connection, but we already have %d general-purpose client "
- "circuits pending. Waiting until some finish.",
- n_pending);
+ "circuits pending. Waiting until some finish.%s",
+ n_pending, m);
tor_free(m);
}
return 0;
@@ -1570,9 +1803,9 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
escaped_safe_str_client(conn->socks_request->address));
return -1;
}
- extend_info = extend_info_alloc(conn->chosen_exit_name+1,
- digest, NULL, &addr,
- conn->socks_request->port);
+ extend_info = extend_info_new(conn->chosen_exit_name+1,
+ digest, NULL, NULL, &addr,
+ conn->socks_request->port);
} else {
/* We will need an onion key for the router, and we
* don't have one. Refuse or relax requirements. */
@@ -1634,8 +1867,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
if (circ) {
/* write the service_id into circ */
circ->rend_data = rend_data_dup(ENTRY_TO_EDGE_CONN(conn)->rend_data);
- if (circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
- circ->_base.state == CIRCUIT_STATE_OPEN)
+ if (circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
+ circ->base_.state == CIRCUIT_STATE_OPEN)
rend_client_rendcirc_has_opened(circ);
}
}
@@ -1697,8 +1930,8 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
const node_t *exitnode;
/* add it into the linked list of streams on this circuit */
- log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.",
- circ->_base.n_circ_id);
+ log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %u.",
+ (unsigned)circ->base_.n_circ_id);
/* reset it, so we can measure circ timeouts */
ENTRY_TO_CONN(apconn)->timestamp_lastread = time(NULL);
ENTRY_TO_EDGE_CONN(apconn)->next_stream = circ->p_streams;
@@ -1734,7 +1967,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
exitnode->rs) {
/* Okay; we know what exit node this is. */
if (optimistic_data_enabled() &&
- circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL &&
+ circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL &&
exitnode->rs->version_supports_optimistic_data)
apconn->may_use_optimistic_data = 1;
else
@@ -1820,12 +2053,14 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn,
base_conn->state == AP_CONN_STATE_CONTROLLER_WAIT);
tor_assert(conn->socks_request);
tor_assert(circ);
- tor_assert(circ->_base.state == CIRCUIT_STATE_OPEN);
+ tor_assert(circ->base_.state == CIRCUIT_STATE_OPEN);
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
- if (!circ->_base.timestamp_dirty)
- circ->_base.timestamp_dirty = time(NULL);
+ if (!circ->base_.timestamp_dirty)
+ circ->base_.timestamp_dirty = time(NULL);
+
+ pathbias_count_use_attempt(circ);
link_apconn_to_circ(conn, circ, cpath);
tor_assert(conn->socks_request);
@@ -1920,8 +2155,8 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
return retval;
log_debug(LD_APP|LD_CIRC,
- "Attaching apconn to circ %d (stream %d sec old).",
- circ->_base.n_circ_id, conn_age);
+ "Attaching apconn to circ %u (stream %d sec old).",
+ (unsigned)circ->base_.n_circ_id, conn_age);
/* print the circ's path, so people can figure out which circs are
* sucking. */
circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ);
@@ -1946,25 +2181,30 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
log_info(LD_REND,
"rend joined circ %d already here. attaching. "
"(stream %d sec old)",
- rendcirc->_base.n_circ_id, conn_age);
+ (unsigned)rendcirc->base_.n_circ_id, conn_age);
/* Mark rendezvous circuits as 'newly dirty' every time you use
* them, since the process of rebuilding a rendezvous circ is so
* expensive. There is a tradeoff between linkability and
* feasibility, at this point.
*/
- rendcirc->_base.timestamp_dirty = time(NULL);
+ rendcirc->base_.timestamp_dirty = time(NULL);
+
+ /* We've also attempted to use them. If they fail, we need to
+ * probe them for path bias */
+ pathbias_count_use_attempt(rendcirc);
+
link_apconn_to_circ(conn, rendcirc, NULL);
if (connection_ap_handshake_send_begin(conn) < 0)
return 0; /* already marked, let them fade away */
return 1;
}
- if (rendcirc && (rendcirc->_base.purpose ==
+ if (rendcirc && (rendcirc->base_.purpose ==
CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) {
log_info(LD_REND,
- "pending-join circ %d already here, with intro ack. "
+ "pending-join circ %u already here, with intro ack. "
"Stalling. (stream %d sec old)",
- rendcirc->_base.n_circ_id, conn_age);
+ (unsigned)rendcirc->base_.n_circ_id, conn_age);
return 0;
}
@@ -1975,51 +2215,40 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
if (retval > 0) {
/* one has already sent the intro. keep waiting. */
- circuit_t *c = NULL;
tor_assert(introcirc);
- log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). "
+ log_info(LD_REND, "Intro circ %u present and awaiting ack (rend %u). "
"Stalling. (stream %d sec old)",
- introcirc->_base.n_circ_id,
- rendcirc ? rendcirc->_base.n_circ_id : 0,
+ (unsigned)introcirc->base_.n_circ_id,
+ rendcirc ? (unsigned)rendcirc->base_.n_circ_id : 0,
conn_age);
- /* abort parallel intro circs, if any */
- for (c = global_circuitlist; c; c = c->next) {
- if (c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING &&
- !c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) {
- origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(c);
- if (oc->rend_data &&
- !rend_cmp_service_ids(
- ENTRY_TO_EDGE_CONN(conn)->rend_data->onion_address,
- oc->rend_data->onion_address)) {
- log_info(LD_REND|LD_CIRC, "Closing introduction circuit that we "
- "built in parallel.");
- circuit_mark_for_close(c, END_CIRC_REASON_TIMEOUT);
- }
- }
- }
return 0;
}
/* now rendcirc and introcirc are each either undefined or not finished */
if (rendcirc && introcirc &&
- rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY) {
+ rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY) {
log_info(LD_REND,
- "ready rend circ %d already here (no intro-ack yet on "
- "intro %d). (stream %d sec old)",
- rendcirc->_base.n_circ_id,
- introcirc->_base.n_circ_id, conn_age);
-
- tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- if (introcirc->_base.state == CIRCUIT_STATE_OPEN) {
- log_info(LD_REND,"found open intro circ %d (rend %d); sending "
+ "ready rend circ %u already here (no intro-ack yet on "
+ "intro %u). (stream %d sec old)",
+ (unsigned)rendcirc->base_.n_circ_id,
+ (unsigned)introcirc->base_.n_circ_id, conn_age);
+
+ tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ if (introcirc->base_.state == CIRCUIT_STATE_OPEN) {
+ log_info(LD_REND,"found open intro circ %u (rend %u); sending "
"introduction. (stream %d sec old)",
- introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id,
+ (unsigned)introcirc->base_.n_circ_id,
+ (unsigned)rendcirc->base_.n_circ_id,
conn_age);
switch (rend_client_send_introduction(introcirc, rendcirc)) {
case 0: /* success */
- rendcirc->_base.timestamp_dirty = time(NULL);
- introcirc->_base.timestamp_dirty = time(NULL);
+ rendcirc->base_.timestamp_dirty = time(NULL);
+ introcirc->base_.timestamp_dirty = time(NULL);
+
+ pathbias_count_use_attempt(introcirc);
+ pathbias_count_use_attempt(rendcirc);
+
assert_circuit_ok(TO_CIRCUIT(rendcirc));
assert_circuit_ok(TO_CIRCUIT(introcirc));
return 0;
@@ -2034,10 +2263,10 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
}
}
- log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. "
+ log_info(LD_REND, "Intro (%u) and rend (%u) circs are not both ready. "
"Stalling conn. (%d sec old)",
- introcirc ? introcirc->_base.n_circ_id : 0,
- rendcirc ? rendcirc->_base.n_circ_id : 0, conn_age);
+ introcirc ? (unsigned)introcirc->base_.n_circ_id : 0,
+ rendcirc ? (unsigned)rendcirc->base_.n_circ_id : 0, conn_age);
return 0;
}
}
@@ -2078,3 +2307,23 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
}
}
+/** Mark <b>circ</b> so that no more connections can be attached to it. */
+void
+mark_circuit_unusable_for_new_conns(origin_circuit_t *circ)
+{
+ const or_options_t *options = get_options();
+ tor_assert(circ);
+
+ /* XXXX025 This is a kludge; we're only keeping it around in case there's
+ * something that doesn't check unusable_for_new_conns, and to avoid
+ * deeper refactoring of our expiration logic. */
+ if (! circ->base_.timestamp_dirty)
+ circ->base_.timestamp_dirty = approx_time();
+ if (options->MaxCircuitDirtiness >= circ->base_.timestamp_dirty)
+ circ->base_.timestamp_dirty = 1; /* prevent underflow */
+ else
+ circ->base_.timestamp_dirty -= options->MaxCircuitDirtiness;
+
+ circ->unusable_for_new_conns = 1;
+}
+
diff --git a/src/or/circuituse.h b/src/or/circuituse.h
index be2bd7ec5..11e5a6416 100644
--- a/src/or/circuituse.h
+++ b/src/or/circuituse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for circuituse.c.
**/
-#ifndef _TOR_CIRCUITUSE_H
-#define _TOR_CIRCUITUSE_H
+#ifndef TOR_CIRCUITUSE_H
+#define TOR_CIRCUITUSE_H
void circuit_expire_building(void);
void circuit_remove_handled_ports(smartlist_t *needed_ports);
@@ -55,6 +55,7 @@ void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose);
int hostname_in_track_host_exits(const or_options_t *options,
const char *address);
+void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ);
#endif
diff --git a/src/or/command.c b/src/or/command.c
index 61e1e13a7..699b02fb4 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,10 +12,12 @@
/* In-points to command.c:
*
* - command_process_cell(), called from
- * connection_or_process_cells_from_inbuf() in connection_or.c
+ * incoming cell handlers of channel_t instances;
+ * callbacks registered in command_setup_channel(),
+ * called when channels are created in circuitbuild.c
*/
-
#include "or.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "command.h"
@@ -27,12 +29,11 @@
#include "hibernate.h"
#include "nodelist.h"
#include "onion.h"
+#include "rephist.h"
#include "relay.h"
#include "router.h"
#include "routerlist.h"
-/** How many CELL_PADDING cells have we received, ever? */
-uint64_t stats_n_padding_cells_processed = 0;
/** How many CELL_CREATE cells have we received, ever? */
uint64_t stats_n_create_cells_processed = 0;
/** How many CELL_CREATED cells have we received, ever? */
@@ -41,38 +42,16 @@ uint64_t stats_n_created_cells_processed = 0;
uint64_t stats_n_relay_cells_processed = 0;
/** How many CELL_DESTROY cells have we received, ever? */
uint64_t stats_n_destroy_cells_processed = 0;
-/** How many CELL_VERSIONS cells have we received, ever? */
-uint64_t stats_n_versions_cells_processed = 0;
-/** How many CELL_NETINFO cells have we received, ever? */
-uint64_t stats_n_netinfo_cells_processed = 0;
-/** How many CELL_VPADDING cells have we received, ever? */
-uint64_t stats_n_vpadding_cells_processed = 0;
-/** How many CELL_CERTS cells have we received, ever? */
-uint64_t stats_n_certs_cells_processed = 0;
-/** How many CELL_AUTH_CHALLENGE cells have we received, ever? */
-uint64_t stats_n_auth_challenge_cells_processed = 0;
-/** How many CELL_AUTHENTICATE cells have we received, ever? */
-uint64_t stats_n_authenticate_cells_processed = 0;
-/** How many CELL_AUTHORIZE cells have we received, ever? */
-uint64_t stats_n_authorize_cells_processed = 0;
+/* Handle an incoming channel */
+static void command_handle_incoming_channel(channel_listener_t *listener,
+ channel_t *chan);
/* These are the main functions for processing cells */
-static void command_process_create_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_created_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_relay_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_versions_cell(var_cell_t *cell,
- or_connection_t *conn);
-static void command_process_netinfo_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_certs_cell(var_cell_t *cell,
- or_connection_t *conn);
-static void command_process_auth_challenge_cell(var_cell_t *cell,
- or_connection_t *conn);
-static void command_process_authenticate_cell(var_cell_t *cell,
- or_connection_t *conn);
-static int enter_v3_handshake_with_cell(var_cell_t *cell,
- or_connection_t *conn);
+static void command_process_create_cell(cell_t *cell, channel_t *chan);
+static void command_process_created_cell(cell_t *cell, channel_t *chan);
+static void command_process_relay_cell(cell_t *cell, channel_t *chan);
+static void command_process_destroy_cell(cell_t *cell, channel_t *chan);
#ifdef KEEP_TIMING_STATS
/** This is a wrapper function around the actual function that processes the
@@ -80,15 +59,15 @@ static int enter_v3_handshake_with_cell(var_cell_t *cell,
* by the number of microseconds used by the call to <b>*func(cell, conn)</b>.
*/
static void
-command_time_process_cell(cell_t *cell, or_connection_t *conn, int *time,
- void (*func)(cell_t *, or_connection_t *))
+command_time_process_cell(cell_t *cell, channel_t *chan, int *time,
+ void (*func)(cell_t *, channel_t *))
{
struct timeval start, end;
long time_passed;
tor_gettimeofday(&start);
- (*func)(cell, conn);
+ (*func)(cell, chan);
tor_gettimeofday(&end);
time_passed = tv_udiff(&start, &end) ;
@@ -104,15 +83,14 @@ command_time_process_cell(cell_t *cell, or_connection_t *conn, int *time,
}
#endif
-/** Process a <b>cell</b> that was just received on <b>conn</b>. Keep internal
+/** Process a <b>cell</b> that was just received on <b>chan</b>. Keep internal
* statistics about how many of each cell we've processed so far
* this second, and the total number of microseconds it took to
* process each type of cell.
*/
void
-command_process_cell(cell_t *cell, or_connection_t *conn)
+command_process_cell(channel_t *chan, cell_t *cell)
{
- int handshaking = (conn->_base.state != OR_CONN_STATE_OPEN);
#ifdef KEEP_TIMING_STATS
/* how many of each cell have we seen so far this second? needs better
* name. */
@@ -152,263 +130,130 @@ command_process_cell(cell_t *cell, or_connection_t *conn)
#define PROCESS_CELL(tp, cl, cn) command_process_ ## tp ## _cell(cl, cn)
#endif
- if (conn->_base.marked_for_close)
- return;
-
- /* Reject all but VERSIONS and NETINFO when handshaking. */
- /* (VERSIONS should actually be impossible; it's variable-length.) */
- if (handshaking && cell->command != CELL_VERSIONS &&
- cell->command != CELL_NETINFO) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received unexpected cell command %d in state %s; closing the "
- "connection.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state));
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
-
- if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
- or_handshake_state_record_cell(conn->handshake_state, cell, 1);
-
switch (cell->command) {
- case CELL_PADDING:
- ++stats_n_padding_cells_processed;
- /* do nothing */
- break;
case CELL_CREATE:
case CELL_CREATE_FAST:
+ case CELL_CREATE2:
++stats_n_create_cells_processed;
- PROCESS_CELL(create, cell, conn);
+ PROCESS_CELL(create, cell, chan);
break;
case CELL_CREATED:
case CELL_CREATED_FAST:
+ case CELL_CREATED2:
++stats_n_created_cells_processed;
- PROCESS_CELL(created, cell, conn);
+ PROCESS_CELL(created, cell, chan);
break;
case CELL_RELAY:
case CELL_RELAY_EARLY:
++stats_n_relay_cells_processed;
- PROCESS_CELL(relay, cell, conn);
+ PROCESS_CELL(relay, cell, chan);
break;
case CELL_DESTROY:
++stats_n_destroy_cells_processed;
- PROCESS_CELL(destroy, cell, conn);
- break;
- case CELL_VERSIONS:
- tor_fragile_assert();
- break;
- case CELL_NETINFO:
- ++stats_n_netinfo_cells_processed;
- PROCESS_CELL(netinfo, cell, conn);
+ PROCESS_CELL(destroy, cell, chan);
break;
default:
log_fn(LOG_INFO, LD_PROTOCOL,
- "Cell of unknown type (%d) received. Dropping.", cell->command);
+ "Cell of unknown or unexpected type (%d) received. "
+ "Dropping.",
+ cell->command);
break;
}
}
-/** Return true if <b>command</b> is a cell command that's allowed to start a
- * V3 handshake. */
-static int
-command_allowed_before_handshake(uint8_t command)
-{
- switch (command) {
- case CELL_VERSIONS:
- case CELL_VPADDING:
- case CELL_AUTHORIZE:
- return 1;
- default:
- return 0;
- }
-}
-
-/** Process a <b>cell</b> that was just received on <b>conn</b>. Keep internal
- * statistics about how many of each cell we've processed so far
- * this second, and the total number of microseconds it took to
- * process each type of cell.
+/** Process an incoming var_cell from a channel; in the current protocol all
+ * the var_cells are handshake-related and handled below the channel layer,
+ * so this just logs a warning and drops the cell.
*/
+
void
-command_process_var_cell(var_cell_t *cell, or_connection_t *conn)
+command_process_var_cell(channel_t *chan, var_cell_t *var_cell)
{
-#ifdef KEEP_TIMING_STATS
- /* how many of each cell have we seen so far this second? needs better
- * name. */
- static int num_versions=0, num_certs=0;
-
- time_t now = time(NULL);
-
- if (now > current_second) { /* the second has rolled over */
- /* print stats */
- log_info(LD_OR,
- "At end of second: %d versions (%d ms), %d certs (%d ms)",
- num_versions, versions_time/1000,
- num_certs, certs_time/1000);
-
- num_versions = num_certs = 0;
- versions_time = certs_time = 0;
-
- /* remember which second it is, for next time */
- current_second = now;
- }
-#endif
+ tor_assert(chan);
+ tor_assert(var_cell);
- if (conn->_base.marked_for_close)
- return;
-
- switch (conn->_base.state)
- {
- case OR_CONN_STATE_OR_HANDSHAKING_V2:
- if (cell->command != CELL_VERSIONS) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received a cell with command %d in state %s; "
- "closing the connection.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state));
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- break;
- case OR_CONN_STATE_TLS_HANDSHAKING:
- /* If we're using bufferevents, it's entirely possible for us to
- * notice "hey, data arrived!" before we notice "hey, the handshake
- * finished!" And we need to be accepting both at once to handle both
- * the v2 and v3 handshakes. */
-
- /* fall through */
- case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
- if (! command_allowed_before_handshake(cell->command)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received a cell with command %d in state %s; "
- "closing the connection.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state));
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else {
- if (enter_v3_handshake_with_cell(cell, conn)<0)
- return;
- }
- break;
- case OR_CONN_STATE_OR_HANDSHAKING_V3:
- if (cell->command != CELL_AUTHENTICATE)
- or_handshake_state_record_var_cell(conn->handshake_state, cell, 1);
- break; /* Everything is allowed */
- case OR_CONN_STATE_OPEN:
- if (conn->link_proto < 3) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received a variable-length cell with command %d in state %s "
- "with link protocol %d; ignoring it.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state),
- (int)conn->link_proto);
- return;
- }
- break;
- default:
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received var-length cell with command %d in unexpected state "
- "%s [%d]; ignoring it.",
- (int)cell->command,
- conn_state_to_string(CONN_TYPE_OR,conn->_base.state),
- (int)conn->_base.state);
- return;
- }
-
- switch (cell->command) {
- case CELL_VERSIONS:
- ++stats_n_versions_cells_processed;
- PROCESS_CELL(versions, cell, conn);
- break;
- case CELL_VPADDING:
- ++stats_n_vpadding_cells_processed;
- /* Do nothing */
- break;
- case CELL_CERTS:
- ++stats_n_certs_cells_processed;
- PROCESS_CELL(certs, cell, conn);
- break;
- case CELL_AUTH_CHALLENGE:
- ++stats_n_auth_challenge_cells_processed;
- PROCESS_CELL(auth_challenge, cell, conn);
- break;
- case CELL_AUTHENTICATE:
- ++stats_n_authenticate_cells_processed;
- PROCESS_CELL(authenticate, cell, conn);
- break;
- case CELL_AUTHORIZE:
- ++stats_n_authorize_cells_processed;
- /* Ignored so far. */
- break;
- default:
- log_fn(LOG_INFO, LD_PROTOCOL,
- "Variable-length cell of unknown type (%d) received.",
- cell->command);
- break;
- }
+ log_info(LD_PROTOCOL,
+ "Received unexpected var_cell above the channel layer of type %d"
+ "; dropping it.",
+ var_cell->command);
}
-/** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a
+/** Process a 'create' <b>cell</b> that just arrived from <b>chan</b>. Make a
* new circuit with the p_circ_id specified in cell. Put the circuit in state
* onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
* picked up again when the cpuworker finishes decrypting it.
*/
static void
-command_process_create_cell(cell_t *cell, or_connection_t *conn)
+command_process_create_cell(cell_t *cell, channel_t *chan)
{
or_circuit_t *circ;
const or_options_t *options = get_options();
int id_is_high;
+ create_cell_t *create_cell;
+
+ tor_assert(cell);
+ tor_assert(chan);
+
+ log_debug(LD_OR,
+ "Got a CREATE cell for circ_id %u on channel " U64_FORMAT
+ " (%p)",
+ (unsigned)cell->circ_id,
+ U64_PRINTF_ARG(chan->global_identifier), chan);
if (we_are_hibernating()) {
log_info(LD_OR,
"Received create cell but we're shutting down. Sending back "
"destroy.");
- connection_or_send_destroy(cell->circ_id, conn,
+ channel_send_destroy(cell->circ_id, chan,
END_CIRC_REASON_HIBERNATING);
return;
}
if (!server_mode(options) ||
- (!public_server_mode(options) && conn->is_outgoing)) {
+ (!public_server_mode(options) && channel_is_outgoing(chan))) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received create cell (type %d) from %s:%d, but we're connected "
+ "Received create cell (type %d) from %s, but we're connected "
"to it as a client. "
"Sending back a destroy.",
- (int)cell->command, conn->_base.address, conn->_base.port);
- connection_or_send_destroy(cell->circ_id, conn,
- END_CIRC_REASON_TORPROTOCOL);
+ (int)cell->command, channel_get_canonical_remote_descr(chan));
+ channel_send_destroy(cell->circ_id, chan,
+ END_CIRC_REASON_TORPROTOCOL);
return;
}
if (cell->circ_id == 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received a create cell (type %d) from %s:%d with zero circID; "
- " ignoring.", (int)cell->command, conn->_base.address,
- conn->_base.port);
+ "Received a create cell (type %d) from %s with zero circID; "
+ " ignoring.", (int)cell->command,
+ channel_get_actual_remote_descr(chan));
return;
}
/* If the high bit of the circuit ID is not as expected, close the
* circ. */
- id_is_high = cell->circ_id & (1<<15);
- if ((id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) ||
- (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER)) {
+ if (chan->wide_circ_ids)
+ id_is_high = cell->circ_id & (1u<<31);
+ else
+ id_is_high = cell->circ_id & (1u<<15);
+ if ((id_is_high &&
+ chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ||
+ (!id_is_high &&
+ chan->circ_id_type == CIRC_ID_TYPE_LOWER)) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received create cell with unexpected circ_id %d. Closing.",
- cell->circ_id);
- connection_or_send_destroy(cell->circ_id, conn,
- END_CIRC_REASON_TORPROTOCOL);
+ "Received create cell with unexpected circ_id %u. Closing.",
+ (unsigned)cell->circ_id);
+ channel_send_destroy(cell->circ_id, chan,
+ END_CIRC_REASON_TORPROTOCOL);
return;
}
- if (circuit_id_in_use_on_orconn(cell->circ_id, conn)) {
- const node_t *node = node_get_by_id(conn->identity_digest);
+ if (circuit_id_in_use_on_channel(cell->circ_id, chan)) {
+ const node_t *node = node_get_by_id(chan->identity_digest);
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received CREATE cell (circID %d) for known circ. "
+ "Received CREATE cell (circID %u) for known circ. "
"Dropping (age %d).",
- cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created));
+ (unsigned)cell->circ_id,
+ (int)(time(NULL) - channel_when_created(chan)));
if (node) {
char *p = esc_for_log(node_get_platform(node));
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -419,23 +264,24 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
return;
}
- circ = or_circuit_new(cell->circ_id, conn);
- circ->_base.purpose = CIRCUIT_PURPOSE_OR;
+ circ = or_circuit_new(cell->circ_id, chan);
+ circ->base_.purpose = CIRCUIT_PURPOSE_OR;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
- if (cell->command == CELL_CREATE) {
- char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
- memcpy(onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
+ create_cell = tor_malloc_zero(sizeof(create_cell_t));
+ if (create_cell_parse(create_cell, cell) < 0) {
+ tor_free(create_cell);
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Bogus/unrecognized create cell; closing.");
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
+ return;
+ }
+ if (create_cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST) {
/* hand it off to the cpuworkers, and then return. */
- if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) {
-#define WARN_HANDOFF_FAILURE_INTERVAL (6*60*60)
- static ratelim_t handoff_warning =
- RATELIM_INIT(WARN_HANDOFF_FAILURE_INTERVAL);
- char *m;
- if ((m = rate_limit_log(&handoff_warning, approx_time()))) {
- log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.%s",m);
- tor_free(m);
- }
+ if (connection_or_digest_is_known_relay(chan->identity_digest))
+ rep_hist_note_circuit_handshake_requested(create_cell->handshake_type);
+ if (assign_onionskin_to_cpuworker(NULL, circ, create_cell) < 0) {
+ log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return;
}
@@ -443,30 +289,44 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
} else {
/* This is a CREATE_FAST cell; we can handle it immediately without using
* a CPU worker. */
- char keys[CPATH_KEY_MATERIAL_LEN];
- char reply[DIGEST_LEN*2];
-
- tor_assert(cell->command == CELL_CREATE_FAST);
+ uint8_t keys[CPATH_KEY_MATERIAL_LEN];
+ uint8_t rend_circ_nonce[DIGEST_LEN];
+ int len;
+ created_cell_t created_cell;
/* Make sure we never try to use the OR connection on which we
* received this cell to satisfy an EXTEND request, */
- conn->is_connection_with_client = 1;
-
- if (fast_server_handshake(cell->payload, (uint8_t*)reply,
- (uint8_t*)keys, sizeof(keys))<0) {
+ channel_mark_client(chan);
+
+ memset(&created_cell, 0, sizeof(created_cell));
+ len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST,
+ create_cell->onionskin,
+ create_cell->handshake_len,
+ NULL,
+ created_cell.reply,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce);
+ tor_free(create_cell);
+ if (len < 0) {
log_warn(LD_OR,"Failed to generate key material. Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
+ tor_free(create_cell);
return;
}
- if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
+ created_cell.cell_type = CELL_CREATED_FAST;
+ created_cell.handshake_len = len;
+
+ if (onionskin_answer(circ, &created_cell,
+ (const char *)keys, rend_circ_nonce)<0) {
log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
+ memwipe(keys, 0, sizeof(keys));
}
}
-/** Process a 'created' <b>cell</b> that just arrived from <b>conn</b>.
+/** Process a 'created' <b>cell</b> that just arrived from <b>chan</b>.
* Find the circuit
* that it's intended for. If we're not the origin of the circuit, package
* the 'created' cell in an 'extended' relay cell and pass it back. If we
@@ -475,16 +335,17 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn)
* extend to the next hop in the circuit if necessary.
*/
static void
-command_process_created_cell(cell_t *cell, or_connection_t *conn)
+command_process_created_cell(cell_t *cell, channel_t *chan)
{
circuit_t *circ;
+ extended_cell_t extended_cell;
- circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
+ circ = circuit_get_by_circid_channel(cell->circ_id, chan);
if (!circ) {
log_info(LD_OR,
- "(circID %d) unknown circ (probably got a destroy earlier). "
- "Dropping.", cell->circ_id);
+ "(circID %u) unknown circ (probably got a destroy earlier). "
+ "Dropping.", (unsigned)cell->circ_id);
return;
}
@@ -495,12 +356,18 @@ command_process_created_cell(cell_t *cell, or_connection_t *conn)
return;
}
+ if (created_cell_parse(&extended_cell.created_cell, cell) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR, "Unparseable created cell.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
+ return;
+ }
+
if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
int err_reason = 0;
log_debug(LD_OR,"at OP. Finishing handshake.");
- if ((err_reason = circuit_finish_handshake(origin_circ, cell->command,
- cell->payload)) < 0) {
+ if ((err_reason = circuit_finish_handshake(origin_circ,
+ &extended_cell.created_cell)) < 0) {
log_warn(LD_OR,"circuit_finish_handshake failed.");
circuit_mark_for_close(circ, -err_reason);
return;
@@ -513,11 +380,24 @@ command_process_created_cell(cell_t *cell, or_connection_t *conn)
return;
}
} else { /* pack it into an extended relay cell, and send it. */
+ uint8_t command=0;
+ uint16_t len=0;
+ uint8_t payload[RELAY_PAYLOAD_SIZE];
log_debug(LD_OR,
"Converting created cell to extended relay cell, sending.");
- relay_send_command_from_edge(0, circ, RELAY_COMMAND_EXTENDED,
- (char*)cell->payload, ONIONSKIN_REPLY_LEN,
- NULL);
+ memset(payload, 0, sizeof(payload));
+ if (extended_cell.created_cell.cell_type == CELL_CREATED2)
+ extended_cell.cell_type = RELAY_COMMAND_EXTENDED2;
+ else
+ extended_cell.cell_type = RELAY_COMMAND_EXTENDED;
+ if (extended_cell_format(&command, &len, payload, &extended_cell) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR, "Can't format extended cell.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
+ return;
+ }
+
+ relay_send_command_from_edge(0, circ, command,
+ (const char*)payload, len, NULL);
}
}
@@ -526,17 +406,18 @@ command_process_created_cell(cell_t *cell, or_connection_t *conn)
* circuit_receive_relay_cell() for actual processing.
*/
static void
-command_process_relay_cell(cell_t *cell, or_connection_t *conn)
+command_process_relay_cell(cell_t *cell, channel_t *chan)
{
circuit_t *circ;
int reason, direction;
- circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
+ circ = circuit_get_by_circid_channel(cell->circ_id, chan);
if (!circ) {
log_debug(LD_OR,
- "unknown circuit %d on connection from %s:%d. Dropping.",
- cell->circ_id, conn->_base.address, conn->_base.port);
+ "unknown circuit %u on connection from %s. Dropping.",
+ (unsigned)cell->circ_id,
+ channel_get_canonical_remote_descr(chan));
return;
}
@@ -549,7 +430,7 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn)
if (CIRCUIT_IS_ORIGIN(circ)) {
/* if we're a relay and treating connections with recent local
* traffic better, then this is one of them. */
- conn->client_used = time(NULL);
+ channel_timestamp_client(chan);
}
if (!CIRCUIT_IS_ORIGIN(circ) &&
@@ -570,10 +451,10 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn)
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
if (or_circ->remaining_relay_early_cells == 0) {
log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received too many RELAY_EARLY cells on circ %d from %s:%d."
+ "Received too many RELAY_EARLY cells on circ %u from %s."
" Closing circuit.",
- cell->circ_id, safe_str(conn->_base.address),
- conn->_base.port);
+ (unsigned)cell->circ_id,
+ safe_str(channel_get_canonical_remote_descr(chan)));
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
return;
}
@@ -590,7 +471,7 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn)
}
/** Process a 'destroy' <b>cell</b> that just arrived from
- * <b>conn</b>. Find the circ that it refers to (if any).
+ * <b>chan</b>. Find the circ that it refers to (if any).
*
* If the circ is in state
* onionskin_pending, then call onion_pending_remove() to remove it
@@ -603,28 +484,29 @@ command_process_relay_cell(cell_t *cell, or_connection_t *conn)
* and passes the destroy cell onward if necessary).
*/
static void
-command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
+command_process_destroy_cell(cell_t *cell, channel_t *chan)
{
circuit_t *circ;
int reason;
- circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
+ circ = circuit_get_by_circid_channel(cell->circ_id, chan);
if (!circ) {
- log_info(LD_OR,"unknown circuit %d on connection from %s:%d. Dropping.",
- cell->circ_id, conn->_base.address, conn->_base.port);
+ log_info(LD_OR,"unknown circuit %u on connection from %s. Dropping.",
+ (unsigned)cell->circ_id,
+ channel_get_canonical_remote_descr(chan));
return;
}
- log_debug(LD_OR,"Received for circID %d.",cell->circ_id);
+ log_debug(LD_OR,"Received for circID %u.",(unsigned)cell->circ_id);
reason = (uint8_t)cell->payload[0];
if (!CIRCUIT_IS_ORIGIN(circ) &&
cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
/* the destroy came from behind */
- circuit_set_p_circid_orconn(TO_OR_CIRCUIT(circ), 0, NULL);
+ circuit_set_p_circid_chan(TO_OR_CIRCUIT(circ), 0, NULL);
circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE);
} else { /* the destroy came from ahead */
- circuit_set_n_circid_orconn(circ, 0, NULL);
+ circuit_set_n_circid_chan(circ, 0, NULL);
if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE);
} else {
@@ -637,740 +519,43 @@ command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
}
}
-/** Called when we as a server receive an appropriate cell while waiting
- * either for a cell or a TLS handshake. Set the connection's state to
- * "handshaking_v3', initializes the or_handshake_state field as needed,
- * and add the cell to the hash of incoming cells.)
- *
- * Return 0 on success; return -1 and mark the connection on failure.
+/** Callback to handle a new channel; call command_setup_channel() to give
+ * it the right cell handlers.
*/
-static int
-enter_v3_handshake_with_cell(var_cell_t *cell, or_connection_t *conn)
-{
- const int started_here = connection_or_nonopen_was_started_here(conn);
-
- tor_assert(conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING ||
- conn->_base.state == OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
-
- if (started_here) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a cell while TLS-handshaking, not in "
- "OR_HANDSHAKING_V3, on a connection we originated.");
- }
- connection_or_block_renegotiation(conn);
- conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
- if (connection_init_or_handshake_state(conn, started_here) < 0) {
- connection_mark_for_close(TO_CONN(conn));
- return -1;
- }
- or_handshake_state_record_var_cell(conn->handshake_state, cell, 1);
- return 0;
-}
-
-/** Process a 'versions' cell. The current link protocol version must be 0
- * to indicate that no version has yet been negotiated. We compare the
- * versions in the cell to the list of versions we support, pick the
- * highest version we have in common, and continue the negotiation from
- * there.
- */
-static void
-command_process_versions_cell(var_cell_t *cell, or_connection_t *conn)
-{
- int highest_supported_version = 0;
- const uint8_t *cp, *end;
- const int started_here = connection_or_nonopen_was_started_here(conn);
- if (conn->link_proto != 0 ||
- (conn->handshake_state && conn->handshake_state->received_versions)) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a VERSIONS cell on a connection with its version "
- "already set to %d; dropping", (int) conn->link_proto);
- return;
- }
- switch (conn->_base.state)
- {
- case OR_CONN_STATE_OR_HANDSHAKING_V2:
- case OR_CONN_STATE_OR_HANDSHAKING_V3:
- break;
- case OR_CONN_STATE_TLS_HANDSHAKING:
- case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
- default:
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "VERSIONS cell while in unexpected state");
- return;
- }
-
- tor_assert(conn->handshake_state);
- end = cell->payload + cell->payload_len;
- for (cp = cell->payload; cp+1 < end; ++cp) {
- uint16_t v = ntohs(get_uint16(cp));
- if (is_or_protocol_version_known(v) && v > highest_supported_version)
- highest_supported_version = v;
- }
- if (!highest_supported_version) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Couldn't find a version in common between my version list and the "
- "list in the VERSIONS cell; closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else if (highest_supported_version == 1) {
- /* Negotiating version 1 makes no sense, since version 1 has no VERSIONS
- * cells. */
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Used version negotiation protocol to negotiate a v1 connection. "
- "That's crazily non-compliant. Closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else if (highest_supported_version < 3 &&
- conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Negotiated link protocol 2 or lower after doing a v3 TLS "
- "handshake. Closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else if (highest_supported_version != 2 &&
- conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V2) {
- /* XXXX This should eventually be a log_protocol_warn */
- log_fn(LOG_WARN, LD_OR,
- "Negotiated link with non-2 protocol after doing a v2 TLS "
- "handshake with %s. Closing connection.",
- fmt_addr(&conn->_base.addr));
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
-
- conn->link_proto = highest_supported_version;
- conn->handshake_state->received_versions = 1;
-
- if (conn->link_proto == 2) {
- log_info(LD_OR, "Negotiated version %d with %s:%d; sending NETINFO.",
- highest_supported_version,
- safe_str_client(conn->_base.address),
- conn->_base.port);
-
- if (connection_or_send_netinfo(conn) < 0) {
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- } else {
- const int send_versions = !started_here;
- /* If we want to authenticate, send a CERTS cell */
- const int send_certs = !started_here || public_server_mode(get_options());
- /* If we're a host that got a connection, ask for authentication. */
- const int send_chall = !started_here;
- /* If our certs cell will authenticate us, we can send a netinfo cell
- * right now. */
- const int send_netinfo = !started_here;
- const int send_any =
- send_versions || send_certs || send_chall || send_netinfo;
- tor_assert(conn->link_proto >= 3);
-
- log_info(LD_OR, "Negotiated version %d with %s:%d; %s%s%s%s%s",
- highest_supported_version,
- safe_str_client(conn->_base.address),
- conn->_base.port,
- send_any ? "Sending cells:" : "Waiting for CERTS cell",
- send_versions ? " VERSIONS" : "",
- send_certs ? " CERTS" : "",
- send_chall ? " AUTH_CHALLENGE" : "",
- send_netinfo ? " NETINFO" : "");
-
-#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
- if (1) {
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
-#endif
-
- if (send_versions) {
- if (connection_or_send_versions(conn, 1) < 0) {
- log_warn(LD_OR, "Couldn't send versions cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- }
- if (send_certs) {
- if (connection_or_send_certs_cell(conn) < 0) {
- log_warn(LD_OR, "Couldn't send certs cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- }
- if (send_chall) {
- if (connection_or_send_auth_challenge_cell(conn) < 0) {
- log_warn(LD_OR, "Couldn't send auth_challenge cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- }
- if (send_netinfo) {
- if (connection_or_send_netinfo(conn) < 0) {
- log_warn(LD_OR, "Couldn't send netinfo cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- }
- }
-}
-/** Process a 'netinfo' cell: read and act on its contents, and set the
- * connection state to "open". */
static void
-command_process_netinfo_cell(cell_t *cell, or_connection_t *conn)
+command_handle_incoming_channel(channel_listener_t *listener, channel_t *chan)
{
- time_t timestamp;
- uint8_t my_addr_type;
- uint8_t my_addr_len;
- const uint8_t *my_addr_ptr;
- const uint8_t *cp, *end;
- uint8_t n_other_addrs;
- time_t now = time(NULL);
-
- long apparent_skew = 0;
- uint32_t my_apparent_addr = 0;
-
- if (conn->link_proto < 2) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a NETINFO cell on %s connection; dropping.",
- conn->link_proto == 0 ? "non-versioned" : "a v1");
- return;
- }
- if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V2 &&
- conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a NETINFO cell on non-handshaking connection; dropping.");
- return;
- }
- tor_assert(conn->handshake_state &&
- conn->handshake_state->received_versions);
-
- if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) {
- tor_assert(conn->link_proto >= 3);
- if (conn->handshake_state->started_here) {
- if (!conn->handshake_state->authenticated) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got a NETINFO cell from server, "
- "but no authentication. Closing the connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- } else {
- /* we're the server. If the client never authenticated, we have
- some housekeeping to do.*/
- if (!conn->handshake_state->authenticated) {
- tor_assert(tor_digest_is_zero(
- (const char*)conn->handshake_state->authenticated_peer_id));
- connection_or_set_circid_type(conn, NULL);
-
- connection_or_init_conn_from_address(conn,
- &conn->_base.addr,
- conn->_base.port,
- (const char*)conn->handshake_state->authenticated_peer_id,
- 0);
- }
- }
- }
-
- /* Decode the cell. */
- timestamp = ntohl(get_uint32(cell->payload));
- if (labs(now - conn->handshake_state->sent_versions_at) < 180) {
- apparent_skew = now - timestamp;
- }
-
- my_addr_type = (uint8_t) cell->payload[4];
- my_addr_len = (uint8_t) cell->payload[5];
- my_addr_ptr = (uint8_t*) cell->payload + 6;
- end = cell->payload + CELL_PAYLOAD_SIZE;
- cp = cell->payload + 6 + my_addr_len;
- if (cp >= end) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Addresses too long in netinfo cell; closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- } else if (my_addr_type == RESOLVED_TYPE_IPV4 && my_addr_len == 4) {
- my_apparent_addr = ntohl(get_uint32(my_addr_ptr));
- }
-
- n_other_addrs = (uint8_t) *cp++;
- while (n_other_addrs && cp < end-2) {
- /* Consider all the other addresses; if any matches, this connection is
- * "canonical." */
- tor_addr_t addr;
- const uint8_t *next =
- decode_address_from_payload(&addr, cp, (int)(end-cp));
- if (next == NULL) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Bad address in netinfo cell; closing connection.");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- if (tor_addr_eq(&addr, &conn->real_addr)) {
- conn->is_canonical = 1;
- break;
- }
- cp = next;
- --n_other_addrs;
- }
-
- /* 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 &&
- router_get_by_id_digest(conn->identity_digest)) {
- char dbuf[64];
- int severity;
- /*XXXX be smarter about when everybody says we are skewed. */
- if (router_digest_is_trusted_dir(conn->identity_digest))
- severity = LOG_WARN;
- else
- severity = LOG_INFO;
- format_time_interval(dbuf, sizeof(dbuf), apparent_skew);
- log_fn(severity, LD_GENERAL, "Received NETINFO cell with skewed time from "
- "server at %s:%d. It seems that our clock is %s by %s, or "
- "that theirs is %s. Tor requires an accurate clock to work: "
- "please check your time and date settings.",
- conn->_base.address, (int)conn->_base.port,
- apparent_skew>0 ? "ahead" : "behind", dbuf,
- apparent_skew>0 ? "behind" : "ahead");
- if (severity == LOG_WARN) /* only tell the controller if an authority */
- control_event_general_status(LOG_WARN,
- "CLOCK_SKEW SKEW=%ld SOURCE=OR:%s:%d",
- apparent_skew,
- conn->_base.address, conn->_base.port);
- }
-
- /* XXX maybe act on my_apparent_addr, if the source is sufficiently
- * trustworthy. */
- (void)my_apparent_addr;
-
- if (! conn->handshake_state->sent_netinfo) {
- /* If we were prepared to authenticate, but we never got an AUTH_CHALLENGE
- * cell, then we would not previously have sent a NETINFO cell. Do so
- * now. */
- if (connection_or_send_netinfo(conn) < 0) {
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- }
+ tor_assert(listener);
+ tor_assert(chan);
- if (connection_or_set_state_open(conn)<0) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got good NETINFO cell from %s:%d; but "
- "was unable to make the OR connection become open.",
- safe_str_client(conn->_base.address),
- conn->_base.port);
- connection_mark_for_close(TO_CONN(conn));
- } else {
- log_info(LD_OR, "Got good NETINFO cell from %s:%d; OR connection is now "
- "open, using protocol version %d. Its ID digest is %s",
- safe_str_client(conn->_base.address),
- conn->_base.port, (int)conn->link_proto,
- hex_str(conn->identity_digest, DIGEST_LEN));
- }
- assert_connection_ok(TO_CONN(conn),time(NULL));
+ command_setup_channel(chan);
}
-/** Process a CERTS cell from an OR connection.
- *
- * If the other side should not have sent us a CERTS cell, or the cell is
- * malformed, or it is supposed to authenticate the TLS key but it doesn't,
- * then mark the connection.
- *
- * If the cell has a good cert chain and we're doing a v3 handshake, then
- * store the certificates in or_handshake_state. If this is the client side
- * of the connection, we then authenticate the server or mark the connection.
- * If it's the server side, wait for an AUTHENTICATE cell.
+/** Given a channel, install the right handlers to process incoming
+ * cells on it.
*/
-static void
-command_process_certs_cell(var_cell_t *cell, or_connection_t *conn)
-{
-#define ERR(s) \
- do { \
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
- "Received a bad CERTS cell from %s:%d: %s", \
- safe_str(conn->_base.address), conn->_base.port, (s)); \
- connection_mark_for_close(TO_CONN(conn)); \
- goto err; \
- } while (0)
-
- tor_cert_t *link_cert = NULL;
- tor_cert_t *id_cert = NULL;
- tor_cert_t *auth_cert = NULL;
-
- uint8_t *ptr;
- int n_certs, i;
- int send_netinfo = 0;
-
- if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
- ERR("We're not doing a v3 handshake!");
- if (conn->link_proto < 3)
- ERR("We're not using link protocol >= 3");
- if (conn->handshake_state->received_certs_cell)
- ERR("We already got one");
- if (conn->handshake_state->authenticated) {
- /* Should be unreachable, but let's make sure. */
- ERR("We're already authenticated!");
- }
- if (cell->payload_len < 1)
- ERR("It had no body");
- if (cell->circ_id)
- ERR("It had a nonzero circuit ID");
-
- n_certs = cell->payload[0];
- ptr = cell->payload + 1;
- for (i = 0; i < n_certs; ++i) {
- uint8_t cert_type;
- uint16_t cert_len;
- if (ptr + 3 > cell->payload + cell->payload_len) {
- goto truncated;
- }
- cert_type = *ptr;
- cert_len = ntohs(get_uint16(ptr+1));
- if (ptr + 3 + cert_len > cell->payload + cell->payload_len) {
- goto truncated;
- }
- if (cert_type == OR_CERT_TYPE_TLS_LINK ||
- cert_type == OR_CERT_TYPE_ID_1024 ||
- cert_type == OR_CERT_TYPE_AUTH_1024) {
- tor_cert_t *cert = tor_cert_decode(ptr + 3, cert_len);
- if (!cert) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received undecodable certificate in CERTS cell from %s:%d",
- safe_str(conn->_base.address), conn->_base.port);
- } else {
- if (cert_type == OR_CERT_TYPE_TLS_LINK) {
- if (link_cert) {
- tor_cert_free(cert);
- ERR("Too many TLS_LINK certificates");
- }
- link_cert = cert;
- } else if (cert_type == OR_CERT_TYPE_ID_1024) {
- if (id_cert) {
- tor_cert_free(cert);
- ERR("Too many ID_1024 certificates");
- }
- id_cert = cert;
- } else if (cert_type == OR_CERT_TYPE_AUTH_1024) {
- if (auth_cert) {
- tor_cert_free(cert);
- ERR("Too many AUTH_1024 certificates");
- }
- auth_cert = cert;
- } else {
- tor_cert_free(cert);
- }
- }
- }
- ptr += 3 + cert_len;
- continue;
-
- truncated:
- ERR("It ends in the middle of a certificate");
- }
-
- if (conn->handshake_state->started_here) {
- int severity;
- if (! (id_cert && link_cert))
- ERR("The certs we wanted were missing");
- /* Okay. We should be able to check the certificates now. */
- if (! tor_tls_cert_matches_key(conn->tls, link_cert)) {
- ERR("The link certificate didn't match the TLS public key");
- }
- /* Note that this warns more loudly about time and validity if we were
- * _trying_ to connect to an authority, not necessarily if we _did_ connect
- * to one. */
- if (router_digest_is_trusted_dir(conn->identity_digest))
- severity = LOG_WARN;
- else
- severity = LOG_PROTOCOL_WARN;
-
- if (! tor_tls_cert_is_valid(severity, link_cert, id_cert, 0))
- ERR("The link certificate was not valid");
- if (! tor_tls_cert_is_valid(severity, id_cert, id_cert, 1))
- ERR("The ID certificate was not valid");
-
- conn->handshake_state->authenticated = 1;
- {
- const digests_t *id_digests = tor_cert_get_id_digests(id_cert);
- crypto_pk_t *identity_rcvd;
- if (!id_digests)
- ERR("Couldn't compute digests for key in ID cert");
-
- identity_rcvd = tor_tls_cert_get_key(id_cert);
- if (!identity_rcvd)
- ERR("Internal error: Couldn't get RSA key from ID cert.");
- memcpy(conn->handshake_state->authenticated_peer_id,
- id_digests->d[DIGEST_SHA1], DIGEST_LEN);
- connection_or_set_circid_type(conn, identity_rcvd);
- crypto_pk_free(identity_rcvd);
- }
- if (connection_or_client_learned_peer_id(conn,
- conn->handshake_state->authenticated_peer_id) < 0)
- ERR("Problem setting or checking peer id");
-
- log_info(LD_OR, "Got some good certificates from %s:%d: Authenticated it.",
- safe_str(conn->_base.address), conn->_base.port);
-
- conn->handshake_state->id_cert = id_cert;
- id_cert = NULL;
-
- if (!public_server_mode(get_options())) {
- /* If we initiated the connection and we are not a public server, we
- * aren't planning to authenticate at all. At this point we know who we
- * are talking to, so we can just send a netinfo now. */
- send_netinfo = 1;
- }
- } else {
- if (! (id_cert && auth_cert))
- ERR("The certs we wanted were missing");
-
- /* Remember these certificates so we can check an AUTHENTICATE cell */
- if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, auth_cert, id_cert, 1))
- ERR("The authentication certificate was not valid");
- if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, id_cert, id_cert, 1))
- ERR("The ID certificate was not valid");
-
- log_info(LD_OR, "Got some good certificates from %s:%d: "
- "Waiting for AUTHENTICATE.",
- safe_str(conn->_base.address), conn->_base.port);
- /* XXXX check more stuff? */
-
- conn->handshake_state->id_cert = id_cert;
- conn->handshake_state->auth_cert = auth_cert;
- id_cert = auth_cert = NULL;
- }
-
- conn->handshake_state->received_certs_cell = 1;
-
- if (send_netinfo) {
- if (connection_or_send_netinfo(conn) < 0) {
- log_warn(LD_OR, "Couldn't send netinfo cell");
- connection_mark_for_close(TO_CONN(conn));
- goto err;
- }
- }
-
- err:
- tor_cert_free(id_cert);
- tor_cert_free(link_cert);
- tor_cert_free(auth_cert);
-#undef ERR
-}
-
-/** Process an AUTH_CHALLENGE cell from an OR connection.
- *
- * If we weren't supposed to get one (for example, because we're not the
- * originator of the connection), or it's ill-formed, or we aren't doing a v3
- * handshake, mark the connection. If the cell is well-formed but we don't
- * want to authenticate, just drop it. If the cell is well-formed *and* we
- * want to authenticate, send an AUTHENTICATE cell and then a NETINFO cell. */
-static void
-command_process_auth_challenge_cell(var_cell_t *cell, or_connection_t *conn)
+void
+command_setup_channel(channel_t *chan)
{
- int n_types, i, use_type = -1;
- uint8_t *cp;
-
-#define ERR(s) \
- do { \
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
- "Received a bad AUTH_CHALLENGE cell from %s:%d: %s", \
- safe_str(conn->_base.address), conn->_base.port, (s)); \
- connection_mark_for_close(TO_CONN(conn)); \
- return; \
- } while (0)
-
- if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
- ERR("We're not currently doing a v3 handshake");
- if (conn->link_proto < 3)
- ERR("We're not using link protocol >= 3");
- if (! conn->handshake_state->started_here)
- ERR("We didn't originate this connection");
- if (conn->handshake_state->received_auth_challenge)
- ERR("We already received one");
- if (! conn->handshake_state->received_certs_cell)
- ERR("We haven't gotten a CERTS cell yet");
- if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2)
- ERR("It was too short");
- if (cell->circ_id)
- ERR("It had a nonzero circuit ID");
-
- n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN));
- if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types)
- ERR("It looks truncated");
-
- /* Now see if there is an authentication type we can use */
- cp=cell->payload+OR_AUTH_CHALLENGE_LEN+2;
- for (i=0; i < n_types; ++i, cp += 2) {
- uint16_t authtype = ntohs(get_uint16(cp));
- if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET)
- use_type = authtype;
- }
-
- conn->handshake_state->received_auth_challenge = 1;
+ tor_assert(chan);
- if (! public_server_mode(get_options())) {
- /* If we're not a public server then we don't want to authenticate on a
- connection we originated, and we already sent a NETINFO cell when we
- got the CERTS cell. We have nothing more to do. */
- return;
- }
-
- if (use_type >= 0) {
- log_info(LD_OR, "Got an AUTH_CHALLENGE cell from %s:%d: Sending "
- "authentication",
- safe_str(conn->_base.address), conn->_base.port);
-
- if (connection_or_send_authenticate_cell(conn, use_type) < 0) {
- log_warn(LD_OR, "Couldn't send authenticate cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
- } else {
- log_info(LD_OR, "Got an AUTH_CHALLENGE cell from %s:%d, but we don't "
- "know any of its authentication types. Not authenticating.",
- safe_str(conn->_base.address), conn->_base.port);
- }
-
- if (connection_or_send_netinfo(conn) < 0) {
- log_warn(LD_OR, "Couldn't send netinfo cell");
- connection_mark_for_close(TO_CONN(conn));
- return;
- }
-
-#undef ERR
+ channel_set_cell_handlers(chan,
+ command_process_cell,
+ command_process_var_cell);
}
-/** Process an AUTHENTICATE cell from an OR connection.
- *
- * If it's ill-formed or we weren't supposed to get one or we're not doing a
- * v3 handshake, then mark the connection. If it does not authenticate the
- * other side of the connection successfully (because it isn't signed right,
- * we didn't get a CERTS cell, etc) mark the connection. Otherwise, accept
- * the identity of the router on the other side of the connection.
+/** Given a listener, install the right handler to process incoming
+ * channels on it.
*/
-static void
-command_process_authenticate_cell(var_cell_t *cell, or_connection_t *conn)
-{
- uint8_t expected[V3_AUTH_FIXED_PART_LEN];
- const uint8_t *auth;
- int authlen;
-
-#define ERR(s) \
- do { \
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
- "Received a bad AUTHENTICATE cell from %s:%d: %s", \
- safe_str(conn->_base.address), conn->_base.port, (s)); \
- connection_mark_for_close(TO_CONN(conn)); \
- return; \
- } while (0)
-
- if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
- ERR("We're not doing a v3 handshake");
- if (conn->link_proto < 3)
- ERR("We're not using link protocol >= 3");
- if (conn->handshake_state->started_here)
- ERR("We originated this connection");
- if (conn->handshake_state->received_authenticate)
- ERR("We already got one!");
- if (conn->handshake_state->authenticated) {
- /* Should be impossible given other checks */
- ERR("The peer is already authenticated");
- }
- if (! conn->handshake_state->received_certs_cell)
- ERR("We never got a certs cell");
- if (conn->handshake_state->auth_cert == NULL)
- ERR("We never got an authentication certificate");
- if (conn->handshake_state->id_cert == NULL)
- ERR("We never got an identity certificate");
- if (cell->payload_len < 4)
- ERR("Cell was way too short");
-
- auth = cell->payload;
- {
- uint16_t type = ntohs(get_uint16(auth));
- uint16_t len = ntohs(get_uint16(auth+2));
- if (4 + len > cell->payload_len)
- ERR("Authenticator was truncated");
-
- if (type != AUTHTYPE_RSA_SHA256_TLSSECRET)
- ERR("Authenticator type was not recognized");
-
- auth += 4;
- authlen = len;
- }
-
- if (authlen < V3_AUTH_BODY_LEN + 1)
- ERR("Authenticator was too short");
-
- if (connection_or_compute_authenticate_cell_body(
- conn, expected, sizeof(expected), NULL, 1) < 0)
- ERR("Couldn't compute expected AUTHENTICATE cell body");
- if (tor_memneq(expected, auth, sizeof(expected)))
- ERR("Some field in the AUTHENTICATE cell body was not as expected");
-
- {
- crypto_pk_t *pk = tor_tls_cert_get_key(
- conn->handshake_state->auth_cert);
- char d[DIGEST256_LEN];
- char *signed_data;
- size_t keysize;
- int signed_len;
-
- if (!pk)
- ERR("Internal error: couldn't get RSA key from AUTH cert.");
- crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256);
-
- keysize = crypto_pk_keysize(pk);
- signed_data = tor_malloc(keysize);
- signed_len = crypto_pk_public_checksig(pk, signed_data, keysize,
- (char*)auth + V3_AUTH_BODY_LEN,
- authlen - V3_AUTH_BODY_LEN);
- crypto_pk_free(pk);
- if (signed_len < 0) {
- tor_free(signed_data);
- ERR("Signature wasn't valid");
- }
- if (signed_len < DIGEST256_LEN) {
- tor_free(signed_data);
- ERR("Not enough data was signed");
- }
- /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here,
- * in case they're later used to hold a SHA3 digest or something. */
- if (tor_memneq(signed_data, d, DIGEST256_LEN)) {
- tor_free(signed_data);
- ERR("Signature did not match data to be signed.");
- }
- tor_free(signed_data);
- }
-
- /* Okay, we are authenticated. */
- conn->handshake_state->received_authenticate = 1;
- conn->handshake_state->authenticated = 1;
- conn->handshake_state->digest_received_data = 0;
- {
- crypto_pk_t *identity_rcvd =
- tor_tls_cert_get_key(conn->handshake_state->id_cert);
- const digests_t *id_digests =
- tor_cert_get_id_digests(conn->handshake_state->id_cert);
-
- /* This must exist; we checked key type when reading the cert. */
- tor_assert(id_digests);
-
- memcpy(conn->handshake_state->authenticated_peer_id,
- id_digests->d[DIGEST_SHA1], DIGEST_LEN);
-
- connection_or_set_circid_type(conn, identity_rcvd);
- crypto_pk_free(identity_rcvd);
-
- connection_or_init_conn_from_address(conn,
- &conn->_base.addr,
- conn->_base.port,
- (const char*)conn->handshake_state->authenticated_peer_id,
- 0);
-
- log_info(LD_OR, "Got an AUTHENTICATE cell from %s:%d: Looks good.",
- safe_str(conn->_base.address), conn->_base.port);
- }
+void
+command_setup_listener(channel_listener_t *listener)
+{
+ tor_assert(listener);
+ tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING);
-#undef ERR
+ channel_listener_set_listener_fn(listener, command_handle_incoming_channel);
}
diff --git a/src/or/command.h b/src/or/command.h
index 078ccc9f5..913f46a5c 100644
--- a/src/or/command.h
+++ b/src/or/command.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,11 +9,15 @@
* \brief Header file for command.c.
**/
-#ifndef _TOR_COMMAND_H
-#define _TOR_COMMAND_H
+#ifndef TOR_COMMAND_H
+#define TOR_COMMAND_H
-void command_process_cell(cell_t *cell, or_connection_t *conn);
-void command_process_var_cell(var_cell_t *cell, or_connection_t *conn);
+#include "channel.h"
+
+void command_process_cell(channel_t *chan, cell_t *cell);
+void command_process_var_cell(channel_t *chan, var_cell_t *cell);
+void command_setup_channel(channel_t *chan);
+void command_setup_listener(channel_listener_t *chan_l);
extern uint64_t stats_n_padding_cells_processed;
extern uint64_t stats_n_create_cells_processed;
diff --git a/src/or/config.c b/src/or/config.c
index d5c568947..3984755dd 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -1,7 +1,7 @@
-/* Copyright (c) 2001 Matej Pfajfar.
+ /* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,21 +12,28 @@
#define CONFIG_PRIVATE
#include "or.h"
+#include "addressmap.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitmux.h"
+#include "circuitmux_ewma.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
+#include "confparse.h"
#include "cpuworker.h"
#include "dirserv.h"
#include "dirvote.h"
#include "dns.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
#include "networkstatus.h"
+#include "nodelist.h"
#include "policies.h"
#include "relay.h"
#include "rendclient.h"
@@ -35,6 +42,8 @@
#include "router.h"
#include "util.h"
#include "routerlist.h"
+#include "routerset.h"
+#include "statefile.h"
#include "transports.h"
#ifdef _WIN32
#include <shlobj.h>
@@ -45,51 +54,9 @@
/* From main.c */
extern int quiet_level;
-/** Enumeration of types which option values can take */
-typedef enum config_type_t {
- CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
- CONFIG_TYPE_FILENAME, /**< A filename: some prefixes get expanded. */
- CONFIG_TYPE_UINT, /**< A non-negative integer less than MAX_INT */
- CONFIG_TYPE_INT, /**< Any integer. */
- CONFIG_TYPE_PORT, /**< A port from 1...65535, 0 for "not set", or
- * "auto". */
- CONFIG_TYPE_INTERVAL, /**< A number of seconds, with optional units*/
- CONFIG_TYPE_MSEC_INTERVAL,/**< A number of milliseconds, with optional
- * units */
- CONFIG_TYPE_MEMUNIT, /**< A number of bytes, with optional units*/
- CONFIG_TYPE_DOUBLE, /**< A floating-point value */
- CONFIG_TYPE_BOOL, /**< A boolean value, expressed as 0 or 1. */
- CONFIG_TYPE_AUTOBOOL, /**< A boolean+auto value, expressed 0 for false,
- * 1 for true, and -1 for auto */
- CONFIG_TYPE_ISOTIME, /**< An ISO-formatted time relative to GMT. */
- CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and
- * optional whitespace. */
- CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
- CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines,
- * mixed with other keywords. */
- CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize
- * context-sensitive config lines when fetching.
- */
- CONFIG_TYPE_ROUTERSET, /**< A list of router names, addrs, and fps,
- * parsed into a routerset_t. */
- CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
-} config_type_t;
-
-/** An abbreviation for a configuration option allowed on the command line. */
-typedef struct config_abbrev_t {
- const char *abbreviated;
- const char *full;
- int commandline_only;
- int warn;
-} config_abbrev_t;
-
-/* Handy macro for declaring "In the config file or on the command line,
- * you can abbreviate <b>tok</b>s as <b>tok</b>". */
-#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
-
/** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */
-static config_abbrev_t _option_abbrevs[] = {
+static config_abbrev_t option_abbrevs_[] = {
PLURAL(AuthDirBadDirCC),
PLURAL(AuthDirBadExitCC),
PLURAL(AuthDirInvalidCC),
@@ -114,6 +81,7 @@ static config_abbrev_t _option_abbrevs[] = {
{ "BandwidthRateBytes", "BandwidthRate", 0, 0},
{ "BandwidthBurstBytes", "BandwidthBurst", 0, 0},
{ "DirFetchPostPeriod", "StatusFetchPeriod", 0, 0},
+ { "DirServer", "DirAuthority", 0, 0}, /* XXXX024 later, make this warn? */
{ "MaxConn", "ConnLimit", 0, 1},
{ "ORBindAddress", "ORListenAddress", 0, 0},
{ "DirBindAddress", "DirListenAddress", 0, 0},
@@ -130,31 +98,11 @@ static config_abbrev_t _option_abbrevs[] = {
{ "HashedControlPassword", "__HashedControlSessionPassword", 1, 0},
{ "StrictEntryNodes", "StrictNodes", 0, 1},
{ "StrictExitNodes", "StrictNodes", 0, 1},
+ { "VirtualAddrNetwork", "VirtualAddrNetworkIPv4", 0, 0},
+ { "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1},
{ NULL, NULL, 0, 0},
};
-/** A list of state-file "abbreviations," for compatibility. */
-static config_abbrev_t _state_abbrevs[] = {
- { "AccountingBytesReadInterval", "AccountingBytesReadInInterval", 0, 0 },
- { "HelperNode", "EntryGuard", 0, 0 },
- { "HelperNodeDownSince", "EntryGuardDownSince", 0, 0 },
- { "HelperNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
- { "EntryNode", "EntryGuard", 0, 0 },
- { "EntryNodeDownSince", "EntryGuardDownSince", 0, 0 },
- { "EntryNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
- { NULL, NULL, 0, 0},
-};
-#undef PLURAL
-
-/** A variable allowed in the configuration file or on the command line. */
-typedef struct config_var_t {
- const char *name; /**< The full keyword (case insensitive). */
- config_type_t type; /**< How to interpret the type and turn it into a
- * value. */
- off_t var_offset; /**< Offset of the corresponding member of or_options_t. */
- const char *initvalue; /**< String (or null) describing initial value. */
-} config_var_t;
-
/** An entry for config_vars: "The option <b>name</b> has type
* CONFIG_TYPE_<b>conftype</b>, and corresponds to
* or_options_t.<b>member</b>"
@@ -175,7 +123,7 @@ typedef struct config_var_t {
* abbreviations, order is significant, since the first matching option will
* be chosen first.
*/
-static config_var_t _option_vars[] = {
+static config_var_t option_vars_[] = {
OBSOLETE("AccountingMaxKB"),
V(AccountingMax, MEMUNIT, "0 bytes"),
V(AccountingStart, STRING, NULL),
@@ -204,12 +152,13 @@ static config_var_t _option_vars[] = {
V(AuthDirListBadExits, BOOL, "0"),
V(AuthDirMaxServersPerAddr, UINT, "2"),
V(AuthDirMaxServersPerAuthAddr,UINT, "5"),
+ V(AuthDirHasIPv6Connectivity, BOOL, "0"),
VAR("AuthoritativeDirectory", BOOL, AuthoritativeDir, "0"),
V(AutomapHostsOnResolve, BOOL, "0"),
V(AutomapHostsSuffixes, CSV, ".onion,.exit"),
V(AvoidDiskWrites, BOOL, "0"),
- V(BandwidthBurst, MEMUNIT, "10 MB"),
- V(BandwidthRate, MEMUNIT, "5 MB"),
+ V(BandwidthBurst, MEMUNIT, "1 GB"),
+ V(BandwidthRate, MEMUNIT, "1 GB"),
V(BridgeAuthoritativeDir, BOOL, "0"),
VAR("Bridge", LINELIST, Bridges, NULL),
V(BridgePassword, STRING, NULL),
@@ -223,8 +172,10 @@ static config_var_t _option_vars[] = {
V(CircuitPriorityHalflife, DOUBLE, "-100.0"), /*negative:'Use default'*/
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
V(ClientOnly, BOOL, "0"),
+ V(ClientPreferIPv6ORPort, BOOL, "0"),
V(ClientRejectInternalAddresses, BOOL, "1"),
V(ClientTransportPlugin, LINELIST, NULL),
+ V(ClientUseIPv6, BOOL, "0"),
V(ConsensusParams, STRING, NULL),
V(ConnLimit, UINT, "1000"),
V(ConnDirectionStatistics, BOOL, "0"),
@@ -257,10 +208,12 @@ static config_var_t _option_vars[] = {
OBSOLETE("DirRecordUsageRetainIPs"),
OBSOLETE("DirRecordUsageSaveInterval"),
V(DirReqStatistics, BOOL, "1"),
- VAR("DirServer", LINELIST, DirServers, NULL),
+ VAR("DirAuthority", LINELIST, DirAuthorities, NULL),
+ V(DirAuthorityFallbackRate, DOUBLE, "1.0"),
V(DisableAllSwap, BOOL, "0"),
V(DisableDebuggerAttachment, BOOL, "1"),
V(DisableIOCP, BOOL, "1"),
+ V(DisableV2DirectoryInfo_, BOOL, "0"),
V(DynamicDHGroups, BOOL, "0"),
VPORT(DNSPort, LINELIST, NULL),
V(DNSListenAddress, LINELIST, NULL),
@@ -278,13 +231,9 @@ static config_var_t _option_vars[] = {
V(ExitPortStatistics, BOOL, "0"),
V(ExtendAllowPrivateAddresses, BOOL, "0"),
V(ExtraInfoStatistics, BOOL, "1"),
+ V(FallbackDir, LINELIST, NULL),
-#if defined (WINCE)
- V(FallbackNetworkstatusFile, FILENAME, "fallback-consensus"),
-#else
- V(FallbackNetworkstatusFile, FILENAME,
- SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "fallback-consensus"),
-#endif
+ OBSOLETE("FallbackNetworkstatusFile"),
V(FascistFirewall, BOOL, "0"),
V(FirewallPorts, CSV, ""),
V(FastFirstHopPK, BOOL, "1"),
@@ -294,14 +243,19 @@ static config_var_t _option_vars[] = {
V(FetchHidServDescriptors, BOOL, "1"),
V(FetchUselessDescriptors, BOOL, "0"),
V(FetchV2Networkstatus, BOOL, "0"),
+ V(GeoIPExcludeUnknown, AUTOBOOL, "auto"),
#ifdef _WIN32
V(GeoIPFile, FILENAME, "<default>"),
+ V(GeoIPv6File, FILENAME, "<default>"),
#else
V(GeoIPFile, FILENAME,
SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip"),
+ V(GeoIPv6File, FILENAME,
+ SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip6"),
#endif
OBSOLETE("GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays"),
OBSOLETE("Group"),
+ V(GuardLifetime, INTERVAL, "0 minutes"),
V(HardwareAccel, BOOL, "0"),
V(HeartbeatPeriod, INTERVAL, "6 hours"),
V(AccelName, STRING, NULL),
@@ -324,7 +278,9 @@ static config_var_t _option_vars[] = {
V(HTTPProxyAuthenticator, STRING, NULL),
V(HTTPSProxy, STRING, NULL),
V(HTTPSProxyAuthenticator, STRING, NULL),
+ V(IPv6Exit, BOOL, "0"),
VAR("ServerTransportPlugin", LINELIST, ServerTransportPlugin, NULL),
+ V(ServerTransportListenAddr, LINELIST, NULL),
V(Socks4Proxy, STRING, NULL),
V(Socks5Proxy, STRING, NULL),
V(Socks5ProxyUsername, STRING, NULL),
@@ -344,7 +300,9 @@ static config_var_t _option_vars[] = {
V(MaxCircuitDirtiness, INTERVAL, "10 minutes"),
V(MaxClientCircuitsPending, UINT, "32"),
V(MaxMemInCellQueues, MEMUNIT, "8 GB"),
- V(MaxOnionsPending, UINT, "100"),
+ OBSOLETE("MaxOnionsPending"),
+ V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"),
+ V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"),
OBSOLETE("MonthlyAccountingStart"),
V(MyFamily, STRING, NULL),
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
@@ -356,22 +314,36 @@ static config_var_t _option_vars[] = {
OBSOLETE("NoPublish"),
VAR("NodeFamily", LINELIST, NodeFamilies, NULL),
V(NumCPUs, UINT, "0"),
+ V(NumDirectoryGuards, UINT, "0"),
V(NumEntryGuards, UINT, "3"),
V(ORListenAddress, LINELIST, NULL),
VPORT(ORPort, LINELIST, NULL),
- V(OutboundBindAddress, STRING, NULL),
+ V(OutboundBindAddress, LINELIST, NULL),
+ OBSOLETE("PathBiasDisableRate"),
V(PathBiasCircThreshold, INT, "-1"),
V(PathBiasNoticeRate, DOUBLE, "-1"),
- V(PathBiasDisableRate, DOUBLE, "-1"),
+ V(PathBiasWarnRate, DOUBLE, "-1"),
+ V(PathBiasExtremeRate, DOUBLE, "-1"),
V(PathBiasScaleThreshold, INT, "-1"),
- V(PathBiasScaleFactor, INT, "-1"),
+ OBSOLETE("PathBiasScaleFactor"),
+ OBSOLETE("PathBiasMultFactor"),
+ V(PathBiasDropGuards, AUTOBOOL, "0"),
+ OBSOLETE("PathBiasUseCloseCounts"),
+ V(PathBiasUseThreshold, INT, "-1"),
+ V(PathBiasNoticeUseRate, DOUBLE, "-1"),
+ V(PathBiasExtremeUseRate, DOUBLE, "-1"),
+ V(PathBiasScaleUseThreshold, INT, "-1"),
+
+ V(PathsNeededToBuildCircuits, DOUBLE, "-1"),
OBSOLETE("PathlenCoinWeight"),
V(PerConnBWBurst, MEMUNIT, "0"),
V(PerConnBWRate, MEMUNIT, "0"),
V(PidFile, STRING, NULL),
V(TestingTorNetwork, BOOL, "0"),
+ V(TestingMinExitFlagThreshold, MEMUNIT, "0"),
+ V(TestingMinFastFlagThreshold, MEMUNIT, "0"),
V(OptimisticData, AUTOBOOL, "auto"),
V(PortForwarding, BOOL, "0"),
V(PortForwardingHelper, FILENAME, "tor-fw-helper"),
@@ -413,13 +385,16 @@ static config_var_t _option_vars[] = {
V(SocksPolicy, LINELIST, NULL),
VPORT(SocksPort, LINELIST, NULL),
V(SocksTimeout, INTERVAL, "2 minutes"),
+ V(SSLKeyLifetime, INTERVAL, "0"),
OBSOLETE("StatusFetchPeriod"),
V(StrictNodes, BOOL, "0"),
+ V(Support022HiddenServices, AUTOBOOL, "auto"),
OBSOLETE("SysLog"),
V(TestSocks, BOOL, "0"),
OBSOLETE("TestVia"),
V(TokenBucketRefillInterval, MSEC_INTERVAL, "100 msec"),
V(Tor2webMode, BOOL, "0"),
+ V(TLSECGroup, STRING, NULL),
V(TrackHostExits, CSV, NULL),
V(TrackHostExitsExpire, INTERVAL, "30 minutes"),
OBSOLETE("TrafficShaping"),
@@ -429,7 +404,9 @@ static config_var_t _option_vars[] = {
V(UpdateBridgesFromAuthority, BOOL, "0"),
V(UseBridges, BOOL, "0"),
V(UseEntryGuards, BOOL, "1"),
+ V(UseEntryGuardsAsDirGuards, BOOL, "1"),
V(UseMicrodescriptors, AUTOBOOL, "auto"),
+ V(UseNTorHandshake, AUTOBOOL, "auto"),
V(User, STRING, NULL),
V(UserspaceIOCPBuffers, BOOL, "0"),
VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"),
@@ -445,9 +422,10 @@ static config_var_t _option_vars[] = {
V(V3AuthUseLegacyKey, BOOL, "0"),
V(V3BandwidthsFile, FILENAME, NULL),
VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
- V(VirtualAddrNetwork, STRING, "127.192.0.0/10"),
+ V(VirtualAddrNetworkIPv4, STRING, "127.192.0.0/10"),
+ V(VirtualAddrNetworkIPv6, STRING, "[FE80::]/10"),
V(WarnPlaintextPorts, CSV, "23,109,110,143"),
- V(_UseFilteringSSLBufferevents, BOOL, "0"),
+ V(UseFilteringSSLBufferevents, BOOL, "0"),
VAR("__ReloadTorrcOnSIGHUP", BOOL, ReloadTorrcOnSIGHUP, "1"),
VAR("__AllDirActionsPrivate", BOOL, AllDirActionsPrivate, "0"),
VAR("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"),
@@ -457,7 +435,7 @@ static config_var_t _option_vars[] = {
VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL),
V(MinUptimeHidServDirectoryV2, INTERVAL, "25 hours"),
V(VoteOnHidServDirectoriesV2, BOOL, "1"),
- V(_UsingTestNetworkDefaults, BOOL, "0"),
+ VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
@@ -485,127 +463,18 @@ static const config_var_t testing_tor_network_defaults[] = {
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"),
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"),
V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"),
- V(_UsingTestNetworkDefaults, BOOL, "1"),
+ VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
-#undef VAR
-
-#define VAR(name,conftype,member,initvalue) \
- { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_state_t, member), \
- initvalue }
-
-/** Array of "state" variables saved to the ~/.tor/state file. */
-static config_var_t _state_vars[] = {
- /* Remember to document these in state-contents.txt ! */
-
- V(AccountingBytesReadInInterval, MEMUNIT, NULL),
- V(AccountingBytesWrittenInInterval, MEMUNIT, NULL),
- V(AccountingExpectedUsage, MEMUNIT, NULL),
- V(AccountingIntervalStart, ISOTIME, NULL),
- V(AccountingSecondsActive, INTERVAL, NULL),
- V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL),
- V(AccountingSoftLimitHitAt, ISOTIME, NULL),
- V(AccountingBytesAtSoftLimit, MEMUNIT, NULL),
-
- VAR("EntryGuard", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardUnlistedSince", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardAddedBy", LINELIST_S, EntryGuards, NULL),
- VAR("EntryGuardPathBias", LINELIST_S, EntryGuards, NULL),
- V(EntryGuards, LINELIST_V, NULL),
-
- VAR("TransportProxy", LINELIST_S, TransportProxies, NULL),
- V(TransportProxies, LINELIST_V, NULL),
-
- V(BWHistoryReadEnds, ISOTIME, NULL),
- V(BWHistoryReadInterval, UINT, "900"),
- V(BWHistoryReadValues, CSV, ""),
- V(BWHistoryReadMaxima, CSV, ""),
- V(BWHistoryWriteEnds, ISOTIME, NULL),
- V(BWHistoryWriteInterval, UINT, "900"),
- V(BWHistoryWriteValues, CSV, ""),
- V(BWHistoryWriteMaxima, CSV, ""),
- V(BWHistoryDirReadEnds, ISOTIME, NULL),
- V(BWHistoryDirReadInterval, UINT, "900"),
- V(BWHistoryDirReadValues, CSV, ""),
- V(BWHistoryDirReadMaxima, CSV, ""),
- V(BWHistoryDirWriteEnds, ISOTIME, NULL),
- V(BWHistoryDirWriteInterval, UINT, "900"),
- V(BWHistoryDirWriteValues, CSV, ""),
- V(BWHistoryDirWriteMaxima, CSV, ""),
-
- V(TorVersion, STRING, NULL),
-
- V(LastRotatedOnionKey, ISOTIME, NULL),
- V(LastWritten, ISOTIME, NULL),
-
- V(TotalBuildTimes, UINT, NULL),
- V(CircuitBuildAbandonedCount, UINT, "0"),
- VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL),
- VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL),
- { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
-};
#undef VAR
#undef V
#undef OBSOLETE
-/** Represents an English description of a configuration variable; used when
- * generating configuration file comments. */
-typedef struct config_var_description_t {
- const char *name;
- const char *description;
-} config_var_description_t;
-
-/** Type of a callback to validate whether a given configuration is
- * well-formed and consistent. See options_trial_assign() for documentation
- * of arguments. */
-typedef int (*validate_fn_t)(void*,void*,int,char**);
-
-/** Information on the keys, value types, key-to-struct-member mappings,
- * variable descriptions, validation functions, and abbreviations for a
- * configuration or storage format. */
-typedef struct {
- size_t size; /**< Size of the struct that everything gets parsed into. */
- uint32_t magic; /**< Required 'magic value' to make sure we have a struct
- * of the right type. */
- off_t magic_offset; /**< Offset of the magic value within the struct. */
- config_abbrev_t *abbrevs; /**< List of abbreviations that we expand when
- * parsing this format. */
- config_var_t *vars; /**< List of variables we recognize, their default
- * values, and where we stick them in the structure. */
- validate_fn_t validate_fn; /**< Function to validate config. */
- /** If present, extra is a LINELIST variable for unrecognized
- * lines. Otherwise, unrecognized lines are an error. */
- config_var_t *extra;
-} config_format_t;
-
-/** Macro: assert that <b>cfg</b> has the right magic field for format
- * <b>fmt</b>. */
-#define CHECK(fmt, cfg) STMT_BEGIN \
- tor_assert(fmt && cfg); \
- tor_assert((fmt)->magic == \
- *(uint32_t*)STRUCT_VAR_P(cfg,fmt->magic_offset)); \
- STMT_END
-
#ifdef _WIN32
static char *get_windows_conf_root(void);
#endif
-static void config_line_append(config_line_t **lst,
- const char *key, const char *val);
-static void option_clear(const config_format_t *fmt, or_options_t *options,
- const config_var_t *var);
-static void option_reset(const config_format_t *fmt, or_options_t *options,
- const config_var_t *var, int use_defaults);
-static void config_free(const config_format_t *fmt, void *options);
-static int config_lines_eq(config_line_t *a, config_line_t *b);
-static int config_count_key(const config_line_t *a, const char *key);
-static int option_is_same(const config_format_t *fmt,
- const or_options_t *o1, const or_options_t *o2,
- const char *name);
-static or_options_t *options_dup(const config_format_t *fmt,
- const or_options_t *old);
static int options_validate(or_options_t *old_options,
or_options_t *options,
int from_setconf, char **msg);
@@ -624,9 +493,13 @@ static int parse_bridge_line(const char *line, int validate_only);
static int parse_client_transport_line(const char *line, int validate_only);
static int parse_server_transport_line(const char *line, int validate_only);
-static int parse_dir_server_line(const char *line,
+static char *get_bindaddr_from_transport_listen_line(const char *line,
+ const char *transport);
+static int parse_dir_authority_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
+static int parse_dir_fallback_line(const char *line,
+ int validate_only);
static void port_cfg_free(port_cfg_t *port);
static int parse_ports(or_options_t *options, int validate_only,
char **msg_out, int *n_ports_out);
@@ -636,20 +509,14 @@ static int check_server_ports(const smartlist_t *ports,
static int validate_data_directory(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
-static config_line_t *get_assigned_option(const config_format_t *fmt,
- const void *options, const char *key,
- int escape_val);
-static void config_init(const config_format_t *fmt, void *options);
-static int or_state_validate(or_state_t *old_options, or_state_t *options,
- int from_setconf, char **msg);
-static int or_state_load(void);
static int options_init_logs(or_options_t *options, int validate_only);
-static uint64_t config_parse_memunit(const char *s, int *ok);
-static int config_parse_msec_interval(const char *s, int *ok);
-static int config_parse_interval(const char *s, int *ok);
static void init_libevent(const or_options_t *options);
static int opt_streq(const char *s1, const char *s2);
+static int parse_outbound_addresses(or_options_t *options, int validate_only,
+ char **msg);
+static void config_maybe_load_geoip_files_(const or_options_t *options,
+ const or_options_t *old_options);
/** Magic value for or_options_t. */
#define OR_OPTIONS_MAGIC 9090909
@@ -658,33 +525,13 @@ static int opt_streq(const char *s1, const char *s2);
static config_format_t options_format = {
sizeof(or_options_t),
OR_OPTIONS_MAGIC,
- STRUCT_OFFSET(or_options_t, _magic),
- _option_abbrevs,
- _option_vars,
+ STRUCT_OFFSET(or_options_t, magic_),
+ option_abbrevs_,
+ option_vars_,
(validate_fn_t)options_validate,
NULL
};
-/** Magic value for or_state_t. */
-#define OR_STATE_MAGIC 0x57A73f57
-
-/** "Extra" variable in the state that receives lines we can't parse. This
- * lets us preserve options from versions of Tor newer than us. */
-static config_var_t state_extra_var = {
- "__extra", CONFIG_TYPE_LINELIST, STRUCT_OFFSET(or_state_t, ExtraLines), NULL
-};
-
-/** Configuration format for or_state_t. */
-static const config_format_t state_format = {
- sizeof(or_state_t),
- OR_STATE_MAGIC,
- STRUCT_OFFSET(or_state_t, _magic),
- _state_abbrevs,
- _state_vars,
- (validate_fn_t)or_state_validate,
- &state_extra_var,
-};
-
/*
* Functions to read and write the global options pointer.
*/
@@ -698,8 +545,6 @@ static or_options_t *global_default_options = NULL;
static char *torrc_fname = NULL;
/** Name of the most recently read torrc-defaults file.*/
static char *torrc_defaults_fname;
-/** Persistent serialized state. */
-static or_state_t *global_state = NULL;
/** Configuration Options set by command line. */
static config_line_t *global_cmdline_options = NULL;
/** Contents of most recently read DirPortFrontPage file. */
@@ -714,16 +559,6 @@ get_dirportfrontpage(void)
return global_dirfrontpagecontents;
}
-/** Allocate an empty configuration object of a given format type. */
-static void *
-config_alloc(const config_format_t *fmt)
-{
- void *opts = tor_malloc_zero(fmt->size);
- *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
- CHECK(fmt, opts);
- return opts;
-}
-
/** Return the currently configured options. */
or_options_t *
get_options_mutable(void)
@@ -774,21 +609,26 @@ set_options(or_options_t *new_val, char **msg)
var->type == CONFIG_TYPE_OBSOLETE) {
continue;
}
- if (!option_is_same(&options_format, new_val, old_options, var_name)) {
- line = get_assigned_option(&options_format, new_val, var_name, 1);
+ if (!config_is_same(&options_format, new_val, old_options, var_name)) {
+ line = config_get_assigned_option(&options_format, new_val,
+ var_name, 1);
if (line) {
- for (; line; line = line->next) {
+ config_line_t *next;
+ for (; line; line = next) {
+ next = line->next;
smartlist_add(elements, line->key);
smartlist_add(elements, line->value);
+ tor_free(line);
}
} else {
- smartlist_add(elements, (char*)options_format.vars[i].name);
+ smartlist_add(elements, tor_strdup(options_format.vars[i].name));
smartlist_add(elements, NULL);
}
}
}
control_event_conf_changed(elements);
+ SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
smartlist_free(elements);
}
@@ -844,13 +684,13 @@ or_options_free(or_options_t *options)
if (!options)
return;
- routerset_free(options->_ExcludeExitNodesUnion);
+ routerset_free(options->ExcludeExitNodesUnion_);
if (options->NodeFamilySets) {
SMARTLIST_FOREACH(options->NodeFamilySets, routerset_t *,
rs, routerset_free(rs));
smartlist_free(options->NodeFamilySets);
}
- tor_free(options->_BridgePassword_AuthDigest);
+ tor_free(options->BridgePassword_AuthDigest_);
config_free(&options_format, options);
}
@@ -864,15 +704,12 @@ config_free_all(void)
or_options_free(global_default_options);
global_default_options = NULL;
- config_free(&state_format, global_state);
- global_state = NULL;
-
config_free_lines(global_cmdline_options);
global_cmdline_options = NULL;
if (configured_ports) {
SMARTLIST_FOREACH(configured_ports,
- port_cfg_t *, p, tor_free(p));
+ port_cfg_t *, p, port_cfg_free(p));
smartlist_free(configured_ports);
configured_ports = NULL;
}
@@ -881,6 +718,9 @@ config_free_all(void)
tor_free(torrc_defaults_fname);
tor_free(the_tor_version);
tor_free(global_dirfrontpagecontents);
+
+ tor_free(the_short_tor_version);
+ tor_free(the_tor_version);
}
/** Make <b>address</b> -- a piece of information related to our operation as
@@ -893,7 +733,7 @@ const char *
safe_str_client(const char *address)
{
tor_assert(address);
- if (get_options()->_SafeLogging == SAFELOG_SCRUB_ALL)
+ if (get_options()->SafeLogging_ == SAFELOG_SCRUB_ALL)
return "[scrubbed]";
else
return address;
@@ -910,7 +750,7 @@ const char *
safe_str(const char *address)
{
tor_assert(address);
- if (get_options()->_SafeLogging != SAFELOG_SCRUB_NONE)
+ if (get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE)
return "[scrubbed]";
else
return address;
@@ -922,7 +762,7 @@ safe_str(const char *address)
const char *
escaped_safe_str_client(const char *address)
{
- if (get_options()->_SafeLogging == SAFELOG_SCRUB_ALL)
+ if (get_options()->SafeLogging_ == SAFELOG_SCRUB_ALL)
return "[scrubbed]";
else
return escaped(address);
@@ -934,7 +774,7 @@ escaped_safe_str_client(const char *address)
const char *
escaped_safe_str(const char *address)
{
- if (get_options()->_SafeLogging != SAFELOG_SCRUB_NONE)
+ if (get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE)
return "[scrubbed]";
else
return escaped(address);
@@ -946,7 +786,7 @@ static void
add_default_trusted_dir_authorities(dirinfo_type_t type)
{
int i;
- const char *dirservers[] = {
+ const char *authorities[] = {
"moria1 orport=9101 no-v2 "
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
@@ -975,10 +815,27 @@ add_default_trusted_dir_authorities(dirinfo_type_t type)
"154.35.32.5:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC",
NULL
};
- for (i=0; dirservers[i]; i++) {
- if (parse_dir_server_line(dirservers[i], type, 0)<0) {
- log_err(LD_BUG, "Couldn't parse internal dirserver line %s",
- dirservers[i]);
+ for (i=0; authorities[i]; i++) {
+ if (parse_dir_authority_line(authorities[i], type, 0)<0) {
+ log_err(LD_BUG, "Couldn't parse internal DirAuthority line %s",
+ authorities[i]);
+ }
+ }
+}
+
+/** Add the default fallback directory servers into the fallback directory
+ * server list. */
+static void
+add_default_fallback_dir_servers(void)
+{
+ int i;
+ const char *fallback[] = {
+ NULL
+ };
+ for (i=0; fallback[i]; i++) {
+ if (parse_dir_fallback_line(fallback[i], 0)<0) {
+ log_err(LD_BUG, "Couldn't parse internal FallbackDir line %s",
+ fallback[i]);
}
}
}
@@ -988,28 +845,29 @@ add_default_trusted_dir_authorities(dirinfo_type_t type)
* user if we changed any dangerous ones.
*/
static int
-validate_dir_authorities(or_options_t *options, or_options_t *old_options)
+validate_dir_servers(or_options_t *options, or_options_t *old_options)
{
config_line_t *cl;
- if (options->DirServers &&
+ if (options->DirAuthorities &&
(options->AlternateDirAuthority || options->AlternateBridgeAuthority ||
options->AlternateHSAuthority)) {
log_warn(LD_CONFIG,
- "You cannot set both DirServers and Alternate*Authority.");
+ "You cannot set both DirAuthority and Alternate*Authority.");
return -1;
}
/* do we want to complain to the user about being partitionable? */
- if ((options->DirServers &&
+ if ((options->DirAuthorities &&
(!old_options ||
- !config_lines_eq(options->DirServers, old_options->DirServers))) ||
+ !config_lines_eq(options->DirAuthorities,
+ old_options->DirAuthorities))) ||
(options->AlternateDirAuthority &&
(!old_options ||
!config_lines_eq(options->AlternateDirAuthority,
old_options->AlternateDirAuthority)))) {
log_warn(LD_CONFIG,
- "You have used DirServer or AlternateDirAuthority to "
+ "You have used DirAuthority or AlternateDirAuthority to "
"specify alternate directory authorities in "
"your configuration. This is potentially dangerous: it can "
"make you look different from all other Tor users, and hurt "
@@ -1020,17 +878,20 @@ validate_dir_authorities(or_options_t *options, or_options_t *old_options)
/* Now go through the four ways you can configure an alternate
* set of directory authorities, and make sure none are broken. */
- for (cl = options->DirServers; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
+ for (cl = options->DirAuthorities; cl; cl = cl->next)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
return -1;
for (cl = options->AlternateBridgeAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
return -1;
for (cl = options->AlternateDirAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
return -1;
for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 1)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
+ return -1;
+ for (cl = options->FallbackDir; cl; cl = cl->next)
+ if (parse_dir_fallback_line(cl->value, 1)<0)
return -1;
return 0;
}
@@ -1039,13 +900,15 @@ validate_dir_authorities(or_options_t *options, or_options_t *old_options)
* as appropriate.
*/
static int
-consider_adding_dir_authorities(const or_options_t *options,
- const or_options_t *old_options)
+consider_adding_dir_servers(const or_options_t *options,
+ const or_options_t *old_options)
{
config_line_t *cl;
int need_to_update =
- !smartlist_len(router_get_trusted_dir_servers()) || !old_options ||
- !config_lines_eq(options->DirServers, old_options->DirServers) ||
+ !smartlist_len(router_get_trusted_dir_servers()) ||
+ !smartlist_len(router_get_fallback_dir_servers()) || !old_options ||
+ !config_lines_eq(options->DirAuthorities, old_options->DirAuthorities) ||
+ !config_lines_eq(options->FallbackDir, old_options->FallbackDir) ||
!config_lines_eq(options->AlternateBridgeAuthority,
old_options->AlternateBridgeAuthority) ||
!config_lines_eq(options->AlternateDirAuthority,
@@ -1057,9 +920,9 @@ consider_adding_dir_authorities(const or_options_t *options,
return 0; /* all done */
/* Start from a clean slate. */
- clear_trusted_dir_servers();
+ clear_dir_servers();
- if (!options->DirServers) {
+ if (!options->DirAuthorities) {
/* then we may want some of the defaults */
dirinfo_type_t type = NO_DIRINFO;
if (!options->AlternateBridgeAuthority)
@@ -1071,18 +934,23 @@ consider_adding_dir_authorities(const or_options_t *options,
type |= HIDSERV_DIRINFO;
add_default_trusted_dir_authorities(type);
}
+ if (!options->FallbackDir)
+ add_default_fallback_dir_servers();
- for (cl = options->DirServers; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
+ for (cl = options->DirAuthorities; cl; cl = cl->next)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
return -1;
for (cl = options->AlternateBridgeAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
return -1;
for (cl = options->AlternateDirAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
return -1;
for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
- if (parse_dir_server_line(cl->value, NO_DIRINFO, 0)<0)
+ if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
+ return -1;
+ for (cl = options->FallbackDir; cl; cl = cl->next)
+ if (parse_dir_fallback_line(cl->value, 0)<0)
return -1;
return 0;
}
@@ -1131,7 +999,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
int n_ports=0;
/* We need to set the connection limit before we can open the listeners. */
if (set_max_file_descriptors((unsigned)options->ConnLimit,
- &options->_ConnLimit) < 0) {
+ &options->ConnLimit_) < 0) {
*msg = tor_strdup("Problem with ConnLimit value. See logs for details.");
goto rollback;
}
@@ -1237,7 +1105,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
mark_logs_temp(); /* Close current logs once new logs are open. */
logs_marked = 1;
- if (options_init_logs(options, 0)<0) { /* Configure the log(s) */
+ if (options_init_logs(options, 0)<0) { /* Configure the tor_log(s) */
*msg = tor_strdup("Failed to init Log options. See logs for details.");
goto rollback;
}
@@ -1272,7 +1140,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
if (set_conn_limit && old_options)
set_max_file_descriptors((unsigned)old_options->ConnLimit,
- &options->_ConnLimit);
+ &options->ConnLimit_);
SMARTLIST_FOREACH(new_listeners, connection_t *, conn,
{
@@ -1354,6 +1222,9 @@ options_transition_requires_fresh_tls_context(const or_options_t *old_options,
return 1;
}
+ if (!opt_streq(old_options->TLSECGroup, new_options->TLSECGroup))
+ return 1;
+
return 0;
}
@@ -1372,9 +1243,10 @@ options_act(const or_options_t *old_options)
config_line_t *cl;
or_options_t *options = get_options_mutable();
int running_tor = options->command == CMD_RUN_TOR;
- char *msg;
+ char *msg=NULL;
const int transition_affects_workers =
old_options && options_transition_affects_workers(old_options, options);
+ int old_ewma_enabled;
/* disable ptrace and later, other basic debugging techniques */
{
@@ -1405,11 +1277,11 @@ options_act(const or_options_t *old_options)
return -1;
}
- if (consider_adding_dir_authorities(options, old_options) < 0)
+ if (consider_adding_dir_servers(options, old_options) < 0)
return -1;
#ifdef NON_ANONYMOUS_MODE_ENABLED
- log(LOG_WARN, LD_GENERAL, "This copy of Tor was compiled to run in a "
+ log_warn(LD_GENERAL, "This copy of Tor was compiled to run in a "
"non-anonymous mode. It will provide NO ANONYMITY.");
#endif
@@ -1455,7 +1327,7 @@ options_act(const or_options_t *old_options)
}
/* Load state */
- if (! global_state && running_tor) {
+ if (! or_state_loaded() && running_tor) {
if (or_state_load())
return -1;
rep_hist_load_mtbf_data(time(NULL));
@@ -1541,7 +1413,8 @@ options_act(const or_options_t *old_options)
/* Register addressmap directives */
config_register_addressmaps(options);
- parse_virtual_addr_network(options->VirtualAddrNetwork, 0, &msg);
+ parse_virtual_addr_network(options->VirtualAddrNetworkIPv4, AF_INET,0,NULL);
+ parse_virtual_addr_network(options->VirtualAddrNetworkIPv6, AF_INET6,0,NULL);
/* Update address policies. */
if (policies_parse_from_options(options) < 0) {
@@ -1558,7 +1431,7 @@ options_act(const or_options_t *old_options)
monitor_owning_controller_process(options->OwningControllerProcess);
/* reload keys as needed for rendezvous services. */
- if (rend_service_load_keys()<0) {
+ if (rend_service_load_all_keys()<0) {
log_warn(LD_GENERAL,"Error loading rendezvous service keys");
return -1;
}
@@ -1582,8 +1455,16 @@ options_act(const or_options_t *old_options)
connection_bucket_init();
#endif
+ old_ewma_enabled = cell_ewma_enabled();
/* Change the cell EWMA settings */
cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus());
+ /* If we just enabled ewma, set the cmux policy on all active channels */
+ if (cell_ewma_enabled() && !old_ewma_enabled) {
+ channel_set_cmux_policy_everywhere(&ewma_policy);
+ } else if (!cell_ewma_enabled() && old_ewma_enabled) {
+ /* Turn it off everywhere */
+ channel_set_cmux_policy_everywhere(NULL);
+ }
/* Update the BridgePassword's hashed version as needed. We store this as a
* digest so that we can do side-channel-proof comparisons on it.
@@ -1596,13 +1477,19 @@ options_act(const or_options_t *old_options)
"BridgePassword.");
return -1;
}
- options->_BridgePassword_AuthDigest = tor_malloc(DIGEST256_LEN);
- crypto_digest256(options->_BridgePassword_AuthDigest,
+ options->BridgePassword_AuthDigest_ = tor_malloc(DIGEST256_LEN);
+ crypto_digest256(options->BridgePassword_AuthDigest_,
http_authenticator, strlen(http_authenticator),
DIGEST_SHA256);
tor_free(http_authenticator);
}
+ if (parse_outbound_addresses(options, 0, &msg) < 0) {
+ log_warn(LD_BUG, "Failed parsing oubound bind addresses: %s", msg);
+ tor_free(msg);
+ return -1;
+ }
+
/* Check for transitions that need action. */
if (old_options) {
int revise_trackexithosts = 0;
@@ -1622,7 +1509,7 @@ options_act(const or_options_t *old_options)
"preferred or excluded node lists. "
"Abandoning previous circuits.");
circuit_mark_all_unused_circs();
- circuit_expire_all_dirty_circs();
+ circuit_mark_all_dirty_circs_as_unusable();
revise_trackexithosts = 1;
}
@@ -1640,8 +1527,10 @@ options_act(const or_options_t *old_options)
if (!smartlist_strings_eq(old_options->AutomapHostsSuffixes,
options->AutomapHostsSuffixes))
revise_automap_entries = 1;
- else if (!opt_streq(old_options->VirtualAddrNetwork,
- options->VirtualAddrNetwork))
+ else if (!opt_streq(old_options->VirtualAddrNetworkIPv4,
+ options->VirtualAddrNetworkIPv4) ||
+ !opt_streq(old_options->VirtualAddrNetworkIPv6,
+ options->VirtualAddrNetworkIPv6))
revise_automap_entries = 1;
}
@@ -1696,23 +1585,18 @@ options_act(const or_options_t *old_options)
connection_or_update_token_buckets(get_connection_array(), options);
}
- /* Maybe load geoip file */
- if (options->GeoIPFile &&
- ((!old_options || !opt_streq(old_options->GeoIPFile, options->GeoIPFile))
- || !geoip_is_loaded())) {
- /* XXXX Don't use this "<default>" junk; make our filename options
- * understand prefixes somehow. -NM */
- /* XXXX024 Reload GeoIPFile on SIGHUP. -NM */
- char *actual_fname = tor_strdup(options->GeoIPFile);
-#ifdef _WIN32
- if (!strcmp(actual_fname, "<default>")) {
- const char *conf_root = get_windows_conf_root();
- tor_free(actual_fname);
- tor_asprintf(&actual_fname, "%s\\geoip", conf_root);
- }
-#endif
- geoip_load_file(actual_fname, options);
- tor_free(actual_fname);
+ config_maybe_load_geoip_files_(options, old_options);
+
+ if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) {
+ /* ExcludeUnknown is true or "auto" */
+ const int is_auto = options->GeoIPExcludeUnknown == -1;
+ int changed;
+
+ changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto);
+ changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto);
+
+ if (changed)
+ routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto);
}
if (options->CellStatistics || options->DirReqStatistics ||
@@ -1737,7 +1621,7 @@ options_act(const or_options_t *old_options)
}
if ((!old_options || !old_options->DirReqStatistics) &&
options->DirReqStatistics) {
- if (geoip_is_loaded()) {
+ if (geoip_is_loaded(AF_INET)) {
geoip_dirreq_stats_init(now);
print_notice = 1;
} else {
@@ -1752,7 +1636,7 @@ options_act(const or_options_t *old_options)
}
if ((!old_options || !old_options->EntryStatistics) &&
options->EntryStatistics && !should_record_bridge_info(options)) {
- if (geoip_is_loaded()) {
+ if (geoip_is_loaded(AF_INET) || geoip_is_loaded(AF_INET6)) {
geoip_entry_stats_init(now);
print_notice = 1;
} else {
@@ -1848,42 +1732,6 @@ options_act(const or_options_t *old_options)
return 0;
}
-/*
- * Functions to parse config options
- */
-
-/** If <b>option</b> is an official abbreviation for a longer option,
- * return the longer option. Otherwise return <b>option</b>.
- * If <b>command_line</b> is set, apply all abbreviations. Otherwise, only
- * apply abbreviations that work for the config file and the command line.
- * If <b>warn_obsolete</b> is set, warn about deprecated names. */
-static const char *
-expand_abbrev(const config_format_t *fmt, const char *option, int command_line,
- int warn_obsolete)
-{
- int i;
- if (! fmt->abbrevs)
- return option;
- for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
- /* Abbreviations are case insensitive. */
- if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
- (command_line || !fmt->abbrevs[i].commandline_only)) {
- if (warn_obsolete && fmt->abbrevs[i].warn) {
- log_warn(LD_CONFIG,
- "The configuration option '%s' is deprecated; "
- "use '%s' instead.",
- fmt->abbrevs[i].abbreviated,
- fmt->abbrevs[i].full);
- }
- /* Keep going through the list in case we want to rewrite it more.
- * (We could imagine recursing here, but I don't want to get the
- * user into an infinite loop if we craft our list wrong.) */
- option = fmt->abbrevs[i].full;
- }
- }
- return option;
-}
-
/** Helper: Read a list of configuration options from the command line.
* If successful, put them in *<b>result</b> and return 0, and return
* -1 and leave *<b>result</b> alone. */
@@ -1943,11 +1791,11 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
return -1;
}
- (*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1, 1));
+ (*new)->key = tor_strdup(config_expand_abbrev(&options_format, s, 1, 1));
(*new)->value = want_arg ? tor_strdup(argv[i+1]) : tor_strdup("");
(*new)->command = command;
(*new)->next = NULL;
- log(LOG_DEBUG, LD_CONFIG, "command line: parsed keyword '%s', value '%s'",
+ log_debug(LD_CONFIG, "command line: parsed keyword '%s', value '%s'",
(*new)->key, (*new)->value);
new = &((*new)->next);
@@ -1957,444 +1805,6 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
return 0;
}
-/** Helper: allocate a new configuration option mapping 'key' to 'val',
- * append it to *<b>lst</b>. */
-static void
-config_line_append(config_line_t **lst,
- const char *key,
- const char *val)
-{
- 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;
- while (*lst)
- lst = &((*lst)->next);
-
- (*lst) = newline;
-}
-
-/** Helper: parse the config string and strdup into key/value
- * strings. Set *result to the list, or NULL if parsing the string
- * failed. Return 0 on success, -1 on failure. Warn and ignore any
- * misformatted lines.
- *
- * If <b>extended</b> is set, then treat keys beginning with / and with + as
- * indicating "clear" and "append" respectively. */
-int
-config_get_lines(const char *string, config_line_t **result, int extended)
-{
- config_line_t *list = NULL, **next;
- char *k, *v;
-
- next = &list;
- do {
- k = v = NULL;
- string = parse_config_line_from_str(string, &k, &v);
- if (!string) {
- config_free_lines(list);
- tor_free(k);
- tor_free(v);
- return -1;
- }
- if (k && v) {
- unsigned command = CONFIG_LINE_NORMAL;
- if (extended) {
- if (k[0] == '+') {
- char *k_new = tor_strdup(k+1);
- tor_free(k);
- k = k_new;
- command = CONFIG_LINE_APPEND;
- } else if (k[0] == '/') {
- char *k_new = tor_strdup(k+1);
- tor_free(k);
- k = k_new;
- tor_free(v);
- v = tor_strdup("");
- command = CONFIG_LINE_CLEAR;
- }
- }
- /* This list can get long, so we keep a pointer to the end of it
- * rather than using config_line_append over and over and getting
- * n^2 performance. */
- *next = tor_malloc_zero(sizeof(config_line_t));
- (*next)->key = k;
- (*next)->value = v;
- (*next)->next = NULL;
- (*next)->command = command;
- next = &((*next)->next);
- } else {
- tor_free(k);
- tor_free(v);
- }
- } while (*string);
-
- *result = list;
- return 0;
-}
-
-/**
- * Free all the configuration lines on the linked list <b>front</b>.
- */
-void
-config_free_lines(config_line_t *front)
-{
- config_line_t *tmp;
-
- while (front) {
- tmp = front;
- front = tmp->next;
-
- tor_free(tmp->key);
- tor_free(tmp->value);
- tor_free(tmp);
- }
-}
-
-/** As config_find_option, but return a non-const pointer. */
-static config_var_t *
-config_find_option_mutable(config_format_t *fmt, const char *key)
-{
- int i;
- size_t keylen = strlen(key);
- if (!keylen)
- return NULL; /* if they say "--" on the command line, it's not an option */
- /* First, check for an exact (case-insensitive) match */
- for (i=0; fmt->vars[i].name; ++i) {
- if (!strcasecmp(key, fmt->vars[i].name)) {
- return &fmt->vars[i];
- }
- }
- /* If none, check for an abbreviated match */
- for (i=0; fmt->vars[i].name; ++i) {
- if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
- log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
- "Please use '%s' instead",
- key, fmt->vars[i].name);
- return &fmt->vars[i];
- }
- }
- /* Okay, unrecognized option */
- return NULL;
-}
-
-/** If <b>key</b> is a configuration option, return the corresponding const
- * config_var_t. Otherwise, if <b>key</b> is a non-standard abbreviation,
- * warn, and return the corresponding const config_var_t. Otherwise return
- * NULL.
- */
-static const config_var_t *
-config_find_option(const config_format_t *fmt, const char *key)
-{
- return config_find_option_mutable((config_format_t*)fmt, key);
-}
-
-/** Return the number of option entries in <b>fmt</b>. */
-static int
-config_count_options(const config_format_t *fmt)
-{
- int i;
- for (i=0; fmt->vars[i].name; ++i)
- ;
- return i;
-}
-
-/*
- * Functions to assign config options.
- */
-
-/** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
- * with <b>c</b>-\>value and return 0, or return -1 if bad value.
- *
- * Called from config_assign_line() and option_reset().
- */
-static int
-config_assign_value(const config_format_t *fmt, or_options_t *options,
- config_line_t *c, char **msg)
-{
- int i, ok;
- const config_var_t *var;
- void *lvalue;
-
- CHECK(fmt, options);
-
- var = config_find_option(fmt, c->key);
- tor_assert(var);
-
- lvalue = STRUCT_VAR_P(options, var->var_offset);
-
- switch (var->type) {
-
- case CONFIG_TYPE_PORT:
- if (!strcasecmp(c->value, "auto")) {
- *(int *)lvalue = CFG_AUTO_PORT;
- break;
- }
- /* fall through */
- case CONFIG_TYPE_INT:
- case CONFIG_TYPE_UINT:
- i = (int)tor_parse_long(c->value, 10,
- var->type==CONFIG_TYPE_INT ? INT_MIN : 0,
- var->type==CONFIG_TYPE_PORT ? 65535 : INT_MAX,
- &ok, NULL);
- if (!ok) {
- tor_asprintf(msg,
- "Int keyword '%s %s' is malformed or out of bounds.",
- c->key, c->value);
- return -1;
- }
- *(int *)lvalue = i;
- break;
-
- case CONFIG_TYPE_INTERVAL: {
- i = config_parse_interval(c->value, &ok);
- if (!ok) {
- tor_asprintf(msg,
- "Interval '%s %s' is malformed or out of bounds.",
- c->key, c->value);
- return -1;
- }
- *(int *)lvalue = i;
- break;
- }
-
- case CONFIG_TYPE_MSEC_INTERVAL: {
- i = config_parse_msec_interval(c->value, &ok);
- if (!ok) {
- tor_asprintf(msg,
- "Msec interval '%s %s' is malformed or out of bounds.",
- c->key, c->value);
- return -1;
- }
- *(int *)lvalue = i;
- break;
- }
-
- case CONFIG_TYPE_MEMUNIT: {
- uint64_t u64 = config_parse_memunit(c->value, &ok);
- if (!ok) {
- tor_asprintf(msg,
- "Value '%s %s' is malformed or out of bounds.",
- c->key, c->value);
- return -1;
- }
- *(uint64_t *)lvalue = u64;
- break;
- }
-
- case CONFIG_TYPE_BOOL:
- i = (int)tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
- if (!ok) {
- tor_asprintf(msg,
- "Boolean '%s %s' expects 0 or 1.",
- c->key, c->value);
- return -1;
- }
- *(int *)lvalue = i;
- break;
-
- case CONFIG_TYPE_AUTOBOOL:
- if (!strcmp(c->value, "auto"))
- *(int *)lvalue = -1;
- else if (!strcmp(c->value, "0"))
- *(int *)lvalue = 0;
- else if (!strcmp(c->value, "1"))
- *(int *)lvalue = 1;
- else {
- tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.",
- c->key, c->value);
- return -1;
- }
- break;
-
- case CONFIG_TYPE_STRING:
- case CONFIG_TYPE_FILENAME:
- tor_free(*(char **)lvalue);
- *(char **)lvalue = tor_strdup(c->value);
- break;
-
- case CONFIG_TYPE_DOUBLE:
- *(double *)lvalue = atof(c->value);
- break;
-
- case CONFIG_TYPE_ISOTIME:
- if (parse_iso_time(c->value, (time_t *)lvalue)) {
- tor_asprintf(msg,
- "Invalid time '%s' for keyword '%s'", c->value, c->key);
- return -1;
- }
- break;
-
- case CONFIG_TYPE_ROUTERSET:
- if (*(routerset_t**)lvalue) {
- routerset_free(*(routerset_t**)lvalue);
- }
- *(routerset_t**)lvalue = routerset_new();
- if (routerset_parse(*(routerset_t**)lvalue, c->value, c->key)<0) {
- tor_asprintf(msg, "Invalid exit list '%s' for option '%s'",
- c->value, c->key);
- return -1;
- }
- break;
-
- case CONFIG_TYPE_CSV:
- if (*(smartlist_t**)lvalue) {
- SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
- smartlist_clear(*(smartlist_t**)lvalue);
- } else {
- *(smartlist_t**)lvalue = smartlist_new();
- }
-
- smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- break;
-
- case CONFIG_TYPE_LINELIST:
- case CONFIG_TYPE_LINELIST_S:
- {
- config_line_t *lastval = *(config_line_t**)lvalue;
- if (lastval && lastval->fragile) {
- if (c->command != CONFIG_LINE_APPEND) {
- config_free_lines(lastval);
- *(config_line_t**)lvalue = NULL;
- } else {
- lastval->fragile = 0;
- }
- }
-
- config_line_append((config_line_t**)lvalue, c->key, c->value);
- }
- break;
- case CONFIG_TYPE_OBSOLETE:
- log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key);
- break;
- case CONFIG_TYPE_LINELIST_V:
- tor_asprintf(msg,
- "You may not provide a value for virtual option '%s'", c->key);
- return -1;
- default:
- tor_assert(0);
- break;
- }
- return 0;
-}
-
-/** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
- * to it will replace old ones. */
-static void
-config_mark_lists_fragile(const config_format_t *fmt, or_options_t *options)
-{
- int i;
- tor_assert(fmt);
- tor_assert(options);
-
- for (i = 0; fmt->vars[i].name; ++i) {
- const config_var_t *var = &fmt->vars[i];
- config_line_t *list;
- if (var->type != CONFIG_TYPE_LINELIST &&
- var->type != CONFIG_TYPE_LINELIST_V)
- continue;
-
- list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset);
- if (list)
- list->fragile = 1;
- }
-}
-
-/** If <b>c</b> is a syntactically valid configuration line, update
- * <b>options</b> with its value and return 0. Otherwise return -1 for bad
- * key, -2 for bad value.
- *
- * If <b>clear_first</b> is set, clear the value first. Then if
- * <b>use_defaults</b> is set, set the value to the default.
- *
- * Called from config_assign().
- */
-static int
-config_assign_line(const config_format_t *fmt, or_options_t *options,
- config_line_t *c, int use_defaults,
- int clear_first, bitarray_t *options_seen, char **msg)
-{
- const config_var_t *var;
-
- CHECK(fmt, options);
-
- var = config_find_option(fmt, c->key);
- if (!var) {
- if (fmt->extra) {
- void *lvalue = STRUCT_VAR_P(options, fmt->extra->var_offset);
- log_info(LD_CONFIG,
- "Found unrecognized option '%s'; saving it.", c->key);
- config_line_append((config_line_t**)lvalue, c->key, c->value);
- return 0;
- } else {
- tor_asprintf(msg,
- "Unknown option '%s'. Failing.", c->key);
- return -1;
- }
- }
-
- /* Put keyword into canonical case. */
- if (strcmp(var->name, c->key)) {
- tor_free(c->key);
- c->key = tor_strdup(var->name);
- }
-
- if (!strlen(c->value)) {
- /* reset or clear it, then return */
- if (!clear_first) {
- if ((var->type == CONFIG_TYPE_LINELIST ||
- var->type == CONFIG_TYPE_LINELIST_S) &&
- c->command != CONFIG_LINE_CLEAR) {
- /* We got an empty linelist from the torrc or command line.
- As a special case, call this an error. Warn and ignore. */
- log_warn(LD_CONFIG,
- "Linelist option '%s' has no value. Skipping.", c->key);
- } else { /* not already cleared */
- option_reset(fmt, options, var, use_defaults);
- }
- }
- return 0;
- } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
- option_reset(fmt, options, var, use_defaults);
- }
-
- if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
- var->type != CONFIG_TYPE_LINELIST_S)) {
- /* We're tracking which options we've seen, and this option is not
- * supposed to occur more than once. */
- int var_index = (int)(var - fmt->vars);
- if (bitarray_is_set(options_seen, var_index)) {
- log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
- "value will be ignored.", var->name);
- }
- bitarray_set(options_seen, var_index);
- }
-
- if (config_assign_value(fmt, options, c, msg) < 0)
- return -2;
- return 0;
-}
-
-/** Restore the option named <b>key</b> in options to its default value.
- * Called from config_assign(). */
-static void
-config_reset_line(const config_format_t *fmt, or_options_t *options,
- const char *key, int use_defaults)
-{
- const config_var_t *var;
-
- CHECK(fmt, options);
-
- var = config_find_option(fmt, key);
- if (!var)
- return; /* give error on next pass. */
-
- option_reset(fmt, options, var, use_defaults);
-}
-
/** Return true iff key is a valid configuration option. */
int
option_is_recognized(const char *key)
@@ -2417,287 +1827,7 @@ option_get_canonical_name(const char *key)
config_line_t *
option_get_assignment(const or_options_t *options, const char *key)
{
- return get_assigned_option(&options_format, options, key, 1);
-}
-
-/** Return true iff value needs to be quoted and escaped to be used in
- * a configuration file. */
-static int
-config_value_needs_escape(const char *value)
-{
- if (*value == '\"')
- return 1;
- while (*value) {
- switch (*value)
- {
- case '\r':
- case '\n':
- case '#':
- /* Note: quotes and backspaces need special handling when we are using
- * quotes, not otherwise, so they don't trigger escaping on their
- * own. */
- return 1;
- default:
- if (!TOR_ISPRINT(*value))
- return 1;
- }
- ++value;
- }
- return 0;
-}
-
-/** Return a newly allocated deep copy of the lines in <b>inp</b>. */
-static config_line_t *
-config_lines_dup(const config_line_t *inp)
-{
- config_line_t *result = NULL;
- config_line_t **next_out = &result;
- while (inp) {
- *next_out = tor_malloc_zero(sizeof(config_line_t));
- (*next_out)->key = tor_strdup(inp->key);
- (*next_out)->value = tor_strdup(inp->value);
- inp = inp->next;
- next_out = &((*next_out)->next);
- }
- (*next_out) = NULL;
- return result;
-}
-
-/** Return newly allocated line or lines corresponding to <b>key</b> in the
- * configuration <b>options</b>. If <b>escape_val</b> is true and a
- * value needs to be quoted before it's put in a config file, quote and
- * escape that value. Return NULL if no such key exists. */
-static config_line_t *
-get_assigned_option(const config_format_t *fmt, const void *options,
- const char *key, int escape_val)
-{
- const config_var_t *var;
- const void *value;
- config_line_t *result;
- tor_assert(options && key);
-
- CHECK(fmt, options);
-
- var = config_find_option(fmt, key);
- if (!var) {
- log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
- return NULL;
- }
- value = STRUCT_VAR_P(options, var->var_offset);
-
- result = tor_malloc_zero(sizeof(config_line_t));
- result->key = tor_strdup(var->name);
- switch (var->type)
- {
- case CONFIG_TYPE_STRING:
- case CONFIG_TYPE_FILENAME:
- if (*(char**)value) {
- result->value = tor_strdup(*(char**)value);
- } else {
- tor_free(result->key);
- tor_free(result);
- return NULL;
- }
- break;
- case CONFIG_TYPE_ISOTIME:
- if (*(time_t*)value) {
- result->value = tor_malloc(ISO_TIME_LEN+1);
- format_iso_time(result->value, *(time_t*)value);
- } else {
- tor_free(result->key);
- tor_free(result);
- }
- escape_val = 0; /* Can't need escape. */
- break;
- case CONFIG_TYPE_PORT:
- if (*(int*)value == CFG_AUTO_PORT) {
- result->value = tor_strdup("auto");
- escape_val = 0;
- break;
- }
- /* fall through */
- case CONFIG_TYPE_INTERVAL:
- case CONFIG_TYPE_MSEC_INTERVAL:
- case CONFIG_TYPE_UINT:
- case CONFIG_TYPE_INT:
- /* This means every or_options_t uint or bool element
- * needs to be an int. Not, say, a uint16_t or char. */
- tor_asprintf(&result->value, "%d", *(int*)value);
- escape_val = 0; /* Can't need escape. */
- break;
- case CONFIG_TYPE_MEMUNIT:
- tor_asprintf(&result->value, U64_FORMAT,
- U64_PRINTF_ARG(*(uint64_t*)value));
- escape_val = 0; /* Can't need escape. */
- break;
- case CONFIG_TYPE_DOUBLE:
- tor_asprintf(&result->value, "%f", *(double*)value);
- escape_val = 0; /* Can't need escape. */
- break;
-
- case CONFIG_TYPE_AUTOBOOL:
- if (*(int*)value == -1) {
- result->value = tor_strdup("auto");
- escape_val = 0;
- break;
- }
- /* fall through */
- case CONFIG_TYPE_BOOL:
- result->value = tor_strdup(*(int*)value ? "1" : "0");
- escape_val = 0; /* Can't need escape. */
- break;
- case CONFIG_TYPE_ROUTERSET:
- result->value = routerset_to_string(*(routerset_t**)value);
- break;
- case CONFIG_TYPE_CSV:
- if (*(smartlist_t**)value)
- result->value =
- smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL);
- else
- result->value = tor_strdup("");
- break;
- case CONFIG_TYPE_OBSOLETE:
- log_fn(LOG_PROTOCOL_WARN, LD_CONFIG,
- "You asked me for the value of an obsolete config option '%s'.",
- key);
- tor_free(result->key);
- tor_free(result);
- return NULL;
- case CONFIG_TYPE_LINELIST_S:
- log_warn(LD_CONFIG,
- "Can't return context-sensitive '%s' on its own", key);
- tor_free(result->key);
- tor_free(result);
- return NULL;
- case CONFIG_TYPE_LINELIST:
- case CONFIG_TYPE_LINELIST_V:
- tor_free(result->key);
- tor_free(result);
- result = config_lines_dup(*(const config_line_t**)value);
- break;
- default:
- tor_free(result->key);
- tor_free(result);
- log_warn(LD_BUG,"Unknown type %d for known key '%s'",
- var->type, key);
- return NULL;
- }
-
- if (escape_val) {
- config_line_t *line;
- for (line = result; line; line = line->next) {
- if (line->value && config_value_needs_escape(line->value)) {
- char *newval = esc_for_log(line->value);
- tor_free(line->value);
- line->value = newval;
- }
- }
- }
-
- return result;
-}
-
-/** Iterate through the linked list of requested options <b>list</b>.
- * For each item, convert as appropriate and assign to <b>options</b>.
- * If an item is unrecognized, set *msg and return -1 immediately,
- * else return 0 for success.
- *
- * If <b>clear_first</b>, interpret config options as replacing (not
- * extending) their previous values. If <b>clear_first</b> is set,
- * then <b>use_defaults</b> to decide if you set to defaults after
- * clearing, or make the value 0 or NULL.
- *
- * Here are the use cases:
- * 1. A non-empty AllowInvalid line in your torrc. Appends to current
- * if linelist, replaces current if csv.
- * 2. An empty AllowInvalid line in your torrc. Should clear it.
- * 3. "RESETCONF AllowInvalid" sets it to default.
- * 4. "SETCONF AllowInvalid" makes it NULL.
- * 5. "SETCONF AllowInvalid=foo" clears it and sets it to "foo".
- *
- * Use_defaults Clear_first
- * 0 0 "append"
- * 1 0 undefined, don't use
- * 0 1 "set to null first"
- * 1 1 "set to defaults first"
- * Return 0 on success, -1 on bad key, -2 on bad value.
- *
- * As an additional special case, if a LINELIST config option has
- * no value and clear_first is 0, then warn and ignore it.
- */
-
-/*
-There are three call cases for config_assign() currently.
-
-Case one: Torrc entry
-options_init_from_torrc() calls config_assign(0, 0)
- calls config_assign_line(0, 0).
- if value is empty, calls option_reset(0) and returns.
- calls config_assign_value(), appends.
-
-Case two: setconf
-options_trial_assign() calls config_assign(0, 1)
- calls config_reset_line(0)
- calls option_reset(0)
- calls option_clear().
- calls config_assign_line(0, 1).
- if value is empty, returns.
- calls config_assign_value(), appends.
-
-Case three: resetconf
-options_trial_assign() calls config_assign(1, 1)
- calls config_reset_line(1)
- calls option_reset(1)
- calls option_clear().
- calls config_assign_value(default)
- calls config_assign_line(1, 1).
- returns.
-*/
-static int
-config_assign(const config_format_t *fmt, void *options, config_line_t *list,
- int use_defaults, int clear_first, char **msg)
-{
- config_line_t *p;
- bitarray_t *options_seen;
- const int n_options = config_count_options(fmt);
-
- CHECK(fmt, options);
-
- /* pass 1: normalize keys */
- for (p = list; p; p = p->next) {
- const char *full = expand_abbrev(fmt, p->key, 0, 1);
- if (strcmp(full,p->key)) {
- tor_free(p->key);
- p->key = tor_strdup(full);
- }
- }
-
- /* pass 2: if we're reading from a resetting source, clear all
- * mentioned config options, and maybe set to their defaults. */
- if (clear_first) {
- for (p = list; p; p = p->next)
- config_reset_line(fmt, options, p->key, use_defaults);
- }
-
- options_seen = bitarray_init_zero(n_options);
- /* pass 3: assign. */
- while (list) {
- int r;
- if ((r=config_assign_line(fmt, options, list, use_defaults,
- clear_first, options_seen, msg))) {
- bitarray_free(options_seen);
- return r;
- }
- list = list->next;
- }
- bitarray_free(options_seen);
-
- /** Now we're done assigning a group of options to the configuration.
- * Subsequent group assignments should _replace_ linelists, not extend
- * them. */
- config_mark_lists_fragile(fmt, options);
-
- return 0;
+ return config_get_assigned_option(&options_format, options, key, 1);
}
/** Try assigning <b>list</b> to the global options. You do this by duping
@@ -2714,7 +1844,7 @@ options_trial_assign(config_line_t *list, int use_defaults,
int clear_first, char **msg)
{
int r;
- or_options_t *trial_options = options_dup(&options_format, get_options());
+ or_options_t *trial_options = config_dup(&options_format, get_options());
if ((r=config_assign(&options_format, trial_options,
list, use_defaults, clear_first, msg)) < 0) {
@@ -2741,90 +1871,6 @@ options_trial_assign(config_line_t *list, int use_defaults,
return SETOPT_OK;
}
-/** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
- * Called from option_reset() and config_free(). */
-static void
-option_clear(const config_format_t *fmt, or_options_t *options,
- const config_var_t *var)
-{
- void *lvalue = STRUCT_VAR_P(options, var->var_offset);
- (void)fmt; /* unused */
- switch (var->type) {
- case CONFIG_TYPE_STRING:
- case CONFIG_TYPE_FILENAME:
- tor_free(*(char**)lvalue);
- break;
- case CONFIG_TYPE_DOUBLE:
- *(double*)lvalue = 0.0;
- break;
- case CONFIG_TYPE_ISOTIME:
- *(time_t*)lvalue = 0;
- break;
- case CONFIG_TYPE_INTERVAL:
- case CONFIG_TYPE_MSEC_INTERVAL:
- case CONFIG_TYPE_UINT:
- case CONFIG_TYPE_INT:
- case CONFIG_TYPE_PORT:
- case CONFIG_TYPE_BOOL:
- *(int*)lvalue = 0;
- break;
- case CONFIG_TYPE_AUTOBOOL:
- *(int*)lvalue = -1;
- break;
- case CONFIG_TYPE_MEMUNIT:
- *(uint64_t*)lvalue = 0;
- break;
- case CONFIG_TYPE_ROUTERSET:
- if (*(routerset_t**)lvalue) {
- routerset_free(*(routerset_t**)lvalue);
- *(routerset_t**)lvalue = NULL;
- }
- break;
- case CONFIG_TYPE_CSV:
- if (*(smartlist_t**)lvalue) {
- SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp));
- smartlist_free(*(smartlist_t **)lvalue);
- *(smartlist_t **)lvalue = NULL;
- }
- break;
- case CONFIG_TYPE_LINELIST:
- case CONFIG_TYPE_LINELIST_S:
- config_free_lines(*(config_line_t **)lvalue);
- *(config_line_t **)lvalue = NULL;
- break;
- case CONFIG_TYPE_LINELIST_V:
- /* handled by linelist_s. */
- break;
- case CONFIG_TYPE_OBSOLETE:
- break;
- }
-}
-
-/** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
- * <b>use_defaults</b>, set it to its default value.
- * Called by config_init() and option_reset_line() and option_assign_line(). */
-static void
-option_reset(const config_format_t *fmt, or_options_t *options,
- const config_var_t *var, int use_defaults)
-{
- config_line_t *c;
- char *msg = NULL;
- CHECK(fmt, options);
- option_clear(fmt, options, var); /* clear it first */
- if (!use_defaults)
- return; /* all done */
- if (var->initvalue) {
- c = tor_malloc_zero(sizeof(config_line_t));
- c->key = tor_strdup(var->name);
- c->value = tor_strdup(var->initvalue);
- if (config_assign_value(fmt, options, c, &msg) < 0) {
- log_warn(LD_BUG, "Failed to assign default: %s", msg);
- tor_free(msg); /* if this happens it's a bug */
- }
- config_free_lines(c);
- }
-}
-
/** Print a usage message for tor. */
static void
print_usage(void)
@@ -2832,7 +1878,7 @@ print_usage(void)
printf(
"Copyright (c) 2001-2004, Roger Dingledine\n"
"Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n"
-"Copyright (c) 2007-2012, The Tor Project, Inc.\n\n"
+"Copyright (c) 2007-2013, The Tor Project, Inc.\n\n"
"tor -f <torrc> [args]\n"
"See man page for options, or https://www.torproject.org/ for "
"documentation.\n");
@@ -2844,8 +1890,8 @@ list_torrc_options(void)
{
int i;
smartlist_t *lines = smartlist_new();
- for (i = 0; _option_vars[i].name; ++i) {
- const config_var_t *var = &_option_vars[i];
+ for (i = 0; option_vars_[i].name; ++i) {
+ const config_var_t *var = &option_vars_[i];
if (var->type == CONFIG_TYPE_OBSOLETE ||
var->type == CONFIG_TYPE_LINELIST_V)
continue;
@@ -2856,21 +1902,41 @@ list_torrc_options(void)
/** Last value actually set by resolve_my_address. */
static uint32_t last_resolved_addr = 0;
+
+/** Accessor for last_resolved_addr from outside this file. */
+uint32_t
+get_last_resolved_addr(void)
+{
+ return last_resolved_addr;
+}
+
/**
- * Based on <b>options-\>Address</b>, guess our public IP address and put it
- * (in host order) into *<b>addr_out</b>. If <b>hostname_out</b> is provided,
- * set *<b>hostname_out</b> to a new string holding the hostname we used to
- * get the address. Return 0 if all is well, or -1 if we can't find a suitable
+ * Use <b>options-\>Address</b> to guess our public IP address.
+ *
+ * Return 0 if all is well, or -1 if we can't find a suitable
* public IP address.
+ *
+ * If we are returning 0:
+ * - Put our public IP address (in host order) into *<b>addr_out</b>.
+ * - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
+ * string describing how we arrived at our answer.
+ * - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
+ * get our address, set *<b>hostname_out</b> to a newly allocated string
+ * holding that hostname. (If we didn't get our address by resolving a
+ * hostname, set *<b>hostname_out</b> to NULL.)
+ *
* XXXX ipv6
*/
int
resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out, char **hostname_out)
+ uint32_t *addr_out,
+ const char **method_out, char **hostname_out)
{
struct in_addr in;
uint32_t addr; /* host order */
char hostname[256];
+ const char *method_used;
+ const char *hostname_used;
int explicit_ip=1;
int explicit_hostname=1;
int from_interface=0;
@@ -2881,6 +1947,10 @@ resolve_my_address(int warn_severity, const or_options_t *options,
tor_assert(addr_out);
+ /*
+ * Step one: Fill in 'hostname' to be our best guess.
+ */
+
if (address && *address) {
strlcpy(hostname, address, sizeof(hostname));
} else { /* then we need to guess our address */
@@ -2891,10 +1961,14 @@ resolve_my_address(int warn_severity, const or_options_t *options,
log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
return -1;
}
- log_debug(LD_CONFIG,"Guessed local host name as '%s'",hostname);
+ log_debug(LD_CONFIG, "Guessed local host name as '%s'", hostname);
}
- /* now we know hostname. resolve it and keep only the IP address */
+ /*
+ * Step two: Now that we know 'hostname', parse it or resolve it. If
+ * it doesn't parse or resolve, look at the interface address. Set 'addr'
+ * to be our (host-order) 32-bit answer.
+ */
if (tor_inet_aton(hostname, &in) == 0) {
/* then we have to resolve it */
@@ -2951,21 +2025,26 @@ resolve_my_address(int warn_severity, const or_options_t *options,
* illformed */
}
+ /*
+ * Step three: Check whether 'addr' is an internal IP address, and error
+ * out if it is and we don't want that.
+ */
+
addr_string = tor_dup_ip(addr);
if (is_internal_IP(addr, 0)) {
/* make sure we're ok with publishing an internal IP */
- if (!options->DirServers && !options->AlternateDirAuthority) {
- /* if they are using the default dirservers, disallow internal IPs
+ if (!options->DirAuthorities && !options->AlternateDirAuthority) {
+ /* if they are using the default authorities, disallow internal IPs
* always. */
log_fn(warn_severity, LD_CONFIG,
"Address '%s' resolves to private IP address '%s'. "
- "Tor servers that use the default DirServers must have public "
- "IP addresses.", hostname, addr_string);
+ "Tor servers that use the default DirAuthorities must have "
+ "public IP addresses.", hostname, addr_string);
tor_free(addr_string);
return -1;
}
if (!explicit_ip) {
- /* even if they've set their own dirservers, require an explicit IP if
+ /* even if they've set their own authorities, require an explicit IP if
* they're using an internal address. */
log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
"IP address '%s'. Please set the Address config option to be "
@@ -2975,37 +2054,65 @@ resolve_my_address(int warn_severity, const or_options_t *options,
}
}
- log_debug(LD_CONFIG, "Resolved Address to '%s'.", fmt_addr32(addr));
+ /*
+ * Step four: We have a winner! 'addr' is our answer for sure, and
+ * 'addr_string' is its string form. Fill out the various fields to
+ * say how we decided it.
+ */
+
+ log_debug(LD_CONFIG, "Resolved Address to '%s'.", addr_string);
+
+ if (explicit_ip) {
+ method_used = "CONFIGURED";
+ hostname_used = NULL;
+ } else if (explicit_hostname) {
+ method_used = "RESOLVED";
+ hostname_used = hostname;
+ } else if (from_interface) {
+ method_used = "INTERFACE";
+ hostname_used = NULL;
+ } else {
+ method_used = "GETHOSTNAME";
+ hostname_used = hostname;
+ }
+
*addr_out = addr;
+ if (method_out)
+ *method_out = method_used;
+ if (hostname_out)
+ *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL;
+
+ /*
+ * Step five: Check if the answer has changed since last time (or if
+ * there was no last time), and if so call various functions to keep
+ * us up-to-date.
+ */
+
if (last_resolved_addr && last_resolved_addr != *addr_out) {
/* Leave this as a notice, regardless of the requested severity,
* at least until dynamic IP address support becomes bulletproof. */
log_notice(LD_NET,
- "Your IP address seems to have changed to %s. Updating.",
- addr_string);
+ "Your IP address seems to have changed to %s "
+ "(METHOD=%s%s%s). Updating.",
+ addr_string, method_used,
+ hostname_used ? " HOSTNAME=" : "",
+ hostname_used ? hostname_used : "");
ip_address_changed(0);
}
+
if (last_resolved_addr != *addr_out) {
- const char *method;
- const char *h = hostname;
- if (explicit_ip) {
- method = "CONFIGURED";
- h = NULL;
- } else if (explicit_hostname) {
- method = "RESOLVED";
- } else if (from_interface) {
- method = "INTERFACE";
- h = NULL;
- } else {
- method = "GETHOSTNAME";
- }
control_event_server_status(LOG_NOTICE,
- "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s %s%s",
- addr_string, method, h?"HOSTNAME=":"", h);
+ "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
+ addr_string, method_used,
+ hostname_used ? " HOSTNAME=" : "",
+ hostname_used ? hostname_used : "");
}
last_resolved_addr = *addr_out;
- if (hostname_out)
- *hostname_out = tor_strdup(hostname);
+
+ /*
+ * And finally, clean up and return success.
+ */
+
tor_free(addr_string);
return 0;
}
@@ -3039,112 +2146,11 @@ is_local_addr(const tor_addr_t *addr)
return 0;
}
-/** Release storage held by <b>options</b>. */
-static void
-config_free(const config_format_t *fmt, void *options)
-{
- int i;
-
- if (!options)
- return;
-
- tor_assert(fmt);
-
- for (i=0; fmt->vars[i].name; ++i)
- option_clear(fmt, options, &(fmt->vars[i]));
- if (fmt->extra) {
- config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->var_offset);
- config_free_lines(*linep);
- *linep = NULL;
- }
- tor_free(options);
-}
-
-/** Return true iff a and b contain identical keys and values in identical
- * order. */
-static int
-config_lines_eq(config_line_t *a, config_line_t *b)
-{
- while (a && b) {
- if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
- return 0;
- a = a->next;
- b = b->next;
- }
- if (a || b)
- return 0;
- return 1;
-}
-
-/** Return the number of lines in <b>a</b> whose key is <b>key</b>. */
-static int
-config_count_key(const config_line_t *a, const char *key)
-{
- int n = 0;
- while (a) {
- if (!strcasecmp(a->key, key)) {
- ++n;
- }
- a = a->next;
- }
- return n;
-}
-
-/** Return true iff the option <b>name</b> has the same value in <b>o1</b>
- * and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
- */
-static int
-option_is_same(const config_format_t *fmt,
- const or_options_t *o1, const or_options_t *o2,
- const char *name)
-{
- config_line_t *c1, *c2;
- int r = 1;
- CHECK(fmt, o1);
- CHECK(fmt, o2);
-
- c1 = get_assigned_option(fmt, o1, name, 0);
- c2 = get_assigned_option(fmt, o2, name, 0);
- r = config_lines_eq(c1, c2);
- config_free_lines(c1);
- config_free_lines(c2);
- return r;
-}
-
-/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
-static or_options_t *
-options_dup(const config_format_t *fmt, const or_options_t *old)
-{
- or_options_t *newopts;
- int i;
- config_line_t *line;
-
- newopts = config_alloc(fmt);
- for (i=0; fmt->vars[i].name; ++i) {
- if (fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
- continue;
- if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
- continue;
- line = get_assigned_option(fmt, old, fmt->vars[i].name, 0);
- if (line) {
- char *msg = NULL;
- if (config_assign(fmt, newopts, line, 0, 0, &msg) < 0) {
- log_err(LD_BUG, "Config_get_assigned_option() generated "
- "something we couldn't config_assign(): %s", msg);
- tor_free(msg);
- tor_assert(0);
- }
- }
- config_free_lines(line);
- }
- return newopts;
-}
-
/** Return a new empty or_options_t. Used for testing. */
or_options_t *
options_new(void)
{
- return config_alloc(&options_format);
+ return config_new(&options_format);
}
/** Set <b>options</b> to hold reasonable defaults for most options.
@@ -3155,94 +2161,6 @@ options_init(or_options_t *options)
config_init(&options_format, options);
}
-/** Set all vars in the configuration object <b>options</b> to their default
- * values. */
-static void
-config_init(const config_format_t *fmt, void *options)
-{
- int i;
- const config_var_t *var;
- CHECK(fmt, options);
-
- for (i=0; fmt->vars[i].name; ++i) {
- var = &fmt->vars[i];
- if (!var->initvalue)
- continue; /* defaults to NULL or 0 */
- option_reset(fmt, options, var, 1);
- }
-}
-
-/** Allocate and return a new string holding the written-out values of the vars
- * in 'options'. If 'minimal', do not write out any default-valued vars.
- * Else, if comment_defaults, write default values as comments.
- */
-static char *
-config_dump(const config_format_t *fmt, const void *default_options,
- const void *options, int minimal,
- int comment_defaults)
-{
- smartlist_t *elements;
- const or_options_t *defaults = default_options;
- void *defaults_tmp = NULL;
- config_line_t *line, *assigned;
- char *result;
- int i;
- char *msg = NULL;
-
- if (defaults == NULL) {
- defaults = defaults_tmp = config_alloc(fmt);
- config_init(fmt, defaults_tmp);
- }
-
- /* XXX use a 1 here so we don't add a new log line while dumping */
- if (default_options == NULL) {
- if (fmt->validate_fn(NULL, defaults_tmp, 1, &msg) < 0) {
- log_err(LD_BUG, "Failed to validate default config.");
- tor_free(msg);
- tor_assert(0);
- }
- }
-
- elements = smartlist_new();
- for (i=0; fmt->vars[i].name; ++i) {
- int comment_option = 0;
- if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE ||
- fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
- continue;
- /* Don't save 'hidden' control variables. */
- if (!strcmpstart(fmt->vars[i].name, "__"))
- continue;
- if (minimal && option_is_same(fmt, options, defaults, fmt->vars[i].name))
- continue;
- else if (comment_defaults &&
- option_is_same(fmt, options, defaults, fmt->vars[i].name))
- comment_option = 1;
-
- line = assigned = get_assigned_option(fmt, options, fmt->vars[i].name, 1);
-
- for (; line; line = line->next) {
- smartlist_add_asprintf(elements, "%s%s %s\n",
- comment_option ? "# " : "",
- line->key, line->value);
- }
- config_free_lines(assigned);
- }
-
- if (fmt->extra) {
- line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->var_offset);
- for (; line; line = line->next) {
- smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
- }
- }
-
- result = smartlist_join_strings(elements, "", 0, NULL);
- SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
- smartlist_free(elements);
- if (defaults_tmp)
- config_free(fmt, defaults_tmp);
- return result;
-}
-
/** Return a string containing a possible configuration file that would give
* the configuration in <b>options</b>. If <b>minimal</b> is true, do not
* include options that are the same as Tor's defaults.
@@ -3299,16 +2217,16 @@ ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg)
}
/** Parse an authority type from <b>options</b>-\>PublishServerDescriptor
- * and write it to <b>options</b>-\>_PublishServerDescriptor. Treat "1"
+ * and write it to <b>options</b>-\>PublishServerDescriptor_. Treat "1"
* as "v2,v3" unless BridgeRelay is 1, in which case treat it as "bridge".
* Treat "0" as "".
* Return 0 on success or -1 if not a recognized authority type (in which
- * case the value of _PublishServerDescriptor is undefined). */
+ * case the value of PublishServerDescriptor_ is undefined). */
static int
compute_publishserverdescriptor(or_options_t *options)
{
smartlist_t *list = options->PublishServerDescriptor;
- dirinfo_type_t *auth = &options->_PublishServerDescriptor;
+ dirinfo_type_t *auth = &options->PublishServerDescriptor_;
*auth = NO_DIRINFO;
if (!list) /* empty list, answer is none */
return 0;
@@ -3349,6 +2267,10 @@ compute_publishserverdescriptor(or_options_t *options)
* will generate too many circuits and potentially overload the network. */
#define MIN_MAX_CIRCUIT_DIRTINESS 10
+/** Highest allowable value for MaxCircuitDirtiness: prevents time_t
+ * overflows. */
+#define MAX_MAX_CIRCUIT_DIRTINESS (30*24*60*60)
+
/** Lowest allowable value for CircuitStreamTimeout; if this is too low, Tor
* will generate too many circuits and potentially overload the network. */
#define MIN_CIRCUIT_STREAM_TIMEOUT 10
@@ -3386,7 +2308,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
int n_ports=0;
#define REJECT(arg) \
STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
-#define COMPLAIN(arg) STMT_BEGIN log(LOG_WARN, LD_CONFIG, arg); STMT_END
+#define COMPLAIN(arg) STMT_BEGIN log_warn(LD_CONFIG, arg); STMT_END
tor_assert(msg);
*msg = NULL;
@@ -3395,7 +2317,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
(!strcmpstart(uname, "Windows 95") ||
!strcmpstart(uname, "Windows 98") ||
!strcmpstart(uname, "Windows Me"))) {
- log(LOG_WARN, LD_CONFIG, "Tor is running as a server, but you are "
+ log_warn(LD_CONFIG, "Tor is running as a server, but you are "
"running %s; this probably won't work. See "
"https://wiki.torproject.org/TheOnionRouter/TorFAQ#ServerOS "
"for details.", uname);
@@ -3404,6 +2326,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (parse_ports(options, 1, msg, &n_ports) < 0)
return -1;
+ if (parse_outbound_addresses(options, 1, msg) < 0)
+ return -1;
+
if (validate_data_directory(options)<0)
REJECT("Invalid DataDirectory");
@@ -3421,7 +2346,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (server_mode(options) && !options->ContactInfo)
- log(LOG_NOTICE, LD_CONFIG, "Your ContactInfo config option is not set. "
+ log_notice(LD_CONFIG, "Your ContactInfo config option is not set. "
"Please consider setting it, so we can contact you if your server is "
"misconfigured or something else goes wrong.");
@@ -3433,13 +2358,13 @@ options_validate(or_options_t *old_options, or_options_t *options,
config_line_append(&options->Logs, "Log", "warn stdout");
}
- if (options_init_logs(options, 1)<0) /* Validate the log(s) */
+ if (options_init_logs(options, 1)<0) /* Validate the tor_log(s) */
REJECT("Failed to validate Log options. See logs for details.");
if (authdir_mode(options)) {
/* confirm that our address isn't broken, so we can complain now */
uint32_t tmp;
- if (resolve_my_address(LOG_WARN, options, &tmp, NULL) < 0)
+ if (resolve_my_address(LOG_WARN, options, &tmp, NULL, NULL) < 0)
REJECT("Failed to resolve/guess local address. See logs for details.");
}
@@ -3451,7 +2376,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
/* XXXX require that the only port not be DirPort? */
/* XXXX require that at least one port be listened-upon. */
if (n_ports == 0 && !options->RendConfigLines)
- log(LOG_WARN, LD_CONFIG,
+ log_warn(LD_CONFIG,
"SocksPort, TransPort, NATDPort, DNSPort, and ORPort are all "
"undefined, and there aren't any hidden services configured. "
"Tor will still run, but probably won't do anything.");
@@ -3467,10 +2392,14 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("TokenBucketRefillInterval must be between 1 and 1000 inclusive.");
}
+ if (options->DisableV2DirectoryInfo_ && ! authdir_mode(options)) {
+ REJECT("DisableV2DirectoryInfo_ set, but we aren't an authority.");
+ }
+
if (options->ExcludeExitNodes || options->ExcludeNodes) {
- options->_ExcludeExitNodesUnion = routerset_new();
- routerset_union(options->_ExcludeExitNodesUnion,options->ExcludeExitNodes);
- routerset_union(options->_ExcludeExitNodesUnion,options->ExcludeNodes);
+ options->ExcludeExitNodesUnion_ = routerset_new();
+ routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeExitNodes);
+ routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeNodes);
}
if (options->NodeFamilies) {
@@ -3485,6 +2414,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
+ if (options->TLSECGroup && (strcasecmp(options->TLSECGroup, "P256") &&
+ strcasecmp(options->TLSECGroup, "P224"))) {
+ COMPLAIN("Unrecognized TLSECGroup: Falling back to the default.");
+ tor_free(options->TLSECGroup);
+ }
+
if (options->ExcludeNodes && options->StrictNodes) {
COMPLAIN("You have asked to exclude certain relays from all positions "
"in your circuits. Expect hidden services and other Tor "
@@ -3552,6 +2487,18 @@ options_validate(or_options_t *old_options, or_options_t *options,
return -1;
}
+ if (options->PathsNeededToBuildCircuits >= 0.0) {
+ if (options->PathsNeededToBuildCircuits < 0.25) {
+ log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too low. Increasing "
+ "to 0.25");
+ options->PathsNeededToBuildCircuits = 0.25;
+ } else if (options->PathsNeededToBuildCircuits > 0.95) {
+ log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too high. Decreasing "
+ "to 0.95");
+ options->PathsNeededToBuildCircuits = 0.95;
+ }
+ }
+
if (options->MaxClientCircuitsPending <= 0 ||
options->MaxClientCircuitsPending > MAX_MAX_CLIENT_CIRCUITS_PENDING) {
tor_asprintf(msg,
@@ -3593,7 +2540,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
});
new_line->value = smartlist_join_strings(instead,",",0,NULL);
/* These have been deprecated since 0.1.1.5-alpha-cvs */
- log(LOG_NOTICE, LD_CONFIG,
+ log_notice(LD_CONFIG,
"Converting FascistFirewall and FirewallPorts "
"config options to new format: \"ReachableAddresses %s\"",
new_line->value);
@@ -3608,7 +2555,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
new_line->key = tor_strdup("ReachableDirAddresses");
new_line->value = tor_strdup("*:80");
options->ReachableDirAddresses = new_line;
- log(LOG_NOTICE, LD_CONFIG, "Converting FascistFirewall config option "
+ log_notice(LD_CONFIG, "Converting FascistFirewall config option "
"to new format: \"ReachableDirAddresses *:80\"");
}
if (!options->ReachableORAddresses) {
@@ -3616,7 +2563,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
new_line->key = tor_strdup("ReachableORAddresses");
new_line->value = tor_strdup("*:443");
options->ReachableORAddresses = new_line;
- log(LOG_NOTICE, LD_CONFIG, "Converting FascistFirewall config option "
+ log_notice(LD_CONFIG, "Converting FascistFirewall config option "
"to new format: \"ReachableORAddresses *:443\"");
}
}
@@ -3665,9 +2612,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->UseBridges && options->EntryNodes)
REJECT("You cannot set both UseBridges and EntryNodes.");
- if (options->EntryNodes && !options->UseEntryGuards)
- log_warn(LD_CONFIG, "EntryNodes is set, but UseEntryGuards is disabled. "
- "EntryNodes will be ignored.");
+ if (options->EntryNodes && !options->UseEntryGuards) {
+ REJECT("If EntryNodes is set, UseEntryGuards must be enabled.");
+ }
if (options->MaxMemInCellQueues < (500 << 20)) {
log_warn(LD_CONFIG, "MaxMemInCellQueues must be at least 500 MB for now. "
@@ -3675,19 +2622,20 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->MaxMemInCellQueues = (500 << 20);
}
- options->_AllowInvalid = 0;
+ options->AllowInvalid_ = 0;
+
if (options->AllowInvalidNodes) {
SMARTLIST_FOREACH_BEGIN(options->AllowInvalidNodes, const char *, cp) {
if (!strcasecmp(cp, "entry"))
- options->_AllowInvalid |= ALLOW_INVALID_ENTRY;
+ options->AllowInvalid_ |= ALLOW_INVALID_ENTRY;
else if (!strcasecmp(cp, "exit"))
- options->_AllowInvalid |= ALLOW_INVALID_EXIT;
+ options->AllowInvalid_ |= ALLOW_INVALID_EXIT;
else if (!strcasecmp(cp, "middle"))
- options->_AllowInvalid |= ALLOW_INVALID_MIDDLE;
+ options->AllowInvalid_ |= ALLOW_INVALID_MIDDLE;
else if (!strcasecmp(cp, "introduction"))
- options->_AllowInvalid |= ALLOW_INVALID_INTRODUCTION;
+ options->AllowInvalid_ |= ALLOW_INVALID_INTRODUCTION;
else if (!strcasecmp(cp, "rendezvous"))
- options->_AllowInvalid |= ALLOW_INVALID_RENDEZVOUS;
+ options->AllowInvalid_ |= ALLOW_INVALID_RENDEZVOUS;
else {
tor_asprintf(msg,
"Unrecognized value '%s' in AllowInvalidNodes", cp);
@@ -3698,11 +2646,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (!options->SafeLogging ||
!strcasecmp(options->SafeLogging, "0")) {
- options->_SafeLogging = SAFELOG_SCRUB_NONE;
+ options->SafeLogging_ = SAFELOG_SCRUB_NONE;
} else if (!strcasecmp(options->SafeLogging, "relay")) {
- options->_SafeLogging = SAFELOG_SCRUB_RELAY;
+ options->SafeLogging_ = SAFELOG_SCRUB_RELAY;
} else if (!strcasecmp(options->SafeLogging, "1")) {
- options->_SafeLogging = SAFELOG_SCRUB_ALL;
+ options->SafeLogging_ = SAFELOG_SCRUB_ALL;
} else {
tor_asprintf(msg,
"Unrecognized value '%s' in SafeLogging",
@@ -3716,8 +2664,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if ((options->BridgeRelay
- || options->_PublishServerDescriptor & BRIDGE_DIRINFO)
- && (options->_PublishServerDescriptor
+ || options->PublishServerDescriptor_ & BRIDGE_DIRINFO)
+ && (options->PublishServerDescriptor_
& (V1_DIRINFO|V2_DIRINFO|V3_DIRINFO))) {
REJECT("Bridges are not supposed to publish router descriptors to the "
"directory authorities. Please correct your "
@@ -3768,15 +2716,73 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->LearnCircuitBuildTimeout = 0;
}
- if (!(options->LearnCircuitBuildTimeout) &&
- options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) {
+ if (options->Tor2webMode && options->UseEntryGuards) {
+ /* tor2web mode clients do not (and should not) use entry guards
+ * in any meaningful way. Further, tor2web mode causes the hidden
+ * service client code to do things which break the path bias
+ * detector, and it's far easier to turn off entry guards (and
+ * thus the path bias detector with it) than to figure out how to
+ * make a piece of code which cannot possibly help tor2web mode
+ * users compatible with tor2web mode.
+ */
+ log_notice(LD_CONFIG,
+ "Tor2WebMode is enabled; disabling UseEntryGuards.");
+ options->UseEntryGuards = 0;
+ }
+
+ if (!(options->UseEntryGuards) &&
+ (options->RendConfigLines != NULL)) {
log_warn(LD_CONFIG,
- "CircuitBuildTimeout is shorter (%d seconds) than recommended "
- "(%d seconds), and LearnCircuitBuildTimeout is disabled. "
+ "UseEntryGuards is disabled, but you have configured one or more "
+ "hidden services on this Tor instance. Your hidden services "
+ "will be very easy to locate using a well-known attack -- see "
+ "http://freehaven.net/anonbib/#hs-attack06 for details.");
+ }
+
+ if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout &&
+ options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) {
+ log_warn(LD_CONFIG,
+ "CircuitBuildTimeout is shorter (%d seconds) than the recommended "
+ "minimum (%d seconds), and LearnCircuitBuildTimeout is disabled. "
"If tor isn't working, raise this value or enable "
"LearnCircuitBuildTimeout.",
options->CircuitBuildTimeout,
RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT );
+ } else if (!options->LearnCircuitBuildTimeout &&
+ !options->CircuitBuildTimeout) {
+ log_notice(LD_CONFIG, "You disabled LearnCircuitBuildTimeout, but didn't "
+ "a CircuitBuildTimeout. I'll pick a plausible default.");
+ }
+
+ if (options->PathBiasNoticeRate > 1.0) {
+ tor_asprintf(msg,
+ "PathBiasNoticeRate is too high. "
+ "It must be between 0 and 1.0");
+ return -1;
+ }
+ if (options->PathBiasWarnRate > 1.0) {
+ tor_asprintf(msg,
+ "PathBiasWarnRate is too high. "
+ "It must be between 0 and 1.0");
+ return -1;
+ }
+ if (options->PathBiasExtremeRate > 1.0) {
+ tor_asprintf(msg,
+ "PathBiasExtremeRate is too high. "
+ "It must be between 0 and 1.0");
+ return -1;
+ }
+ if (options->PathBiasNoticeUseRate > 1.0) {
+ tor_asprintf(msg,
+ "PathBiasNoticeUseRate is too high. "
+ "It must be between 0 and 1.0");
+ return -1;
+ }
+ if (options->PathBiasExtremeUseRate > 1.0) {
+ tor_asprintf(msg,
+ "PathBiasExtremeUseRate is too high. "
+ "It must be between 0 and 1.0");
+ return -1;
}
if (options->MaxCircuitDirtiness < MIN_MAX_CIRCUIT_DIRTINESS) {
@@ -3785,6 +2791,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->MaxCircuitDirtiness = MIN_MAX_CIRCUIT_DIRTINESS;
}
+ if (options->MaxCircuitDirtiness > MAX_MAX_CIRCUIT_DIRTINESS) {
+ log_warn(LD_CONFIG, "MaxCircuitDirtiness option is too high; "
+ "setting to %d days.", MAX_MAX_CIRCUIT_DIRTINESS/86400);
+ options->MaxCircuitDirtiness = MAX_MAX_CIRCUIT_DIRTINESS;
+ }
+
if (options->CircuitStreamTimeout &&
options->CircuitStreamTimeout < MIN_CIRCUIT_STREAM_TIMEOUT) {
log_warn(LD_CONFIG, "CircuitStreamTimeout option is too short; "
@@ -4042,8 +3054,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (validate_addr_policies(options, msg) < 0)
return -1;
- if (validate_dir_authorities(options, old_options) < 0)
- REJECT("Directory authority line did not parse. See logs for details.");
+ if (validate_dir_servers(options, old_options) < 0)
+ REJECT("Directory authority/fallback line did not parse. See logs "
+ "for details.");
if (options->UseBridges && !options->Bridges)
REJECT("If you set UseBridges, you must specify at least one bridge.");
@@ -4069,7 +3082,23 @@ options_validate(or_options_t *old_options, or_options_t *options,
log_notice(LD_GENERAL, "Tor is not configured as a relay but you specified"
" a ServerTransportPlugin line (%s). The ServerTransportPlugin "
"line will be ignored.",
- esc_for_log(options->ServerTransportPlugin->value));
+ escaped(options->ServerTransportPlugin->value));
+ }
+
+ for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
+ /** If get_bindaddr_from_transport_listen_line() fails with
+ 'transport' being NULL, it means that something went wrong
+ while parsing the ServerTransportListenAddr line. */
+ char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL);
+ if (!bindaddr)
+ REJECT("ServerTransportListenAddr did not parse. See logs for details.");
+ tor_free(bindaddr);
+ }
+
+ if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) {
+ log_notice(LD_GENERAL, "You need at least a single managed-proxy to "
+ "specify a transport listen address. The "
+ "ServerTransportListenAddr line will be ignored.");
}
if (options->ConstrainedSockets) {
@@ -4123,7 +3152,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("Failed to configure client authorization for hidden services. "
"See logs for details.");
- if (parse_virtual_addr_network(options->VirtualAddrNetwork, 1, NULL)<0)
+ if (parse_virtual_addr_network(options->VirtualAddrNetworkIPv4,
+ AF_INET, 1, msg)<0)
+ return -1;
+ if (parse_virtual_addr_network(options->VirtualAddrNetworkIPv6,
+ AF_INET6, 1, msg)<0)
return -1;
if (options->PreferTunneledDirConns && !options->TunnelDirConns)
@@ -4145,15 +3178,15 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingTorNetwork &&
- !(options->DirServers ||
+ !(options->DirAuthorities ||
(options->AlternateDirAuthority &&
options->AlternateBridgeAuthority))) {
REJECT("TestingTorNetwork may only be configured in combination with "
- "a non-default set of DirServer or both of AlternateDirAuthority "
- "and AlternateBridgeAuthority configured.");
+ "a non-default set of DirAuthority or both of "
+ "AlternateDirAuthority and AlternateBridgeAuthority configured.");
}
- if (options->AllowSingleHopExits && !options->DirServers) {
+ if (options->AllowSingleHopExits && !options->DirAuthorities) {
COMPLAIN("You have set AllowSingleHopExits; now your relay will allow "
"others to make one-hop exits. However, since by default most "
"clients avoid relays that set this option, most clients will "
@@ -4165,7 +3198,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
/* Keep changes to hard-coded values synchronous to man page and default
* values table. */
if (options->TestingV3AuthInitialVotingInterval != 30*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingV3AuthInitialVotingInterval may only be changed in testing "
"Tor networks!");
} else if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) {
@@ -4176,7 +3209,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingV3AuthInitialVoteDelay != 5*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingV3AuthInitialVoteDelay may only be changed in testing "
"Tor networks!");
@@ -4185,7 +3218,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingV3AuthInitialDistDelay != 5*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingV3AuthInitialDistDelay may only be changed in testing "
"Tor networks!");
} else if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) {
@@ -4200,7 +3233,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingAuthDirTimeToLearnReachability != 30*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingAuthDirTimeToLearnReachability may only be changed in "
"testing Tor networks!");
} else if (options->TestingAuthDirTimeToLearnReachability < 0) {
@@ -4210,7 +3243,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingEstimatedDescriptorPropagationTime != 10*60 &&
- !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingEstimatedDescriptorPropagationTime may only be changed in "
"testing Tor networks!");
} else if (options->TestingEstimatedDescriptorPropagationTime < 0) {
@@ -4346,7 +3379,7 @@ options_transition_affects_workers(const or_options_t *old_options,
!config_lines_eq(old_options->ORPort_lines, new_options->ORPort_lines) ||
old_options->ServerDNSSearchDomains !=
new_options->ServerDNSSearchDomains ||
- old_options->_SafeLogging != new_options->_SafeLogging ||
+ old_options->SafeLogging_ != new_options->SafeLogging_ ||
old_options->ClientOnly != new_options->ClientOnly ||
public_server_mode(old_options) != public_server_mode(new_options) ||
!config_lines_eq(old_options->Logs, new_options->Logs) ||
@@ -4373,14 +3406,15 @@ options_transition_affects_descriptor(const or_options_t *old_options,
!config_lines_eq(old_options->ExitPolicy,new_options->ExitPolicy) ||
old_options->ExitPolicyRejectPrivate !=
new_options->ExitPolicyRejectPrivate ||
+ old_options->IPv6Exit != new_options->IPv6Exit ||
!config_lines_eq(old_options->ORPort_lines,
new_options->ORPort_lines) ||
!config_lines_eq(old_options->DirPort_lines,
new_options->DirPort_lines) ||
old_options->ClientOnly != new_options->ClientOnly ||
old_options->DisableNetwork != new_options->DisableNetwork ||
- old_options->_PublishServerDescriptor !=
- new_options->_PublishServerDescriptor ||
+ old_options->PublishServerDescriptor_ !=
+ new_options->PublishServerDescriptor_ ||
get_effective_bwrate(old_options) != get_effective_bwrate(new_options) ||
get_effective_bwburst(old_options) !=
get_effective_bwburst(new_options) ||
@@ -4531,7 +3565,7 @@ find_torrc_filename(int argc, char **argv,
for (i = 1; i < argc; ++i) {
if (i < argc-1 && !strcmp(argv[i],fname_opt)) {
if (fname) {
- log(LOG_WARN, LD_CONFIG, "Duplicate %s options on command line.",
+ log_warn(LD_CONFIG, "Duplicate %s options on command line.",
fname_opt);
tor_free(fname);
}
@@ -4594,7 +3628,7 @@ load_torrc_from_disk(int argc, char **argv, int defaults_file)
fname = find_torrc_filename(argc, argv, defaults_file,
&using_default_torrc, &ignore_missing_torrc);
tor_assert(fname);
- log(LOG_DEBUG, LD_CONFIG, "Opening config file \"%s\"", fname);
+ log_debug(LD_CONFIG, "Opening config file \"%s\"", fname);
tor_free(*fname_var);
*fname_var = fname;
@@ -4604,18 +3638,18 @@ load_torrc_from_disk(int argc, char **argv, int defaults_file)
!(cf = read_file_to_str(fname,0,NULL))) {
if (using_default_torrc == 1 || ignore_missing_torrc) {
if (!defaults_file)
- log(LOG_NOTICE, LD_CONFIG, "Configuration file \"%s\" not present, "
+ log_notice(LD_CONFIG, "Configuration file \"%s\" not present, "
"using reasonable defaults.", fname);
tor_free(fname); /* sets fname to NULL */
*fname_var = NULL;
cf = tor_strdup("");
} else {
- log(LOG_WARN, LD_CONFIG,
+ log_warn(LD_CONFIG,
"Unable to open configuration file \"%s\".", fname);
goto err;
}
} else {
- log(LOG_NOTICE, LD_CONFIG, "Read configuration file \"%s\".", fname);
+ log_notice(LD_CONFIG, "Read configuration file \"%s\".", fname);
}
return cf;
@@ -4691,6 +3725,7 @@ options_init_from_torrc(int argc, char **argv)
}
if (command == CMD_HASH_PASSWORD) {
+ cf_defaults = tor_strdup("");
cf = tor_strdup("");
} else {
cf_defaults = load_torrc_from_disk(argc, argv, 1);
@@ -4707,7 +3742,7 @@ options_init_from_torrc(int argc, char **argv)
tor_free(cf);
tor_free(cf_defaults);
if (errmsg) {
- log(LOG_WARN,LD_CONFIG,"%s", errmsg);
+ log_warn(LD_CONFIG,"%s", errmsg);
tor_free(errmsg);
}
return retval < 0 ? -1 : 0;
@@ -4737,7 +3772,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
this is the first time we run*/
newoptions = tor_malloc_zero(sizeof(or_options_t));
- newoptions->_magic = OR_OPTIONS_MAGIC;
+ newoptions->magic_ = OR_OPTIONS_MAGIC;
options_init(newoptions);
newoptions->command = command;
newoptions->command_arg = command_arg;
@@ -4759,7 +3794,11 @@ options_init_from_string(const char *cf_defaults, const char *cf,
goto err;
}
if (i==0)
- newdefaultoptions = options_dup(&options_format, newoptions);
+ newdefaultoptions = config_dup(&options_format, newoptions);
+ }
+
+ if (newdefaultoptions == NULL) {
+ newdefaultoptions = config_dup(&options_format, global_default_options);
}
/* Go through command-line variables too */
@@ -4797,7 +3836,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
config_free(&options_format, newdefaultoptions);
newdefaultoptions = NULL;
newoptions = tor_malloc_zero(sizeof(or_options_t));
- newoptions->_magic = OR_OPTIONS_MAGIC;
+ newoptions->magic_ = OR_OPTIONS_MAGIC;
options_init(newoptions);
newoptions->command = command;
newoptions->command_arg = command_arg;
@@ -4820,7 +3859,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
goto err;
}
if (i==0)
- newdefaultoptions = options_dup(&options_format, newoptions);
+ newdefaultoptions = config_dup(&options_format, newoptions);
}
/* Assign command-line variables a second time too */
retval = config_assign(&options_format, newoptions,
@@ -5154,8 +4193,8 @@ parse_bridge_line(const char *line, int validate_only)
}
if (!validate_only) {
- log_debug(LD_DIR, "Bridge at %s:%d (transport: %s) (%s)",
- fmt_addr(&addr), (int)port,
+ log_debug(LD_DIR, "Bridge at %s (transport: %s) (%s)",
+ fmt_addrport(&addr, port),
transport_name ? transport_name : "no transport",
fingerprint ? fingerprint : "no key listed");
bridge_add_from_config(&addr, port,
@@ -5288,8 +4327,8 @@ parse_client_transport_line(const char *line, int validate_only)
transport_add_from_config(&addr, port, smartlist_get(transport_list, 0),
socks_ver);
- log_info(LD_DIR, "Transport '%s' found at %s:%d",
- transports, fmt_addr(&addr), (int)port);
+ log_info(LD_DIR, "Transport '%s' found at %s",
+ transports, fmt_addrport(&addr, port));
}
}
@@ -5310,6 +4349,80 @@ parse_client_transport_line(const char *line, int validate_only)
return r;
}
+/** Given a ServerTransportListenAddr <b>line</b>, return its
+ * <address:port> string. Return NULL if the line was not
+ * well-formed.
+ *
+ * If <b>transport</b> is set, return NULL if the line is not
+ * referring to <b>transport</b>.
+ *
+ * The returned string is allocated on the heap and it's the
+ * responsibility of the caller to free it. */
+static char *
+get_bindaddr_from_transport_listen_line(const char *line,const char *transport)
+{
+ smartlist_t *items = NULL;
+ const char *parsed_transport = NULL;
+ char *addrport = NULL;
+ tor_addr_t addr;
+ uint16_t port = 0;
+
+ items = smartlist_new();
+ smartlist_split_string(items, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(items) < 2) {
+ log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line.");
+ goto err;
+ }
+
+ parsed_transport = smartlist_get(items, 0);
+ addrport = tor_strdup(smartlist_get(items, 1));
+
+ /* If 'transport' is given, check if it matches the one on the line */
+ if (transport && strcmp(transport, parsed_transport))
+ goto err;
+
+ /* Validate addrport */
+ if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port)<0) {
+ log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr "
+ "address '%s'", addrport);
+ goto err;
+ }
+
+ goto done;
+
+ err:
+ tor_free(addrport);
+ addrport = NULL;
+
+ done:
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+
+ return addrport;
+}
+
+/** Given the name of a pluggable transport in <b>transport</b>, check
+ * the configuration file to see if the user has explicitly asked for
+ * it to listen on a specific port. Return a <address:port> string if
+ * so, otherwise NULL. */
+char *
+get_transport_bindaddr_from_config(const char *transport)
+{
+ config_line_t *cl;
+ const or_options_t *options = get_options();
+
+ for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
+ char *bindaddr =
+ get_bindaddr_from_transport_listen_line(cl->value, transport);
+ if (bindaddr)
+ return bindaddr;
+ }
+
+ return NULL;
+}
+
/** Read the contents of a ServerTransportPlugin line from
* <b>line</b>. Return 0 if the line is well-formed, and -1 if it
* isn't.
@@ -5408,8 +4521,8 @@ parse_server_transport_line(const char *line, int validate_only)
}
if (!validate_only) {
- log_info(LD_DIR, "Server transport '%s' at %s:%d.",
- transports, fmt_addr(&addr), (int)port);
+ log_info(LD_DIR, "Server transport '%s' at %s.",
+ transports, fmt_addrport(&addr, port));
}
}
@@ -5430,15 +4543,15 @@ parse_server_transport_line(const char *line, int validate_only)
return r;
}
-/** Read the contents of a DirServer line from <b>line</b>. If
+/** Read the contents of a DirAuthority line from <b>line</b>. If
* <b>validate_only</b> is 0, and the line is well-formed, and it
* shares any bits with <b>required_type</b> or <b>required_type</b>
* is 0, then add the dirserver described in the line (minus whatever
* bits it's missing) as a valid authority. Return 0 on success,
* or -1 if the line isn't well-formed or if we can't add it. */
static int
-parse_dir_server_line(const char *line, dirinfo_type_t required_type,
- int validate_only)
+parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
+ int validate_only)
{
smartlist_t *items = NULL;
int r;
@@ -5448,12 +4561,13 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
char v3_digest[DIGEST_LEN];
dirinfo_type_t type = V2_DIRINFO;
int is_not_hidserv_authority = 0, is_not_v2_authority = 0;
+ double weight = 1.0;
items = smartlist_new();
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
if (smartlist_len(items) < 1) {
- log_warn(LD_CONFIG, "No arguments on DirServer line.");
+ log_warn(LD_CONFIG, "No arguments on DirAuthority line.");
goto err;
}
@@ -5481,19 +4595,27 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
char *portstring = flag + strlen("orport=");
or_port = (uint16_t) tor_parse_long(portstring, 10, 1, 65535, &ok, NULL);
if (!ok)
- log_warn(LD_CONFIG, "Invalid orport '%s' on DirServer line.",
+ log_warn(LD_CONFIG, "Invalid orport '%s' on DirAuthority line.",
portstring);
+ } else if (!strcmpstart(flag, "weight=")) {
+ int ok;
+ const char *wstring = flag + strlen("weight=");
+ weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_CONFIG, "Invalid weight '%s' on DirAuthority line.",flag);
+ weight=1.0;
+ }
} else if (!strcasecmpstart(flag, "v3ident=")) {
char *idstr = flag + strlen("v3ident=");
if (strlen(idstr) != HEX_DIGEST_LEN ||
base16_decode(v3_digest, DIGEST_LEN, idstr, HEX_DIGEST_LEN)<0) {
- log_warn(LD_CONFIG, "Bad v3 identity digest '%s' on DirServer line",
+ log_warn(LD_CONFIG, "Bad v3 identity digest '%s' on DirAuthority line",
flag);
} else {
type |= V3_DIRINFO|EXTRAINFO_DIRINFO|MICRODESC_DIRINFO;
}
} else {
- log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirServer line",
+ log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirAuthority line",
flag);
}
tor_free(flag);
@@ -5505,24 +4627,24 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
type &= ~V2_DIRINFO;
if (smartlist_len(items) < 2) {
- log_warn(LD_CONFIG, "Too few arguments to DirServer line.");
+ log_warn(LD_CONFIG, "Too few arguments to DirAuthority line.");
goto err;
}
addrport = smartlist_get(items, 0);
smartlist_del_keeporder(items, 0);
if (addr_port_lookup(LOG_WARN, addrport, &address, NULL, &dir_port)<0) {
- log_warn(LD_CONFIG, "Error parsing DirServer address '%s'", addrport);
+ log_warn(LD_CONFIG, "Error parsing DirAuthority address '%s'", addrport);
goto err;
}
if (!dir_port) {
- log_warn(LD_CONFIG, "Missing port in DirServer address '%s'",addrport);
+ log_warn(LD_CONFIG, "Missing port in DirAuthority address '%s'",addrport);
goto err;
}
fingerprint = smartlist_join_strings(items, "", 0, NULL);
if (strlen(fingerprint) != HEX_DIGEST_LEN) {
- log_warn(LD_CONFIG, "Key digest for DirServer is wrong length %d.",
- (int)strlen(fingerprint));
+ log_warn(LD_CONFIG, "Key digest '%s' for DirAuthority is wrong length %d.",
+ fingerprint, (int)strlen(fingerprint));
goto err;
}
if (!strcmp(fingerprint, "E623F7625FBE0C87820F11EC5F6D5377ED816294")) {
@@ -5534,19 +4656,21 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
goto err;
}
if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) {
- log_warn(LD_CONFIG, "Unable to decode DirServer key digest.");
+ log_warn(LD_CONFIG, "Unable to decode DirAuthority key digest.");
goto err;
}
if (!validate_only && (!required_type || required_type & type)) {
+ dir_server_t *ds;
if (required_type)
type &= required_type; /* pare down what we think of them as an
* authority for. */
log_debug(LD_DIR, "Trusted %d dirserver at %s:%d (%s)", (int)type,
address, (int)dir_port, (char*)smartlist_get(items,0));
- if (!add_trusted_dir_server(nickname, address, dir_port, or_port,
- digest, v3_digest, type))
+ if (!(ds = trusted_dir_server_new(nickname, address, dir_port, or_port,
+ digest, v3_digest, type, weight)))
goto err;
+ dir_server_add(ds);
}
r = 0;
@@ -5565,6 +4689,110 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
return r;
}
+/** Read the contents of a FallbackDir line from <b>line</b>. If
+ * <b>validate_only</b> is 0, and the line is well-formed, then add the
+ * dirserver described in the line as a fallback directory. Return 0 on
+ * success, or -1 if the line isn't well-formed or if we can't add it. */
+static int
+parse_dir_fallback_line(const char *line,
+ int validate_only)
+{
+ int r = -1;
+ smartlist_t *items = smartlist_new(), *positional = smartlist_new();
+ int orport = -1;
+ uint16_t dirport;
+ tor_addr_t addr;
+ int ok;
+ char id[DIGEST_LEN];
+ char *address=NULL;
+ double weight=1.0;
+
+ memset(id, 0, sizeof(id));
+ smartlist_split_string(items, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+ SMARTLIST_FOREACH_BEGIN(items, const char *, cp) {
+ const char *eq = strchr(cp, '=');
+ ok = 1;
+ if (! eq) {
+ smartlist_add(positional, (char*)cp);
+ continue;
+ }
+ if (!strcmpstart(cp, "orport=")) {
+ orport = (int)tor_parse_long(cp+strlen("orport="), 10,
+ 1, 65535, &ok, NULL);
+ } else if (!strcmpstart(cp, "id=")) {
+ ok = !base16_decode(id, DIGEST_LEN,
+ cp+strlen("id="), strlen(cp)-strlen("id="));
+ } else if (!strcmpstart(cp, "weight=")) {
+ int ok;
+ const char *wstring = cp + strlen("weight=");
+ weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_CONFIG, "Invalid weight '%s' on FallbackDir line.", cp);
+ weight=1.0;
+ }
+ }
+
+ if (!ok) {
+ log_warn(LD_CONFIG, "Bad FallbackDir option %s", escaped(cp));
+ goto end;
+ }
+ } SMARTLIST_FOREACH_END(cp);
+
+ if (smartlist_len(positional) != 1) {
+ log_warn(LD_CONFIG, "Couldn't parse FallbackDir line %s", escaped(line));
+ goto end;
+ }
+
+ if (tor_digest_is_zero(id)) {
+ log_warn(LD_CONFIG, "Missing identity on FallbackDir line");
+ goto end;
+ }
+
+ if (orport <= 0) {
+ log_warn(LD_CONFIG, "Missing orport on FallbackDir line");
+ goto end;
+ }
+
+ if (tor_addr_port_split(LOG_INFO, smartlist_get(positional, 0),
+ &address, &dirport) < 0 ||
+ tor_addr_parse(&addr, address)<0) {
+ log_warn(LD_CONFIG, "Couldn't parse address:port %s on FallbackDir line",
+ (const char*)smartlist_get(positional, 0));
+ goto end;
+ }
+
+ if (!validate_only) {
+ dir_server_t *ds;
+ ds = fallback_dir_server_new(&addr, dirport, orport, id, weight);
+ if (!ds) {
+ log_warn(LD_CONFIG, "Couldn't create FallbackDir %s", escaped(line));
+ goto end;
+ }
+ dir_server_add(ds);
+ }
+
+ r = 0;
+
+ end:
+ SMARTLIST_FOREACH(items, char *, cp, tor_free(cp));
+ smartlist_free(items);
+ smartlist_free(positional);
+ tor_free(address);
+ return r;
+}
+
+/** Allocate and return a new port_cfg_t with reasonable defaults. */
+static port_cfg_t *
+port_cfg_new(void)
+{
+ port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
+ cfg->ipv4_traffic = 1;
+ cfg->cache_ipv4_answers = 1;
+ cfg->prefer_ipv6_virtaddr = 1;
+ return cfg;
+}
+
/** Free all storage held in <b>port</b> */
static void
port_cfg_free(port_cfg_t *port)
@@ -5572,24 +4800,29 @@ port_cfg_free(port_cfg_t *port)
tor_free(port);
}
-/** Warn for every port in <b>ports</b> that is on a publicly routable
- * address. */
+/** Warn for every port in <b>ports</b> of type <b>listener_type</b> that is
+ * on a publicly routable address. */
static void
-warn_nonlocal_client_ports(const smartlist_t *ports, const char *portname)
+warn_nonlocal_client_ports(const smartlist_t *ports, const char *portname,
+ int listener_type)
{
SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
+ if (port->type != listener_type)
+ continue;
if (port->is_unix_addr) {
/* Unix sockets aren't accessible over a network. */
} else if (!tor_addr_is_internal(&port->addr, 1)) {
- log_warn(LD_CONFIG, "You specified a public address for %sPort. "
+ log_warn(LD_CONFIG, "You specified a public address '%s' for %sPort. "
"Other people on the Internet might find your computer and "
"use it as an open proxy. Please don't allow this unless you "
- "have a good reason.", portname);
+ "have a good reason.",
+ fmt_addrport(&port->addr, port->port), portname);
} else if (!tor_addr_is_loopback(&port->addr)) {
- log_notice(LD_CONFIG, "You configured a non-loopback address for "
- "%sPort. This allows everybody on your local network to use "
- "your machine as a proxy. Make sure this is what you wanted.",
- portname);
+ log_notice(LD_CONFIG, "You configured a non-loopback address '%s' "
+ "for %sPort. This allows everybody on your local network to "
+ "use your machine as a proxy. Make sure this is what you "
+ "wanted.",
+ fmt_addrport(&port->addr, port->port), portname);
}
} SMARTLIST_FOREACH_END(port);
}
@@ -5641,6 +4874,7 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
#define CL_PORT_ALLOW_EXTRA_LISTENADDR (1u<<2)
#define CL_PORT_SERVER_OPTIONS (1u<<3)
#define CL_PORT_FORBID_NONLOCAL (1u<<4)
+#define CL_PORT_TAKES_HOSTNAMES (1u<<5)
/**
* Parse port configuration for a single port type.
@@ -5673,6 +4907,9 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
* isolation options in the FooPort entries; instead allow the
* server-port option set.
*
+ * If CL_PORT_TAKES_HOSTNAMES is set in <b>flags</b>, allow the options
+ * {No,}IPv{4,6}Traffic.
+ *
* On success, if <b>out</b> is given, add a new port_cfg_t entry to
* <b>out</b> for every port that the client should listen on. Return 0
* on success, -1 on failure.
@@ -5696,6 +4933,7 @@ parse_port_config(smartlist_t *out,
const unsigned forbid_nonlocal = flags & CL_PORT_FORBID_NONLOCAL;
const unsigned allow_spurious_listenaddr =
flags & CL_PORT_ALLOW_EXTRA_LISTENADDR;
+ const unsigned takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES;
int got_zero_port=0, got_nonzero_port=0;
/* FooListenAddress is deprecated; let's make it work like it used to work,
@@ -5732,12 +4970,14 @@ parse_port_config(smartlist_t *out,
if (use_server_options && out) {
/* Add a no_listen port. */
- port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
+ port_cfg_t *cfg = port_cfg_new();
cfg->type = listener_type;
cfg->port = mainport;
tor_addr_make_unspec(&cfg->addr); /* Server ports default to 0.0.0.0 */
cfg->no_listen = 1;
- cfg->ipv4_only = 1;
+ cfg->bind_ipv4_only = 1;
+ cfg->ipv4_traffic = 1;
+ cfg->prefer_ipv6_virtaddr = 1;
smartlist_add(out, cfg);
}
@@ -5750,7 +4990,7 @@ parse_port_config(smartlist_t *out,
return -1;
}
if (out) {
- port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
+ port_cfg_t *cfg = port_cfg_new();
cfg->type = listener_type;
cfg->port = port ? port : mainport;
tor_addr_copy(&cfg->addr, &addr);
@@ -5765,7 +5005,7 @@ parse_port_config(smartlist_t *out,
if (is_control)
warn_nonlocal_controller_ports(out, forbid_nonlocal);
else
- warn_nonlocal_client_ports(out, portname);
+ warn_nonlocal_client_ports(out, portname, listener_type);
}
return 0;
} /* end if (listenaddrs) */
@@ -5774,7 +5014,7 @@ parse_port_config(smartlist_t *out,
* one. */
if (! ports) {
if (defaultport && out) {
- port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
+ port_cfg_t *cfg = port_cfg_new();
cfg->type = listener_type;
cfg->port = defaultport;
tor_addr_parse(&cfg->addr, defaultaddr);
@@ -5794,12 +5034,17 @@ parse_port_config(smartlist_t *out,
int port;
int sessiongroup = SESSION_GROUP_UNSET;
unsigned isolation = ISO_DEFAULT;
+ int prefer_no_auth = 0;
char *addrport;
uint16_t ptmp=0;
int ok;
int no_listen = 0, no_advertise = 0, all_addrs = 0,
- ipv4_only = 0, ipv6_only = 0;
+ bind_ipv4_only = 0, bind_ipv6_only = 0,
+ ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0,
+ cache_ipv4 = 1, use_cached_ipv4 = 0,
+ cache_ipv6 = 0, use_cached_ipv6 = 0,
+ prefer_ipv6_automap = 1;
smartlist_split_string(elts, ports->value, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
@@ -5864,9 +5109,9 @@ parse_port_config(smartlist_t *out,
all_addrs = 1;
#endif
} else if (!strcasecmp(elt, "IPv4Only")) {
- ipv4_only = 1;
+ bind_ipv4_only = 1;
} else if (!strcasecmp(elt, "IPv6Only")) {
- ipv6_only = 1;
+ bind_ipv6_only = 1;
} else {
log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'",
portname, escaped(elt));
@@ -5879,18 +5124,18 @@ parse_port_config(smartlist_t *out,
portname, escaped(ports->value));
goto err;
}
- if (ipv4_only && ipv6_only) {
+ if (bind_ipv4_only && bind_ipv6_only) {
log_warn(LD_CONFIG, "Tried to set both IPv4Only and IPv6Only "
"on %sPort line '%s'",
portname, escaped(ports->value));
goto err;
}
- if (ipv4_only && tor_addr_family(&addr) == AF_INET6) {
+ if (bind_ipv4_only && tor_addr_family(&addr) == AF_INET6) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
portname);
goto err;
}
- if (ipv6_only && tor_addr_family(&addr) == AF_INET) {
+ if (bind_ipv6_only && tor_addr_family(&addr) == AF_INET) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
portname);
goto err;
@@ -5923,6 +5168,45 @@ parse_port_config(smartlist_t *out,
no = 1;
elt += 2;
}
+
+ if (takes_hostnames) {
+ if (!strcasecmp(elt, "IPv4Traffic")) {
+ ipv4_traffic = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "IPv6Traffic")) {
+ ipv6_traffic = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "PreferIPv6")) {
+ prefer_ipv6 = ! no;
+ continue;
+ }
+ }
+ if (!strcasecmp(elt, "CacheIPv4DNS")) {
+ cache_ipv4 = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "CacheIPv6DNS")) {
+ cache_ipv6 = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "CacheDNS")) {
+ cache_ipv4 = cache_ipv6 = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "UseIPv4Cache")) {
+ use_cached_ipv4 = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "UseIPv6Cache")) {
+ use_cached_ipv6 = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "UseDNSCache")) {
+ use_cached_ipv4 = use_cached_ipv6 = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "PreferIPv6Automap")) {
+ prefer_ipv6_automap = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "PreferSOCKSNoAuth")) {
+ prefer_no_auth = ! no;
+ continue;
+ }
+
if (!strcasecmpend(elt, "s"))
elt[strlen(elt)-1] = '\0'; /* kill plurals. */
@@ -5954,8 +5238,14 @@ parse_port_config(smartlist_t *out,
else
got_zero_port = 1;
+ if (ipv4_traffic == 0 && ipv6_traffic == 0) {
+ log_warn(LD_CONFIG, "You have a %sPort entry with both IPv4 and "
+ "IPv6 disabled; that won't work.", portname);
+ goto err;
+ }
+
if (out && port) {
- port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
+ port_cfg_t *cfg = port_cfg_new();
tor_addr_copy(&cfg->addr, &addr);
cfg->port = port;
cfg->type = listener_type;
@@ -5964,8 +5254,19 @@ parse_port_config(smartlist_t *out,
cfg->no_advertise = no_advertise;
cfg->no_listen = no_listen;
cfg->all_addrs = all_addrs;
- cfg->ipv4_only = ipv4_only;
- cfg->ipv6_only = ipv6_only;
+ cfg->bind_ipv4_only = bind_ipv4_only;
+ cfg->bind_ipv6_only = bind_ipv6_only;
+ cfg->ipv4_traffic = ipv4_traffic;
+ cfg->ipv6_traffic = ipv6_traffic;
+ cfg->prefer_ipv6 = prefer_ipv6;
+ cfg->cache_ipv4_answers = cache_ipv4;
+ cfg->cache_ipv6_answers = cache_ipv6;
+ cfg->use_cached_ipv4_answers = use_cached_ipv4;
+ cfg->use_cached_ipv6_answers = use_cached_ipv6;
+ cfg->prefer_ipv6_virtaddr = prefer_ipv6_automap;
+ cfg->socks_prefer_no_auth = prefer_no_auth;
+ if (! (isolation & ISO_SOCKSAUTH))
+ cfg->socks_prefer_no_auth = 1;
smartlist_add(out, cfg);
}
@@ -5977,7 +5278,7 @@ parse_port_config(smartlist_t *out,
if (is_control)
warn_nonlocal_controller_ports(out, forbid_nonlocal);
else
- warn_nonlocal_client_ports(out, portname);
+ warn_nonlocal_client_ports(out, portname, listener_type);
}
if (got_zero_port && got_nonzero_port) {
@@ -6058,7 +5359,8 @@ parse_ports(or_options_t *options, int validate_only,
options->SocksPort_lines, options->SocksListenAddress,
"Socks", CONN_TYPE_AP_LISTENER,
"127.0.0.1", 9050,
- CL_PORT_WARN_NONLOCAL|CL_PORT_ALLOW_EXTRA_LISTENADDR) < 0) {
+ CL_PORT_WARN_NONLOCAL|CL_PORT_ALLOW_EXTRA_LISTENADDR|
+ CL_PORT_TAKES_HOSTNAMES) < 0) {
*msg = tor_strdup("Invalid SocksPort/SocksListenAddress configuration");
goto err;
}
@@ -6066,7 +5368,7 @@ parse_ports(or_options_t *options, int validate_only,
options->DNSPort_lines, options->DNSListenAddress,
"DNS", CONN_TYPE_AP_DNS_LISTENER,
"127.0.0.1", 0,
- CL_PORT_WARN_NONLOCAL) < 0) {
+ CL_PORT_WARN_NONLOCAL|CL_PORT_TAKES_HOSTNAMES) < 0) {
*msg = tor_strdup("Invalid DNSPort/DNSListenAddress configuration");
goto err;
}
@@ -6198,7 +5500,8 @@ check_server_ports(const smartlist_t *ports,
if (! port->no_advertise) {
++n_orport_advertised;
if (tor_addr_family(&port->addr) == AF_INET ||
- (tor_addr_family(&port->addr) == AF_UNSPEC && !port->ipv6_only))
+ (tor_addr_family(&port->addr) == AF_UNSPEC &&
+ !port->bind_ipv6_only))
++n_orport_advertised_ipv4;
}
if (! port->no_listen)
@@ -6207,7 +5510,7 @@ check_server_ports(const smartlist_t *ports,
continue;
}
#ifndef _WIN32
- if (!port->no_advertise && port->port < 1024)
+ if (!port->no_listen && port->port < 1024)
++n_low_port;
#endif
} SMARTLIST_FOREACH_END(port);
@@ -6217,6 +5520,13 @@ check_server_ports(const smartlist_t *ports,
"listening on one.");
r = -1;
}
+ if (n_orport_listeners && !n_orport_advertised) {
+ log_warn(LD_CONFIG, "We are listening on an ORPort, but not advertising "
+ "any ORPorts. This will keep us from building a %s "
+ "descriptor, and make us impossible to use.",
+ options->BridgeRelay ? "bridge" : "router");
+ r = -1;
+ }
if (n_dirport_advertised && !n_dirport_listeners) {
log_warn(LD_CONFIG, "We are advertising a DirPort, but not actually "
"listening on one.");
@@ -6234,7 +5544,7 @@ check_server_ports(const smartlist_t *ports,
}
if (n_low_port && options->AccountingMax) {
- log(LOG_WARN, LD_CONFIG,
+ log_warn(LD_CONFIG,
"You have set AccountingMax to use hibernation. You have also "
"chosen a low DirPort or OrPort. This combination can make Tor stop "
"working when it tries to re-attach the port after a period of "
@@ -6298,7 +5608,8 @@ get_first_listener_addrport_string(int listener_type)
to iterate all listener connections and find out in which
port it ended up listening: */
if (cfg->port == CFG_AUTO_PORT) {
- port = router_get_active_listener_port_by_type(listener_type);
+ port = router_get_active_listener_port_by_type_af(listener_type,
+ tor_addr_family(&cfg->addr));
if (!port)
return NULL;
} else {
@@ -6328,8 +5639,8 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family)
(tor_addr_family(&cfg->addr) == address_family ||
tor_addr_family(&cfg->addr) == AF_UNSPEC)) {
if (tor_addr_family(&cfg->addr) != AF_UNSPEC ||
- (address_family == AF_INET && !cfg->ipv6_only) ||
- (address_family == AF_INET6 && !cfg->ipv4_only)) {
+ (address_family == AF_INET && !cfg->bind_ipv6_only) ||
+ (address_family == AF_INET6 && !cfg->bind_ipv4_only)) {
return cfg->port;
}
}
@@ -6490,180 +5801,6 @@ options_save_current(void)
return write_configuration_file(get_torrc_fname(0), get_options());
}
-/** Mapping from a unit name to a multiplier for converting that unit into a
- * base unit. Used by config_parse_unit. */
-struct unit_table_t {
- const char *unit; /**< The name of the unit */
- uint64_t multiplier; /**< How many of the base unit appear in this unit */
-};
-
-/** Table to map the names of memory units to the number of bytes they
- * contain. */
-static struct unit_table_t memory_units[] = {
- { "", 1 },
- { "b", 1<< 0 },
- { "byte", 1<< 0 },
- { "bytes", 1<< 0 },
- { "kb", 1<<10 },
- { "kbyte", 1<<10 },
- { "kbytes", 1<<10 },
- { "kilobyte", 1<<10 },
- { "kilobytes", 1<<10 },
- { "m", 1<<20 },
- { "mb", 1<<20 },
- { "mbyte", 1<<20 },
- { "mbytes", 1<<20 },
- { "megabyte", 1<<20 },
- { "megabytes", 1<<20 },
- { "gb", 1<<30 },
- { "gbyte", 1<<30 },
- { "gbytes", 1<<30 },
- { "gigabyte", 1<<30 },
- { "gigabytes", 1<<30 },
- { "tb", U64_LITERAL(1)<<40 },
- { "terabyte", U64_LITERAL(1)<<40 },
- { "terabytes", U64_LITERAL(1)<<40 },
- { NULL, 0 },
-};
-
-/** Table to map the names of time units to the number of seconds they
- * contain. */
-static struct unit_table_t time_units[] = {
- { "", 1 },
- { "second", 1 },
- { "seconds", 1 },
- { "minute", 60 },
- { "minutes", 60 },
- { "hour", 60*60 },
- { "hours", 60*60 },
- { "day", 24*60*60 },
- { "days", 24*60*60 },
- { "week", 7*24*60*60 },
- { "weeks", 7*24*60*60 },
- { NULL, 0 },
-};
-
-/** Table to map the names of time units to the number of milliseconds
- * they contain. */
-static struct unit_table_t time_msec_units[] = {
- { "", 1 },
- { "msec", 1 },
- { "millisecond", 1 },
- { "milliseconds", 1 },
- { "second", 1000 },
- { "seconds", 1000 },
- { "minute", 60*1000 },
- { "minutes", 60*1000 },
- { "hour", 60*60*1000 },
- { "hours", 60*60*1000 },
- { "day", 24*60*60*1000 },
- { "days", 24*60*60*1000 },
- { "week", 7*24*60*60*1000 },
- { "weeks", 7*24*60*60*1000 },
- { NULL, 0 },
-};
-
-/** Parse a string <b>val</b> containing a number, zero or more
- * spaces, and an optional unit string. If the unit appears in the
- * table <b>u</b>, then multiply the number by the unit multiplier.
- * On success, set *<b>ok</b> to 1 and return this product.
- * Otherwise, set *<b>ok</b> to 0.
- */
-static uint64_t
-config_parse_units(const char *val, struct unit_table_t *u, int *ok)
-{
- uint64_t v = 0;
- double d = 0;
- int use_float = 0;
- char *cp;
-
- tor_assert(ok);
-
- v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp);
- if (!*ok || (cp && *cp == '.')) {
- d = tor_parse_double(val, 0, UINT64_MAX, ok, &cp);
- if (!*ok)
- goto done;
- use_float = 1;
- }
-
- if (!cp) {
- *ok = 1;
- v = use_float ? DBL_TO_U64(d) : v;
- goto done;
- }
-
- cp = (char*) eat_whitespace(cp);
-
- for ( ;u->unit;++u) {
- if (!strcasecmp(u->unit, cp)) {
- if (use_float)
- v = u->multiplier * d;
- else
- v *= u->multiplier;
- *ok = 1;
- goto done;
- }
- }
- log_warn(LD_CONFIG, "Unknown unit '%s'.", cp);
- *ok = 0;
- done:
-
- if (*ok)
- return v;
- else
- return 0;
-}
-
-/** Parse a string in the format "number unit", where unit is a unit of
- * information (byte, KB, M, etc). On success, set *<b>ok</b> to true
- * and return the number of bytes specified. Otherwise, set
- * *<b>ok</b> to false and return 0. */
-static uint64_t
-config_parse_memunit(const char *s, int *ok)
-{
- uint64_t u = config_parse_units(s, memory_units, ok);
- return u;
-}
-
-/** Parse a string in the format "number unit", where unit is a unit of
- * time in milliseconds. On success, set *<b>ok</b> to true and return
- * the number of milliseconds in the provided interval. Otherwise, set
- * *<b>ok</b> to 0 and return -1. */
-static int
-config_parse_msec_interval(const char *s, int *ok)
-{
- uint64_t r;
- r = config_parse_units(s, time_msec_units, ok);
- if (!ok)
- return -1;
- if (r > INT_MAX) {
- log_warn(LD_CONFIG, "Msec interval '%s' is too long", s);
- *ok = 0;
- return -1;
- }
- return (int)r;
-}
-
-/** Parse a string in the format "number unit", where unit is a unit of time.
- * On success, set *<b>ok</b> to true and return the number of seconds in
- * the provided interval. Otherwise, set *<b>ok</b> to 0 and return -1.
- */
-static int
-config_parse_interval(const char *s, int *ok)
-{
- uint64_t r;
- r = config_parse_units(s, time_units, ok);
- if (!ok)
- return -1;
- if (r > INT_MAX) {
- log_warn(LD_CONFIG, "Interval '%s' is too long", s);
- *ok = 0;
- return -1;
- }
- return (int)r;
-}
-
/** Return the number of cpus configured in <b>options</b>. If we are
* told to auto-detect the number of cpus, return the auto-detected number. */
int
@@ -6717,14 +5854,6 @@ init_libevent(const or_options_t *options)
}
}
-/** Return the persistent state struct for this Tor. */
-or_state_t *
-get_or_state(void)
-{
- tor_assert(global_state);
- return global_state;
-}
-
/** Return a newly allocated string holding a filename relative to the data
* directory. If <b>sub1</b> is present, it is the first path component after
* the data directory. If <b>sub2</b> is also present, it is the second path
@@ -6775,474 +5904,6 @@ options_get_datadir_fname2_suffix(const or_options_t *options,
return fname;
}
-/** Return true if <b>line</b> is a valid state TransportProxy line.
- * Return false otherwise. */
-static int
-state_transport_line_is_valid(const char *line)
-{
- smartlist_t *items = NULL;
- char *addrport=NULL;
- tor_addr_t addr;
- uint16_t port = 0;
- int r;
-
- items = smartlist_new();
- smartlist_split_string(items, line, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
-
- if (smartlist_len(items) != 2) {
- log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line.");
- goto err;
- }
-
- addrport = smartlist_get(items, 1);
- if (tor_addr_port_lookup(addrport, &addr, &port) < 0) {
- log_warn(LD_CONFIG, "state: Could not parse addrport.");
- goto err;
- }
-
- if (!port) {
- log_warn(LD_CONFIG, "state: Transport line did not contain port.");
- goto err;
- }
-
- r = 1;
- goto done;
-
- err:
- r = 0;
-
- done:
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
- return r;
-}
-
-/** Return 0 if all TransportProxy lines in <b>state</b> are well
- * formed. Otherwise, return -1. */
-static int
-validate_transports_in_state(or_state_t *state)
-{
- int broken = 0;
- config_line_t *line;
-
- for (line = state->TransportProxies ; line ; line = line->next) {
- tor_assert(!strcmp(line->key, "TransportProxy"));
- if (!state_transport_line_is_valid(line->value))
- broken = 1;
- }
-
- if (broken)
- log_warn(LD_CONFIG, "state: State file seems to be broken.");
-
- return 0;
-}
-
-/** Return 0 if every setting in <b>state</b> is reasonable, and a
- * permissible transition from <b>old_state</b>. Else warn and return -1.
- * Should have no side effects, except for normalizing the contents of
- * <b>state</b>.
- */
-/* XXX from_setconf is here because of bug 238 */
-static int
-or_state_validate(or_state_t *old_state, or_state_t *state,
- int from_setconf, char **msg)
-{
- /* We don't use these; only options do. Still, we need to match that
- * signature. */
- (void) from_setconf;
- (void) old_state;
-
- if (entry_guards_parse_state(state, 0, msg)<0)
- return -1;
-
- if (validate_transports_in_state(state)<0)
- return -1;
-
- return 0;
-}
-
-/** Replace the current persistent state with <b>new_state</b> */
-static int
-or_state_set(or_state_t *new_state)
-{
- char *err = NULL;
- int ret = 0;
- tor_assert(new_state);
- config_free(&state_format, global_state);
- global_state = new_state;
- if (entry_guards_parse_state(global_state, 1, &err)<0) {
- log_warn(LD_GENERAL,"%s",err);
- tor_free(err);
- ret = -1;
- }
- if (rep_hist_load_state(global_state, &err)<0) {
- log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
- tor_free(err);
- ret = -1;
- }
- if (circuit_build_times_parse_state(&circ_times, global_state) < 0) {
- ret = -1;
- }
- return ret;
-}
-
-/**
- * Save a broken state file to a backup location.
- */
-static void
-or_state_save_broken(char *fname)
-{
- int i;
- file_status_t status;
- char *fname2 = NULL;
- for (i = 0; i < 100; ++i) {
- tor_asprintf(&fname2, "%s.%d", fname, i);
- status = file_status(fname2);
- if (status == FN_NOENT)
- break;
- tor_free(fname2);
- }
- if (i == 100) {
- log_warn(LD_BUG, "Unable to parse state in \"%s\"; too many saved bad "
- "state files to move aside. Discarding the old state file.",
- fname);
- unlink(fname);
- } else {
- log_warn(LD_BUG, "Unable to parse state in \"%s\". Moving it aside "
- "to \"%s\". This could be a bug in Tor; please tell "
- "the developers.", fname, fname2);
- if (rename(fname, fname2) < 0) {
- log_warn(LD_BUG, "Weirdly, I couldn't even move the state aside. The "
- "OS gave an error of %s", strerror(errno));
- }
- }
- tor_free(fname2);
-}
-
-/** Reload the persistent state from disk, generating a new state as needed.
- * Return 0 on success, less than 0 on failure.
- */
-static int
-or_state_load(void)
-{
- or_state_t *new_state = NULL;
- char *contents = NULL, *fname;
- char *errmsg = NULL;
- int r = -1, badstate = 0;
-
- fname = get_datadir_fname("state");
- switch (file_status(fname)) {
- case FN_FILE:
- if (!(contents = read_file_to_str(fname, 0, NULL))) {
- log_warn(LD_FS, "Unable to read state file \"%s\"", fname);
- goto done;
- }
- break;
- case FN_NOENT:
- break;
- case FN_ERROR:
- case FN_DIR:
- default:
- log_warn(LD_GENERAL,"State file \"%s\" is not a file? Failing.", fname);
- goto done;
- }
- new_state = tor_malloc_zero(sizeof(or_state_t));
- new_state->_magic = OR_STATE_MAGIC;
- config_init(&state_format, new_state);
- if (contents) {
- config_line_t *lines=NULL;
- int assign_retval;
- if (config_get_lines(contents, &lines, 0)<0)
- goto done;
- assign_retval = config_assign(&state_format, new_state,
- lines, 0, 0, &errmsg);
- config_free_lines(lines);
- if (assign_retval<0)
- badstate = 1;
- if (errmsg) {
- log_warn(LD_GENERAL, "%s", errmsg);
- tor_free(errmsg);
- }
- }
-
- if (!badstate && or_state_validate(NULL, new_state, 1, &errmsg) < 0)
- badstate = 1;
-
- if (errmsg) {
- log_warn(LD_GENERAL, "%s", errmsg);
- tor_free(errmsg);
- }
-
- if (badstate && !contents) {
- log_warn(LD_BUG, "Uh oh. We couldn't even validate our own default state."
- " This is a bug in Tor.");
- goto done;
- } else if (badstate && contents) {
- or_state_save_broken(fname);
-
- tor_free(contents);
- config_free(&state_format, new_state);
-
- new_state = tor_malloc_zero(sizeof(or_state_t));
- new_state->_magic = OR_STATE_MAGIC;
- config_init(&state_format, new_state);
- } else if (contents) {
- log_info(LD_GENERAL, "Loaded state from \"%s\"", fname);
- } else {
- log_info(LD_GENERAL, "Initialized state");
- }
- if (or_state_set(new_state) == -1) {
- or_state_save_broken(fname);
- }
- new_state = NULL;
- if (!contents) {
- global_state->next_write = 0;
- or_state_save(time(NULL));
- }
- r = 0;
-
- done:
- tor_free(fname);
- tor_free(contents);
- if (new_state)
- config_free(&state_format, new_state);
-
- return r;
-}
-
-/** Did the last time we tried to write the state file fail? If so, we
- * should consider disabling such features as preemptive circuit generation
- * to compute circuit-build-time. */
-static int last_state_file_write_failed = 0;
-
-/** Return whether the state file failed to write last time we tried. */
-int
-did_last_state_file_write_fail(void)
-{
- return last_state_file_write_failed;
-}
-
-/** If writing the state to disk fails, try again after this many seconds. */
-#define STATE_WRITE_RETRY_INTERVAL 3600
-
-/** If we're a relay, how often should we checkpoint our state file even
- * if nothing else dirties it? This will checkpoint ongoing stats like
- * bandwidth used, per-country user stats, etc. */
-#define STATE_RELAY_CHECKPOINT_INTERVAL (12*60*60)
-
-/** Write the persistent state to disk. Return 0 for success, <0 on failure. */
-int
-or_state_save(time_t now)
-{
- char *state, *contents;
- char tbuf[ISO_TIME_LEN+1];
- char *fname;
-
- tor_assert(global_state);
-
- if (global_state->next_write > now)
- return 0;
-
- /* Call everything else that might dirty the state even more, in order
- * to avoid redundant writes. */
- entry_guards_update_state(global_state);
- rep_hist_update_state(global_state);
- circuit_build_times_update_state(&circ_times, global_state);
- if (accounting_is_enabled(get_options()))
- accounting_run_housekeeping(now);
-
- global_state->LastWritten = now;
-
- tor_free(global_state->TorVersion);
- tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
-
- state = config_dump(&state_format, NULL, global_state, 1, 0);
- format_local_iso_time(tbuf, now);
- tor_asprintf(&contents,
- "# Tor state file last generated on %s local time\n"
- "# Other times below are in GMT\n"
- "# You *do not* need to edit this file.\n\n%s",
- tbuf, state);
- tor_free(state);
- fname = get_datadir_fname("state");
- if (write_str_to_file(fname, contents, 0)<0) {
- log_warn(LD_FS, "Unable to write state to file \"%s\"; "
- "will try again later", fname);
- last_state_file_write_failed = 1;
- tor_free(fname);
- tor_free(contents);
- /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state
- * changes sooner). */
- global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL;
- return -1;
- }
-
- last_state_file_write_failed = 0;
- log_info(LD_GENERAL, "Saved state to \"%s\"", fname);
- tor_free(fname);
- tor_free(contents);
-
- if (server_mode(get_options()))
- global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL;
- else
- global_state->next_write = TIME_MAX;
-
- return 0;
-}
-
-/** Return the config line for transport <b>transport</b> in the current state.
- * Return NULL if there is no config line for <b>transport</b>. */
-static config_line_t *
-get_transport_in_state_by_name(const char *transport)
-{
- or_state_t *or_state = get_or_state();
- config_line_t *line;
- config_line_t *ret = NULL;
- smartlist_t *items = NULL;
-
- for (line = or_state->TransportProxies ; line ; line = line->next) {
- tor_assert(!strcmp(line->key, "TransportProxy"));
-
- items = smartlist_new();
- smartlist_split_string(items, line->value, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
- if (smartlist_len(items) != 2) /* broken state */
- goto done;
-
- if (!strcmp(smartlist_get(items, 0), transport)) {
- ret = line;
- goto done;
- }
-
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
- items = NULL;
- }
-
- done:
- if (items) {
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
- }
- return ret;
-}
-
-/** Return string containing the address:port part of the
- * TransportProxy <b>line</b> for transport <b>transport</b>.
- * If the line is corrupted, return NULL. */
-static const char *
-get_transport_bindaddr(const char *line, const char *transport)
-{
- char *line_tmp = NULL;
-
- if (strlen(line) < strlen(transport) + 2) {
- goto broken_state;
- } else {
- /* line should start with the name of the transport and a space.
- (for example, "obfs2 127.0.0.1:47245") */
- tor_asprintf(&line_tmp, "%s ", transport);
- if (strcmpstart(line, line_tmp))
- goto broken_state;
-
- tor_free(line_tmp);
- return (line+strlen(transport)+1);
- }
-
- broken_state:
- tor_free(line_tmp);
- return NULL;
-}
-
-/** Return a string containing the address:port that a proxy transport
- * should bind on. The string is stored on the heap and must be freed
- * by the caller of this function. */
-char *
-get_stored_bindaddr_for_server_transport(const char *transport)
-{
- char *default_addrport = NULL;
- const char *stored_bindaddr = NULL;
-
- config_line_t *line = get_transport_in_state_by_name(transport);
- if (!line) /* Found no references in state for this transport. */
- goto no_bindaddr_found;
-
- stored_bindaddr = get_transport_bindaddr(line->value, transport);
- if (stored_bindaddr) /* found stored bindaddr in state file. */
- return tor_strdup(stored_bindaddr);
-
- no_bindaddr_found:
- /** If we didn't find references for this pluggable transport in the
- state file, we should instruct the pluggable transport proxy to
- listen on INADDR_ANY on a random ephemeral port. */
- tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0");
- return default_addrport;
-}
-
-/** Save <b>transport</b> listening on <b>addr</b>:<b>port</b> to
- state */
-void
-save_transport_to_state(const char *transport,
- const tor_addr_t *addr, uint16_t port)
-{
- or_state_t *state = get_or_state();
-
- char *transport_addrport=NULL;
-
- /** find where to write on the state */
- config_line_t **next, *line;
-
- /* see if this transport is already stored in state */
- config_line_t *transport_line =
- get_transport_in_state_by_name(transport);
-
- if (transport_line) { /* if transport already exists in state... */
- const char *prev_bindaddr = /* get its addrport... */
- get_transport_bindaddr(transport_line->value, transport);
- tor_asprintf(&transport_addrport, "%s:%d", fmt_addr(addr), (int)port);
-
- /* if transport in state has the same address as this one, life is good */
- if (!strcmp(prev_bindaddr, transport_addrport)) {
- log_info(LD_CONFIG, "Transport seems to have spawned on its usual "
- "address:port.");
- goto done;
- } else { /* if addrport in state is different than the one we got */
- log_info(LD_CONFIG, "Transport seems to have spawned on different "
- "address:port. Let's update the state file with the new "
- "address:port");
- tor_free(transport_line->value); /* free the old line */
- tor_asprintf(&transport_line->value, "%s %s:%d", transport,
- fmt_addr(addr),
- (int) port); /* replace old addrport line with new line */
- }
- } else { /* never seen this one before; save it in state for next time */
- log_info(LD_CONFIG, "It's the first time we see this transport. "
- "Let's save its address:port");
- next = &state->TransportProxies;
- /* find the last TransportProxy line in the state and point 'next'
- right after it */
- line = state->TransportProxies;
- while (line) {
- next = &(line->next);
- line = line->next;
- }
-
- /* allocate space for the new line and fill it in */
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("TransportProxy");
- tor_asprintf(&line->value, "%s %s:%d", transport,
- fmt_addr(addr), (int) port);
-
- next = &(line->next);
- }
-
- if (!get_options()->AvoidDiskWrites)
- or_state_mark_dirty(state, 0);
-
- done:
- tor_free(transport_addrport);
-}
-
/** Given a file name check to see whether the file exists but has not been
* modified for a very long time. If so, remove it. */
void
@@ -7260,6 +5921,43 @@ remove_file_if_very_old(const char *fname, time_t now)
}
}
+/** Return a smartlist of ports that must be forwarded by
+ * tor-fw-helper. The smartlist contains the ports in a string format
+ * that is understandable by tor-fw-helper. */
+smartlist_t *
+get_list_of_ports_to_forward(void)
+{
+ smartlist_t *ports_to_forward = smartlist_new();
+ int port = 0;
+
+ /** XXX TODO tor-fw-helper does not support forwarding ports to
+ other hosts than the local one. If the user is binding to a
+ different IP address, tor-fw-helper won't work. */
+ port = router_get_advertised_or_port(get_options()); /* Get ORPort */
+ if (port)
+ smartlist_add_asprintf(ports_to_forward, "%d:%d", port, port);
+
+ port = router_get_advertised_dir_port(get_options(), 0); /* Get DirPort */
+ if (port)
+ smartlist_add_asprintf(ports_to_forward, "%d:%d", port, port);
+
+ /* Get ports of transport proxies */
+ {
+ smartlist_t *transport_ports = get_transport_proxy_ports();
+ if (transport_ports) {
+ smartlist_add_all(ports_to_forward, transport_ports);
+ smartlist_free(transport_ports);
+ }
+ }
+
+ if (!smartlist_len(ports_to_forward)) {
+ smartlist_free(ports_to_forward);
+ ports_to_forward = NULL;
+ }
+
+ return ports_to_forward;
+}
+
/** Helper to implement GETINFO functions about configuration variables (not
* their values). Given a "config/names" question, set *<b>answer</b> to a
* new string describing the supported configuration variables and their
@@ -7274,9 +5972,12 @@ getinfo_helper_config(control_connection_t *conn,
if (!strcmp(question, "config/names")) {
smartlist_t *sl = smartlist_new();
int i;
- for (i = 0; _option_vars[i].name; ++i) {
- const config_var_t *var = &_option_vars[i];
+ for (i = 0; option_vars_[i].name; ++i) {
+ const config_var_t *var = &option_vars_[i];
const char *type;
+ /* don't tell controller about triple-underscore options */
+ if (!strncmp(option_vars_[i].name, "___", 3))
+ continue;
switch (var->type) {
case CONFIG_TYPE_STRING: type = "String"; break;
case CONFIG_TYPE_FILENAME: type = "Filename"; break;
@@ -7306,7 +6007,120 @@ getinfo_helper_config(control_connection_t *conn,
*answer = smartlist_join_strings(sl, "", 0, NULL);
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
+ } else if (!strcmp(question, "config/defaults")) {
+ smartlist_t *sl = smartlist_new();
+ int i;
+ for (i = 0; option_vars_[i].name; ++i) {
+ const config_var_t *var = &option_vars_[i];
+ if (var->initvalue != NULL) {
+ char *val = esc_for_log(var->initvalue);
+ smartlist_add_asprintf(sl, "%s %s\n",var->name,val);
+ tor_free(val);
+ }
+ }
+ *answer = smartlist_join_strings(sl, "", 0, NULL);
+ SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
+ smartlist_free(sl);
+ }
+ return 0;
+}
+
+/** Parse outbound bind address option lines. If <b>validate_only</b>
+ * is not 0 update OutboundBindAddressIPv4_ and
+ * OutboundBindAddressIPv6_ in <b>options</b>. On failure, set
+ * <b>msg</b> (if provided) to a newly allocated string containing a
+ * description of the problem and return -1. */
+static int
+parse_outbound_addresses(or_options_t *options, int validate_only, char **msg)
+{
+ const config_line_t *lines = options->OutboundBindAddress;
+ int found_v4 = 0, found_v6 = 0;
+
+ if (!validate_only) {
+ memset(&options->OutboundBindAddressIPv4_, 0,
+ sizeof(options->OutboundBindAddressIPv4_));
+ memset(&options->OutboundBindAddressIPv6_, 0,
+ sizeof(options->OutboundBindAddressIPv6_));
+ }
+ while (lines) {
+ tor_addr_t addr, *dst_addr = NULL;
+ int af = tor_addr_parse(&addr, lines->value);
+ switch (af) {
+ case AF_INET:
+ if (found_v4) {
+ if (msg)
+ tor_asprintf(msg, "Multiple IPv4 outbound bind addresses "
+ "configured: %s", lines->value);
+ return -1;
+ }
+ found_v4 = 1;
+ dst_addr = &options->OutboundBindAddressIPv4_;
+ break;
+ case AF_INET6:
+ if (found_v6) {
+ if (msg)
+ tor_asprintf(msg, "Multiple IPv6 outbound bind addresses "
+ "configured: %s", lines->value);
+ return -1;
+ }
+ found_v6 = 1;
+ dst_addr = &options->OutboundBindAddressIPv6_;
+ break;
+ default:
+ if (msg)
+ tor_asprintf(msg, "Outbound bind address '%s' didn't parse.",
+ lines->value);
+ return -1;
+ }
+ if (!validate_only)
+ tor_addr_copy(dst_addr, &addr);
+ lines = lines->next;
}
return 0;
}
+/** Load one of the geoip files, <a>family</a> determining which
+ * one. <a>default_fname</a> is used if on Windows and
+ * <a>fname</a> equals "<default>". */
+static void
+config_load_geoip_file_(sa_family_t family,
+ const char *fname,
+ const char *default_fname)
+{
+#ifdef _WIN32
+ char *free_fname = NULL; /* Used to hold any temporary-allocated value */
+ /* XXXX Don't use this "<default>" junk; make our filename options
+ * understand prefixes somehow. -NM */
+ if (!strcmp(fname, "<default>")) {
+ const char *conf_root = get_windows_conf_root();
+ tor_asprintf(&free_fname, "%s\\%s", conf_root, default_fname);
+ fname = free_fname;
+ }
+ geoip_load_file(family, fname);
+ tor_free(free_fname);
+#else
+ (void)default_fname;
+ geoip_load_file(family, fname);
+#endif
+}
+
+/** Load geoip files for IPv4 and IPv6 if <a>options</a> and
+ * <a>old_options</a> indicate we should. */
+static void
+config_maybe_load_geoip_files_(const or_options_t *options,
+ const or_options_t *old_options)
+{
+ /* XXXX024 Reload GeoIPFile on SIGHUP. -NM */
+
+ if (options->GeoIPFile &&
+ ((!old_options || !opt_streq(old_options->GeoIPFile,
+ options->GeoIPFile))
+ || !geoip_is_loaded(AF_INET)))
+ config_load_geoip_file_(AF_INET, options->GeoIPFile, "geoip");
+ if (options->GeoIPv6File &&
+ ((!old_options || !opt_streq(old_options->GeoIPv6File,
+ options->GeoIPv6File))
+ || !geoip_is_loaded(AF_INET6)))
+ config_load_geoip_file_(AF_INET6, options->GeoIPv6File, "geoip6");
+}
+
diff --git a/src/or/config.h b/src/or/config.h
index dd76edcf1..ef4acac51 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for config.c.
**/
-#ifndef _TOR_CONFIG_H
-#define _TOR_CONFIG_H
+#ifndef TOR_CONFIG_H
+#define TOR_CONFIG_H
const char *get_dirportfrontpage(void);
const or_options_t *get_options(void);
@@ -23,13 +23,13 @@ const char *escaped_safe_str_client(const char *address);
const char *escaped_safe_str(const char *address);
const char *get_version(void);
const char *get_short_version(void);
-
-int config_get_lines(const char *string, config_line_t **result, int extended);
-void config_free_lines(config_line_t *front);
setopt_err_t options_trial_assign(config_line_t *list, int use_defaults,
int clear_first, char **msg);
+
+uint32_t get_last_resolved_addr(void);
int resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr, char **hostname_out);
+ uint32_t *addr_out,
+ const char **method_out, char **hostname_out);
int is_local_addr(const tor_addr_t *addr);
void options_init(or_options_t *options);
char *options_dump(const or_options_t *options, int minimal);
@@ -61,10 +61,6 @@ char *options_get_datadir_fname2_suffix(const or_options_t *options,
int get_num_cpus(const or_options_t *options);
-or_state_t *get_or_state(void);
-int did_last_state_file_write_fail(void);
-int or_state_save(time_t now);
-
const smartlist_t *get_configured_ports(void);
int get_first_advertised_port_by_type_af(int listener_type,
int address_family);
@@ -78,9 +74,7 @@ char *get_first_listener_addrport_string(int listener_type);
int options_need_geoip_info(const or_options_t *options,
const char **reason_out);
-void save_transport_to_state(const char *transport_name,
- const tor_addr_t *addr, uint16_t port);
-char *get_stored_bindaddr_for_server_transport(const char *transport);
+smartlist_t *get_list_of_ports_to_forward(void);
int getinfo_helper_config(control_connection_t *conn,
const char *question, char **answer,
@@ -90,6 +84,8 @@ const char *tor_get_digests(void);
uint32_t get_effective_bwrate(const or_options_t *options);
uint32_t get_effective_bwburst(const or_options_t *options);
+char *get_transport_bindaddr_from_config(const char *transport);
+
#ifdef CONFIG_PRIVATE
/* Used only by config.c and test.c */
or_options_t *options_new(void);
diff --git a/src/or/confparse.c b/src/or/confparse.c
new file mode 100644
index 000000000..8863d9240
--- /dev/null
+++ b/src/or/confparse.c
@@ -0,0 +1,1231 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "confparse.h"
+#include "routerset.h"
+
+static uint64_t config_parse_memunit(const char *s, int *ok);
+static int config_parse_msec_interval(const char *s, int *ok);
+static int config_parse_interval(const char *s, int *ok);
+static void config_reset(const config_format_t *fmt, void *options,
+ const config_var_t *var, int use_defaults);
+
+/** Allocate an empty configuration object of a given format type. */
+void *
+config_new(const config_format_t *fmt)
+{
+ void *opts = tor_malloc_zero(fmt->size);
+ *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
+ CONFIG_CHECK(fmt, opts);
+ return opts;
+}
+
+/*
+ * Functions to parse config options
+ */
+
+/** If <b>option</b> is an official abbreviation for a longer option,
+ * return the longer option. Otherwise return <b>option</b>.
+ * If <b>command_line</b> is set, apply all abbreviations. Otherwise, only
+ * apply abbreviations that work for the config file and the command line.
+ * If <b>warn_obsolete</b> is set, warn about deprecated names. */
+const char *
+config_expand_abbrev(const config_format_t *fmt, const char *option,
+ int command_line, int warn_obsolete)
+{
+ int i;
+ if (! fmt->abbrevs)
+ return option;
+ for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
+ /* Abbreviations are case insensitive. */
+ if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
+ (command_line || !fmt->abbrevs[i].commandline_only)) {
+ if (warn_obsolete && fmt->abbrevs[i].warn) {
+ log_warn(LD_CONFIG,
+ "The configuration option '%s' is deprecated; "
+ "use '%s' instead.",
+ fmt->abbrevs[i].abbreviated,
+ fmt->abbrevs[i].full);
+ }
+ /* Keep going through the list in case we want to rewrite it more.
+ * (We could imagine recursing here, but I don't want to get the
+ * user into an infinite loop if we craft our list wrong.) */
+ option = fmt->abbrevs[i].full;
+ }
+ }
+ return option;
+}
+
+/** Helper: allocate a new configuration option mapping 'key' to 'val',
+ * append it to *<b>lst</b>. */
+void
+config_line_append(config_line_t **lst,
+ const char *key,
+ const char *val)
+{
+ 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;
+ while (*lst)
+ lst = &((*lst)->next);
+
+ (*lst) = newline;
+}
+
+/** Helper: parse the config string and strdup into key/value
+ * strings. Set *result to the list, or NULL if parsing the string
+ * failed. Return 0 on success, -1 on failure. Warn and ignore any
+ * misformatted lines.
+ *
+ * If <b>extended</b> is set, then treat keys beginning with / and with + as
+ * indicating "clear" and "append" respectively. */
+int
+config_get_lines(const char *string, config_line_t **result, int extended)
+{
+ config_line_t *list = NULL, **next;
+ char *k, *v;
+ const char *parse_err;
+
+ next = &list;
+ do {
+ k = v = NULL;
+ string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err);
+ if (!string) {
+ log_warn(LD_CONFIG, "Error while parsing configuration: %s",
+ parse_err?parse_err:"<unknown>");
+ config_free_lines(list);
+ tor_free(k);
+ tor_free(v);
+ return -1;
+ }
+ if (k && v) {
+ unsigned command = CONFIG_LINE_NORMAL;
+ if (extended) {
+ if (k[0] == '+') {
+ char *k_new = tor_strdup(k+1);
+ tor_free(k);
+ k = k_new;
+ command = CONFIG_LINE_APPEND;
+ } else if (k[0] == '/') {
+ char *k_new = tor_strdup(k+1);
+ tor_free(k);
+ k = k_new;
+ tor_free(v);
+ v = tor_strdup("");
+ command = CONFIG_LINE_CLEAR;
+ }
+ }
+ /* This list can get long, so we keep a pointer to the end of it
+ * rather than using config_line_append over and over and getting
+ * n^2 performance. */
+ *next = tor_malloc_zero(sizeof(config_line_t));
+ (*next)->key = k;
+ (*next)->value = v;
+ (*next)->next = NULL;
+ (*next)->command = command;
+ next = &((*next)->next);
+ } else {
+ tor_free(k);
+ tor_free(v);
+ }
+ } while (*string);
+
+ *result = list;
+ return 0;
+}
+
+/**
+ * Free all the configuration lines on the linked list <b>front</b>.
+ */
+void
+config_free_lines(config_line_t *front)
+{
+ config_line_t *tmp;
+
+ while (front) {
+ tmp = front;
+ front = tmp->next;
+
+ tor_free(tmp->key);
+ tor_free(tmp->value);
+ tor_free(tmp);
+ }
+}
+
+/** As config_find_option, but return a non-const pointer. */
+config_var_t *
+config_find_option_mutable(config_format_t *fmt, const char *key)
+{
+ int i;
+ size_t keylen = strlen(key);
+ if (!keylen)
+ return NULL; /* if they say "--" on the command line, it's not an option */
+ /* First, check for an exact (case-insensitive) match */
+ for (i=0; fmt->vars[i].name; ++i) {
+ if (!strcasecmp(key, fmt->vars[i].name)) {
+ return &fmt->vars[i];
+ }
+ }
+ /* If none, check for an abbreviated match */
+ for (i=0; fmt->vars[i].name; ++i) {
+ if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
+ log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
+ "Please use '%s' instead",
+ key, fmt->vars[i].name);
+ return &fmt->vars[i];
+ }
+ }
+ /* Okay, unrecognized option */
+ return NULL;
+}
+
+/** If <b>key</b> is a configuration option, return the corresponding const
+ * config_var_t. Otherwise, if <b>key</b> is a non-standard abbreviation,
+ * warn, and return the corresponding const config_var_t. Otherwise return
+ * NULL.
+ */
+const config_var_t *
+config_find_option(const config_format_t *fmt, const char *key)
+{
+ return config_find_option_mutable((config_format_t*)fmt, key);
+}
+
+/** Return the number of option entries in <b>fmt</b>. */
+static int
+config_count_options(const config_format_t *fmt)
+{
+ int i;
+ for (i=0; fmt->vars[i].name; ++i)
+ ;
+ return i;
+}
+
+/*
+ * Functions to assign config options.
+ */
+
+/** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
+ * with <b>c</b>-\>value and return 0, or return -1 if bad value.
+ *
+ * Called from config_assign_line() and option_reset().
+ */
+static int
+config_assign_value(const config_format_t *fmt, void *options,
+ config_line_t *c, char **msg)
+{
+ int i, ok;
+ const config_var_t *var;
+ void *lvalue;
+
+ CONFIG_CHECK(fmt, options);
+
+ var = config_find_option(fmt, c->key);
+ tor_assert(var);
+
+ lvalue = STRUCT_VAR_P(options, var->var_offset);
+
+ switch (var->type) {
+
+ case CONFIG_TYPE_PORT:
+ if (!strcasecmp(c->value, "auto")) {
+ *(int *)lvalue = CFG_AUTO_PORT;
+ break;
+ }
+ /* fall through */
+ case CONFIG_TYPE_INT:
+ case CONFIG_TYPE_UINT:
+ i = (int)tor_parse_long(c->value, 10,
+ var->type==CONFIG_TYPE_INT ? INT_MIN : 0,
+ var->type==CONFIG_TYPE_PORT ? 65535 : INT_MAX,
+ &ok, NULL);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Int keyword '%s %s' is malformed or out of bounds.",
+ c->key, c->value);
+ return -1;
+ }
+ *(int *)lvalue = i;
+ break;
+
+ case CONFIG_TYPE_INTERVAL: {
+ i = config_parse_interval(c->value, &ok);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Interval '%s %s' is malformed or out of bounds.",
+ c->key, c->value);
+ return -1;
+ }
+ *(int *)lvalue = i;
+ break;
+ }
+
+ case CONFIG_TYPE_MSEC_INTERVAL: {
+ i = config_parse_msec_interval(c->value, &ok);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Msec interval '%s %s' is malformed or out of bounds.",
+ c->key, c->value);
+ return -1;
+ }
+ *(int *)lvalue = i;
+ break;
+ }
+
+ case CONFIG_TYPE_MEMUNIT: {
+ uint64_t u64 = config_parse_memunit(c->value, &ok);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Value '%s %s' is malformed or out of bounds.",
+ c->key, c->value);
+ return -1;
+ }
+ *(uint64_t *)lvalue = u64;
+ break;
+ }
+
+ case CONFIG_TYPE_BOOL:
+ i = (int)tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Boolean '%s %s' expects 0 or 1.",
+ c->key, c->value);
+ return -1;
+ }
+ *(int *)lvalue = i;
+ break;
+
+ case CONFIG_TYPE_AUTOBOOL:
+ if (!strcmp(c->value, "auto"))
+ *(int *)lvalue = -1;
+ else if (!strcmp(c->value, "0"))
+ *(int *)lvalue = 0;
+ else if (!strcmp(c->value, "1"))
+ *(int *)lvalue = 1;
+ else {
+ tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.",
+ c->key, c->value);
+ return -1;
+ }
+ break;
+
+ case CONFIG_TYPE_STRING:
+ case CONFIG_TYPE_FILENAME:
+ tor_free(*(char **)lvalue);
+ *(char **)lvalue = tor_strdup(c->value);
+ break;
+
+ case CONFIG_TYPE_DOUBLE:
+ *(double *)lvalue = atof(c->value);
+ break;
+
+ case CONFIG_TYPE_ISOTIME:
+ if (parse_iso_time(c->value, (time_t *)lvalue)) {
+ tor_asprintf(msg,
+ "Invalid time '%s' for keyword '%s'", c->value, c->key);
+ return -1;
+ }
+ break;
+
+ case CONFIG_TYPE_ROUTERSET:
+ if (*(routerset_t**)lvalue) {
+ routerset_free(*(routerset_t**)lvalue);
+ }
+ *(routerset_t**)lvalue = routerset_new();
+ if (routerset_parse(*(routerset_t**)lvalue, c->value, c->key)<0) {
+ tor_asprintf(msg, "Invalid exit list '%s' for option '%s'",
+ c->value, c->key);
+ return -1;
+ }
+ break;
+
+ case CONFIG_TYPE_CSV:
+ if (*(smartlist_t**)lvalue) {
+ SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
+ smartlist_clear(*(smartlist_t**)lvalue);
+ } else {
+ *(smartlist_t**)lvalue = smartlist_new();
+ }
+
+ smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ break;
+
+ case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_S:
+ {
+ config_line_t *lastval = *(config_line_t**)lvalue;
+ if (lastval && lastval->fragile) {
+ if (c->command != CONFIG_LINE_APPEND) {
+ config_free_lines(lastval);
+ *(config_line_t**)lvalue = NULL;
+ } else {
+ lastval->fragile = 0;
+ }
+ }
+
+ config_line_append((config_line_t**)lvalue, c->key, c->value);
+ }
+ break;
+ case CONFIG_TYPE_OBSOLETE:
+ log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key);
+ break;
+ case CONFIG_TYPE_LINELIST_V:
+ tor_asprintf(msg,
+ "You may not provide a value for virtual option '%s'", c->key);
+ return -1;
+ default:
+ tor_assert(0);
+ break;
+ }
+ return 0;
+}
+
+/** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
+ * to it will replace old ones. */
+static void
+config_mark_lists_fragile(const config_format_t *fmt, void *options)
+{
+ int i;
+ tor_assert(fmt);
+ tor_assert(options);
+
+ for (i = 0; fmt->vars[i].name; ++i) {
+ const config_var_t *var = &fmt->vars[i];
+ config_line_t *list;
+ if (var->type != CONFIG_TYPE_LINELIST &&
+ var->type != CONFIG_TYPE_LINELIST_V)
+ continue;
+
+ list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset);
+ if (list)
+ list->fragile = 1;
+ }
+}
+
+/** If <b>c</b> is a syntactically valid configuration line, update
+ * <b>options</b> with its value and return 0. Otherwise return -1 for bad
+ * key, -2 for bad value.
+ *
+ * If <b>clear_first</b> is set, clear the value first. Then if
+ * <b>use_defaults</b> is set, set the value to the default.
+ *
+ * Called from config_assign().
+ */
+static int
+config_assign_line(const config_format_t *fmt, void *options,
+ config_line_t *c, int use_defaults,
+ int clear_first, bitarray_t *options_seen, char **msg)
+{
+ const config_var_t *var;
+
+ CONFIG_CHECK(fmt, options);
+
+ var = config_find_option(fmt, c->key);
+ if (!var) {
+ if (fmt->extra) {
+ void *lvalue = STRUCT_VAR_P(options, fmt->extra->var_offset);
+ log_info(LD_CONFIG,
+ "Found unrecognized option '%s'; saving it.", c->key);
+ config_line_append((config_line_t**)lvalue, c->key, c->value);
+ return 0;
+ } else {
+ tor_asprintf(msg,
+ "Unknown option '%s'. Failing.", c->key);
+ return -1;
+ }
+ }
+
+ /* Put keyword into canonical case. */
+ if (strcmp(var->name, c->key)) {
+ tor_free(c->key);
+ c->key = tor_strdup(var->name);
+ }
+
+ if (!strlen(c->value)) {
+ /* reset or clear it, then return */
+ if (!clear_first) {
+ if ((var->type == CONFIG_TYPE_LINELIST ||
+ var->type == CONFIG_TYPE_LINELIST_S) &&
+ c->command != CONFIG_LINE_CLEAR) {
+ /* We got an empty linelist from the torrc or command line.
+ As a special case, call this an error. Warn and ignore. */
+ log_warn(LD_CONFIG,
+ "Linelist option '%s' has no value. Skipping.", c->key);
+ } else { /* not already cleared */
+ config_reset(fmt, options, var, use_defaults);
+ }
+ }
+ return 0;
+ } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
+ config_reset(fmt, options, var, use_defaults);
+ }
+
+ if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
+ var->type != CONFIG_TYPE_LINELIST_S)) {
+ /* We're tracking which options we've seen, and this option is not
+ * supposed to occur more than once. */
+ int var_index = (int)(var - fmt->vars);
+ if (bitarray_is_set(options_seen, var_index)) {
+ log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
+ "value will be ignored.", var->name);
+ }
+ bitarray_set(options_seen, var_index);
+ }
+
+ if (config_assign_value(fmt, options, c, msg) < 0)
+ return -2;
+ return 0;
+}
+
+/** Restore the option named <b>key</b> in options to its default value.
+ * Called from config_assign(). */
+static void
+config_reset_line(const config_format_t *fmt, void *options,
+ const char *key, int use_defaults)
+{
+ const config_var_t *var;
+
+ CONFIG_CHECK(fmt, options);
+
+ var = config_find_option(fmt, key);
+ if (!var)
+ return; /* give error on next pass. */
+
+ config_reset(fmt, options, var, use_defaults);
+}
+
+/** Return true iff value needs to be quoted and escaped to be used in
+ * a configuration file. */
+static int
+config_value_needs_escape(const char *value)
+{
+ if (*value == '\"')
+ return 1;
+ while (*value) {
+ switch (*value)
+ {
+ case '\r':
+ case '\n':
+ case '#':
+ /* Note: quotes and backspaces need special handling when we are using
+ * quotes, not otherwise, so they don't trigger escaping on their
+ * own. */
+ return 1;
+ default:
+ if (!TOR_ISPRINT(*value))
+ return 1;
+ }
+ ++value;
+ }
+ return 0;
+}
+
+/** Return a newly allocated deep copy of the lines in <b>inp</b>. */
+config_line_t *
+config_lines_dup(const config_line_t *inp)
+{
+ config_line_t *result = NULL;
+ config_line_t **next_out = &result;
+ while (inp) {
+ *next_out = tor_malloc_zero(sizeof(config_line_t));
+ (*next_out)->key = tor_strdup(inp->key);
+ (*next_out)->value = tor_strdup(inp->value);
+ inp = inp->next;
+ next_out = &((*next_out)->next);
+ }
+ (*next_out) = NULL;
+ return result;
+}
+
+/** Return newly allocated line or lines corresponding to <b>key</b> in the
+ * configuration <b>options</b>. If <b>escape_val</b> is true and a
+ * value needs to be quoted before it's put in a config file, quote and
+ * escape that value. Return NULL if no such key exists. */
+config_line_t *
+config_get_assigned_option(const config_format_t *fmt, const void *options,
+ const char *key, int escape_val)
+{
+ const config_var_t *var;
+ const void *value;
+ config_line_t *result;
+ tor_assert(options && key);
+
+ CONFIG_CHECK(fmt, options);
+
+ var = config_find_option(fmt, key);
+ if (!var) {
+ log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
+ return NULL;
+ }
+ value = STRUCT_VAR_P(options, var->var_offset);
+
+ result = tor_malloc_zero(sizeof(config_line_t));
+ result->key = tor_strdup(var->name);
+ switch (var->type)
+ {
+ case CONFIG_TYPE_STRING:
+ case CONFIG_TYPE_FILENAME:
+ if (*(char**)value) {
+ result->value = tor_strdup(*(char**)value);
+ } else {
+ tor_free(result->key);
+ tor_free(result);
+ return NULL;
+ }
+ break;
+ case CONFIG_TYPE_ISOTIME:
+ if (*(time_t*)value) {
+ result->value = tor_malloc(ISO_TIME_LEN+1);
+ format_iso_time(result->value, *(time_t*)value);
+ } else {
+ tor_free(result->key);
+ tor_free(result);
+ }
+ escape_val = 0; /* Can't need escape. */
+ break;
+ case CONFIG_TYPE_PORT:
+ if (*(int*)value == CFG_AUTO_PORT) {
+ result->value = tor_strdup("auto");
+ escape_val = 0;
+ break;
+ }
+ /* fall through */
+ case CONFIG_TYPE_INTERVAL:
+ case CONFIG_TYPE_MSEC_INTERVAL:
+ case CONFIG_TYPE_UINT:
+ case CONFIG_TYPE_INT:
+ /* This means every or_options_t uint or bool element
+ * needs to be an int. Not, say, a uint16_t or char. */
+ tor_asprintf(&result->value, "%d", *(int*)value);
+ escape_val = 0; /* Can't need escape. */
+ break;
+ case CONFIG_TYPE_MEMUNIT:
+ tor_asprintf(&result->value, U64_FORMAT,
+ U64_PRINTF_ARG(*(uint64_t*)value));
+ escape_val = 0; /* Can't need escape. */
+ break;
+ case CONFIG_TYPE_DOUBLE:
+ tor_asprintf(&result->value, "%f", *(double*)value);
+ escape_val = 0; /* Can't need escape. */
+ break;
+
+ case CONFIG_TYPE_AUTOBOOL:
+ if (*(int*)value == -1) {
+ result->value = tor_strdup("auto");
+ escape_val = 0;
+ break;
+ }
+ /* fall through */
+ case CONFIG_TYPE_BOOL:
+ result->value = tor_strdup(*(int*)value ? "1" : "0");
+ escape_val = 0; /* Can't need escape. */
+ break;
+ case CONFIG_TYPE_ROUTERSET:
+ result->value = routerset_to_string(*(routerset_t**)value);
+ break;
+ case CONFIG_TYPE_CSV:
+ if (*(smartlist_t**)value)
+ result->value =
+ smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL);
+ else
+ result->value = tor_strdup("");
+ break;
+ case CONFIG_TYPE_OBSOLETE:
+ log_fn(LOG_INFO, LD_CONFIG,
+ "You asked me for the value of an obsolete config option '%s'.",
+ key);
+ tor_free(result->key);
+ tor_free(result);
+ return NULL;
+ case CONFIG_TYPE_LINELIST_S:
+ log_warn(LD_CONFIG,
+ "Can't return context-sensitive '%s' on its own", key);
+ tor_free(result->key);
+ tor_free(result);
+ return NULL;
+ case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_V:
+ tor_free(result->key);
+ tor_free(result);
+ result = config_lines_dup(*(const config_line_t**)value);
+ break;
+ default:
+ tor_free(result->key);
+ tor_free(result);
+ log_warn(LD_BUG,"Unknown type %d for known key '%s'",
+ var->type, key);
+ return NULL;
+ }
+
+ if (escape_val) {
+ config_line_t *line;
+ for (line = result; line; line = line->next) {
+ if (line->value && config_value_needs_escape(line->value)) {
+ char *newval = esc_for_log(line->value);
+ tor_free(line->value);
+ line->value = newval;
+ }
+ }
+ }
+
+ return result;
+}
+/** Iterate through the linked list of requested options <b>list</b>.
+ * For each item, convert as appropriate and assign to <b>options</b>.
+ * If an item is unrecognized, set *msg and return -1 immediately,
+ * else return 0 for success.
+ *
+ * If <b>clear_first</b>, interpret config options as replacing (not
+ * extending) their previous values. If <b>clear_first</b> is set,
+ * then <b>use_defaults</b> to decide if you set to defaults after
+ * clearing, or make the value 0 or NULL.
+ *
+ * Here are the use cases:
+ * 1. A non-empty AllowInvalid line in your torrc. Appends to current
+ * if linelist, replaces current if csv.
+ * 2. An empty AllowInvalid line in your torrc. Should clear it.
+ * 3. "RESETCONF AllowInvalid" sets it to default.
+ * 4. "SETCONF AllowInvalid" makes it NULL.
+ * 5. "SETCONF AllowInvalid=foo" clears it and sets it to "foo".
+ *
+ * Use_defaults Clear_first
+ * 0 0 "append"
+ * 1 0 undefined, don't use
+ * 0 1 "set to null first"
+ * 1 1 "set to defaults first"
+ * Return 0 on success, -1 on bad key, -2 on bad value.
+ *
+ * As an additional special case, if a LINELIST config option has
+ * no value and clear_first is 0, then warn and ignore it.
+ */
+
+/*
+There are three call cases for config_assign() currently.
+
+Case one: Torrc entry
+options_init_from_torrc() calls config_assign(0, 0)
+ calls config_assign_line(0, 0).
+ if value is empty, calls config_reset(0) and returns.
+ calls config_assign_value(), appends.
+
+Case two: setconf
+options_trial_assign() calls config_assign(0, 1)
+ calls config_reset_line(0)
+ calls config_reset(0)
+ calls option_clear().
+ calls config_assign_line(0, 1).
+ if value is empty, returns.
+ calls config_assign_value(), appends.
+
+Case three: resetconf
+options_trial_assign() calls config_assign(1, 1)
+ calls config_reset_line(1)
+ calls config_reset(1)
+ calls option_clear().
+ calls config_assign_value(default)
+ calls config_assign_line(1, 1).
+ returns.
+*/
+int
+config_assign(const config_format_t *fmt, void *options, config_line_t *list,
+ int use_defaults, int clear_first, char **msg)
+{
+ config_line_t *p;
+ bitarray_t *options_seen;
+ const int n_options = config_count_options(fmt);
+
+ CONFIG_CHECK(fmt, options);
+
+ /* pass 1: normalize keys */
+ for (p = list; p; p = p->next) {
+ const char *full = config_expand_abbrev(fmt, p->key, 0, 1);
+ if (strcmp(full,p->key)) {
+ tor_free(p->key);
+ p->key = tor_strdup(full);
+ }
+ }
+
+ /* pass 2: if we're reading from a resetting source, clear all
+ * mentioned config options, and maybe set to their defaults. */
+ if (clear_first) {
+ for (p = list; p; p = p->next)
+ config_reset_line(fmt, options, p->key, use_defaults);
+ }
+
+ options_seen = bitarray_init_zero(n_options);
+ /* pass 3: assign. */
+ while (list) {
+ int r;
+ if ((r=config_assign_line(fmt, options, list, use_defaults,
+ clear_first, options_seen, msg))) {
+ bitarray_free(options_seen);
+ return r;
+ }
+ list = list->next;
+ }
+ bitarray_free(options_seen);
+
+ /** Now we're done assigning a group of options to the configuration.
+ * Subsequent group assignments should _replace_ linelists, not extend
+ * them. */
+ config_mark_lists_fragile(fmt, options);
+
+ return 0;
+}
+
+/** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
+ * Called from config_reset() and config_free(). */
+static void
+config_clear(const config_format_t *fmt, void *options,
+ const config_var_t *var)
+{
+ void *lvalue = STRUCT_VAR_P(options, var->var_offset);
+ (void)fmt; /* unused */
+ switch (var->type) {
+ case CONFIG_TYPE_STRING:
+ case CONFIG_TYPE_FILENAME:
+ tor_free(*(char**)lvalue);
+ break;
+ case CONFIG_TYPE_DOUBLE:
+ *(double*)lvalue = 0.0;
+ break;
+ case CONFIG_TYPE_ISOTIME:
+ *(time_t*)lvalue = 0;
+ break;
+ case CONFIG_TYPE_INTERVAL:
+ case CONFIG_TYPE_MSEC_INTERVAL:
+ case CONFIG_TYPE_UINT:
+ case CONFIG_TYPE_INT:
+ case CONFIG_TYPE_PORT:
+ case CONFIG_TYPE_BOOL:
+ *(int*)lvalue = 0;
+ break;
+ case CONFIG_TYPE_AUTOBOOL:
+ *(int*)lvalue = -1;
+ break;
+ case CONFIG_TYPE_MEMUNIT:
+ *(uint64_t*)lvalue = 0;
+ break;
+ case CONFIG_TYPE_ROUTERSET:
+ if (*(routerset_t**)lvalue) {
+ routerset_free(*(routerset_t**)lvalue);
+ *(routerset_t**)lvalue = NULL;
+ }
+ break;
+ case CONFIG_TYPE_CSV:
+ if (*(smartlist_t**)lvalue) {
+ SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp));
+ smartlist_free(*(smartlist_t **)lvalue);
+ *(smartlist_t **)lvalue = NULL;
+ }
+ break;
+ case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_S:
+ config_free_lines(*(config_line_t **)lvalue);
+ *(config_line_t **)lvalue = NULL;
+ break;
+ case CONFIG_TYPE_LINELIST_V:
+ /* handled by linelist_s. */
+ break;
+ case CONFIG_TYPE_OBSOLETE:
+ break;
+ }
+}
+
+/** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
+ * <b>use_defaults</b>, set it to its default value.
+ * Called by config_init() and option_reset_line() and option_assign_line(). */
+static void
+config_reset(const config_format_t *fmt, void *options,
+ const config_var_t *var, int use_defaults)
+{
+ config_line_t *c;
+ char *msg = NULL;
+ CONFIG_CHECK(fmt, options);
+ config_clear(fmt, options, var); /* clear it first */
+ if (!use_defaults)
+ return; /* all done */
+ if (var->initvalue) {
+ c = tor_malloc_zero(sizeof(config_line_t));
+ c->key = tor_strdup(var->name);
+ c->value = tor_strdup(var->initvalue);
+ if (config_assign_value(fmt, options, c, &msg) < 0) {
+ log_warn(LD_BUG, "Failed to assign default: %s", msg);
+ tor_free(msg); /* if this happens it's a bug */
+ }
+ config_free_lines(c);
+ }
+}
+
+/** Release storage held by <b>options</b>. */
+void
+config_free(const config_format_t *fmt, void *options)
+{
+ int i;
+
+ if (!options)
+ return;
+
+ tor_assert(fmt);
+
+ for (i=0; fmt->vars[i].name; ++i)
+ config_clear(fmt, options, &(fmt->vars[i]));
+ if (fmt->extra) {
+ config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->var_offset);
+ config_free_lines(*linep);
+ *linep = NULL;
+ }
+ tor_free(options);
+}
+
+/** Return true iff a and b contain identical keys and values in identical
+ * order. */
+int
+config_lines_eq(config_line_t *a, config_line_t *b)
+{
+ while (a && b) {
+ if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
+ return 0;
+ a = a->next;
+ b = b->next;
+ }
+ if (a || b)
+ return 0;
+ return 1;
+}
+
+/** Return the number of lines in <b>a</b> whose key is <b>key</b>. */
+int
+config_count_key(const config_line_t *a, const char *key)
+{
+ int n = 0;
+ while (a) {
+ if (!strcasecmp(a->key, key)) {
+ ++n;
+ }
+ a = a->next;
+ }
+ return n;
+}
+
+/** Return true iff the option <b>name</b> has the same value in <b>o1</b>
+ * and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
+ */
+int
+config_is_same(const config_format_t *fmt,
+ const void *o1, const void *o2,
+ const char *name)
+{
+ config_line_t *c1, *c2;
+ int r = 1;
+ CONFIG_CHECK(fmt, o1);
+ CONFIG_CHECK(fmt, o2);
+
+ c1 = config_get_assigned_option(fmt, o1, name, 0);
+ c2 = config_get_assigned_option(fmt, o2, name, 0);
+ r = config_lines_eq(c1, c2);
+ config_free_lines(c1);
+ config_free_lines(c2);
+ return r;
+}
+
+/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
+void *
+config_dup(const config_format_t *fmt, const void *old)
+{
+ void *newopts;
+ int i;
+ config_line_t *line;
+
+ newopts = config_new(fmt);
+ for (i=0; fmt->vars[i].name; ++i) {
+ if (fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
+ continue;
+ if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
+ continue;
+ line = config_get_assigned_option(fmt, old, fmt->vars[i].name, 0);
+ if (line) {
+ char *msg = NULL;
+ if (config_assign(fmt, newopts, line, 0, 0, &msg) < 0) {
+ log_err(LD_BUG, "config_get_assigned_option() generated "
+ "something we couldn't config_assign(): %s", msg);
+ tor_free(msg);
+ tor_assert(0);
+ }
+ }
+ config_free_lines(line);
+ }
+ return newopts;
+}
+/** Set all vars in the configuration object <b>options</b> to their default
+ * values. */
+void
+config_init(const config_format_t *fmt, void *options)
+{
+ int i;
+ const config_var_t *var;
+ CONFIG_CHECK(fmt, options);
+
+ for (i=0; fmt->vars[i].name; ++i) {
+ var = &fmt->vars[i];
+ if (!var->initvalue)
+ continue; /* defaults to NULL or 0 */
+ config_reset(fmt, options, var, 1);
+ }
+}
+
+/** Allocate and return a new string holding the written-out values of the vars
+ * in 'options'. If 'minimal', do not write out any default-valued vars.
+ * Else, if comment_defaults, write default values as comments.
+ */
+char *
+config_dump(const config_format_t *fmt, const void *default_options,
+ const void *options, int minimal,
+ int comment_defaults)
+{
+ smartlist_t *elements;
+ const void *defaults = default_options;
+ void *defaults_tmp = NULL;
+ config_line_t *line, *assigned;
+ char *result;
+ int i;
+ char *msg = NULL;
+
+ if (defaults == NULL) {
+ defaults = defaults_tmp = config_new(fmt);
+ config_init(fmt, defaults_tmp);
+ }
+
+ /* XXX use a 1 here so we don't add a new log line while dumping */
+ if (default_options == NULL) {
+ if (fmt->validate_fn(NULL, defaults_tmp, 1, &msg) < 0) {
+ log_err(LD_BUG, "Failed to validate default config.");
+ tor_free(msg);
+ tor_assert(0);
+ }
+ }
+
+ elements = smartlist_new();
+ for (i=0; fmt->vars[i].name; ++i) {
+ int comment_option = 0;
+ if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE ||
+ fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
+ continue;
+ /* Don't save 'hidden' control variables. */
+ if (!strcmpstart(fmt->vars[i].name, "__"))
+ continue;
+ if (minimal && config_is_same(fmt, options, defaults, fmt->vars[i].name))
+ continue;
+ else if (comment_defaults &&
+ config_is_same(fmt, options, defaults, fmt->vars[i].name))
+ comment_option = 1;
+
+ line = assigned =
+ config_get_assigned_option(fmt, options, fmt->vars[i].name, 1);
+
+ for (; line; line = line->next) {
+ smartlist_add_asprintf(elements, "%s%s %s\n",
+ comment_option ? "# " : "",
+ line->key, line->value);
+ }
+ config_free_lines(assigned);
+ }
+
+ if (fmt->extra) {
+ line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->var_offset);
+ for (; line; line = line->next) {
+ smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
+ }
+ }
+
+ result = smartlist_join_strings(elements, "", 0, NULL);
+ SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
+ smartlist_free(elements);
+ if (defaults_tmp)
+ config_free(fmt, defaults_tmp);
+ return result;
+}
+
+/** Mapping from a unit name to a multiplier for converting that unit into a
+ * base unit. Used by config_parse_unit. */
+struct unit_table_t {
+ const char *unit; /**< The name of the unit */
+ uint64_t multiplier; /**< How many of the base unit appear in this unit */
+};
+
+/** Table to map the names of memory units to the number of bytes they
+ * contain. */
+static struct unit_table_t memory_units[] = {
+ { "", 1 },
+ { "b", 1<< 0 },
+ { "byte", 1<< 0 },
+ { "bytes", 1<< 0 },
+ { "kb", 1<<10 },
+ { "kbyte", 1<<10 },
+ { "kbytes", 1<<10 },
+ { "kilobyte", 1<<10 },
+ { "kilobytes", 1<<10 },
+ { "m", 1<<20 },
+ { "mb", 1<<20 },
+ { "mbyte", 1<<20 },
+ { "mbytes", 1<<20 },
+ { "megabyte", 1<<20 },
+ { "megabytes", 1<<20 },
+ { "gb", 1<<30 },
+ { "gbyte", 1<<30 },
+ { "gbytes", 1<<30 },
+ { "gigabyte", 1<<30 },
+ { "gigabytes", 1<<30 },
+ { "tb", U64_LITERAL(1)<<40 },
+ { "terabyte", U64_LITERAL(1)<<40 },
+ { "terabytes", U64_LITERAL(1)<<40 },
+ { NULL, 0 },
+};
+
+/** Table to map the names of time units to the number of seconds they
+ * contain. */
+static struct unit_table_t time_units[] = {
+ { "", 1 },
+ { "second", 1 },
+ { "seconds", 1 },
+ { "minute", 60 },
+ { "minutes", 60 },
+ { "hour", 60*60 },
+ { "hours", 60*60 },
+ { "day", 24*60*60 },
+ { "days", 24*60*60 },
+ { "week", 7*24*60*60 },
+ { "weeks", 7*24*60*60 },
+ { "month", 2629728, }, /* about 30.437 days */
+ { "months", 2629728, },
+ { NULL, 0 },
+};
+
+/** Table to map the names of time units to the number of milliseconds
+ * they contain. */
+static struct unit_table_t time_msec_units[] = {
+ { "", 1 },
+ { "msec", 1 },
+ { "millisecond", 1 },
+ { "milliseconds", 1 },
+ { "second", 1000 },
+ { "seconds", 1000 },
+ { "minute", 60*1000 },
+ { "minutes", 60*1000 },
+ { "hour", 60*60*1000 },
+ { "hours", 60*60*1000 },
+ { "day", 24*60*60*1000 },
+ { "days", 24*60*60*1000 },
+ { "week", 7*24*60*60*1000 },
+ { "weeks", 7*24*60*60*1000 },
+ { NULL, 0 },
+};
+
+/** Parse a string <b>val</b> containing a number, zero or more
+ * spaces, and an optional unit string. If the unit appears in the
+ * table <b>u</b>, then multiply the number by the unit multiplier.
+ * On success, set *<b>ok</b> to 1 and return this product.
+ * Otherwise, set *<b>ok</b> to 0.
+ */
+static uint64_t
+config_parse_units(const char *val, struct unit_table_t *u, int *ok)
+{
+ uint64_t v = 0;
+ double d = 0;
+ int use_float = 0;
+ char *cp;
+
+ tor_assert(ok);
+
+ v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp);
+ if (!*ok || (cp && *cp == '.')) {
+ d = tor_parse_double(val, 0, UINT64_MAX, ok, &cp);
+ if (!*ok)
+ goto done;
+ use_float = 1;
+ }
+
+ if (!cp) {
+ *ok = 1;
+ v = use_float ? DBL_TO_U64(d) : v;
+ goto done;
+ }
+
+ cp = (char*) eat_whitespace(cp);
+
+ for ( ;u->unit;++u) {
+ if (!strcasecmp(u->unit, cp)) {
+ if (use_float)
+ v = u->multiplier * d;
+ else
+ v *= u->multiplier;
+ *ok = 1;
+ goto done;
+ }
+ }
+ log_warn(LD_CONFIG, "Unknown unit '%s'.", cp);
+ *ok = 0;
+ done:
+
+ if (*ok)
+ return v;
+ else
+ return 0;
+}
+
+/** Parse a string in the format "number unit", where unit is a unit of
+ * information (byte, KB, M, etc). On success, set *<b>ok</b> to true
+ * and return the number of bytes specified. Otherwise, set
+ * *<b>ok</b> to false and return 0. */
+static uint64_t
+config_parse_memunit(const char *s, int *ok)
+{
+ uint64_t u = config_parse_units(s, memory_units, ok);
+ return u;
+}
+
+/** Parse a string in the format "number unit", where unit is a unit of
+ * time in milliseconds. On success, set *<b>ok</b> to true and return
+ * the number of milliseconds in the provided interval. Otherwise, set
+ * *<b>ok</b> to 0 and return -1. */
+static int
+config_parse_msec_interval(const char *s, int *ok)
+{
+ uint64_t r;
+ r = config_parse_units(s, time_msec_units, ok);
+ if (!ok)
+ return -1;
+ if (r > INT_MAX) {
+ log_warn(LD_CONFIG, "Msec interval '%s' is too long", s);
+ *ok = 0;
+ return -1;
+ }
+ return (int)r;
+}
+
+/** Parse a string in the format "number unit", where unit is a unit of time.
+ * On success, set *<b>ok</b> to true and return the number of seconds in
+ * the provided interval. Otherwise, set *<b>ok</b> to 0 and return -1.
+ */
+static int
+config_parse_interval(const char *s, int *ok)
+{
+ uint64_t r;
+ r = config_parse_units(s, time_units, ok);
+ if (!ok)
+ return -1;
+ if (r > INT_MAX) {
+ log_warn(LD_CONFIG, "Interval '%s' is too long", s);
+ *ok = 0;
+ return -1;
+ }
+ return (int)r;
+}
+
diff --git a/src/or/confparse.h b/src/or/confparse.h
new file mode 100644
index 000000000..1b987f3bf
--- /dev/null
+++ b/src/or/confparse.h
@@ -0,0 +1,132 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_CONFPARSE_H
+#define TOR_CONFPARSE_H
+
+/** Enumeration of types which option values can take */
+typedef enum config_type_t {
+ CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
+ CONFIG_TYPE_FILENAME, /**< A filename: some prefixes get expanded. */
+ CONFIG_TYPE_UINT, /**< A non-negative integer less than MAX_INT */
+ CONFIG_TYPE_INT, /**< Any integer. */
+ CONFIG_TYPE_PORT, /**< A port from 1...65535, 0 for "not set", or
+ * "auto". */
+ CONFIG_TYPE_INTERVAL, /**< A number of seconds, with optional units*/
+ CONFIG_TYPE_MSEC_INTERVAL,/**< A number of milliseconds, with optional
+ * units */
+ CONFIG_TYPE_MEMUNIT, /**< A number of bytes, with optional units*/
+ CONFIG_TYPE_DOUBLE, /**< A floating-point value */
+ CONFIG_TYPE_BOOL, /**< A boolean value, expressed as 0 or 1. */
+ CONFIG_TYPE_AUTOBOOL, /**< A boolean+auto value, expressed 0 for false,
+ * 1 for true, and -1 for auto */
+ CONFIG_TYPE_ISOTIME, /**< An ISO-formatted time relative to UTC. */
+ CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and
+ * optional whitespace. */
+ CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
+ CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines,
+ * mixed with other keywords. */
+ CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize
+ * context-sensitive config lines when fetching.
+ */
+ CONFIG_TYPE_ROUTERSET, /**< A list of router names, addrs, and fps,
+ * parsed into a routerset_t. */
+ CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
+} config_type_t;
+
+/** An abbreviation for a configuration option allowed on the command line. */
+typedef struct config_abbrev_t {
+ const char *abbreviated;
+ const char *full;
+ int commandline_only;
+ int warn;
+} config_abbrev_t;
+
+/* Handy macro for declaring "In the config file or on the command line,
+ * you can abbreviate <b>tok</b>s as <b>tok</b>". */
+#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
+
+/** A variable allowed in the configuration file or on the command line. */
+typedef struct config_var_t {
+ const char *name; /**< The full keyword (case insensitive). */
+ config_type_t type; /**< How to interpret the type and turn it into a
+ * value. */
+ off_t var_offset; /**< Offset of the corresponding member of or_options_t. */
+ const char *initvalue; /**< String (or null) describing initial value. */
+} config_var_t;
+
+/** Represents an English description of a configuration variable; used when
+ * generating configuration file comments. */
+typedef struct config_var_description_t {
+ const char *name;
+ const char *description;
+} config_var_description_t;
+
+/** Type of a callback to validate whether a given configuration is
+ * well-formed and consistent. See options_trial_assign() for documentation
+ * of arguments. */
+typedef int (*validate_fn_t)(void*,void*,int,char**);
+
+/** Information on the keys, value types, key-to-struct-member mappings,
+ * variable descriptions, validation functions, and abbreviations for a
+ * configuration or storage format. */
+typedef struct {
+ size_t size; /**< Size of the struct that everything gets parsed into. */
+ uint32_t magic; /**< Required 'magic value' to make sure we have a struct
+ * of the right type. */
+ off_t magic_offset; /**< Offset of the magic value within the struct. */
+ config_abbrev_t *abbrevs; /**< List of abbreviations that we expand when
+ * parsing this format. */
+ config_var_t *vars; /**< List of variables we recognize, their default
+ * values, and where we stick them in the structure. */
+ validate_fn_t validate_fn; /**< Function to validate config. */
+ /** If present, extra is a LINELIST variable for unrecognized
+ * lines. Otherwise, unrecognized lines are an error. */
+ config_var_t *extra;
+} config_format_t;
+
+/** Macro: assert that <b>cfg</b> has the right magic field for format
+ * <b>fmt</b>. */
+#define CONFIG_CHECK(fmt, cfg) STMT_BEGIN \
+ tor_assert(fmt && cfg); \
+ tor_assert((fmt)->magic == \
+ *(uint32_t*)STRUCT_VAR_P(cfg,fmt->magic_offset)); \
+ STMT_END
+
+void *config_new(const config_format_t *fmt);
+void config_line_append(config_line_t **lst,
+ const char *key, const char *val);
+config_line_t *config_lines_dup(const config_line_t *inp);
+void config_free(const config_format_t *fmt, void *options);
+int config_lines_eq(config_line_t *a, config_line_t *b);
+int config_count_key(const config_line_t *a, const char *key);
+config_line_t *config_get_assigned_option(const config_format_t *fmt,
+ const void *options, const char *key,
+ int escape_val);
+int config_is_same(const config_format_t *fmt,
+ const void *o1, const void *o2,
+ const char *name);
+void config_init(const config_format_t *fmt, void *options);
+void *config_dup(const config_format_t *fmt, const void *old);
+char *config_dump(const config_format_t *fmt, const void *default_options,
+ const void *options, int minimal,
+ int comment_defaults);
+int config_assign(const config_format_t *fmt, void *options,
+ config_line_t *list,
+ int use_defaults, int clear_first, char **msg);
+config_var_t *config_find_option_mutable(config_format_t *fmt,
+ const char *key);
+const config_var_t *config_find_option(const config_format_t *fmt,
+ const char *key);
+
+int config_get_lines(const char *string, config_line_t **result, int extended);
+void config_free_lines(config_line_t *front);
+const char *config_expand_abbrev(const config_format_t *fmt,
+ const char *option,
+ int command_line, int warn_obsolete);
+
+#endif
+
diff --git a/src/or/connection.c b/src/or/connection.c
index e366e0e77..4f74a1d04 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,6 +12,13 @@
#include "or.h"
#include "buffers.h"
+/*
+ * Define this so we get channel internal functions, since we're implementing
+ * part of a subclass (channel_tls_t).
+ */
+#define TOR_CHANNEL_INTERNAL_
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
@@ -25,6 +32,7 @@
#include "dirserv.h"
#include "dns.h"
#include "dnsserv.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "main.h"
#include "policies.h"
@@ -34,6 +42,7 @@
#include "rendcommon.h"
#include "rephist.h"
#include "router.h"
+#include "transports.h"
#include "routerparse.h"
#ifdef USE_BUFFEREVENTS
@@ -238,7 +247,16 @@ dir_connection_new(int socket_family)
}
/** Allocate and return a new or_connection_t, initialized as by
- * connection_init(). */
+ * connection_init().
+ *
+ * Set timestamp_last_added_nonpadding to now.
+ *
+ * Assign a pseudorandom next_circ_id between 0 and 2**15.
+ *
+ * Initialize active_circuit_pqueue.
+ *
+ * Set active_circuit_pqueue_last_recalibrated to current cell_ewma tick.
+ */
or_connection_t *
or_connection_new(int socket_family)
{
@@ -247,16 +265,15 @@ or_connection_new(int socket_family)
connection_init(now, TO_CONN(or_conn), CONN_TYPE_OR, socket_family);
or_conn->timestamp_last_added_nonpadding = time(NULL);
- or_conn->next_circ_id = crypto_rand_int(1<<15);
-
- or_conn->active_circuit_pqueue = smartlist_new();
- or_conn->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick();
return or_conn;
}
/** Allocate and return a new entry_connection_t, initialized as by
- * connection_init(). */
+ * connection_init().
+ *
+ * Allocate space to store the socks_request.
+ */
entry_connection_t *
entry_connection_new(int type, int socket_family)
{
@@ -264,6 +281,13 @@ entry_connection_new(int type, int socket_family)
tor_assert(type == CONN_TYPE_AP);
connection_init(time(NULL), ENTRY_TO_CONN(entry_conn), type, socket_family);
entry_conn->socks_request = socks_request_new();
+ /* If this is coming from a listener, we'll set it up based on the listener
+ * in a little while. Otherwise, we're doing this as a linked connection
+ * of some kind, and we should set it up here based on the socket family */
+ if (socket_family == AF_INET)
+ entry_conn->ipv4_traffic_ok = 1;
+ else if (socket_family == AF_INET6)
+ entry_conn->ipv6_traffic_ok = 1;
return entry_conn;
}
@@ -338,14 +362,11 @@ connection_new(int type, int socket_family)
/** Initializes conn. (you must call connection_add() to link it into the main
* array).
*
+ * Set conn-\>magic to the correct value.
+ *
* Set conn-\>type to <b>type</b>. Set conn-\>s and conn-\>conn_array_index to
* -1 to signify they are not yet assigned.
*
- * If conn is not a listener type, allocate buffers for it. If it's
- * an AP type, allocate space to store the socks_request.
- *
- * Assign a pseudorandom next_circ_id between 0 and 2**15.
- *
* Initialize conn's timestamps to now.
*/
static void
@@ -414,7 +435,7 @@ connection_link_connections(connection_t *conn_a, connection_t *conn_b)
* if <b>conn</b> is an OR or OP connection.
*/
static void
-_connection_free(connection_t *conn)
+connection_free_(connection_t *conn)
{
void *mem;
size_t memlen;
@@ -492,8 +513,23 @@ _connection_free(connection_t *conn)
or_conn->tls = NULL;
or_handshake_state_free(or_conn->handshake_state);
or_conn->handshake_state = NULL;
- smartlist_free(or_conn->active_circuit_pqueue);
tor_free(or_conn->nickname);
+ if (or_conn->chan) {
+ /* Owww, this shouldn't happen, but... */
+ log_info(LD_CHANNEL,
+ "Freeing orconn at %p, saw channel %p with ID "
+ U64_FORMAT " left un-NULLed",
+ or_conn, TLS_CHAN_TO_BASE(or_conn->chan),
+ U64_PRINTF_ARG(
+ TLS_CHAN_TO_BASE(or_conn->chan)->global_identifier));
+ if (!(TLS_CHAN_TO_BASE(or_conn->chan)->state == CHANNEL_STATE_CLOSED ||
+ TLS_CHAN_TO_BASE(or_conn->chan)->state == CHANNEL_STATE_ERROR)) {
+ channel_close_for_error(TLS_CHAN_TO_BASE(or_conn->chan));
+ }
+
+ or_conn->chan->conn = NULL;
+ or_conn->chan = NULL;
+ }
}
if (conn->type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = TO_ENTRY_CONN(conn);
@@ -592,7 +628,7 @@ connection_free(connection_t *conn)
connection_control_closed(TO_CONTROL_CONN(conn));
}
connection_unregister_events(conn);
- _connection_free(conn);
+ connection_free_(conn);
}
/**
@@ -668,7 +704,42 @@ connection_close_immediate(connection_t *conn)
/** Mark <b>conn</b> to be closed next time we loop through
* conn_close_if_marked() in main.c. */
void
-_connection_mark_for_close(connection_t *conn, int line, const char *file)
+connection_mark_for_close_(connection_t *conn, int line, const char *file)
+{
+ assert_connection_ok(conn,0);
+ tor_assert(line);
+ tor_assert(line < 1<<16); /* marked_for_close can only fit a uint16_t. */
+ tor_assert(file);
+
+ if (conn->type == CONN_TYPE_OR) {
+ /*
+ * An or_connection should have been closed through one of the channel-
+ * aware functions in connection_or.c. We'll assume this is an error
+ * close and do that, and log a bug warning.
+ */
+ log_warn(LD_CHANNEL | LD_BUG,
+ "Something tried to close an or_connection_t without going "
+ "through channels at %s:%d",
+ file, line);
+ connection_or_close_for_error(TO_OR_CONN(conn), 0);
+ } else {
+ /* Pass it down to the real function */
+ connection_mark_for_close_internal_(conn, line, file);
+ }
+}
+
+/** Mark <b>conn</b> to be closed next time we loop through
+ * conn_close_if_marked() in main.c; the _internal version bypasses the
+ * CONN_TYPE_OR checks; this should be called when you either are sure that
+ * if this is an or_connection_t the controlling channel has been notified
+ * (e.g. with connection_or_notify_error()), or you actually are the
+ * connection_or_close_for_error() or connection_or_close_normally function.
+ * For all other cases, use connection_mark_and_flush() instead, which
+ * checks for or_connection_t properly, instead. See below.
+ */
+void
+connection_mark_for_close_internal_(connection_t *conn,
+ int line, const char *file)
{
assert_connection_ok(conn,0);
tor_assert(line);
@@ -676,13 +747,24 @@ _connection_mark_for_close(connection_t *conn, int line, const char *file)
tor_assert(file);
if (conn->marked_for_close) {
- log(LOG_WARN,LD_BUG,"Duplicate call to connection_mark_for_close at %s:%d"
+ log_warn(LD_BUG,"Duplicate call to connection_mark_for_close at %s:%d"
" (first at %s:%d)", file, line, conn->marked_for_close_file,
conn->marked_for_close);
tor_fragile_assert();
return;
}
+ if (conn->type == CONN_TYPE_OR) {
+ /*
+ * Bad news if this happens without telling the controlling channel; do
+ * this so we can find things that call this wrongly when the asserts hit.
+ */
+ log_debug(LD_CHANNEL,
+ "Calling connection_mark_for_close_internal_() on an OR conn "
+ "at %s:%d",
+ file, line);
+ }
+
conn->marked_for_close = line;
conn->marked_for_close_file = file;
add_connection_to_closeable_list(conn);
@@ -852,11 +934,35 @@ make_socket_reuseable(tor_socket_t sock)
* right after somebody else has let it go. But REUSEADDR on win32
* means you can bind to the port _even when somebody else
* already has it bound_. So, don't do that on Win32. */
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
- (socklen_t)sizeof(one));
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
+ (socklen_t)sizeof(one)) == -1) {
+ log_warn(LD_NET, "Error setting SO_REUSEADDR flag: %s",
+ tor_socket_strerror(errno));
+ }
#endif
}
+/** Max backlog to pass to listen. We start at */
+static int listen_limit = INT_MAX;
+
+/* Listen on <b>fd</b> with appropriate backlog. Return as for listen. */
+static int
+tor_listen(tor_socket_t fd)
+{
+ int r;
+
+ if ((r = listen(fd, listen_limit)) < 0) {
+ if (listen_limit == SOMAXCONN)
+ return r;
+ if ((r = listen(fd, SOMAXCONN)) == 0) {
+ listen_limit = SOMAXCONN;
+ log_warn(LD_NET, "Setting listen backlog to INT_MAX connections "
+ "didn't work, but SOMAXCONN did. Lowering backlog limit.");
+ }
+ }
+ return r;
+}
+
/** Bind a new non-blocking socket listening to the socket described
* by <b>listensockaddr</b>.
*
@@ -881,7 +987,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
static int global_next_session_group = SESSION_GROUP_FIRST_AUTO;
tor_addr_t addr;
- if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
+ if (get_n_open_sockets() >= get_options()->ConnLimit_-1) {
warn_too_many_conns();
return NULL;
}
@@ -894,8 +1000,8 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
- log_notice(LD_NET, "Opening %s on %s:%d",
- conn_type_to_string(type), fmt_addr(&addr), usePort);
+ log_notice(LD_NET, "Opening %s on %s",
+ conn_type_to_string(type), fmt_addrport(&addr, usePort));
s = tor_open_socket(tor_addr_family(&addr),
is_tcp ? SOCK_STREAM : SOCK_DGRAM,
@@ -940,7 +1046,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
if (is_tcp) {
- if (listen(s,SOMAXCONN) < 0) {
+ if (tor_listen(s) < 0) {
log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
tor_socket_strerror(tor_socket_errno(s)));
tor_close_socket(s);
@@ -992,6 +1098,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) {
log_warn(LD_NET,"Bind to %s failed: %s.", address,
tor_socket_strerror(tor_socket_errno(s)));
+ tor_close_socket(s);
goto err;
}
#ifdef HAVE_PWD_H
@@ -1000,9 +1107,12 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (pw == NULL) {
log_warn(LD_NET,"Unable to chown() %s socket: user %s not found.",
address, options->User);
+ tor_close_socket(s);
+ goto err;
} else if (chown(address, pw->pw_uid, pw->pw_gid) < 0) {
log_warn(LD_NET,"Unable to chown() %s socket: %s.",
address, strerror(errno));
+ tor_close_socket(s);
goto err;
}
}
@@ -1032,7 +1142,10 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_assert(0);
}
- set_socket_nonblocking(s);
+ if (set_socket_nonblocking(s) == -1) {
+ tor_close_socket(s);
+ goto err;
+ }
lis_conn = listener_connection_new(type, listensockaddr->sa_family);
conn = TO_CONN(lis_conn);
@@ -1056,6 +1169,20 @@ connection_listener_new(const struct sockaddr *listensockaddr,
lis_conn->session_group = global_next_session_group--;
}
}
+ if (type == CONN_TYPE_AP_LISTENER) {
+ lis_conn->socks_ipv4_traffic = port_cfg->ipv4_traffic;
+ lis_conn->socks_ipv6_traffic = port_cfg->ipv6_traffic;
+ lis_conn->socks_prefer_ipv6 = port_cfg->prefer_ipv6;
+ } else {
+ lis_conn->socks_ipv4_traffic = 1;
+ lis_conn->socks_ipv6_traffic = 1;
+ }
+ lis_conn->cache_ipv4_answers = port_cfg->cache_ipv4_answers;
+ lis_conn->cache_ipv6_answers = port_cfg->cache_ipv6_answers;
+ lis_conn->use_cached_ipv4_answers = port_cfg->use_cached_ipv4_answers;
+ lis_conn->use_cached_ipv6_answers = port_cfg->use_cached_ipv6_answers;
+ lis_conn->prefer_ipv6_virtaddr = port_cfg->prefer_ipv6_virtaddr;
+ lis_conn->socks_prefer_no_auth = port_cfg->socks_prefer_no_auth;
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
@@ -1089,7 +1216,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
* nmap does). We want to detect that, and not go on with the connection.
*/
static int
-check_sockaddr(struct sockaddr *sa, int len, int level)
+check_sockaddr(const struct sockaddr *sa, int len, int level)
{
int ok = 1;
@@ -1182,7 +1309,10 @@ connection_handle_listener_read(connection_t *conn, int new_type)
(int)news,(int)conn->s);
make_socket_reuseable(news);
- set_socket_nonblocking(news);
+ if (set_socket_nonblocking(news) == -1) {
+ tor_close_socket(news);
+ return 0;
+ }
if (options->ConstrainedSockets)
set_constrained_socket_buffers(news, (int)options->ConstrainedSockSize);
@@ -1202,11 +1332,6 @@ connection_handle_listener_read(connection_t *conn, int new_type)
return 0;
}
- if (check_sockaddr_family_match(remote->sa_family, conn) < 0) {
- tor_close_socket(news);
- return 0;
- }
-
tor_addr_from_sockaddr(&addr, remote, &port);
/* process entrance policies here, before we even create the connection */
@@ -1215,7 +1340,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
if (socks_policy_permits_address(&addr) == 0) {
log_notice(LD_APP,
"Denying socks connection from untrusted address %s.",
- fmt_addr(&addr));
+ fmt_and_decorate_addr(&addr));
tor_close_socket(news);
return 0;
}
@@ -1224,7 +1349,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
/* check dirpolicy to see if we should accept it */
if (dir_policy_permits_address(&addr) == 0) {
log_notice(LD_DIRSERV,"Denying dir connection from address %s.",
- fmt_addr(&addr));
+ fmt_and_decorate_addr(&addr));
tor_close_socket(news);
return 0;
}
@@ -1238,6 +1363,11 @@ connection_handle_listener_read(connection_t *conn, int new_type)
newconn->port = port;
newconn->address = tor_dup_addr(&addr);
+ if (new_type == CONN_TYPE_AP) {
+ TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth =
+ TO_LISTENER_CONN(conn)->socks_prefer_no_auth;
+ }
+
} else if (conn->socket_family == AF_UNIX) {
/* For now only control ports can be Unix domain sockets
* and listeners at the same time */
@@ -1276,17 +1406,36 @@ static int
connection_init_accepted_conn(connection_t *conn,
const listener_connection_t *listener)
{
+ int rv;
+
connection_start_reading(conn);
switch (conn->type) {
case CONN_TYPE_OR:
control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0);
- return connection_tls_start_handshake(TO_OR_CONN(conn), 1);
+ rv = connection_tls_start_handshake(TO_OR_CONN(conn), 1);
+ if (rv < 0) {
+ connection_or_close_for_error(TO_OR_CONN(conn), 0);
+ }
+ return rv;
+ break;
case CONN_TYPE_AP:
TO_ENTRY_CONN(conn)->isolation_flags = listener->isolation_flags;
TO_ENTRY_CONN(conn)->session_group = listener->session_group;
TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch();
- TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->_base.type;
+ TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->base_.type;
+ TO_ENTRY_CONN(conn)->ipv4_traffic_ok = listener->socks_ipv4_traffic;
+ TO_ENTRY_CONN(conn)->ipv6_traffic_ok = listener->socks_ipv6_traffic;
+ TO_ENTRY_CONN(conn)->prefer_ipv6_traffic = listener->socks_prefer_ipv6;
+ TO_ENTRY_CONN(conn)->cache_ipv4_answers = listener->cache_ipv4_answers;
+ TO_ENTRY_CONN(conn)->cache_ipv6_answers = listener->cache_ipv6_answers;
+ TO_ENTRY_CONN(conn)->use_cached_ipv4_answers =
+ listener->use_cached_ipv4_answers;
+ TO_ENTRY_CONN(conn)->use_cached_ipv6_answers =
+ listener->use_cached_ipv6_answers;
+ TO_ENTRY_CONN(conn)->prefer_ipv6_virtaddr =
+ listener->prefer_ipv6_virtaddr;
+
switch (TO_CONN(listener)->type) {
case CONN_TYPE_AP_LISTENER:
conn->state = AP_CONN_STATE_SOCKS_WAIT;
@@ -1333,7 +1482,7 @@ connection_connect(connection_t *conn, const char *address,
const or_options_t *options = get_options();
int protocol_family;
- if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
+ if (get_n_open_sockets() >= get_options()->ConnLimit_-1) {
warn_too_many_conns();
*socket_error = SOCK_ERRNO(ENOBUFS);
return -1;
@@ -1348,16 +1497,9 @@ connection_connect(connection_t *conn, const char *address,
/* We should never even try to connect anyplace if DisableNetwork is set.
* Warn if we do, and refuse to make the connection. */
static ratelim_t disablenet_violated = RATELIM_INIT(30*60);
- char *m;
-#ifdef _WIN32
- *socket_error = WSAENETUNREACH;
-#else
- *socket_error = ENETUNREACH;
-#endif
- if ((m = rate_limit_log(&disablenet_violated, approx_time()))) {
- log_warn(LD_BUG, "Tried to open a socket with DisableNetwork set.%s", m);
- tor_free(m);
- }
+ *socket_error = SOCK_ERRNO(ENETUNREACH);
+ log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG,
+ "Tried to open a socket with DisableNetwork set.");
tor_fragile_assert();
return -1;
}
@@ -1372,28 +1514,43 @@ connection_connect(connection_t *conn, const char *address,
make_socket_reuseable(s);
- if (options->OutboundBindAddress && !tor_addr_is_loopback(addr)) {
- struct sockaddr_in ext_addr;
-
- memset(&ext_addr, 0, sizeof(ext_addr));
- ext_addr.sin_family = AF_INET;
- ext_addr.sin_port = 0;
- if (!tor_inet_aton(options->OutboundBindAddress, &ext_addr.sin_addr)) {
- log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
- options->OutboundBindAddress);
- } else {
- if (bind(s, (struct sockaddr*)&ext_addr,
- (socklen_t)sizeof(ext_addr)) < 0) {
- *socket_error = tor_socket_errno(s);
- log_warn(LD_NET,"Error binding network socket: %s",
- tor_socket_strerror(*socket_error));
- tor_close_socket(s);
- return -1;
+ if (!tor_addr_is_loopback(addr)) {
+ const tor_addr_t *ext_addr = NULL;
+ if (protocol_family == AF_INET &&
+ !tor_addr_is_null(&options->OutboundBindAddressIPv4_))
+ ext_addr = &options->OutboundBindAddressIPv4_;
+ else if (protocol_family == AF_INET6 &&
+ !tor_addr_is_null(&options->OutboundBindAddressIPv6_))
+ ext_addr = &options->OutboundBindAddressIPv6_;
+ if (ext_addr) {
+ struct sockaddr_storage ext_addr_sa;
+ socklen_t ext_addr_len = 0;
+ memset(&ext_addr_sa, 0, sizeof(ext_addr_sa));
+ ext_addr_len = tor_addr_to_sockaddr(ext_addr, 0,
+ (struct sockaddr *) &ext_addr_sa,
+ sizeof(ext_addr_sa));
+ if (ext_addr_len == 0) {
+ log_warn(LD_NET,
+ "Error converting OutboundBindAddress %s into sockaddr. "
+ "Ignoring.", fmt_and_decorate_addr(ext_addr));
+ } else {
+ if (bind(s, (struct sockaddr *) &ext_addr_sa, ext_addr_len) < 0) {
+ *socket_error = tor_socket_errno(s);
+ log_warn(LD_NET,"Error binding network socket to %s: %s",
+ fmt_and_decorate_addr(ext_addr),
+ tor_socket_strerror(*socket_error));
+ tor_close_socket(s);
+ return -1;
+ }
}
}
}
- set_socket_nonblocking(s);
+ if (set_socket_nonblocking(s) == -1) {
+ *socket_error = tor_socket_errno(s);
+ tor_close_socket(s);
+ return -1;
+ }
if (options->ConstrainedSockets)
set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
@@ -1424,7 +1581,7 @@ connection_connect(connection_t *conn, const char *address,
/* it succeeded. we're connected. */
log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET,
- "Connection to %s:%u %s (sock %d).",
+ "Connection to %s:%u %s (sock "TOR_SOCKET_T_FORMAT").",
escaped_safe_str_client(address),
port, inprogress?"in progress":"established", s);
conn->s = s;
@@ -1495,17 +1652,17 @@ connection_proxy_connect(connection_t *conn, int type)
}
if (base64_authenticator) {
- const char *addr = fmt_addr(&conn->addr);
- tor_snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\n"
- "Host: %s:%d\r\n"
+ const char *addrport = fmt_addrport(&conn->addr, conn->port);
+ tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.1\r\n"
+ "Host: %s\r\n"
"Proxy-Authorization: Basic %s\r\n\r\n",
- addr, conn->port,
- addr, conn->port,
+ addrport,
+ addrport,
base64_authenticator);
tor_free(base64_authenticator);
} else {
- tor_snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n\r\n",
- fmt_addr(&conn->addr), conn->port);
+ tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.0\r\n\r\n",
+ fmt_addrport(&conn->addr, conn->port));
}
connection_write_to_buf(buf, strlen(buf), conn);
@@ -1607,6 +1764,7 @@ connection_read_https_proxy_response(connection_t *conn)
tor_free(headers);
return -1;
}
+ tor_free(headers);
if (!reason) reason = tor_strdup("[no reason given]");
if (status_code == 200) {
@@ -1952,6 +2110,8 @@ retry_all_listeners(smartlist_t *replaced_conns,
const or_options_t *options = get_options();
int retval = 0;
const uint16_t old_or_port = router_get_advertised_or_port(options);
+ const uint16_t old_or_port_ipv6 =
+ router_get_advertised_or_port_by_af(options,AF_INET6);
const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0);
SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
@@ -1980,8 +2140,9 @@ retry_all_listeners(smartlist_t *replaced_conns,
smartlist_free(listeners);
- /* XXXprop186 should take all advertised ports into account */
if (old_or_port != router_get_advertised_or_port(options) ||
+ old_or_port_ipv6 != router_get_advertised_or_port_by_af(options,
+ AF_INET6) ||
old_dir_port != router_get_advertised_dir_port(options, 0)) {
/* Our chosen ORPort or DirPort is not what it used to be: the
* descriptor we had (if any) should be regenerated. (We won't
@@ -2033,9 +2194,9 @@ connection_mark_all_noncontrol_connections(void)
/** Return 1 if we should apply rate limiting to <b>conn</b>, and 0
* otherwise.
* Right now this just checks if it's an internal IP address or an
- * internal connection. We also check if the connection uses pluggable
- * transports, since we should then limit it even if it comes from an
- * internal IP address. */
+ * internal connection. We also should, but don't, check if the connection
+ * uses pluggable transports, since we should then limit it even if it
+ * comes from an internal IP address. */
static int
connection_is_rate_limited(connection_t *conn)
{
@@ -2075,7 +2236,8 @@ static int
connection_counts_as_relayed_traffic(connection_t *conn, time_t now)
{
if (conn->type == CONN_TYPE_OR &&
- TO_OR_CONN(conn)->client_used + CLIENT_IDLE_TIME_FOR_PRIORITY < now)
+ connection_or_client_used(TO_OR_CONN(conn)) +
+ CLIENT_IDLE_TIME_FOR_PRIORITY < now)
return 1;
if (conn->type == CONN_TYPE_DIR && DIR_CONN_IS_SERVER(conn))
return 1;
@@ -2120,8 +2282,7 @@ connection_bucket_round_robin(int base, int priority,
static ssize_t
connection_bucket_read_limit(connection_t *conn, time_t now)
{
- int base = connection_speaks_cells(conn) ?
- CELL_NETWORK_SIZE : RELAY_PAYLOAD_SIZE;
+ int base = RELAY_PAYLOAD_SIZE;
int priority = conn->type != CONN_TYPE_DIR;
int conn_bucket = -1;
int global_bucket = global_read_bucket;
@@ -2130,6 +2291,7 @@ connection_bucket_read_limit(connection_t *conn, time_t now)
or_connection_t *or_conn = TO_OR_CONN(conn);
if (conn->state == OR_CONN_STATE_OPEN)
conn_bucket = or_conn->read_bucket;
+ base = get_cell_network_size(or_conn->wide_circ_ids);
}
if (!connection_is_rate_limited(conn)) {
@@ -2149,8 +2311,7 @@ connection_bucket_read_limit(connection_t *conn, time_t now)
ssize_t
connection_bucket_write_limit(connection_t *conn, time_t now)
{
- int base = connection_speaks_cells(conn) ?
- CELL_NETWORK_SIZE : RELAY_PAYLOAD_SIZE;
+ int base = RELAY_PAYLOAD_SIZE;
int priority = conn->type != CONN_TYPE_DIR;
int conn_bucket = (int)conn->outbuf_flushlen;
int global_bucket = global_write_bucket;
@@ -2168,6 +2329,7 @@ connection_bucket_write_limit(connection_t *conn, time_t now)
if (or_conn->write_bucket < conn_bucket)
conn_bucket = or_conn->write_bucket >= 0 ?
or_conn->write_bucket : 0;
+ base = get_cell_network_size(or_conn->wide_circ_ids);
}
if (connection_counts_as_relayed_traffic(conn, now) &&
@@ -2358,6 +2520,9 @@ connection_consider_empty_read_buckets(connection_t *conn)
} else
return; /* all good, no need to stop it */
+ if (conn->type == CONN_TYPE_CPUWORKER)
+ return; /* Always okay. */
+
LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason));
conn->read_blocked_on_bw = 1;
connection_stop_reading(conn);
@@ -2382,6 +2547,9 @@ connection_consider_empty_write_buckets(connection_t *conn)
} else
return; /* all good, no need to stop it */
+ if (conn->type == CONN_TYPE_CPUWORKER)
+ return; /* Always okay. */
+
LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason));
conn->write_blocked_on_bw = 1;
connection_stop_writing(conn);
@@ -2429,7 +2597,7 @@ connection_bucket_refill_helper(int *bucket, int rate, int burst,
*bucket = burst;
}
}
- log(LOG_DEBUG, LD_NET,"%s now %d.", name, *bucket);
+ log_debug(LD_NET,"%s now %d.", name, *bucket);
}
}
@@ -2534,7 +2702,7 @@ connection_bucket_should_increase(int bucket, or_connection_t *conn)
{
tor_assert(conn);
- if (conn->_base.state != OR_CONN_STATE_OPEN)
+ if (conn->base_.state != OR_CONN_STATE_OPEN)
return 0; /* only open connections play the rate limiting game */
if (bucket >= conn->bandwidthburst)
return 0;
@@ -2672,11 +2840,14 @@ connection_handle_read_impl(connection_t *conn)
before = buf_datalen(conn->inbuf);
if (connection_read_to_buf(conn, &max_to_read, &socket_error) < 0) {
/* There's a read error; kill the connection.*/
- if (conn->type == CONN_TYPE_OR &&
- conn->state == OR_CONN_STATE_CONNECTING) {
- connection_or_connect_failed(TO_OR_CONN(conn),
- errno_to_orconn_end_reason(socket_error),
- tor_socket_strerror(socket_error));
+ if (conn->type == CONN_TYPE_OR) {
+ connection_or_notify_error(TO_OR_CONN(conn),
+ socket_error != 0 ?
+ errno_to_orconn_end_reason(socket_error) :
+ END_OR_CONN_REASON_CONNRESET,
+ socket_error != 0 ?
+ tor_socket_strerror(socket_error) :
+ "(unknown, errno was 0)");
}
if (CONN_IS_EDGE(conn)) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
@@ -2687,7 +2858,11 @@ connection_handle_read_impl(connection_t *conn)
}
}
connection_close_immediate(conn); /* Don't flush; connection is dead. */
- connection_mark_for_close(conn);
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
return -1;
}
n_read += buf_datalen(conn->inbuf) - before;
@@ -3181,6 +3356,7 @@ connection_handle_write_impl(connection_t *conn, int force)
ssize_t max_to_write;
time_t now = approx_time();
size_t n_read = 0, n_written = 0;
+ int dont_stop_writing = 0;
tor_assert(!connection_is_listener(conn));
@@ -3211,12 +3387,16 @@ connection_handle_write_impl(connection_t *conn, int force)
if (CONN_IS_EDGE(conn))
connection_edge_end_errno(TO_EDGE_CONN(conn));
if (conn->type == CONN_TYPE_OR)
- connection_or_connect_failed(TO_OR_CONN(conn),
- errno_to_orconn_end_reason(e),
- tor_socket_strerror(e));
+ connection_or_notify_error(TO_OR_CONN(conn),
+ errno_to_orconn_end_reason(e),
+ tor_socket_strerror(e));
connection_close_immediate(conn);
- connection_mark_for_close(conn);
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
return -1;
} else {
return 0; /* no change, see if next time is better */
@@ -3233,13 +3413,22 @@ connection_handle_write_impl(connection_t *conn, int force)
if (connection_speaks_cells(conn) &&
conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) {
or_connection_t *or_conn = TO_OR_CONN(conn);
+ size_t initial_size;
if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING ||
conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) {
connection_stop_writing(conn);
if (connection_tls_continue_handshake(or_conn) < 0) {
/* Don't flush; connection is dead. */
+ connection_or_notify_error(or_conn,
+ END_OR_CONN_REASON_MISC,
+ "TLS error in connection_tls_"
+ "continue_handshake()");
connection_close_immediate(conn);
- connection_mark_for_close(conn);
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
return -1;
}
return 0;
@@ -3248,29 +3437,39 @@ connection_handle_write_impl(connection_t *conn, int force)
}
/* else open, or closing */
+ initial_size = buf_datalen(conn->outbuf);
result = flush_buf_tls(or_conn->tls, conn->outbuf,
max_to_write, &conn->outbuf_flushlen);
- /* If we just flushed the last bytes, check if this tunneled dir
- * request is done. */
+ /* If we just flushed the last bytes, tell the channel on the
+ * or_conn to check if it needs to geoip_change_dirreq_state() */
/* XXXX move this to flushed_some or finished_flushing -NM */
- if (buf_datalen(conn->outbuf) == 0 && conn->dirreq_id)
- geoip_change_dirreq_state(conn->dirreq_id, DIRREQ_TUNNELED,
- DIRREQ_OR_CONN_BUFFER_FLUSHED);
+ if (buf_datalen(conn->outbuf) == 0 && or_conn->chan)
+ channel_notify_flushed(TLS_CHAN_TO_BASE(or_conn->chan));
switch (result) {
CASE_TOR_TLS_ERROR_ANY:
case TOR_TLS_CLOSE:
- log_info(LD_NET,result!=TOR_TLS_CLOSE?
+ log_info(LD_NET, result != TOR_TLS_CLOSE ?
"tls error. breaking.":"TLS connection closed on flush");
/* Don't flush; connection is dead. */
+ connection_or_notify_error(or_conn,
+ END_OR_CONN_REASON_MISC,
+ result != TOR_TLS_CLOSE ?
+ "TLS error in during flush" :
+ "TLS closed during flush");
connection_close_immediate(conn);
- connection_mark_for_close(conn);
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
return -1;
case TOR_TLS_WANTWRITE:
log_debug(LD_NET,"wanted write.");
/* we're already writing */
- return 0;
+ dont_stop_writing = 1;
+ break;
case TOR_TLS_WANTREAD:
/* Make sure to avoid a loop if the receive buckets are empty. */
log_debug(LD_NET,"wanted read.");
@@ -3292,6 +3491,12 @@ connection_handle_write_impl(connection_t *conn, int force)
tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written);
log_debug(LD_GENERAL, "After TLS write of %d: %ld read, %ld written",
result, (long)n_read, (long)n_written);
+ /* So we notice bytes were written even on error */
+ /* XXXX024 This cast is safe since we can never write INT_MAX bytes in a
+ * single set of TLS operations. But it looks kinda ugly. If we refactor
+ * the *_buf_tls functions, we should make them return ssize_t or size_t
+ * or something. */
+ result = (int)(initial_size-buf_datalen(conn->outbuf));
} else {
CONN_LOG_PROTECT(conn,
result = flush_buf(conn->s, conn->outbuf,
@@ -3299,6 +3504,10 @@ connection_handle_write_impl(connection_t *conn, int force)
if (result < 0) {
if (CONN_IS_EDGE(conn))
connection_edge_end_errno(TO_EDGE_CONN(conn));
+ if (conn->type == CONN_TYPE_AP) {
+ /* writing failed; we couldn't send a SOCKS reply if we wanted to */
+ TO_ENTRY_CONN(conn)->socks_request->has_finished = 1;
+ }
connection_close_immediate(conn); /* Don't flush; connection is dead. */
connection_mark_for_close(conn);
@@ -3322,11 +3531,24 @@ connection_handle_write_impl(connection_t *conn, int force)
if (result > 0) {
/* If we wrote any bytes from our buffer, then call the appropriate
* functions. */
- if (connection_flushed_some(conn) < 0)
- connection_mark_for_close(conn);
+ if (connection_flushed_some(conn) < 0) {
+ if (connection_speaks_cells(conn)) {
+ connection_or_notify_error(TO_OR_CONN(conn),
+ END_OR_CONN_REASON_MISC,
+ "Got error back from "
+ "connection_flushed_some()");
+ }
+
+ /*
+ * This can bypass normal channel checking since we did
+ * connection_or_notify_error() above.
+ */
+ connection_mark_for_close_internal(conn);
+ }
}
- if (!connection_wants_to_flush(conn)) { /* it's done flushing */
+ if (!connection_wants_to_flush(conn) &&
+ !dont_stop_writing) { /* it's done flushing */
if (connection_finished_flushing(conn) < 0) {
/* already marked */
return -1;
@@ -3375,13 +3597,6 @@ connection_flush(connection_t *conn)
return connection_handle_write(conn, 1);
}
-/** OpenSSL TLS record size is 16383; this is close. The goal here is to
- * push data out as soon as we know there's enough for a TLS record, so
- * during periods of high load we won't read entire megabytes from
- * input before pushing any data out. It also has the feature of not
- * growing huge outbufs unless something is slow. */
-#define MIN_TLS_FLUSHLEN 15872
-
/** Append <b>len</b> bytes of <b>string</b> onto <b>conn</b>'s
* outbuf, and ask it to start writing.
*
@@ -3390,13 +3605,12 @@ connection_flush(connection_t *conn)
* negative, this is the last data to be compressed, and the connection's zlib
* state should be flushed.
*
- * If it's an OR conn and an entire TLS record is ready, then try to
- * flush the record now. Similarly, if it's a local control connection
- * and a 64k chunk is ready, try to flush it all, so we don't end up with
- * many megabytes of controller info queued at once.
+ * If it's a local control connection and a 64k chunk is ready, try to flush
+ * it all, so we don't end up with many megabytes of controller info queued at
+ * once.
*/
void
-_connection_write_to_buf_impl(const char *string, size_t len,
+connection_write_to_buf_impl_(const char *string, size_t len,
connection_t *conn, int zlib)
{
/* XXXX This function really needs to return -1 on failure. */
@@ -3461,7 +3675,6 @@ _connection_write_to_buf_impl(const char *string, size_t len,
if (zlib) {
conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen;
} else {
- ssize_t extra = 0;
conn->outbuf_flushlen += len;
/* Should we try flushing the outbuf now? */
@@ -3471,14 +3684,7 @@ _connection_write_to_buf_impl(const char *string, size_t len,
return;
}
- if (conn->type == CONN_TYPE_OR &&
- conn->outbuf_flushlen-len < MIN_TLS_FLUSHLEN &&
- conn->outbuf_flushlen >= MIN_TLS_FLUSHLEN) {
- /* We just pushed outbuf_flushlen to MIN_TLS_FLUSHLEN or above;
- * we can send out a full TLS frame now if we like. */
- extra = conn->outbuf_flushlen - MIN_TLS_FLUSHLEN;
- conn->outbuf_flushlen = MIN_TLS_FLUSHLEN;
- } else if (conn->type == CONN_TYPE_CONTROL &&
+ if (conn->type == CONN_TYPE_CONTROL &&
!connection_is_rate_limited(conn) &&
conn->outbuf_flushlen-len < 1<<16 &&
conn->outbuf_flushlen >= 1<<16) {
@@ -3498,10 +3704,6 @@ _connection_write_to_buf_impl(const char *string, size_t len,
}
return;
}
- if (extra) {
- conn->outbuf_flushlen += extra;
- connection_start_writing(conn);
- }
}
}
@@ -3792,7 +3994,7 @@ client_check_address_changed(tor_socket_t sock)
} else {
/* The interface changed. We're a client, so we need to regenerate our
* keys. First, reset the state. */
- log(LOG_NOTICE, LD_NET, "Our IP address has changed. Rotating keys...");
+ log_notice(LD_NET, "Our IP address has changed. Rotating keys...");
tor_addr_copy(*last_interface_ip_ptr, &iface_addr);
SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t*, a_ptr, tor_free(a_ptr));
smartlist_clear(outgoing_addrs);
@@ -3876,8 +4078,9 @@ connection_flushed_some(connection_t *conn)
return r;
}
-/** We just finished flushing bytes from conn-\>outbuf, and there
- * are no more bytes remaining.
+/** We just finished flushing bytes to the appropriately low network layer,
+ * and there are no more bytes remaining in conn-\>outbuf, conn-\>bev, or
+ * conn-\>tls to be flushed.
*
* This function just passes conn to the connection-specific
* connection_*_finished_flushing() function.
@@ -3975,9 +4178,9 @@ connection_reached_eof(connection_t *conn)
void
connection_dump_buffer_mem_stats(int severity)
{
- uint64_t used_by_type[_CONN_TYPE_MAX+1];
- uint64_t alloc_by_type[_CONN_TYPE_MAX+1];
- int n_conns_by_type[_CONN_TYPE_MAX+1];
+ uint64_t used_by_type[CONN_TYPE_MAX_+1];
+ uint64_t alloc_by_type[CONN_TYPE_MAX_+1];
+ int n_conns_by_type[CONN_TYPE_MAX_+1];
uint64_t total_alloc = 0;
uint64_t total_used = 0;
int i;
@@ -3999,19 +4202,19 @@ connection_dump_buffer_mem_stats(int severity)
alloc_by_type[tp] += buf_allocation(c->outbuf);
}
} SMARTLIST_FOREACH_END(c);
- for (i=0; i <= _CONN_TYPE_MAX; ++i) {
+ for (i=0; i <= CONN_TYPE_MAX_; ++i) {
total_used += used_by_type[i];
total_alloc += alloc_by_type[i];
}
- log(severity, LD_GENERAL,
+ tor_log(severity, LD_GENERAL,
"In buffers for %d connections: "U64_FORMAT" used/"U64_FORMAT" allocated",
smartlist_len(conns),
U64_PRINTF_ARG(total_used), U64_PRINTF_ARG(total_alloc));
- for (i=_CONN_TYPE_MIN; i <= _CONN_TYPE_MAX; ++i) {
+ for (i=CONN_TYPE_MIN_; i <= CONN_TYPE_MAX_; ++i) {
if (!n_conns_by_type[i])
continue;
- log(severity, LD_GENERAL,
+ tor_log(severity, LD_GENERAL,
" For %d %s connections: "U64_FORMAT" used/"U64_FORMAT" allocated",
n_conns_by_type[i], conn_type_to_string(i),
U64_PRINTF_ARG(used_by_type[i]), U64_PRINTF_ARG(alloc_by_type[i]));
@@ -4026,8 +4229,8 @@ assert_connection_ok(connection_t *conn, time_t now)
{
(void) now; /* XXXX unused. */
tor_assert(conn);
- tor_assert(conn->type >= _CONN_TYPE_MIN);
- tor_assert(conn->type <= _CONN_TYPE_MAX);
+ tor_assert(conn->type >= CONN_TYPE_MIN_);
+ tor_assert(conn->type <= CONN_TYPE_MAX_);
#ifdef USE_BUFFEREVENTS
if (conn->bufev) {
@@ -4142,34 +4345,33 @@ assert_connection_ok(connection_t *conn, time_t now)
tor_assert(conn->state == LISTENER_STATE_READY);
break;
case CONN_TYPE_OR:
- tor_assert(conn->state >= _OR_CONN_STATE_MIN);
- tor_assert(conn->state <= _OR_CONN_STATE_MAX);
- tor_assert(TO_OR_CONN(conn)->n_circuits >= 0);
+ tor_assert(conn->state >= OR_CONN_STATE_MIN_);
+ tor_assert(conn->state <= OR_CONN_STATE_MAX_);
break;
case CONN_TYPE_EXIT:
- tor_assert(conn->state >= _EXIT_CONN_STATE_MIN);
- tor_assert(conn->state <= _EXIT_CONN_STATE_MAX);
- tor_assert(conn->purpose >= _EXIT_PURPOSE_MIN);
- tor_assert(conn->purpose <= _EXIT_PURPOSE_MAX);
+ tor_assert(conn->state >= EXIT_CONN_STATE_MIN_);
+ tor_assert(conn->state <= EXIT_CONN_STATE_MAX_);
+ tor_assert(conn->purpose >= EXIT_PURPOSE_MIN_);
+ tor_assert(conn->purpose <= EXIT_PURPOSE_MAX_);
break;
case CONN_TYPE_AP:
- tor_assert(conn->state >= _AP_CONN_STATE_MIN);
- tor_assert(conn->state <= _AP_CONN_STATE_MAX);
+ tor_assert(conn->state >= AP_CONN_STATE_MIN_);
+ tor_assert(conn->state <= AP_CONN_STATE_MAX_);
tor_assert(TO_ENTRY_CONN(conn)->socks_request);
break;
case CONN_TYPE_DIR:
- tor_assert(conn->state >= _DIR_CONN_STATE_MIN);
- tor_assert(conn->state <= _DIR_CONN_STATE_MAX);
- tor_assert(conn->purpose >= _DIR_PURPOSE_MIN);
- tor_assert(conn->purpose <= _DIR_PURPOSE_MAX);
+ tor_assert(conn->state >= DIR_CONN_STATE_MIN_);
+ tor_assert(conn->state <= DIR_CONN_STATE_MAX_);
+ tor_assert(conn->purpose >= DIR_PURPOSE_MIN_);
+ tor_assert(conn->purpose <= DIR_PURPOSE_MAX_);
break;
case CONN_TYPE_CPUWORKER:
- tor_assert(conn->state >= _CPUWORKER_STATE_MIN);
- tor_assert(conn->state <= _CPUWORKER_STATE_MAX);
+ tor_assert(conn->state >= CPUWORKER_STATE_MIN_);
+ tor_assert(conn->state <= CPUWORKER_STATE_MAX_);
break;
case CONN_TYPE_CONTROL:
- tor_assert(conn->state >= _CONTROL_CONN_STATE_MIN);
- tor_assert(conn->state <= _CONTROL_CONN_STATE_MAX);
+ tor_assert(conn->state >= CONTROL_CONN_STATE_MIN_);
+ tor_assert(conn->state <= CONTROL_CONN_STATE_MAX_);
break;
default:
tor_assert(0);
@@ -4253,10 +4455,10 @@ log_failed_proxy_connection(connection_t *conn)
return; /* if we have no proxy set up, leave this function. */
log_warn(LD_NET,
- "The connection to the %s proxy server at %s:%u just failed. "
+ "The connection to the %s proxy server at %s just failed. "
"Make sure that the proxy server is up and running.",
- proxy_type_to_string(get_proxy_type()), fmt_addr(&proxy_addr),
- proxy_port);
+ proxy_type_to_string(get_proxy_type()),
+ fmt_addrport(&proxy_addr, proxy_port));
}
/** Return string representation of <b>proxy_type</b>. */
@@ -4274,7 +4476,7 @@ proxy_type_to_string(int proxy_type)
return NULL; /*Unreached*/
}
-/** Call _connection_free() on every connection in our array, and release all
+/** Call connection_free_() on every connection in our array, and release all
* storage held by connection.c. This is used by cpuworkers and dnsworkers
* when they fork, so they don't keep resources held open (especially
* sockets).
@@ -4300,7 +4502,7 @@ connection_free_all(void)
/* Clear out our list of broken connections */
clear_broken_connection_map(0);
- SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
+ SMARTLIST_FOREACH(conns, connection_t *, conn, connection_free_(conn));
if (outgoing_addrs) {
SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t *, addr, tor_free(addr));
@@ -4308,6 +4510,9 @@ connection_free_all(void)
outgoing_addrs = NULL;
}
+ tor_free(last_interface_ipv4);
+ tor_free(last_interface_ipv6);
+
#ifdef USE_BUFFEREVENTS
if (global_rate_limit)
bufferevent_rate_limit_group_free(global_rate_limit);
diff --git a/src/or/connection.h b/src/or/connection.h
index 785625e44..c78fe6e65 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for connection.c.
**/
-#ifndef _TOR_CONNECTION_H
-#define _TOR_CONNECTION_H
+#ifndef TOR_CONNECTION_H
+#define TOR_CONNECTION_H
/* XXXX For buf_datalen in inline function */
#include "buffers.h"
@@ -31,25 +31,57 @@ void connection_free(connection_t *conn);
void connection_free_all(void);
void connection_about_to_close_connection(connection_t *conn);
void connection_close_immediate(connection_t *conn);
-void _connection_mark_for_close(connection_t *conn,int line, const char *file);
+void connection_mark_for_close_(connection_t *conn,
+ int line, const char *file);
+void connection_mark_for_close_internal_(connection_t *conn,
+ int line, const char *file);
#define connection_mark_for_close(c) \
- _connection_mark_for_close((c), __LINE__, _SHORT_FILE_)
+ connection_mark_for_close_((c), __LINE__, SHORT_FILE__)
+#define connection_mark_for_close_internal(c) \
+ connection_mark_for_close_internal_((c), __LINE__, SHORT_FILE__)
/**
* Mark 'c' for close, but try to hold it open until all the data is written.
+ * Use the _internal versions of connection_mark_for_close; this should be
+ * called when you either are sure that if this is an or_connection_t the
+ * controlling channel has been notified (e.g. with
+ * connection_or_notify_error()), or you actually are the
+ * connection_or_close_for_error() or connection_or_close_normally function.
+ * For all other cases, use connection_mark_and_flush() instead, which
+ * checks for or_connection_t properly, instead. See below.
*/
-#define _connection_mark_and_flush(c,line,file) \
- do { \
- connection_t *tmp_conn_ = (c); \
- _connection_mark_for_close(tmp_conn_, (line), (file)); \
- tmp_conn_->hold_open_until_flushed = 1; \
- IF_HAS_BUFFEREVENT(tmp_conn_, \
- connection_start_writing(tmp_conn_)); \
+#define connection_mark_and_flush_internal_(c,line,file) \
+ do { \
+ connection_t *tmp_conn_ = (c); \
+ connection_mark_for_close_internal_(tmp_conn_, (line), (file)); \
+ tmp_conn_->hold_open_until_flushed = 1; \
+ IF_HAS_BUFFEREVENT(tmp_conn_, \
+ connection_start_writing(tmp_conn_)); \
+ } while (0)
+
+#define connection_mark_and_flush_internal(c) \
+ connection_mark_and_flush_internal_((c), __LINE__, SHORT_FILE__)
+
+/**
+ * Mark 'c' for close, but try to hold it open until all the data is written.
+ */
+#define connection_mark_and_flush_(c,line,file) \
+ do { \
+ connection_t *tmp_conn_ = (c); \
+ if (tmp_conn_->type == CONN_TYPE_OR) { \
+ log_warn(LD_CHANNEL | LD_BUG, \
+ "Something tried to close (and flush) an or_connection_t" \
+ " without going through channels at %s:%d", \
+ file, line); \
+ connection_or_close_for_error(TO_OR_CONN(tmp_conn_), 1); \
+ } else { \
+ connection_mark_and_flush_internal_(c, line, file); \
+ } \
} while (0)
#define connection_mark_and_flush(c) \
- _connection_mark_and_flush((c), __LINE__, _SHORT_FILE_)
+ connection_mark_and_flush_((c), __LINE__, SHORT_FILE__)
void connection_expire_held_open(void);
@@ -90,7 +122,7 @@ int connection_outbuf_too_full(connection_t *conn);
int connection_handle_write(connection_t *conn, int force);
int connection_flush(connection_t *conn);
-void _connection_write_to_buf_impl(const char *string, size_t len,
+void connection_write_to_buf_impl_(const char *string, size_t len,
connection_t *conn, int zlib);
/* DOCDOC connection_write_to_buf */
static void connection_write_to_buf(const char *string, size_t len,
@@ -101,13 +133,13 @@ static void connection_write_to_buf_zlib(const char *string, size_t len,
static INLINE void
connection_write_to_buf(const char *string, size_t len, connection_t *conn)
{
- _connection_write_to_buf_impl(string, len, conn, 0);
+ connection_write_to_buf_impl_(string, len, conn, 0);
}
static INLINE void
connection_write_to_buf_zlib(const char *string, size_t len,
dir_connection_t *conn, int done)
{
- _connection_write_to_buf_impl(string, len, TO_CONN(conn), done ? -1 : 1);
+ connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1);
}
/* DOCDOC connection_get_inbuf_len */
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 362ad9af9..3a72110ea 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1,16 +1,19 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file connection_edge.c
* \brief Handle edge streams.
**/
+#define CONNECTION_EDGE_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
+#include "channel.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
@@ -33,6 +36,8 @@
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
+#include "routerset.h"
+#include "circuitbuild.h"
#ifdef HAVE_LINUX_TYPES_H
#include <linux/types.h>
@@ -54,17 +59,20 @@
static int connection_ap_handshake_process_socks(entry_connection_t *conn);
static int connection_ap_process_natd(entry_connection_t *conn);
static int connection_exit_connect_dir(edge_connection_t *exitconn);
-static int address_is_in_virtual_range(const char *addr);
static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port);
-static void clear_trackexithost_mappings(const char *exitname);
static int connection_ap_supports_optimistic_data(const entry_connection_t *);
+static void connection_ap_handshake_socks_resolved_addr(
+ entry_connection_t *conn,
+ const tor_addr_t *answer,
+ int ttl,
+ time_t expires);
/** An AP stream has failed/finished. If it hasn't already sent back
* a socks reply, send one now (based on endreason). Also set
* has_sent_end to 1, and mark the conn.
*/
void
-_connection_mark_unattached_ap(entry_connection_t *conn, int endreason,
+connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
int line, const char *file)
{
connection_t *base_conn = ENTRY_TO_CONN(conn);
@@ -87,7 +95,7 @@ _connection_mark_unattached_ap(entry_connection_t *conn, int endreason,
if (base_conn->marked_for_close) {
/* This call will warn as appropriate. */
- _connection_mark_for_close(base_conn, line, file);
+ connection_mark_for_close_(base_conn, line, file);
return;
}
@@ -107,7 +115,7 @@ _connection_mark_unattached_ap(entry_connection_t *conn, int endreason,
conn->socks_request->has_finished = 1;
}
- _connection_mark_and_flush(base_conn, line, file);
+ connection_mark_and_flush_(base_conn, line, file);
ENTRY_TO_EDGE_CONN(conn)->end_reason = endreason;
}
@@ -122,12 +130,13 @@ connection_edge_reached_eof(edge_connection_t *conn)
/* it still has stuff to process. don't let it die yet. */
return 0;
}
- log_info(LD_EDGE,"conn (fd %d) reached eof. Closing.", conn->_base.s);
- if (!conn->_base.marked_for_close) {
+ log_info(LD_EDGE,"conn (fd "TOR_SOCKET_T_FORMAT") reached eof. Closing.",
+ conn->base_.s);
+ if (!conn->base_.marked_for_close) {
/* only mark it if not already marked. it's possible to
* get the 'end' right around when the client hangs up on us. */
connection_edge_end(conn, END_STREAM_REASON_DONE);
- if (conn->_base.type == CONN_TYPE_AP) {
+ if (conn->base_.type == CONN_TYPE_AP) {
/* eof, so don't send a socks reply back */
if (EDGE_TO_ENTRY_CONN(conn)->socks_request)
EDGE_TO_ENTRY_CONN(conn)->socks_request->has_finished = 1;
@@ -152,7 +161,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
{
tor_assert(conn);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case AP_CONN_STATE_SOCKS_WAIT:
if (connection_ap_handshake_process_socks(EDGE_TO_ENTRY_CONN(conn)) <0) {
/* already marked */
@@ -178,7 +187,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
log_info(LD_EDGE,
"data from edge while in '%s' state. Sending it anyway. "
"package_partial=%d, buflen=%ld",
- conn_state_to_string(conn->_base.type, conn->_base.state),
+ conn_state_to_string(conn->base_.type, conn->base_.state),
package_partial,
(long)connection_get_inbuf_len(TO_CONN(conn)));
if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) {
@@ -197,10 +206,10 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
case AP_CONN_STATE_CONTROLLER_WAIT:
log_info(LD_EDGE,
"data from edge while in '%s' state. Leaving it on buffer.",
- conn_state_to_string(conn->_base.type, conn->_base.state));
+ conn_state_to_string(conn->base_.type, conn->base_.state));
return 0;
}
- log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->_base.state);
+ log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->base_.state);
tor_fragile_assert();
connection_edge_end(conn, END_STREAM_REASON_INTERNAL);
connection_mark_for_close(TO_CONN(conn));
@@ -213,10 +222,10 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
int
connection_edge_destroy(circid_t circ_id, edge_connection_t *conn)
{
- if (!conn->_base.marked_for_close) {
- log_info(LD_EDGE,
- "CircID %d: At an edge. Marking connection for close.", circ_id);
- if (conn->_base.type == CONN_TYPE_AP) {
+ if (!conn->base_.marked_for_close) {
+ log_info(LD_EDGE, "CircID %u: At an edge. Marking connection for close.",
+ (unsigned) circ_id);
+ if (conn->base_.type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_DESTROY);
control_event_stream_bandwidth(conn);
@@ -280,10 +289,10 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason)
return -1;
}
- if (conn->_base.marked_for_close) {
+ if (conn->base_.marked_for_close) {
log_warn(LD_BUG,
"called on conn that's already marked for close at %s:%d.",
- conn->_base.marked_for_close_file, conn->_base.marked_for_close);
+ conn->base_.marked_for_close_file, conn->base_.marked_for_close);
return 0;
}
@@ -299,11 +308,11 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason)
if (reason == END_STREAM_REASON_EXITPOLICY &&
!connection_edge_is_rendezvous_stream(conn)) {
int addrlen;
- if (tor_addr_family(&conn->_base.addr) == AF_INET) {
- set_uint32(payload+1, tor_addr_to_ipv4n(&conn->_base.addr));
+ if (tor_addr_family(&conn->base_.addr) == AF_INET) {
+ set_uint32(payload+1, tor_addr_to_ipv4n(&conn->base_.addr));
addrlen = 4;
} else {
- memcpy(payload+1, tor_addr_to_in6_addr8(&conn->_base.addr), 16);
+ memcpy(payload+1, tor_addr_to_in6_addr8(&conn->base_.addr), 16);
addrlen = 16;
}
set_uint32(payload+1+addrlen, htonl(dns_clip_ttl(conn->address_ttl)));
@@ -311,12 +320,14 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason)
}
if (circ && !circ->marked_for_close) {
- log_debug(LD_EDGE,"Sending end on conn (fd %d).",conn->_base.s);
+ log_debug(LD_EDGE,"Sending end on conn (fd "TOR_SOCKET_T_FORMAT").",
+ conn->base_.s);
connection_edge_send_command(conn, RELAY_COMMAND_END,
payload, payload_len);
} else {
- log_debug(LD_EDGE,"No circ to send end on conn (fd %d).",
- conn->_base.s);
+ log_debug(LD_EDGE,"No circ to send end on conn "
+ "(fd "TOR_SOCKET_T_FORMAT").",
+ conn->base_.s);
}
conn->edge_has_sent_end = 1;
@@ -333,7 +344,7 @@ connection_edge_end_errno(edge_connection_t *conn)
{
uint8_t reason;
tor_assert(conn);
- reason = errno_to_stream_end_reason(tor_socket_errno(conn->_base.s));
+ reason = errno_to_stream_end_reason(tor_socket_errno(conn->base_.s));
return connection_edge_end(conn, reason);
}
@@ -345,7 +356,7 @@ connection_edge_end_errno(edge_connection_t *conn)
int
connection_edge_flushed_some(edge_connection_t *conn)
{
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case AP_CONN_STATE_OPEN:
case EXIT_CONN_STATE_OPEN:
connection_edge_consider_sending_sendme(conn);
@@ -369,7 +380,7 @@ connection_edge_finished_flushing(edge_connection_t *conn)
{
tor_assert(conn);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case AP_CONN_STATE_OPEN:
case EXIT_CONN_STATE_OPEN:
connection_edge_consider_sending_sendme(conn);
@@ -383,13 +394,55 @@ connection_edge_finished_flushing(edge_connection_t *conn)
case AP_CONN_STATE_RESOLVE_WAIT:
return 0;
default:
- log_warn(LD_BUG, "Called in unexpected state %d.",conn->_base.state);
+ log_warn(LD_BUG, "Called in unexpected state %d.",conn->base_.state);
tor_fragile_assert();
return -1;
}
return 0;
}
+/** Longest size for the relay payload of a RELAY_CONNECTED cell that we're
+ * able to generate. */
+/* 4 zero bytes; 1 type byte; 16 byte IPv6 address; 4 byte TTL. */
+#define MAX_CONNECTED_CELL_PAYLOAD_LEN 25
+
+/** Set the buffer at <b>payload_out</b> -- which must have at least
+ * MAX_CONNECTED_CELL_PAYLOAD_LEN bytes available -- to the body of a
+ * RELAY_CONNECTED cell indicating that we have connected to <b>addr</b>, and
+ * that the name resolution that led us to <b>addr</b> will be valid for
+ * <b>ttl</b> seconds. Return -1 on error, or the number of bytes used on
+ * success. */
+/* private */int
+connected_cell_format_payload(uint8_t *payload_out,
+ const tor_addr_t *addr,
+ uint32_t ttl)
+{
+ const sa_family_t family = tor_addr_family(addr);
+ int connected_payload_len;
+
+ /* should be needless */
+ memset(payload_out, 0, MAX_CONNECTED_CELL_PAYLOAD_LEN);
+
+ if (family == AF_INET) {
+ set_uint32(payload_out, tor_addr_to_ipv4n(addr));
+ connected_payload_len = 4;
+ } else if (family == AF_INET6) {
+ set_uint32(payload_out, 0);
+ set_uint8(payload_out + 4, 6);
+ memcpy(payload_out + 5, tor_addr_to_in6_addr8(addr), 16);
+ connected_payload_len = 21;
+ } else {
+ return -1;
+ }
+
+ set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl)));
+ connected_payload_len += 4;
+
+ tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN);
+
+ return connected_payload_len;
+}
+
/** Connected handler for exit connections: start writing pending
* data, deliver 'CONNECTED' relay cells as appropriate, and check
* any pending data that may have been received. */
@@ -399,13 +452,13 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
connection_t *conn;
tor_assert(edge_conn);
- tor_assert(edge_conn->_base.type == CONN_TYPE_EXIT);
+ tor_assert(edge_conn->base_.type == CONN_TYPE_EXIT);
conn = TO_CONN(edge_conn);
tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING);
log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.",
escaped_safe_str(conn->address), conn->port,
- safe_str(fmt_addr(&conn->addr)));
+ safe_str(fmt_and_decorate_addr(&conn->addr)));
rep_hist_note_exit_stream_opened(conn->port);
@@ -421,22 +474,16 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
RELAY_COMMAND_CONNECTED, NULL, 0) < 0)
return 0; /* circuit is closed, don't continue */
} else {
- char connected_payload[20];
- int connected_payload_len;
- if (tor_addr_family(&conn->addr) == AF_INET) {
- set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
- set_uint32(connected_payload+4,
- htonl(dns_clip_ttl(edge_conn->address_ttl)));
- connected_payload_len = 8;
- } else {
- memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
- set_uint32(connected_payload+16,
- htonl(dns_clip_ttl(edge_conn->address_ttl)));
- connected_payload_len = 20;
- }
+ uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
+ int connected_payload_len =
+ connected_cell_format_payload(connected_payload, &conn->addr,
+ edge_conn->address_ttl);
+ if (connected_payload_len < 0)
+ return -1;
+
if (connection_edge_send_command(edge_conn,
- RELAY_COMMAND_CONNECTED,
- connected_payload, connected_payload_len) < 0)
+ RELAY_COMMAND_CONNECTED,
+ (char*)connected_payload, connected_payload_len) < 0)
return 0; /* circuit is closed, don't continue */
}
tor_assert(edge_conn->package_window > 0);
@@ -600,12 +647,27 @@ connection_ap_expire_beginning(void)
" '%s.onion'.",
seconds_idle,
safe_str_client(entry_conn->socks_request->address));
+ /* Roll back path bias use state so that we probe the circuit
+ * if nothing else succeeds on it */
+ pathbias_mark_use_rollback(TO_ORIGIN_CIRCUIT(circ));
+
connection_edge_end(conn, END_STREAM_REASON_TIMEOUT);
connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT);
}
continue;
}
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
+ if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL &&
+ circ->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT &&
+ circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) {
+ log_warn(LD_BUG, "circuit->purpose == CIRCUIT_PURPOSE_C_GENERAL failed. "
+ "The purpose on the circuit was %s; it was in state %s, "
+ "path_state %s.",
+ circuit_purpose_to_string(circ->purpose),
+ circuit_state_to_string(circ->state),
+ CIRCUIT_IS_ORIGIN(circ) ?
+ pathbias_state_to_string(TO_ORIGIN_CIRCUIT(circ)->path_state) :
+ "none");
+ }
log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
"We tried for %d seconds to connect to '%s' using exit %s."
" Retrying on a new circuit.",
@@ -619,14 +681,12 @@ connection_ap_expire_beginning(void)
/* un-mark it as ending, since we're going to reuse it */
conn->edge_has_sent_end = 0;
conn->end_reason = 0;
- /* kludge to make us not try this circuit again, yet to allow
- * current streams on it to survive if they can: make it
- * unattractive to use for new streams */
- /* XXXX024 this is a kludgy way to do this. */
- tor_assert(circ->timestamp_dirty);
- circ->timestamp_dirty -= options->MaxCircuitDirtiness;
+ /* make us not try this circuit again, but allow
+ * current streams on it to survive if they can */
+ mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
+
/* give our stream another 'cutoff' seconds to try */
- conn->_base.timestamp_lastread += cutoff;
+ conn->base_.timestamp_lastread += cutoff;
if (entry_conn->num_socks_retries < 250) /* avoid overflow */
entry_conn->num_socks_retries++;
/* move it back into 'pending' state, and try to attach. */
@@ -752,7 +812,7 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info)
/** The AP connection <b>conn</b> has just failed while attaching or
* sending a BEGIN or resolving on <b>circ</b>, but another circuit
* might work. Detach the circuit, and either reattach it, launch a
- * new circuit, tell the controller, or give up as a appropriate.
+ * new circuit, tell the controller, or give up as appropriate.
*
* Returns -1 on err, 1 on success, 0 on not-yet-sure.
*/
@@ -764,6 +824,10 @@ connection_ap_detach_retriable(entry_connection_t *conn,
control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE, reason);
ENTRY_TO_CONN(conn)->timestamp_lastread = time(NULL);
+ /* Roll back path bias use state so that we probe the circuit
+ * if nothing else succeeds on it */
+ pathbias_mark_use_rollback(circ);
+
if (conn->pending_optimistic_data) {
generic_buffer_set_to_copy(&conn->sending_optimistic_data,
conn->pending_optimistic_data);
@@ -782,957 +846,16 @@ connection_ap_detach_retriable(entry_connection_t *conn,
}
}
-/** A client-side struct to remember requests to rewrite addresses
- * to new addresses. These structs are stored in the hash table
- * "addressmap" below.
- *
- * There are 5 ways to set an address mapping:
- * - A MapAddress command from the controller [permanent]
- * - An AddressMap directive in the torrc [permanent]
- * - When a TrackHostExits torrc directive is triggered [temporary]
- * - When a DNS resolve succeeds [temporary]
- * - When a DNS resolve fails [temporary]
- *
- * When an addressmap request is made but one is already registered,
- * the new one is replaced only if the currently registered one has
- * no "new_address" (that is, it's in the process of DNS resolve),
- * or if the new one is permanent (expires==0 or 1).
- *
- * (We overload the 'expires' field, using "0" for mappings set via
- * the configuration file, "1" for mappings set from the control
- * interface, and other values for DNS and TrackHostExit mappings that can
- * expire.)
- *
- * A mapping may be 'wildcarded'. If "src_wildcard" is true, then
- * any address that ends with a . followed by the key for this entry will
- * get remapped by it. If "dst_wildcard" is also true, then only the
- * matching suffix of such addresses will get replaced by new_address.
- */
-typedef struct {
- char *new_address;
- time_t expires;
- addressmap_entry_source_t source:3;
- unsigned src_wildcard:1;
- unsigned dst_wildcard:1;
- short num_resolve_failures;
-} addressmap_entry_t;
-
-/** Entry for mapping addresses to which virtual address we mapped them to. */
-typedef struct {
- char *ipv4_address;
- char *hostname_address;
-} virtaddress_entry_t;
-
-/** A hash table to store client-side address rewrite instructions. */
-static strmap_t *addressmap=NULL;
-/**
- * Table mapping addresses to which virtual address, if any, we
- * assigned them to.
- *
- * We maintain the following invariant: if [A,B] is in
- * virtaddress_reversemap, then B must be a virtual address, and [A,B]
- * must be in addressmap. We do not require that the converse hold:
- * if it fails, then we could end up mapping two virtual addresses to
- * the same address, which is no disaster.
- **/
-static strmap_t *virtaddress_reversemap=NULL;
-
-/** Initialize addressmap. */
-void
-addressmap_init(void)
-{
- addressmap = strmap_new();
- virtaddress_reversemap = strmap_new();
-}
-
-/** Free the memory associated with the addressmap entry <b>_ent</b>. */
-static void
-addressmap_ent_free(void *_ent)
-{
- addressmap_entry_t *ent;
- if (!_ent)
- return;
-
- ent = _ent;
- tor_free(ent->new_address);
- tor_free(ent);
-}
-
-/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
-static void
-addressmap_virtaddress_ent_free(void *_ent)
-{
- virtaddress_entry_t *ent;
- if (!_ent)
- return;
-
- ent = _ent;
- tor_free(ent->ipv4_address);
- tor_free(ent->hostname_address);
- tor_free(ent);
-}
-
-/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
-static void
-addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
-{
- if (ent && ent->new_address &&
- address_is_in_virtual_range(ent->new_address)) {
- virtaddress_entry_t *ve =
- strmap_get(virtaddress_reversemap, ent->new_address);
- /*log_fn(LOG_NOTICE,"remove reverse mapping for %s",ent->new_address);*/
- if (ve) {
- if (!strcmp(address, ve->ipv4_address))
- tor_free(ve->ipv4_address);
- if (!strcmp(address, ve->hostname_address))
- tor_free(ve->hostname_address);
- if (!ve->ipv4_address && !ve->hostname_address) {
- tor_free(ve);
- strmap_remove(virtaddress_reversemap, ent->new_address);
- }
- }
- }
-}
-
-/** Remove <b>ent</b> (which must be mapped to by <b>address</b>) from the
- * client address maps. */
-static void
-addressmap_ent_remove(const char *address, addressmap_entry_t *ent)
-{
- addressmap_virtaddress_remove(address, ent);
- addressmap_ent_free(ent);
-}
-
-/** Unregister all TrackHostExits mappings from any address to
- * *.exitname.exit. */
-static void
-clear_trackexithost_mappings(const char *exitname)
-{
- char *suffix = NULL;
- if (!addressmap || !exitname)
- return;
- tor_asprintf(&suffix, ".%s.exit", exitname);
- tor_strlower(suffix);
-
- STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
- if (ent->source == ADDRMAPSRC_TRACKEXIT &&
- !strcmpend(ent->new_address, suffix)) {
- addressmap_ent_remove(address, ent);
- MAP_DEL_CURRENT(address);
- }
- } STRMAP_FOREACH_END;
-
- tor_free(suffix);
-}
-
-/** Remove all TRACKEXIT mappings from the addressmap for which the target
- * host is unknown or no longer allowed, or for which the source address
- * is no longer in trackexithosts. */
-void
-addressmap_clear_excluded_trackexithosts(const or_options_t *options)
-{
- const routerset_t *allow_nodes = options->ExitNodes;
- const routerset_t *exclude_nodes = options->_ExcludeExitNodesUnion;
-
- if (!addressmap)
- return;
- if (routerset_is_empty(allow_nodes))
- allow_nodes = NULL;
- if (allow_nodes == NULL && routerset_is_empty(exclude_nodes))
- return;
-
- STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
- size_t len;
- const char *target = ent->new_address, *dot;
- char *nodename;
- const node_t *node;
-
- if (!target) {
- /* DNS resolving in progress */
- continue;
- } else if (strcmpend(target, ".exit")) {
- /* Not a .exit mapping */
- continue;
- } else if (ent->source != ADDRMAPSRC_TRACKEXIT) {
- /* Not a trackexit mapping. */
- continue;
- }
- len = strlen(target);
- if (len < 6)
- continue; /* malformed. */
- dot = target + len - 6; /* dot now points to just before .exit */
- while (dot > target && *dot != '.')
- dot--;
- if (*dot == '.') dot++;
- nodename = tor_strndup(dot, len-5-(dot-target));;
- node = node_get_by_nickname(nodename, 0);
- tor_free(nodename);
- if (!node ||
- (allow_nodes && !routerset_contains_node(allow_nodes, node)) ||
- routerset_contains_node(exclude_nodes, node) ||
- !hostname_in_track_host_exits(options, address)) {
- /* We don't know this one, or we want to be rid of it. */
- addressmap_ent_remove(address, ent);
- MAP_DEL_CURRENT(address);
- }
- } STRMAP_FOREACH_END;
-}
-
-/** Remove all AUTOMAP mappings from the addressmap for which the
- * source address no longer matches AutomapHostsSuffixes, which is
- * no longer allowed by AutomapHostsOnResolve, or for which the
- * target address is no longer in the virtual network. */
-void
-addressmap_clear_invalid_automaps(const or_options_t *options)
-{
- int clear_all = !options->AutomapHostsOnResolve;
- const smartlist_t *suffixes = options->AutomapHostsSuffixes;
-
- if (!addressmap)
- return;
-
- if (!suffixes)
- clear_all = 1; /* This should be impossible, but let's be sure. */
-
- STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) {
- int remove = clear_all;
- if (ent->source != ADDRMAPSRC_AUTOMAP)
- continue; /* not an automap mapping. */
-
- if (!remove) {
- int suffix_found = 0;
- SMARTLIST_FOREACH(suffixes, const char *, suffix, {
- if (!strcasecmpend(src_address, suffix)) {
- suffix_found = 1;
- break;
- }
- });
- if (!suffix_found)
- remove = 1;
- }
-
- if (!remove && ! address_is_in_virtual_range(ent->new_address))
- remove = 1;
-
- if (remove) {
- addressmap_ent_remove(src_address, ent);
- MAP_DEL_CURRENT(src_address);
- }
- } STRMAP_FOREACH_END;
-}
-
-/** Remove all entries from the addressmap that were set via the
- * configuration file or the command line. */
-void
-addressmap_clear_configured(void)
-{
- addressmap_get_mappings(NULL, 0, 0, 0);
-}
-
-/** Remove all entries from the addressmap that are set to expire, ever. */
-void
-addressmap_clear_transient(void)
-{
- addressmap_get_mappings(NULL, 2, TIME_MAX, 0);
-}
-
-/** Clean out entries from the addressmap cache that were
- * added long enough ago that they are no longer valid.
- */
-void
-addressmap_clean(time_t now)
-{
- addressmap_get_mappings(NULL, 2, now, 0);
-}
-
-/** Free all the elements in the addressmap, and free the addressmap
- * itself. */
-void
-addressmap_free_all(void)
-{
- strmap_free(addressmap, addressmap_ent_free);
- addressmap = NULL;
-
- strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
- virtaddress_reversemap = NULL;
-}
-
-/** Try to find a match for AddressMap expressions that use
- * wildcard notation such as '*.c.d *.e.f' (so 'a.c.d' will map to 'a.e.f') or
- * '*.c.d a.b.c' (so 'a.c.d' will map to a.b.c).
- * Return the matching entry in AddressMap or NULL if no match is found.
- * For expressions such as '*.c.d *.e.f', truncate <b>address</b> 'a.c.d'
- * to 'a' before we return the matching AddressMap entry.
- *
- * This function does not handle the case where a pattern of the form "*.c.d"
- * matches the address c.d -- that's done by the main addressmap_rewrite
- * function.
- */
-static addressmap_entry_t *
-addressmap_match_superdomains(char *address)
-{
- addressmap_entry_t *val;
- char *cp;
-
- cp = address;
- while ((cp = strchr(cp, '.'))) {
- /* cp now points to a suffix of address that begins with a . */
- val = strmap_get_lc(addressmap, cp+1);
- if (val && val->src_wildcard) {
- if (val->dst_wildcard)
- *cp = '\0';
- return val;
- }
- ++cp;
- }
- return NULL;
-}
-
-/** Look at address, and rewrite it until it doesn't want any
- * more rewrites; but don't get into an infinite loop.
- * Don't write more than maxlen chars into address. Return true if the
- * address changed; false otherwise. Set *<b>expires_out</b> to the
- * expiry time of the result, or to <b>time_max</b> if the result does
- * not expire.
- *
- * If <b>exit_source_out</b> is non-null, we set it as follows. If we the
- * address starts out as a non-exit address, and we remap it to an .exit
- * address at any point, then set *<b>exit_source_out</b> to the
- * address_entry_source_t of the first such rule. Set *<b>exit_source_out</b>
- * to ADDRMAPSRC_NONE if there is no such rewrite, or if the original address
- * was a .exit.
- */
-int
-addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out,
- addressmap_entry_source_t *exit_source_out)
-{
- addressmap_entry_t *ent;
- int rewrites;
- time_t expires = TIME_MAX;
- addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE;
- char *addr_orig = tor_strdup(address);
- char *log_addr_orig = NULL;
-
- for (rewrites = 0; rewrites < 16; rewrites++) {
- int exact_match = 0;
- log_addr_orig = tor_strdup(escaped_safe_str_client(address));
-
- ent = strmap_get(addressmap, address);
-
- if (!ent || !ent->new_address) {
- ent = addressmap_match_superdomains(address);
- } else {
- if (ent->src_wildcard && !ent->dst_wildcard &&
- !strcasecmp(address, ent->new_address)) {
- /* This is a rule like *.example.com example.com, and we just got
- * "example.com" */
- goto done;
- }
-
- exact_match = 1;
- }
-
- if (!ent || !ent->new_address) {
- goto done;
- }
-
- if (ent->dst_wildcard && !exact_match) {
- strlcat(address, ".", maxlen);
- strlcat(address, ent->new_address, maxlen);
- } else {
- strlcpy(address, ent->new_address, maxlen);
- }
-
- if (!strcmpend(address, ".exit") &&
- strcmpend(addr_orig, ".exit") &&
- exit_source == ADDRMAPSRC_NONE) {
- exit_source = ent->source;
- }
-
- log_info(LD_APP, "Addressmap: rewriting %s to %s",
- log_addr_orig, escaped_safe_str_client(address));
- if (ent->expires > 1 && ent->expires < expires)
- expires = ent->expires;
-
- tor_free(log_addr_orig);
- }
- log_warn(LD_CONFIG,
- "Loop detected: we've rewritten %s 16 times! Using it as-is.",
- escaped_safe_str_client(address));
- /* it's fine to rewrite a rewrite, but don't loop forever */
-
- done:
- tor_free(addr_orig);
- tor_free(log_addr_orig);
- if (exit_source_out)
- *exit_source_out = exit_source;
- if (expires_out)
- *expires_out = TIME_MAX;
- return (rewrites > 0);
-}
-
-/** If we have a cached reverse DNS entry for the address stored in the
- * <b>maxlen</b>-byte buffer <b>address</b> (typically, a dotted quad) then
- * rewrite to the cached value and return 1. Otherwise return 0. Set
- * *<b>expires_out</b> to the expiry time of the result, or to <b>time_max</b>
- * if the result does not expire. */
-static int
-addressmap_rewrite_reverse(char *address, size_t maxlen, time_t *expires_out)
-{
- char *s, *cp;
- addressmap_entry_t *ent;
- int r = 0;
- tor_asprintf(&s, "REVERSE[%s]", address);
- ent = strmap_get(addressmap, s);
- if (ent) {
- cp = tor_strdup(escaped_safe_str_client(ent->new_address));
- log_info(LD_APP, "Rewrote reverse lookup %s -> %s",
- escaped_safe_str_client(s), cp);
- tor_free(cp);
- strlcpy(address, ent->new_address, maxlen);
- r = 1;
- }
-
- if (expires_out)
- *expires_out = (ent && ent->expires > 1) ? ent->expires : TIME_MAX;
-
- tor_free(s);
- return r;
-}
-
-/** Return 1 if <b>address</b> is already registered, else return 0. If address
- * is already registered, and <b>update_expires</b> is non-zero, then update
- * the expiry time on the mapping with update_expires if it is a
- * mapping created by TrackHostExits. */
-int
-addressmap_have_mapping(const char *address, int update_expiry)
-{
- addressmap_entry_t *ent;
- if (!(ent=strmap_get_lc(addressmap, address)))
- return 0;
- if (update_expiry && ent->source==ADDRMAPSRC_TRACKEXIT)
- ent->expires=time(NULL) + update_expiry;
- return 1;
-}
-
-/** Register a request to map <b>address</b> to <b>new_address</b>,
- * which will expire on <b>expires</b> (or 0 if never expires from
- * config file, 1 if never expires from controller, 2 if never expires
- * (virtual address mapping) from the controller.)
- *
- * <b>new_address</b> should be a newly dup'ed string, which we'll use or
- * free as appropriate. We will leave address alone.
- *
- * If <b>wildcard_addr</b> is true, then the mapping will match any address
- * equal to <b>address</b>, or any address ending with a period followed by
- * <b>address</b>. If <b>wildcard_addr</b> and <b>wildcard_new_addr</b> are
- * both true, the mapping will rewrite addresses that end with
- * ".<b>address</b>" into ones that end with ".<b>new_address</b>."
- *
- * If <b>new_address</b> is NULL, or <b>new_address</b> is equal to
- * <b>address</b> and <b>wildcard_addr</b> is equal to
- * <b>wildcard_new_addr</b>, remove any mappings that exist from
- * <b>address</b>.
- *
- *
- * It is an error to set <b>wildcard_new_addr</b> if <b>wildcard_addr</b> is
- * not set. */
-void
-addressmap_register(const char *address, char *new_address, time_t expires,
- addressmap_entry_source_t source,
- const int wildcard_addr,
- const int wildcard_new_addr)
-{
- addressmap_entry_t *ent;
-
- if (wildcard_new_addr)
- tor_assert(wildcard_addr);
-
- ent = strmap_get(addressmap, address);
- if (!new_address || (!strcasecmp(address,new_address) &&
- wildcard_addr == wildcard_new_addr)) {
- /* Remove the mapping, if any. */
- tor_free(new_address);
- if (ent) {
- addressmap_ent_remove(address,ent);
- strmap_remove(addressmap, address);
- }
- return;
- }
- if (!ent) { /* make a new one and register it */
- ent = tor_malloc_zero(sizeof(addressmap_entry_t));
- strmap_set(addressmap, address, ent);
- } else if (ent->new_address) { /* we need to clean up the old mapping. */
- if (expires > 1) {
- log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, "
- "since it's already mapped to '%s'",
- safe_str_client(address),
- safe_str_client(new_address),
- safe_str_client(ent->new_address));
- tor_free(new_address);
- return;
- }
- if (address_is_in_virtual_range(ent->new_address) &&
- expires != 2) {
- /* XXX This isn't the perfect test; we want to avoid removing
- * mappings set from the control interface _as virtual mapping */
- addressmap_virtaddress_remove(address, ent);
- }
- tor_free(ent->new_address);
- } /* else { we have an in-progress resolve with no mapping. } */
-
- ent->new_address = new_address;
- ent->expires = expires==2 ? 1 : expires;
- ent->num_resolve_failures = 0;
- ent->source = source;
- ent->src_wildcard = wildcard_addr ? 1 : 0;
- ent->dst_wildcard = wildcard_new_addr ? 1 : 0;
-
- log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
- safe_str_client(address),
- safe_str_client(ent->new_address));
- control_event_address_mapped(address, ent->new_address, expires, NULL);
-}
-
-/** An attempt to resolve <b>address</b> failed at some OR.
- * Increment the number of resolve failures we have on record
- * for it, and then return that number.
- */
-int
-client_dns_incr_failures(const char *address)
-{
- addressmap_entry_t *ent = strmap_get(addressmap, address);
- if (!ent) {
- ent = tor_malloc_zero(sizeof(addressmap_entry_t));
- ent->expires = time(NULL) + MAX_DNS_ENTRY_AGE;
- strmap_set(addressmap,address,ent);
- }
- if (ent->num_resolve_failures < SHORT_MAX)
- ++ent->num_resolve_failures; /* don't overflow */
- log_info(LD_APP, "Address %s now has %d resolve failures.",
- safe_str_client(address),
- ent->num_resolve_failures);
- return ent->num_resolve_failures;
-}
-
-/** If <b>address</b> is in the client DNS addressmap, reset
- * the number of resolve failures we have on record for it.
- * This is used when we fail a stream because it won't resolve:
- * otherwise future attempts on that address will only try once.
- */
-void
-client_dns_clear_failures(const char *address)
-{
- addressmap_entry_t *ent = strmap_get(addressmap, address);
- if (ent)
- ent->num_resolve_failures = 0;
-}
-
-/** Record the fact that <b>address</b> resolved to <b>name</b>.
- * We can now use this in subsequent streams via addressmap_rewrite()
- * so we can more correctly choose an exit that will allow <b>address</b>.
- *
- * If <b>exitname</b> is defined, then append the addresses with
- * ".exitname.exit" before registering the mapping.
- *
- * If <b>ttl</b> is nonnegative, the mapping will be valid for
- * <b>ttl</b>seconds; otherwise, we use the default.
- */
-static void
-client_dns_set_addressmap_impl(const char *address, const char *name,
- const char *exitname,
- int ttl)
-{
- /* <address>.<hex or nickname>.exit\0 or just <address>\0 */
- char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_VERBOSE_NICKNAME_LEN+10];
- /* 123.123.123.123.<hex or nickname>.exit\0 or just 123.123.123.123\0 */
- char extendedval[INET_NTOA_BUF_LEN+MAX_VERBOSE_NICKNAME_LEN+10];
-
- tor_assert(address);
- tor_assert(name);
-
- if (ttl<0)
- ttl = DEFAULT_DNS_TTL;
- else
- ttl = dns_clip_ttl(ttl);
-
- if (exitname) {
- /* XXXX fails to ever get attempts to get an exit address of
- * google.com.digest[=~]nickname.exit; we need a syntax for this that
- * won't make strict RFC952-compliant applications (like us) barf. */
- tor_snprintf(extendedaddress, sizeof(extendedaddress),
- "%s.%s.exit", address, exitname);
- tor_snprintf(extendedval, sizeof(extendedval),
- "%s.%s.exit", name, exitname);
- } else {
- tor_snprintf(extendedaddress, sizeof(extendedaddress),
- "%s", address);
- tor_snprintf(extendedval, sizeof(extendedval),
- "%s", name);
- }
- addressmap_register(extendedaddress, tor_strdup(extendedval),
- time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0);
-}
-
-/** Record the fact that <b>address</b> resolved to <b>val</b>.
- * We can now use this in subsequent streams via addressmap_rewrite()
- * so we can more correctly choose an exit that will allow <b>address</b>.
- *
- * If <b>exitname</b> is defined, then append the addresses with
- * ".exitname.exit" before registering the mapping.
- *
- * If <b>ttl</b> is nonnegative, the mapping will be valid for
- * <b>ttl</b>seconds; otherwise, we use the default.
- */
-void
-client_dns_set_addressmap(const char *address, uint32_t val,
- const char *exitname,
- int ttl)
-{
- struct in_addr in;
- char valbuf[INET_NTOA_BUF_LEN];
-
- tor_assert(address);
-
- if (tor_inet_aton(address, &in))
- return; /* If address was an IP address already, don't add a mapping. */
- in.s_addr = htonl(val);
- tor_inet_ntoa(&in,valbuf,sizeof(valbuf));
-
- client_dns_set_addressmap_impl(address, valbuf, exitname, ttl);
-}
-
-/** Add a cache entry noting that <b>address</b> (ordinarily a dotted quad)
- * resolved via a RESOLVE_PTR request to the hostname <b>v</b>.
- *
- * If <b>exitname</b> is defined, then append the addresses with
- * ".exitname.exit" before registering the mapping.
- *
- * If <b>ttl</b> is nonnegative, the mapping will be valid for
- * <b>ttl</b>seconds; otherwise, we use the default.
- */
-static void
-client_dns_set_reverse_addressmap(const char *address, const char *v,
- const char *exitname,
- int ttl)
-{
- char *s = NULL;
- tor_asprintf(&s, "REVERSE[%s]", address);
- client_dns_set_addressmap_impl(s, v, exitname, ttl);
- tor_free(s);
-}
-
-/* By default, we hand out 127.192.0.1 through 127.254.254.254.
- * These addresses should map to localhost, so even if the
- * application accidentally tried to connect to them directly (not
- * via Tor), it wouldn't get too far astray.
- *
- * These options are configured by parse_virtual_addr_network().
- */
-/** Which network should we use for virtual IPv4 addresses? Only the first
- * bits of this value are fixed. */
-static uint32_t virtual_addr_network = 0x7fc00000u;
-/** How many bits of <b>virtual_addr_network</b> are fixed? */
-static maskbits_t virtual_addr_netmask_bits = 10;
-/** What's the next virtual address we will hand out? */
-static uint32_t next_virtual_addr = 0x7fc00000u;
-
-/** Read a netmask of the form 127.192.0.0/10 from "val", and check whether
- * it's a valid set of virtual addresses to hand out in response to MAPADDRESS
- * requests. Return 0 on success; set *msg (if provided) to a newly allocated
- * string and return -1 on failure. If validate_only is false, sets the
- * actual virtual address range to the parsed value. */
-int
-parse_virtual_addr_network(const char *val, int validate_only,
- char **msg)
-{
- uint32_t addr;
- uint16_t port_min, port_max;
- maskbits_t bits;
-
- if (parse_addr_and_port_range(val, &addr, &bits, &port_min, &port_max)) {
- if (msg) *msg = tor_strdup("Error parsing VirtualAddressNetwork");
- return -1;
- }
-
- if (port_min != 1 || port_max != 65535) {
- if (msg) *msg = tor_strdup("Can't specify ports on VirtualAddressNetwork");
- return -1;
- }
-
- if (bits > 16) {
- if (msg) *msg = tor_strdup("VirtualAddressNetwork expects a /16 "
- "network or larger");
- return -1;
- }
-
- if (validate_only)
- return 0;
-
- virtual_addr_network = (uint32_t)( addr & (0xfffffffful << (32-bits)) );
- virtual_addr_netmask_bits = bits;
-
- if (addr_mask_cmp_bits(next_virtual_addr, addr, bits))
- next_virtual_addr = addr;
-
- return 0;
-}
-
-/**
- * Return true iff <b>addr</b> is likely to have been returned by
- * client_dns_get_unused_address.
- **/
-static int
-address_is_in_virtual_range(const char *address)
-{
- struct in_addr in;
- tor_assert(address);
- if (!strcasecmpend(address, ".virtual")) {
- return 1;
- } else if (tor_inet_aton(address, &in)) {
- uint32_t addr = ntohl(in.s_addr);
- if (!addr_mask_cmp_bits(addr, virtual_addr_network,
- virtual_addr_netmask_bits))
- return 1;
- }
- return 0;
-}
-
-/** Increment the value of next_virtual_addr; reset it to the start of the
- * virtual address range if it wraps around.
- */
-static INLINE void
-increment_virtual_addr(void)
-{
- ++next_virtual_addr;
- if (addr_mask_cmp_bits(next_virtual_addr, virtual_addr_network,
- virtual_addr_netmask_bits))
- next_virtual_addr = virtual_addr_network;
-}
-
-/** Return a newly allocated string holding an address of <b>type</b>
- * (one of RESOLVED_TYPE_{IPV4|HOSTNAME}) that has not yet been mapped,
- * and that is very unlikely to be the address of any real host.
- *
- * May return NULL if we have run out of virtual addresses.
- */
-static char *
-addressmap_get_virtual_address(int type)
-{
- char buf[64];
- tor_assert(addressmap);
-
- if (type == RESOLVED_TYPE_HOSTNAME) {
- char rand[10];
- do {
- crypto_rand(rand, sizeof(rand));
- base32_encode(buf,sizeof(buf),rand,sizeof(rand));
- strlcat(buf, ".virtual", sizeof(buf));
- } while (strmap_get(addressmap, buf));
- return tor_strdup(buf);
- } else if (type == RESOLVED_TYPE_IPV4) {
- // This is an imperfect estimate of how many addresses are available, but
- // that's ok.
- struct in_addr in;
- uint32_t available = 1u << (32-virtual_addr_netmask_bits);
- while (available) {
- /* Don't hand out any .0 or .255 address. */
- while ((next_virtual_addr & 0xff) == 0 ||
- (next_virtual_addr & 0xff) == 0xff) {
- increment_virtual_addr();
- if (! --available) {
- log_warn(LD_CONFIG, "Ran out of virtual addresses!");
- return NULL;
- }
- }
- in.s_addr = htonl(next_virtual_addr);
- tor_inet_ntoa(&in, buf, sizeof(buf));
- if (!strmap_get(addressmap, buf)) {
- increment_virtual_addr();
- break;
- }
-
- increment_virtual_addr();
- --available;
- // log_info(LD_CONFIG, "%d addrs available", (int)available);
- if (! available) {
- log_warn(LD_CONFIG, "Ran out of virtual addresses!");
- return NULL;
- }
- }
- return tor_strdup(buf);
- } else {
- log_warn(LD_BUG, "Called with unsupported address type (%d)", type);
- return NULL;
- }
-}
-
-/** A controller has requested that we map some address of type
- * <b>type</b> to the address <b>new_address</b>. Choose an address
- * that is unlikely to be used, and map it, and return it in a newly
- * allocated string. If another address of the same type is already
- * mapped to <b>new_address</b>, try to return a copy of that address.
- *
- * The string in <b>new_address</b> may be freed or inserted into a map
- * as appropriate. May return NULL if are out of virtual addresses.
- **/
-const char *
-addressmap_register_virtual_address(int type, char *new_address)
-{
- char **addrp;
- virtaddress_entry_t *vent;
- int vent_needs_to_be_added = 0;
-
- tor_assert(new_address);
- tor_assert(addressmap);
- tor_assert(virtaddress_reversemap);
-
- vent = strmap_get(virtaddress_reversemap, new_address);
- if (!vent) {
- vent = tor_malloc_zero(sizeof(virtaddress_entry_t));
- vent_needs_to_be_added = 1;
- }
-
- addrp = (type == RESOLVED_TYPE_IPV4) ?
- &vent->ipv4_address : &vent->hostname_address;
- if (*addrp) {
- addressmap_entry_t *ent = strmap_get(addressmap, *addrp);
- if (ent && ent->new_address &&
- !strcasecmp(new_address, ent->new_address)) {
- tor_free(new_address);
- tor_assert(!vent_needs_to_be_added);
- return tor_strdup(*addrp);
- } else
- log_warn(LD_BUG,
- "Internal confusion: I thought that '%s' was mapped to by "
- "'%s', but '%s' really maps to '%s'. This is a harmless bug.",
- safe_str_client(new_address),
- safe_str_client(*addrp),
- safe_str_client(*addrp),
- ent?safe_str_client(ent->new_address):"(nothing)");
- }
-
- tor_free(*addrp);
- *addrp = addressmap_get_virtual_address(type);
- if (!*addrp) {
- tor_free(vent);
- tor_free(new_address);
- return NULL;
- }
- log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
- if (vent_needs_to_be_added)
- strmap_set(virtaddress_reversemap, new_address, vent);
- addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0);
-
-#if 0
- {
- /* Try to catch possible bugs */
- addressmap_entry_t *ent;
- ent = strmap_get(addressmap, *addrp);
- tor_assert(ent);
- tor_assert(!strcasecmp(ent->new_address,new_address));
- vent = strmap_get(virtaddress_reversemap, new_address);
- tor_assert(vent);
- tor_assert(!strcasecmp(*addrp,
- (type == RESOLVED_TYPE_IPV4) ?
- vent->ipv4_address : vent->hostname_address));
- log_info(LD_APP, "Map from %s to %s okay.",
- safe_str_client(*addrp),
- safe_str_client(new_address));
- }
-#endif
-
- return *addrp;
-}
-
-/** Return 1 if <b>address</b> has funny characters in it like colons. Return
- * 0 if it's fine, or if we're configured to allow it anyway. <b>client</b>
- * should be true if we're using this address as a client; false if we're
- * using it as a server.
- */
-int
-address_is_invalid_destination(const char *address, int client)
-{
- if (client) {
- if (get_options()->AllowNonRFC953Hostnames)
- return 0;
- } else {
- if (get_options()->ServerDNSAllowNonRFC953Hostnames)
- return 0;
- }
-
- while (*address) {
- if (TOR_ISALNUM(*address) ||
- *address == '-' ||
- *address == '.' ||
- *address == '_') /* Underscore is not allowed, but Windows does it
- * sometimes, just to thumb its nose at the IETF. */
- ++address;
- else
- return 1;
- }
- return 0;
-}
-
-/** Iterate over all address mappings which have expiry times between
- * min_expires and max_expires, inclusive. If sl is provided, add an
- * "old-addr new-addr expiry" string to sl for each mapping, omitting
- * the expiry time if want_expiry is false. If sl is NULL, remove the
- * mappings.
- */
-void
-addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
- time_t max_expires, int want_expiry)
-{
- strmap_iter_t *iter;
- const char *key;
- void *_val;
- addressmap_entry_t *val;
-
- if (!addressmap)
- addressmap_init();
-
- for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) {
- strmap_iter_get(iter, &key, &_val);
- val = _val;
- if (val->expires >= min_expires && val->expires <= max_expires) {
- if (!sl) {
- iter = strmap_iter_next_rmv(addressmap,iter);
- addressmap_ent_remove(key, val);
- continue;
- } else if (val->new_address) {
- const char *src_wc = val->src_wildcard ? "*." : "";
- const char *dst_wc = val->dst_wildcard ? "*." : "";
- if (want_expiry) {
- if (val->expires < 3 || val->expires == TIME_MAX)
- smartlist_add_asprintf(sl, "%s%s %s%s NEVER",
- src_wc, key, dst_wc, val->new_address);
- else {
- char time[ISO_TIME_LEN+1];
- format_iso_time(time, val->expires);
- smartlist_add_asprintf(sl, "%s%s %s%s \"%s\"",
- src_wc, key, dst_wc, val->new_address,
- time);
- }
- } else {
- smartlist_add_asprintf(sl, "%s%s %s%s",
- src_wc, key, dst_wc, val->new_address);
- }
- }
- }
- iter = strmap_iter_next(addressmap,iter);
- }
-}
-
/** Check if <b>conn</b> is using a dangerous port. Then warn and/or
* reject depending on our config options. */
static int
consider_plaintext_ports(entry_connection_t *conn, uint16_t port)
{
const or_options_t *options = get_options();
- int reject = smartlist_string_num_isin(options->RejectPlaintextPorts, port);
+ int reject = smartlist_contains_int_as_string(
+ options->RejectPlaintextPorts, port);
- if (smartlist_string_num_isin(options->WarnPlaintextPorts, port)) {
+ if (smartlist_contains_int_as_string(options->WarnPlaintextPorts, port)) {
log_warn(LD_APP, "Application request to port %d: this port is "
"commonly used for unencrypted protocols. Please make sure "
"you don't send anything you would mind the rest of the "
@@ -1798,7 +921,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
socks_request_t *socks = conn->socks_request;
hostname_type_t addresstype;
const or_options_t *options = get_options();
- struct in_addr addr_tmp;
+ tor_addr_t addr_tmp;
/* We set this to true if this is an address we should automatically
* remap to a local address in VirtualAddrNetwork */
int automap = 0;
@@ -1828,17 +951,20 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
conn->original_dest_address = tor_strdup(conn->socks_request->address);
if (socks->command == SOCKS_COMMAND_RESOLVE &&
- !tor_inet_aton(socks->address, &addr_tmp) &&
- options->AutomapHostsOnResolve && options->AutomapHostsSuffixes) {
- SMARTLIST_FOREACH(options->AutomapHostsSuffixes, const char *, cp,
- if (!strcasecmpend(socks->address, cp)) {
- automap = 1;
- break;
- });
+ tor_addr_parse(&addr_tmp, socks->address)<0 &&
+ options->AutomapHostsOnResolve) {
+ automap = addressmap_address_should_automap(socks->address, options);
if (automap) {
const char *new_addr;
+ int addr_type = RESOLVED_TYPE_IPV4;
+ if (conn->socks_request->socks_version != 4) {
+ if (!conn->ipv4_traffic_ok ||
+ (conn->ipv6_traffic_ok && conn->prefer_ipv6_traffic) ||
+ conn->prefer_ipv6_virtaddr)
+ addr_type = RESOLVED_TYPE_IPV6;
+ }
new_addr = addressmap_register_virtual_address(
- RESOLVED_TYPE_IPV4, tor_strdup(socks->address));
+ addr_type, tor_strdup(socks->address));
if (! new_addr) {
log_warn(LD_APP, "Unable to automap address %s",
escaped_safe_str(socks->address));
@@ -1853,8 +979,14 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
+ unsigned rewrite_flags = 0;
+ if (conn->use_cached_ipv4_answers)
+ rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
+ if (conn->use_cached_ipv6_answers)
+ rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
+
if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address),
- &map_expires)) {
+ rewrite_flags, &map_expires)) {
char *result = tor_strdup(socks->address);
/* remember _what_ is supposed to have been resolved. */
tor_snprintf(socks->address, sizeof(socks->address), "REVERSE[%s]",
@@ -1885,8 +1017,13 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
} else if (!automap) {
/* For address map controls, remap the address. */
+ unsigned rewrite_flags = 0;
+ if (conn->use_cached_ipv4_answers)
+ rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
+ if (conn->use_cached_ipv6_answers)
+ rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
if (addressmap_rewrite(socks->address, sizeof(socks->address),
- &map_expires, &exit_source)) {
+ rewrite_flags, &map_expires, &exit_source)) {
control_event_stream_status(conn, STREAM_EVENT_REMAP,
REMAP_STREAM_SOURCE_CACHE);
}
@@ -1923,7 +1060,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
/* If StrictNodes is not set, then .exit overrides ExcludeNodes. */
routerset_t *excludeset = options->StrictNodes ?
- options->_ExcludeExitNodesUnion : options->ExcludeExitNodes;
+ options->ExcludeExitNodesUnion_ : options->ExcludeExitNodes;
const node_t *node;
if (exit_source == ADDRMAPSRC_AUTOMAP && !options->AllowDotExit) {
@@ -2024,17 +1161,13 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
if (socks->command == SOCKS_COMMAND_RESOLVE) {
- uint32_t answer;
- struct in_addr in;
+ tor_addr_t answer;
/* Reply to resolves immediately if we can. */
- if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
- /* leave it in network order */
- answer = in.s_addr;
+ if (tor_addr_parse(&answer, socks->address) >= 0) {/* is it an IP? */
/* remember _what_ is supposed to have been resolved. */
strlcpy(socks->address, orig_address, sizeof(socks->address));
- connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
- (uint8_t*)&answer,
- -1,map_expires);
+ connection_ap_handshake_socks_resolved_addr(conn, &answer, -1,
+ map_expires);
connection_mark_unattached_ap(conn,
END_STREAM_REASON_DONE |
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
@@ -2087,6 +1220,37 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
}
+ {
+ tor_addr_t addr;
+ /* XXX Duplicate call to tor_addr_parse. */
+ if (tor_addr_parse(&addr, socks->address) >= 0) {
+ sa_family_t family = tor_addr_family(&addr);
+ if ((family == AF_INET && ! conn->ipv4_traffic_ok) ||
+ (family == AF_INET6 && ! conn->ipv4_traffic_ok)) {
+ log_warn(LD_NET, "Rejecting SOCKS request for an IP address "
+ "family that this listener does not support.");
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
+ return -1;
+ } else if (family == AF_INET6 && socks->socks_version == 4) {
+ log_warn(LD_NET, "Rejecting SOCKS4 request for an IPv6 address.");
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
+ return -1;
+ } else if (socks->socks_version == 4 && !conn->ipv4_traffic_ok) {
+ log_warn(LD_NET, "Rejecting SOCKS4 request on a listener with "
+ "no IPv4 traffic supported.");
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
+ return -1;
+ } else if (family == AF_INET6) {
+ conn->ipv4_traffic_ok = 0;
+ } else if (family == AF_INET) {
+ conn->ipv6_traffic_ok = 0;
+ }
+ }
+ }
+
+ if (socks->socks_version == 4)
+ conn->ipv6_traffic_ok = 0;
+
if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
/* see if we can find a suitable enclave exit */
const node_t *r =
@@ -2256,7 +1420,7 @@ connection_ap_get_original_destination(entry_connection_t *conn,
}
tor_addr_from_sockaddr(&addr, (struct sockaddr*)&orig_dst, &req->port);
- tor_addr_to_str(req->address, &addr, sizeof(req->address), 0);
+ tor_addr_to_str(req->address, &addr, sizeof(req->address), 1);
return 0;
#elif defined(TRANS_PF)
@@ -2317,7 +1481,7 @@ connection_ap_get_original_destination(entry_connection_t *conn,
return -1;
}
- tor_addr_to_str(req->address, &addr, sizeof(req->address), 0);
+ tor_addr_to_str(req->address, &addr, sizeof(req->address), 1);
req->port = ntohs(pnl.rdport);
return 0;
@@ -2517,7 +1681,7 @@ connection_ap_process_natd(entry_connection_t *conn)
/** Iterate over the two bytes of stream_id until we get one that is not
* already in use; return it. Return 0 if can't get a unique stream_id.
*/
-static streamid_t
+streamid_t
get_unique_stream_id_by_circ(origin_circuit_t *circ)
{
edge_connection_t *tmpconn;
@@ -2555,6 +1719,66 @@ connection_ap_supports_optimistic_data(const entry_connection_t *conn)
return conn->may_use_optimistic_data;
}
+/** Return a bitmask of BEGIN_FLAG_* flags that we should transmit in the
+ * RELAY_BEGIN cell for <b>ap_conn</b>. */
+static uint32_t
+connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
+{
+ edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn);
+ const node_t *exitnode = NULL;
+ const crypt_path_t *cpath_layer = edge_conn->cpath_layer;
+ uint32_t flags = 0;
+
+ /* No flags for begindir */
+ if (ap_conn->use_begindir)
+ return 0;
+
+ /* No flags for hidden services. */
+ if (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL)
+ return 0;
+
+ /* If only IPv4 is supported, no flags */
+ if (ap_conn->ipv4_traffic_ok && !ap_conn->ipv6_traffic_ok)
+ return 0;
+
+ if (! cpath_layer ||
+ ! cpath_layer->extend_info)
+ return 0;
+
+ if (!ap_conn->ipv4_traffic_ok)
+ flags |= BEGIN_FLAG_IPV4_NOT_OK;
+
+ exitnode = node_get_by_id(cpath_layer->extend_info->identity_digest);
+
+ if (ap_conn->ipv6_traffic_ok && exitnode) {
+ tor_addr_t a;
+ tor_addr_make_null(&a, AF_INET6);
+ if (compare_tor_addr_to_node_policy(&a, ap_conn->socks_request->port,
+ exitnode)
+ != ADDR_POLICY_REJECTED) {
+ /* Only say "IPv6 OK" if the exit node supports IPv6. Otherwise there's
+ * no point. */
+ flags |= BEGIN_FLAG_IPV6_OK;
+ }
+ }
+
+ if (flags == BEGIN_FLAG_IPV6_OK) {
+ /* When IPv4 and IPv6 are both allowed, consider whether to say we
+ * prefer IPv6. Otherwise there's no point in declaring a preference */
+ if (ap_conn->prefer_ipv6_traffic)
+ flags |= BEGIN_FLAG_IPV6_PREFERRED;
+ }
+
+ if (flags == BEGIN_FLAG_IPV4_NOT_OK) {
+ log_warn(LD_EDGE, "I'm about to ask a node for a connection that I "
+ "am telling it to fulfil with neither IPv4 nor IPv6. That's "
+ "not going to work. Did you perhaps ask for an IPv6 address "
+ "on an IPv4Only port, or vice versa?");
+ }
+
+ return flags;
+}
+
/** Write a relay begin cell, using destaddr and destport from ap_conn's
* socks_request field, and send it down circ.
*
@@ -2584,17 +1808,22 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
/* Mark this circuit "unusable for new streams". */
- /* XXXX024 this is a kludgy way to do this. */
- tor_assert(circ->_base.timestamp_dirty);
- circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+ mark_circuit_unusable_for_new_conns(circ);
return -1;
}
+ /* Set up begin cell flags. */
+ edge_conn->begincell_flags = connection_ap_get_begincell_flags(ap_conn);
+
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
- (circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
+ (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
ap_conn->socks_request->address : "",
ap_conn->socks_request->port);
payload_len = (int)strlen(payload)+1;
+ if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) {
+ set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags));
+ payload_len += 4;
+ }
log_info(LD_APP,
"Sending relay cell %d to begin stream %d.",
@@ -2617,8 +1846,9 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
edge_conn->package_window = STREAMWINDOW_START;
edge_conn->deliver_window = STREAMWINDOW_START;
base_conn->state = AP_CONN_STATE_CONNECT_WAIT;
- log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
- base_conn->s, circ->_base.n_circ_id);
+ log_info(LD_APP,"Address/port sent, ap socket "TOR_SOCKET_T_FORMAT
+ ", n_circ_id %u",
+ base_conn->s, (unsigned)circ->base_.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0);
/* If there's queued-up data, send it now */
@@ -2657,7 +1887,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
tor_assert(base_conn->type == CONN_TYPE_AP);
tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
tor_assert(ap_conn->socks_request);
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL);
command = ap_conn->socks_request->command;
tor_assert(SOCKS_COMMAND_IS_RESOLVE(command));
@@ -2669,9 +1899,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
/* Mark this circuit "unusable for new streams". */
- /* XXXX024 this is a kludgy way to do this. */
- tor_assert(circ->_base.timestamp_dirty);
- circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+ mark_circuit_unusable_for_new_conns(circ);
return -1;
}
@@ -2686,7 +1914,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
/* We're doing a reverse lookup. The input could be an IP address, or
* could be an .in-addr.arpa or .ip6.arpa address */
- r = tor_addr_parse_PTR_name(&addr, a, AF_INET, 1);
+ r = tor_addr_parse_PTR_name(&addr, a, AF_UNSPEC, 1);
if (r <= 0) {
log_warn(LD_APP, "Rejecting ill-formed reverse lookup of %s",
safe_str_client(a));
@@ -2715,12 +1943,14 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
string_addr, payload_len) < 0)
return -1; /* circuit is closed, don't continue */
- tor_free(base_conn->address); /* Maybe already set by dnsserv. */
- base_conn->address = tor_strdup("(Tor_internal)");
+ if (!base_conn->address) {
+ /* This might be unnecessary. XXXX */
+ base_conn->address = tor_dup_addr(&base_conn->addr);
+ }
base_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
- log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d",
- base_conn->s, circ->_base.n_circ_id);
- control_event_stream_status(ap_conn, STREAM_EVENT_NEW, 0);
+ log_info(LD_APP,"Address sent for resolve, ap socket "TOR_SOCKET_T_FORMAT
+ ", n_circ_id %u",
+ base_conn->s, (unsigned)circ->base_.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE, 0);
return 0;
}
@@ -2812,28 +2042,53 @@ tell_controller_about_resolved_result(entry_connection_t *conn,
int ttl,
time_t expires)
{
-
- if (ttl >= 0 && (answer_type == RESOLVED_TYPE_IPV4 ||
- answer_type == RESOLVED_TYPE_HOSTNAME)) {
- return; /* we already told the controller. */
- } else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) {
+ expires = time(NULL) + ttl;
+ if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) {
char *cp = tor_dup_ip(ntohl(get_uint32(answer)));
control_event_address_mapped(conn->socks_request->address,
- cp, expires, NULL);
+ cp, expires, NULL, 0);
tor_free(cp);
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
char *cp = tor_strndup(answer, answer_len);
control_event_address_mapped(conn->socks_request->address,
- cp, expires, NULL);
+ cp, expires, NULL, 0);
tor_free(cp);
} else {
control_event_address_mapped(conn->socks_request->address,
- "<error>",
- time(NULL)+ttl,
- "error=yes");
+ "<error>", time(NULL)+ttl,
+ "error=yes", 0);
}
}
+/**
+ * As connection_ap_handshake_socks_resolved, but take a tor_addr_t to send
+ * as the answer.
+ */
+static void
+connection_ap_handshake_socks_resolved_addr(entry_connection_t *conn,
+ const tor_addr_t *answer,
+ int ttl,
+ time_t expires)
+{
+ if (tor_addr_family(answer) == AF_INET) {
+ uint32_t a = tor_addr_to_ipv4n(answer); /* network order */
+ connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
+ (uint8_t*)&a,
+ ttl, expires);
+ } else if (tor_addr_family(answer) == AF_INET6) {
+ const uint8_t *a = tor_addr_to_in6_addr8(answer);
+ connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV6,16,
+ a,
+ ttl, expires);
+ } else {
+ log_warn(LD_BUG, "Got called with address of unexpected family %d",
+ tor_addr_family(answer));
+ connection_ap_handshake_socks_resolved(conn,
+ RESOLVED_TYPE_ERROR,0,NULL,-1,-1);
+ }
+}
+
+
/** Send an answer to an AP connection that has requested a DNS lookup via
* SOCKS. The type should be one of RESOLVED_TYPE_(IPV4|IPV6|HOSTNAME) or -1
* for unreachable; the answer should be in the format specified in the socks
@@ -2856,13 +2111,25 @@ connection_ap_handshake_socks_resolved(entry_connection_t *conn,
if (ttl >= 0) {
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
- uint32_t a = ntohl(get_uint32(answer));
- if (a)
- client_dns_set_addressmap(conn->socks_request->address, a,
+ tor_addr_t a;
+ tor_addr_from_ipv4n(&a, get_uint32(answer));
+ if (! tor_addr_is_null(&a)) {
+ client_dns_set_addressmap(conn,
+ conn->socks_request->address, &a,
+ conn->chosen_exit_name, ttl);
+ }
+ } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
+ tor_addr_t a;
+ tor_addr_from_ipv6_bytes(&a, (char*)answer);
+ if (! tor_addr_is_null(&a)) {
+ client_dns_set_addressmap(conn,
+ conn->socks_request->address, &a,
conn->chosen_exit_name, ttl);
+ }
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
char *cp = tor_strndup((char*)answer, answer_len);
- client_dns_set_reverse_addressmap(conn->socks_request->address,
+ client_dns_set_reverse_addressmap(conn,
+ conn->socks_request->address,
cp,
conn->chosen_exit_name, ttl);
tor_free(cp);
@@ -2876,8 +2143,9 @@ connection_ap_handshake_socks_resolved(entry_connection_t *conn,
conn->socks_request->has_finished = 1;
return;
} else {
- /* This must be a request from the controller. We already sent
- * a mapaddress if there's a ttl. */
+ /* This must be a request from the controller. Since answers to those
+ * requests are not cached, they do not generate an ADDRMAP event on
+ * their own. */
tell_controller_about_resolved_result(conn, answer_type, answer_len,
(char*)answer, ttl, expires);
conn->socks_request->has_finished = 1;
@@ -2958,9 +2226,36 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
tor_assert(conn->socks_request); /* make sure it's an AP stream */
- control_event_stream_status(conn,
- status==SOCKS5_SUCCEEDED ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED,
- endreason);
+ if (!SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) {
+ control_event_stream_status(conn, status==SOCKS5_SUCCEEDED ?
+ STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED,
+ endreason);
+ }
+
+ /* Flag this stream's circuit as having completed a stream successfully
+ * (for path bias) */
+ if (status == SOCKS5_SUCCEEDED ||
+ endreason == END_STREAM_REASON_RESOLVEFAILED ||
+ endreason == END_STREAM_REASON_CONNECTREFUSED ||
+ endreason == END_STREAM_REASON_CONNRESET ||
+ endreason == END_STREAM_REASON_NOROUTE ||
+ endreason == END_STREAM_REASON_RESOURCELIMIT) {
+ if (!conn->edge_.on_circuit ||
+ !CIRCUIT_IS_ORIGIN(conn->edge_.on_circuit)) {
+ // DNS remaps can trigger this. So can failed hidden service
+ // lookups.
+ log_info(LD_BUG,
+ "No origin circuit for successful SOCKS stream "U64_FORMAT
+ ". Reason: %d",
+ U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier),
+ endreason);
+ } else {
+ // XXX: Hrmm. It looks like optimistic data can't go through this
+ // codepath, but someone should probably test it and make sure.
+ // We don't want to mark optimistically opened streams as successful.
+ pathbias_mark_use_success(TO_ORIGIN_CIRCUIT(conn->edge_.on_circuit));
+ }
+ }
if (conn->socks_request->has_finished) {
log_warn(LD_BUG, "(Harmless.) duplicate calls to "
@@ -2992,6 +2287,70 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
return;
}
+/** Read a RELAY_BEGIN or RELAY_BEGINDIR cell from <b>cell</b>, decode it, and
+ * place the result in <b>bcell</b>. On success return 0; on failure return
+ * <0 and set *<b>end_reason_out</b> to the end reason we should send back to
+ * the client.
+ *
+ * Return -1 in the case where want to send a RELAY_END cell, and < -1 when
+ * we don't.
+ **/
+/* static */ int
+begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
+ uint8_t *end_reason_out)
+{
+ relay_header_t rh;
+ const uint8_t *body, *nul;
+
+ memset(bcell, 0, sizeof(*bcell));
+ *end_reason_out = END_STREAM_REASON_MISC;
+
+ relay_header_unpack(&rh, cell->payload);
+ if (rh.length > RELAY_PAYLOAD_SIZE) {
+ return -2; /*XXXX why not TORPROTOCOL? */
+ }
+
+ bcell->stream_id = rh.stream_id;
+
+ if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
+ bcell->is_begindir = 1;
+ return 0;
+ } else if (rh.command != RELAY_COMMAND_BEGIN) {
+ log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command);
+ *end_reason_out = END_STREAM_REASON_INTERNAL;
+ return -1;
+ }
+
+ body = cell->payload + RELAY_HEADER_SIZE;
+ nul = memchr(body, 0, rh.length);
+ if (! nul) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Relay begin cell has no \\0. Closing.");
+ *end_reason_out = END_STREAM_REASON_TORPROTOCOL;
+ return -1;
+ }
+
+ if (tor_addr_port_split(LOG_PROTOCOL_WARN,
+ (char*)(body),
+ &bcell->address,&bcell->port)<0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Unable to parse addr:port in relay begin cell. Closing.");
+ *end_reason_out = END_STREAM_REASON_TORPROTOCOL;
+ return -1;
+ }
+ if (bcell->port == 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Missing port in relay begin cell. Closing.");
+ tor_free(bcell->address);
+ *end_reason_out = END_STREAM_REASON_TORPROTOCOL;
+ return -1;
+ }
+ if (body + rh.length >= nul + 4)
+ bcell->flags = ntohl(get_uint32(nul+1));
+
+ return 0;
+}
+
/** A relay 'begin' or 'begin_dir' cell has arrived, and either we are
* an exit hop for the circuit, or we are the origin and it is a
* rendezvous begin.
@@ -3015,10 +2374,13 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
{
edge_connection_t *n_stream;
relay_header_t rh;
- char *address=NULL;
- uint16_t port;
+ char *address = NULL;
+ uint16_t port = 0;
or_circuit_t *or_circ = NULL;
const or_options_t *options = get_options();
+ begin_cell_t bcell;
+ int r;
+ uint8_t end_reason=0;
assert_circuit_ok(circ);
if (!CIRCUIT_IS_ORIGIN(circ))
@@ -3042,52 +2404,43 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
return 0;
}
- if (rh.command == RELAY_COMMAND_BEGIN) {
- if (!memchr(cell->payload+RELAY_HEADER_SIZE, 0, rh.length)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Relay begin cell has no \\0. Closing.");
- relay_send_end_cell_from_edge(rh.stream_id, circ,
- END_STREAM_REASON_TORPROTOCOL, NULL);
- return 0;
- }
- if (tor_addr_port_split(LOG_PROTOCOL_WARN,
- (char*)(cell->payload+RELAY_HEADER_SIZE),
- &address,&port)<0) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Unable to parse addr:port in relay begin cell. Closing.");
- relay_send_end_cell_from_edge(rh.stream_id, circ,
- END_STREAM_REASON_TORPROTOCOL, NULL);
- return 0;
- }
- if (port==0) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Missing port in relay begin cell. Closing.");
- relay_send_end_cell_from_edge(rh.stream_id, circ,
- END_STREAM_REASON_TORPROTOCOL, NULL);
- tor_free(address);
- return 0;
- }
- if (or_circ && or_circ->p_conn && !options->AllowSingleHopExits &&
- (or_circ->is_first_hop ||
- (!connection_or_digest_is_known_relay(
- or_circ->p_conn->identity_digest) &&
+ r = begin_cell_parse(cell, &bcell, &end_reason);
+ if (r < -1) {
+ return -1;
+ } else if (r == -1) {
+ tor_free(bcell.address);
+ relay_send_end_cell_from_edge(rh.stream_id, circ, end_reason, NULL);
+ return 0;
+ }
+
+ if (! bcell.is_begindir) {
+ /* Steal reference */
+ address = bcell.address;
+ port = bcell.port;
+
+ if (or_circ && or_circ->p_chan) {
+ if (!options->AllowSingleHopExits &&
+ (or_circ->is_first_hop ||
+ (!connection_or_digest_is_known_relay(
+ or_circ->p_chan->identity_digest) &&
should_refuse_unknown_exits(options)))) {
- /* Don't let clients use us as a single-hop proxy, unless the user
- * has explicitly allowed that in the config. It attracts attackers
- * and users who'd be better off with, well, single-hop proxies.
- */
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Attempt by %s to open a stream %s. Closing.",
- safe_str(or_circ->p_conn->_base.address),
- or_circ->is_first_hop ? "on first hop of circuit" :
- "from unknown relay");
- relay_send_end_cell_from_edge(rh.stream_id, circ,
- or_circ->is_first_hop ?
- END_STREAM_REASON_TORPROTOCOL :
- END_STREAM_REASON_MISC,
- NULL);
- tor_free(address);
- return 0;
+ /* Don't let clients use us as a single-hop proxy, unless the user
+ * has explicitly allowed that in the config. It attracts attackers
+ * and users who'd be better off with, well, single-hop proxies.
+ */
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Attempt by %s to open a stream %s. Closing.",
+ safe_str(channel_get_canonical_remote_descr(or_circ->p_chan)),
+ or_circ->is_first_hop ? "on first hop of circuit" :
+ "from unknown relay");
+ relay_send_end_cell_from_edge(rh.stream_id, circ,
+ or_circ->is_first_hop ?
+ END_STREAM_REASON_TORPROTOCOL :
+ END_STREAM_REASON_MISC,
+ NULL);
+ tor_free(address);
+ return 0;
+ }
}
} else if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
if (!directory_permits_begindir_requests(options) ||
@@ -3098,10 +2451,10 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
}
/* Make sure to get the 'real' address of the previous hop: the
* caller might want to know whether his IP address has changed, and
- * we might already have corrected _base.addr[ess] for the relay's
+ * we might already have corrected base_.addr[ess] for the relay's
* canonical IP address. */
- if (or_circ && or_circ->p_conn)
- address = tor_dup_addr(&or_circ->p_conn->real_addr);
+ if (or_circ && or_circ->p_chan)
+ address = tor_strdup(channel_get_actual_remote_address(or_circ->p_chan));
else
address = tor_strdup("127.0.0.1");
port = 1; /* XXXX This value is never actually used anywhere, and there
@@ -3114,17 +2467,31 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
return 0;
}
+ if (! options->IPv6Exit) {
+ /* I don't care if you prefer IPv6; I can't give you any. */
+ bcell.flags &= ~BEGIN_FLAG_IPV6_PREFERRED;
+ /* If you don't want IPv4, I can't help. */
+ if (bcell.flags & BEGIN_FLAG_IPV4_NOT_OK) {
+ tor_free(address);
+ relay_send_end_cell_from_edge(rh.stream_id, circ,
+ END_STREAM_REASON_EXITPOLICY, NULL);
+ return 0;
+ }
+ }
+
log_debug(LD_EXIT,"Creating new exit connection.");
+ /* The 'AF_INET' here is temporary; we might need to change it later in
+ * connection_exit_connect(). */
n_stream = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
/* Remember the tunneled request ID in the new edge connection, so that
* we can measure download times. */
- TO_CONN(n_stream)->dirreq_id = circ->dirreq_id;
-
- n_stream->_base.purpose = EXIT_PURPOSE_CONNECT;
+ n_stream->dirreq_id = circ->dirreq_id;
+ n_stream->base_.purpose = EXIT_PURPOSE_CONNECT;
+ n_stream->begincell_flags = bcell.flags;
n_stream->stream_id = rh.stream_id;
- n_stream->_base.port = port;
+ n_stream->base_.port = port;
/* leave n_stream->s at -1, because it's not yet valid */
n_stream->package_window = STREAMWINDOW_START;
n_stream->deliver_window = STREAMWINDOW_START;
@@ -3132,14 +2499,14 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
log_info(LD_REND,"begin is for rendezvous. configuring stream.");
- n_stream->_base.address = tor_strdup("(rendezvous)");
- n_stream->_base.state = EXIT_CONN_STATE_CONNECTING;
+ n_stream->base_.address = tor_strdup("(rendezvous)");
+ n_stream->base_.state = EXIT_CONN_STATE_CONNECTING;
n_stream->rend_data = rend_data_dup(origin_circ->rend_data);
tor_assert(connection_edge_is_rendezvous_stream(n_stream));
assert_circuit_ok(circ);
if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) {
log_info(LD_REND,"Didn't find rendezvous service (port %d)",
- n_stream->_base.port);
+ n_stream->base_.port);
relay_send_end_cell_from_edge(rh.stream_id, circ,
END_STREAM_REASON_EXITPOLICY,
origin_circ->cpath->prev);
@@ -3158,12 +2525,16 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
assert_circuit_ok(circ);
connection_exit_connect(n_stream);
+
+ /* For path bias: This circuit was used successfully */
+ pathbias_mark_use_success(origin_circ);
+
tor_free(address);
return 0;
}
tor_strlower(address);
- n_stream->_base.address = address;
- n_stream->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ n_stream->base_.address = address;
+ n_stream->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
/* default to failed, change in dns_resolve if it turns out not to fail */
if (we_are_hibernating()) {
@@ -3176,9 +2547,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
n_stream->on_circuit = circ;
if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
+ tor_addr_t tmp_addr;
tor_assert(or_circ);
- if (or_circ->p_conn && !tor_addr_is_null(&or_circ->p_conn->real_addr))
- tor_addr_copy(&n_stream->_base.addr, &or_circ->p_conn->real_addr);
+ if (or_circ->p_chan &&
+ channel_get_addr_if_possible(or_circ->p_chan, &tmp_addr)) {
+ tor_addr_copy(&n_stream->base_.addr, &tmp_addr);
+ }
return connection_exit_connect_dir(n_stream);
}
@@ -3228,12 +2602,12 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
*/
dummy_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
dummy_conn->stream_id = rh.stream_id;
- dummy_conn->_base.address = tor_strndup(
+ dummy_conn->base_.address = tor_strndup(
(char*)cell->payload+RELAY_HEADER_SIZE,
rh.length);
- dummy_conn->_base.port = 0;
- dummy_conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
- dummy_conn->_base.purpose = EXIT_PURPOSE_RESOLVE;
+ dummy_conn->base_.port = 0;
+ dummy_conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ dummy_conn->base_.purpose = EXIT_PURPOSE_RESOLVE;
dummy_conn->on_circuit = TO_CIRCUIT(circ);
@@ -3243,7 +2617,7 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
/* Connection freed; don't touch it. */
return 0;
case 1: /* The result was cached; a resolved cell was sent. */
- if (!dummy_conn->_base.marked_for_close)
+ if (!dummy_conn->base_.marked_for_close)
connection_free(TO_CONN(dummy_conn));
return 0;
case 0: /* resolve added to pending list */
@@ -3268,8 +2642,11 @@ connection_exit_connect(edge_connection_t *edge_conn)
connection_t *conn = TO_CONN(edge_conn);
int socket_error = 0;
- if (!connection_edge_is_rendezvous_stream(edge_conn) &&
- router_compare_to_my_exit_policy(edge_conn)) {
+ if ( (!connection_edge_is_rendezvous_stream(edge_conn) &&
+ router_compare_to_my_exit_policy(&edge_conn->base_.addr,
+ edge_conn->base_.port)) ||
+ (tor_addr_family(&conn->addr) == AF_INET6 &&
+ ! get_options()->IPv6Exit)) {
log_info(LD_EXIT,"%s:%d failed exit policy. Closing.",
escaped_safe_str_client(conn->address), conn->port);
connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY);
@@ -3281,6 +2658,9 @@ connection_exit_connect(edge_connection_t *edge_conn)
addr = &conn->addr;
port = conn->port;
+ if (tor_addr_family(addr) == AF_INET6)
+ conn->socket_family = AF_INET6;
+
log_debug(LD_EXIT,"about to try connecting");
switch (connection_connect(conn, conn->address, addr, port, &socket_error)) {
case -1: {
@@ -3318,21 +2698,21 @@ connection_exit_connect(edge_connection_t *edge_conn)
RELAY_COMMAND_CONNECTED,
NULL, 0);
} else { /* normal stream */
- char connected_payload[20];
- int connected_payload_len;
- if (tor_addr_family(&conn->addr) == AF_INET) {
- set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
- connected_payload_len = 4;
- } else {
- memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
- connected_payload_len = 16;
+ uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
+ int connected_payload_len =
+ connected_cell_format_payload(connected_payload, &conn->addr,
+ edge_conn->address_ttl);
+ if (connected_payload_len < 0) {
+ connection_edge_end(edge_conn, END_STREAM_REASON_INTERNAL);
+ circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
+ connection_free(conn);
+ return;
}
- set_uint32(connected_payload+connected_payload_len,
- htonl(dns_clip_ttl(edge_conn->address_ttl)));
- connected_payload_len += 4;
+
connection_edge_send_command(edge_conn,
RELAY_COMMAND_CONNECTED,
- connected_payload, connected_payload_len);
+ (char*)connected_payload,
+ connected_payload_len);
}
}
@@ -3351,20 +2731,20 @@ connection_exit_connect_dir(edge_connection_t *exitconn)
log_info(LD_EXIT, "Opening local connection for anonymized directory exit");
- exitconn->_base.state = EXIT_CONN_STATE_OPEN;
+ exitconn->base_.state = EXIT_CONN_STATE_OPEN;
- dirconn = dir_connection_new(tor_addr_family(&exitconn->_base.addr));
+ dirconn = dir_connection_new(tor_addr_family(&exitconn->base_.addr));
- tor_addr_copy(&dirconn->_base.addr, &exitconn->_base.addr);
- dirconn->_base.port = 0;
- dirconn->_base.address = tor_strdup(exitconn->_base.address);
- dirconn->_base.type = CONN_TYPE_DIR;
- dirconn->_base.purpose = DIR_PURPOSE_SERVER;
- dirconn->_base.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
+ tor_addr_copy(&dirconn->base_.addr, &exitconn->base_.addr);
+ dirconn->base_.port = 0;
+ dirconn->base_.address = tor_strdup(exitconn->base_.address);
+ dirconn->base_.type = CONN_TYPE_DIR;
+ dirconn->base_.purpose = DIR_PURPOSE_SERVER;
+ dirconn->base_.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
/* Note that the new dir conn belongs to the same tunneled request as
* the edge conn, so that we can measure download times. */
- TO_CONN(dirconn)->dirreq_id = TO_CONN(exitconn)->dirreq_id;
+ dirconn->dirreq_id = exitconn->dirreq_id;
connection_link_connections(TO_CONN(dirconn), TO_CONN(exitconn));
@@ -3447,11 +2827,15 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit)
}
if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
- struct in_addr in;
tor_addr_t addr, *addrp = NULL;
addr_policy_result_t r;
- if (tor_inet_aton(conn->socks_request->address, &in)) {
- tor_addr_from_in(&addr, &in);
+ if (0 == tor_addr_parse(&addr, conn->socks_request->address)) {
+ addrp = &addr;
+ } else if (!conn->ipv4_traffic_ok && conn->ipv6_traffic_ok) {
+ tor_addr_make_null(&addr, AF_INET6);
+ addrp = &addr;
+ } else if (conn->ipv4_traffic_ok && !conn->ipv6_traffic_ok) {
+ tor_addr_make_null(&addr, AF_INET);
addrp = &addr;
}
r = compare_tor_addr_to_node_policy(addrp, conn->socks_request->port,exit);
@@ -3466,7 +2850,7 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit)
if (!conn->chosen_exit_name && node_exit_policy_rejects_all(exit))
return 0;
}
- if (routerset_contains_node(options->_ExcludeExitNodesUnion, exit)) {
+ if (routerset_contains_node(options->ExcludeExitNodesUnion_, exit)) {
/* Not a suitable exit. Refuse it. */
return 0;
}
@@ -3477,6 +2861,9 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit)
/** If address is of the form "y.onion" with a well-formed handle y:
* Put a NUL after y, lower-case it, and return ONION_HOSTNAME.
*
+ * If address is of the form "x.y.onion" with a well-formed handle x:
+ * Drop "x.", put a NUL after y, lower-case it, and return ONION_HOSTNAME.
+ *
* If address is of the form "y.onion" with a badly-formed handle y:
* Return BAD_HOSTNAME and log a message.
*
@@ -3490,6 +2877,7 @@ hostname_type_t
parse_extended_hostname(char *address)
{
char *s;
+ char *q;
char query[REND_SERVICE_ID_LEN_BASE32+1];
s = strrchr(address,'.');
@@ -3504,9 +2892,18 @@ parse_extended_hostname(char *address)
/* so it is .onion */
*s = 0; /* NUL-terminate it */
- if (strlcpy(query, address, REND_SERVICE_ID_LEN_BASE32+1) >=
+ /* locate a 'sub-domain' component, in order to remove it */
+ q = strrchr(address, '.');
+ if (q == address) {
+ goto failed; /* reject sub-domain, as DNS does */
+ }
+ q = (NULL == q) ? address : q + 1;
+ if (strlcpy(query, q, REND_SERVICE_ID_LEN_BASE32+1) >=
REND_SERVICE_ID_LEN_BASE32+1)
goto failed;
+ if (q != address) {
+ memmove(address, q, strlen(q) + 1 /* also get \0 */);
+ }
if (rend_valid_service_id(query)) {
return ONION_HOSTNAME; /* success */
}
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index c320d6ba4..ea284cbcf 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,13 +9,13 @@
* \brief Header file for connection_edge.c.
**/
-#ifndef _TOR_CONNECTION_EDGE_H
-#define _TOR_CONNECTION_EDGE_H
+#ifndef TOR_CONNECTION_EDGE_H
+#define TOR_CONNECTION_EDGE_H
#define connection_mark_unattached_ap(conn, endreason) \
- _connection_mark_unattached_ap((conn), (endreason), __LINE__, _SHORT_FILE_)
+ connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__)
-void _connection_mark_unattached_ap(entry_connection_t *conn, int endreason,
+void connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
int line, const char *file);
int connection_edge_reached_eof(edge_connection_t *conn);
int connection_edge_process_inbuf(edge_connection_t *conn,
@@ -67,30 +67,6 @@ int connection_ap_process_transparent(entry_connection_t *conn);
int address_is_invalid_destination(const char *address, int client);
-void addressmap_init(void);
-void addressmap_clear_excluded_trackexithosts(const or_options_t *options);
-void addressmap_clear_invalid_automaps(const or_options_t *options);
-void addressmap_clean(time_t now);
-void addressmap_clear_configured(void);
-void addressmap_clear_transient(void);
-void addressmap_free_all(void);
-int addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out,
- addressmap_entry_source_t *exit_source_out);
-int addressmap_have_mapping(const char *address, int update_timeout);
-
-void addressmap_register(const char *address, char *new_address,
- time_t expires, addressmap_entry_source_t source,
- const int address_wildcard,
- const int new_address_wildcard);
-int parse_virtual_addr_network(const char *val, int validate_only,
- char **msg);
-int client_dns_incr_failures(const char *address);
-void client_dns_clear_failures(const char *address);
-void client_dns_set_addressmap(const char *address, uint32_t val,
- const char *exitname, int ttl);
-const char *addressmap_register_virtual_address(int type, char *new_address);
-void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
- time_t max_expires, int want_expiry);
int connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn,
origin_circuit_t *circ,
crypt_path_t *cpath);
@@ -114,6 +90,52 @@ int connection_edge_update_circuit_isolation(const entry_connection_t *conn,
origin_circuit_t *circ,
int dry_run);
void circuit_clear_isolation(origin_circuit_t *circ);
+streamid_t get_unique_stream_id_by_circ(origin_circuit_t *circ);
+
+/** @name Begin-cell flags
+ *
+ * These flags are used in RELAY_BEGIN cells to change the default behavior
+ * of the cell.
+ *
+ * @{
+ **/
+/** When this flag is set, the client is willing to get connected to IPv6
+ * addresses */
+#define BEGIN_FLAG_IPV6_OK (1u<<0)
+/** When this flag is set, the client DOES NOT support connecting to IPv4
+ * addresses. (The sense of this flag is inverted from IPV6_OK, so that the
+ * old default behavior of Tor is equivalent to having all flags set to 0.)
+ **/
+#define BEGIN_FLAG_IPV4_NOT_OK (1u<<1)
+/** When this flag is set, if we find both an IPv4 and an IPv6 address,
+ * we use the IPv6 address. Otherwise we use the IPv4 address. */
+#define BEGIN_FLAG_IPV6_PREFERRED (1u<<2)
+/**@}*/
+
+#ifdef CONNECTION_EDGE_PRIVATE
+
+/** A parsed BEGIN or BEGIN_DIR cell */
+typedef struct begin_cell_t {
+ /** The address the client has asked us to connect to, or NULL if this is
+ * a BEGIN_DIR cell*/
+ char *address;
+ /** The flags specified in the BEGIN cell's body. One or more of
+ * BEGIN_FLAG_*. */
+ uint32_t flags;
+ /** The client's requested port. */
+ uint16_t port;
+ /** The client's requested Stream ID */
+ uint16_t stream_id;
+ /** True iff this is a BEGIN_DIR cell. */
+ unsigned is_begindir : 1;
+} begin_cell_t;
+
+int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
+ uint8_t *end_reason_out);
+int connected_cell_format_payload(uint8_t *payload_out,
+ const tor_addr_t *addr,
+ uint32_t ttl);
+#endif
#endif
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index fbb7c31e0..8e7cd9ea5 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,17 +9,25 @@
* \brief Functions to handle OR connections, TLS handshaking, and
* cells on the network.
**/
-
#include "or.h"
#include "buffers.h"
+/*
+ * Define this so we get channel internal functions, since we're implementing
+ * part of a subclass (channel_tls_t).
+ */
+#define TOR_CHANNEL_INTERNAL_
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitstats.h"
#include "command.h"
#include "config.h"
#include "connection.h"
#include "connection_or.h"
#include "control.h"
#include "dirserv.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "main.h"
#include "networkstatus.h"
@@ -43,6 +51,17 @@ static int connection_or_check_valid_tls_handshake(or_connection_t *conn,
static void connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn);
+static unsigned int
+connection_or_is_bad_for_new_circs(or_connection_t *or_conn);
+static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn);
+
+/*
+ * Call this when changing connection state, so notifications to the owning
+ * channel can be handled.
+ */
+
+static void connection_or_change_state(or_connection_t *conn, uint8_t state);
+
#ifdef USE_BUFFEREVENTS
static void connection_or_handle_event_cb(struct bufferevent *bufev,
short event, void *arg);
@@ -127,8 +146,11 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
return;
/* If the identity was set previously, remove the old mapping. */
- if (! tor_digest_is_zero(conn->identity_digest))
+ if (! tor_digest_is_zero(conn->identity_digest)) {
connection_or_remove_from_identity_map(conn);
+ if (conn->chan)
+ channel_clear_identity_digest(TLS_CHAN_TO_BASE(conn->chan));
+ }
memcpy(conn->identity_digest, digest, DIGEST_LEN);
@@ -139,6 +161,10 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
tmp = digestmap_set(orconn_identity_map, digest, conn);
conn->next_with_same_id = tmp;
+ /* Deal with channels */
+ if (conn->chan)
+ channel_set_identity_digest(TLS_CHAN_TO_BASE(conn->chan), digest);
+
#if 1
/* Testing code to check for bugs in representation. */
for (; tmp; tmp = tmp->next_with_same_id) {
@@ -268,13 +294,13 @@ connection_or_report_broken_states(int severity, int domain)
smartlist_sort(items, broken_state_count_compare);
- log(severity, domain, "%d connections have failed%s", total,
+ tor_log(severity, domain, "%d connections have failed%s", total,
smartlist_len(items) > MAX_REASONS_TO_REPORT ? ". Top reasons:" : ":");
SMARTLIST_FOREACH_BEGIN(items, const broken_state_count_t *, c) {
if (c_sl_idx > MAX_REASONS_TO_REPORT)
break;
- log(severity, domain,
+ tor_log(severity, domain,
" %d connections died in state %s", (int)c->count, c->state);
} SMARTLIST_FOREACH_END(c);
@@ -282,6 +308,39 @@ connection_or_report_broken_states(int severity, int domain)
smartlist_free(items);
}
+/** Call this to change or_connection_t states, so the owning channel_tls_t can
+ * be notified.
+ */
+
+static void
+connection_or_change_state(or_connection_t *conn, uint8_t state)
+{
+ uint8_t old_state;
+
+ tor_assert(conn);
+
+ old_state = conn->base_.state;
+ conn->base_.state = state;
+
+ if (conn->chan)
+ channel_tls_handle_state_change_on_orconn(conn->chan, conn,
+ old_state, state);
+}
+
+/** Return the number of circuits using an or_connection_t; this used to
+ * be an or_connection_t field, but it got moved to channel_t and we
+ * shouldn't maintain two copies. */
+
+int
+connection_or_get_num_circuits(or_connection_t *conn)
+{
+ tor_assert(conn);
+
+ if (conn->chan) {
+ return channel_num_circuits(TLS_CHAN_TO_BASE(conn->chan));
+ } else return 0;
+}
+
/**************************************************************/
/** Pack the cell_t host-order structure <b>src</b> into network-order
@@ -292,33 +351,56 @@ connection_or_report_broken_states(int severity, int domain)
* should set it or clear it as appropriate.
*/
void
-cell_pack(packed_cell_t *dst, const cell_t *src)
+cell_pack(packed_cell_t *dst, const cell_t *src, int wide_circ_ids)
{
char *dest = dst->body;
- set_uint16(dest, htons(src->circ_id));
- *(uint8_t*)(dest+2) = src->command;
- memcpy(dest+3, src->payload, CELL_PAYLOAD_SIZE);
+ if (wide_circ_ids) {
+ set_uint32(dest, htonl(src->circ_id));
+ dest += 4;
+ } else {
+ set_uint16(dest, htons(src->circ_id));
+ dest += 2;
+ memset(dest+CELL_MAX_NETWORK_SIZE-2, 0, 2); /*make sure it's clear */
+ }
+ set_uint8(dest, src->command);
+ memcpy(dest+1, src->payload, CELL_PAYLOAD_SIZE);
}
/** Unpack the network-order buffer <b>src</b> into a host-order
* cell_t structure <b>dest</b>.
*/
static void
-cell_unpack(cell_t *dest, const char *src)
+cell_unpack(cell_t *dest, const char *src, int wide_circ_ids)
{
- dest->circ_id = ntohs(get_uint16(src));
- dest->command = *(uint8_t*)(src+2);
- memcpy(dest->payload, src+3, CELL_PAYLOAD_SIZE);
+ if (wide_circ_ids) {
+ dest->circ_id = ntohl(get_uint32(src));
+ src += 4;
+ } else {
+ dest->circ_id = ntohs(get_uint16(src));
+ src += 2;
+ }
+ dest->command = get_uint8(src);
+ memcpy(dest->payload, src+1, CELL_PAYLOAD_SIZE);
}
-/** Write the header of <b>cell</b> into the first VAR_CELL_HEADER_SIZE
- * bytes of <b>hdr_out</b>. */
-void
-var_cell_pack_header(const var_cell_t *cell, char *hdr_out)
+/** Write the header of <b>cell</b> into the first VAR_CELL_MAX_HEADER_SIZE
+ * bytes of <b>hdr_out</b>. Returns number of bytes used. */
+int
+var_cell_pack_header(const var_cell_t *cell, char *hdr_out, int wide_circ_ids)
{
- set_uint16(hdr_out, htons(cell->circ_id));
- set_uint8(hdr_out+2, cell->command);
- set_uint16(hdr_out+3, htons(cell->payload_len));
+ int r;
+ if (wide_circ_ids) {
+ set_uint32(hdr_out, htonl(cell->circ_id));
+ hdr_out += 4;
+ r = VAR_CELL_MAX_HEADER_SIZE;
+ } else {
+ set_uint16(hdr_out, htons(cell->circ_id));
+ hdr_out += 2;
+ r = VAR_CELL_MAX_HEADER_SIZE - 2;
+ }
+ set_uint8(hdr_out, cell->command);
+ set_uint16(hdr_out+1, htons(cell->payload_len));
+ return r;
}
/** Allocate and return a new var_cell_t with <b>payload_len</b> bytes of
@@ -327,7 +409,7 @@ var_cell_t *
var_cell_new(uint16_t payload_len)
{
size_t size = STRUCT_OFFSET(var_cell_t, payload) + payload_len;
- var_cell_t *cell = tor_malloc(size);
+ var_cell_t *cell = tor_malloc_zero(size);
cell->payload_len = payload_len;
cell->command = 0;
cell->circ_id = 0;
@@ -345,8 +427,11 @@ var_cell_free(var_cell_t *cell)
int
connection_or_reached_eof(or_connection_t *conn)
{
+ tor_assert(conn);
+
log_info(LD_OR,"OR connection reached EOF. Closing.");
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_normally(conn, 1);
+
return 0;
}
@@ -366,7 +451,7 @@ connection_or_process_inbuf(or_connection_t *conn)
int ret = 0;
tor_assert(conn);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case OR_CONN_STATE_PROXY_HANDSHAKING:
ret = connection_read_proxy_handshake(TO_CONN(conn));
@@ -375,9 +460,12 @@ connection_or_process_inbuf(or_connection_t *conn)
tor_assert(TO_CONN(conn)->proxy_state == PROXY_CONNECTED);
if (connection_tls_start_handshake(conn, 0) < 0)
ret = -1;
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
}
if (ret < 0) {
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
}
return ret;
@@ -385,7 +473,7 @@ connection_or_process_inbuf(or_connection_t *conn)
#ifdef USE_BUFFEREVENTS
if (tor_tls_server_got_renegotiate(conn->tls))
connection_or_tls_renegotiated_cb(conn->tls, conn);
- if (conn->_base.marked_for_close)
+ if (conn->base_.marked_for_close)
return 0;
/* fall through. */
#endif
@@ -403,14 +491,14 @@ connection_or_process_inbuf(or_connection_t *conn)
*
* XXX024 Remove this check once we verify that the above paragraph is
* 100% true. */
- if (buf_datalen(conn->_base.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) {
+ if (buf_datalen(conn->base_.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) {
log_fn(LOG_PROTOCOL_WARN, LD_NET, "Accumulated too much data (%d bytes) "
"on nonopen OR connection %s %s:%u in state %s; closing.",
- (int)buf_datalen(conn->_base.inbuf),
+ (int)buf_datalen(conn->base_.inbuf),
connection_or_nonopen_was_started_here(conn) ? "to" : "from",
- conn->_base.address, conn->_base.port,
- conn_state_to_string(conn->_base.type, conn->_base.state));
- connection_mark_for_close(TO_CONN(conn));
+ conn->base_.address, conn->base_.port,
+ conn_state_to_string(conn->base_.type, conn->base_.state));
+ connection_or_close_for_error(conn, 0);
ret = -1;
}
@@ -430,18 +518,32 @@ connection_or_process_inbuf(or_connection_t *conn)
int
connection_or_flushed_some(or_connection_t *conn)
{
- size_t datalen = connection_get_outbuf_len(TO_CONN(conn));
+ size_t datalen, temp;
+ ssize_t n, flushed;
+ size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids);
+
/* If we're under the low water mark, add cells until we're just over the
* high water mark. */
+ datalen = connection_get_outbuf_len(TO_CONN(conn));
if (datalen < OR_CONN_LOWWATER) {
- ssize_t n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, CELL_NETWORK_SIZE);
- time_t now = approx_time();
- while (conn->active_circuits && n > 0) {
- int flushed;
- flushed = connection_or_flush_from_first_active_circuit(conn, 1, now);
- n -= flushed;
+ while ((conn->chan) && channel_tls_more_to_flush(conn->chan)) {
+ /* Compute how many more cells we want at most */
+ n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, cell_network_size);
+ /* Bail out if we don't want any more */
+ if (n <= 0) break;
+ /* We're still here; try to flush some more cells */
+ flushed = channel_tls_flush_some_cells(conn->chan, n);
+ /* Bail out if it says it didn't flush anything */
+ if (flushed <= 0) break;
+ /* How much in the outbuf now? */
+ temp = connection_get_outbuf_len(TO_CONN(conn));
+ /* Bail out if we didn't actually increase the outbuf size */
+ if (temp <= datalen) break;
+ /* Update datalen for the next iteration */
+ datalen = temp;
}
}
+
return 0;
}
@@ -459,14 +561,14 @@ connection_or_finished_flushing(or_connection_t *conn)
tor_assert(conn);
assert_connection_ok(TO_CONN(conn),0);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case OR_CONN_STATE_PROXY_HANDSHAKING:
case OR_CONN_STATE_OPEN:
case OR_CONN_STATE_OR_HANDSHAKING_V2:
case OR_CONN_STATE_OR_HANDSHAKING_V3:
break;
default:
- log_err(LD_BUG,"Called in unexpected state %d.", conn->_base.state);
+ log_err(LD_BUG,"Called in unexpected state %d.", conn->base_.state);
tor_fragile_assert();
return -1;
}
@@ -480,6 +582,7 @@ connection_or_finished_connecting(or_connection_t *or_conn)
{
const int proxy_type = or_conn->proxy_type;
connection_t *conn;
+
tor_assert(or_conn);
conn = TO_CONN(or_conn);
tor_assert(conn->state == OR_CONN_STATE_CONNECTING);
@@ -491,18 +594,18 @@ connection_or_finished_connecting(or_connection_t *or_conn)
if (proxy_type != PROXY_NONE) {
/* start proxy handshake */
if (connection_proxy_connect(conn, proxy_type) < 0) {
- connection_mark_for_close(conn);
+ connection_or_close_for_error(or_conn, 0);
return -1;
}
connection_start_reading(conn);
- conn->state = OR_CONN_STATE_PROXY_HANDSHAKING;
+ connection_or_change_state(or_conn, OR_CONN_STATE_PROXY_HANDSHAKING);
return 0;
}
if (connection_tls_start_handshake(or_conn, 0) < 0) {
/* TLS handshaking error of some kind. */
- connection_mark_for_close(conn);
+ connection_or_close_for_error(or_conn, 0);
return -1;
}
return 0;
@@ -516,11 +619,19 @@ connection_or_about_to_close(or_connection_t *or_conn)
time_t now = time(NULL);
connection_t *conn = TO_CONN(or_conn);
+ /* Tell the controlling channel we're closed */
+ if (or_conn->chan) {
+ channel_closed(TLS_CHAN_TO_BASE(or_conn->chan));
+ /*
+ * NULL this out because the channel might hang around a little
+ * longer before channel_run_cleanup() gets it.
+ */
+ or_conn->chan->conn = NULL;
+ or_conn->chan = NULL;
+ }
+
/* Remember why we're closing this connection. */
if (conn->state != OR_CONN_STATE_OPEN) {
- /* Inform any pending (not attached) circs that they should
- * give up. */
- circuit_n_conn_done(TO_OR_CONN(conn), 0);
/* now mark things down as needed */
if (connection_or_nonopen_was_started_here(or_conn)) {
const or_options_t *options = get_options();
@@ -548,9 +659,6 @@ connection_or_about_to_close(or_connection_t *or_conn)
control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED,
tls_error_to_orconn_end_reason(or_conn->tls_error));
}
- /* Now close all the attached circuits on it. */
- circuit_unlink_all_from_or_conn(TO_OR_CONN(conn),
- END_CIRC_REASON_OR_CONN_CLOSED);
}
/** Return 1 if identity digest <b>id_digest</b> is known to be a
@@ -613,8 +721,8 @@ connection_or_update_token_buckets_helper(or_connection_t *conn, int reset,
cfg = ev_token_bucket_cfg_new(rate_per_tick, burst, rate_per_tick,
burst, tick);
old_cfg = conn->bucket_cfg;
- if (conn->_base.bufev)
- tor_set_bufferevent_rate_limit(conn->_base.bufev, cfg);
+ if (conn->base_.bufev)
+ tor_set_bufferevent_rate_limit(conn->base_.bufev, cfg);
if (old_cfg)
ev_token_bucket_cfg_free(old_cfg);
conn->bucket_cfg = cfg;
@@ -663,15 +771,15 @@ connection_or_init_conn_from_address(or_connection_t *conn,
connection_or_set_identity_digest(conn, id_digest);
connection_or_update_token_buckets_helper(conn, 1, get_options());
- conn->_base.port = port;
- tor_addr_copy(&conn->_base.addr, addr);
+ conn->base_.port = port;
+ tor_addr_copy(&conn->base_.addr, addr);
tor_addr_copy(&conn->real_addr, addr);
if (r) {
tor_addr_port_t node_ap;
node_get_pref_orport(r, &node_ap);
/* XXXX proposal 186 is making this more complex. For now, a conn
is canonical when it uses the _preferred_ address. */
- if (tor_addr_eq(&conn->_base.addr, &node_ap.addr))
+ if (tor_addr_eq(&conn->base_.addr, &node_ap.addr))
conn->is_canonical = 1;
if (!started_here) {
/* Override the addr/port, so our log messages will make sense.
@@ -684,12 +792,12 @@ connection_or_init_conn_from_address(or_connection_t *conn,
* right IP address and port 56244, that wouldn't be as helpful. now we
* log the "right" port too, so we know if it's moria1 or moria2.
*/
- tor_addr_copy(&conn->_base.addr, &node_ap.addr);
- conn->_base.port = node_ap.port;
+ tor_addr_copy(&conn->base_.addr, &node_ap.addr);
+ conn->base_.port = node_ap.port;
}
conn->nickname = tor_strdup(node_get_nickname(r));
- tor_free(conn->_base.address);
- conn->_base.address = tor_dup_addr(&node_ap.addr);
+ tor_free(conn->base_.address);
+ conn->base_.address = tor_dup_addr(&node_ap.addr);
} else {
const char *n;
/* If we're an authoritative directory server, we may know a
@@ -703,157 +811,31 @@ connection_or_init_conn_from_address(or_connection_t *conn,
base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
conn->identity_digest, DIGEST_LEN);
}
- tor_free(conn->_base.address);
- conn->_base.address = tor_dup_addr(addr);
+ tor_free(conn->base_.address);
+ conn->base_.address = tor_dup_addr(addr);
}
}
-/** Return true iff <b>a</b> is "better" than <b>b</b> for new circuits.
- *
- * A more canonical connection is always better than a less canonical
- * connection. That aside, a connection is better if it has circuits and the
- * other does not, or if it was created more recently.
- *
- * Requires that both input connections are open; not is_bad_for_new_circs,
- * and not impossibly non-canonical.
- *
- * If <b>forgive_new_connections</b> is true, then we do not call
- * <b>a</b>better than <b>b</b> simply because b has no circuits,
- * unless b is also relatively old.
- */
-static int
-connection_or_is_better(time_t now,
- const or_connection_t *a,
- const or_connection_t *b,
- int forgive_new_connections)
-{
- int newer;
-/** Do not definitively deprecate a new connection with no circuits on it
- * until this much time has passed. */
-#define NEW_CONN_GRACE_PERIOD (15*60)
-
- if (b->is_canonical && !a->is_canonical)
- return 0; /* A canonical connection is better than a non-canonical
- * one, no matter how new it is or which has circuits. */
-
- newer = b->_base.timestamp_created < a->_base.timestamp_created;
-
- if (
- /* We prefer canonical connections regardless of newness. */
- (!b->is_canonical && a->is_canonical) ||
- /* If both have circuits we prefer the newer: */
- (b->n_circuits && a->n_circuits && newer) ||
- /* If neither has circuits we prefer the newer: */
- (!b->n_circuits && !a->n_circuits && newer))
- return 1;
+/** These just pass all the is_bad_for_new_circs manipulation on to
+ * channel_t */
- /* If one has no circuits and the other does... */
- if (!b->n_circuits && a->n_circuits) {
- /* Then it's bad, unless it's in its grace period and we're forgiving. */
- if (forgive_new_connections &&
- now < b->_base.timestamp_created + NEW_CONN_GRACE_PERIOD)
- return 0;
- else
- return 1;
- }
+static unsigned int
+connection_or_is_bad_for_new_circs(or_connection_t *or_conn)
+{
+ tor_assert(or_conn);
- return 0;
+ if (or_conn->chan)
+ return channel_is_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan));
+ else return 0;
}
-/** Return the OR connection we should use to extend a circuit to the router
- * whose identity is <b>digest</b>, and whose address we believe (or have been
- * told in an extend cell) is <b>target_addr</b>. If there is no good
- * connection, set *<b>msg_out</b> to a message describing the connection's
- * state and our next action, and set <b>launch_out</b> to a boolean for
- * whether we should launch a new connection or not.
- */
-or_connection_t *
-connection_or_get_for_extend(const char *digest,
- const tor_addr_t *target_addr,
- const char **msg_out,
- int *launch_out)
+static void
+connection_or_mark_bad_for_new_circs(or_connection_t *or_conn)
{
- or_connection_t *conn, *best=NULL;
- int n_inprogress_goodaddr = 0, n_old = 0, n_noncanonical = 0, n_possible = 0;
- time_t now = approx_time();
-
- tor_assert(msg_out);
- tor_assert(launch_out);
-
- if (!orconn_identity_map) {
- *msg_out = "Router not connected (nothing is). Connecting.";
- *launch_out = 1;
- return NULL;
- }
-
- conn = digestmap_get(orconn_identity_map, digest);
-
- for (; conn; conn = conn->next_with_same_id) {
- tor_assert(conn->_base.magic == OR_CONNECTION_MAGIC);
- tor_assert(conn->_base.type == CONN_TYPE_OR);
- tor_assert(tor_memeq(conn->identity_digest, digest, DIGEST_LEN));
- if (conn->_base.marked_for_close)
- continue;
- /* Never return a connection on which the other end appears to be
- * a client. */
- if (conn->is_connection_with_client) {
- continue;
- }
- /* Never return a non-open connection. */
- if (conn->_base.state != OR_CONN_STATE_OPEN) {
- /* If the address matches, don't launch a new connection for this
- * circuit. */
- if (!tor_addr_compare(&conn->real_addr, target_addr, CMP_EXACT))
- ++n_inprogress_goodaddr;
- continue;
- }
- /* Never return a connection that shouldn't be used for circs. */
- if (conn->is_bad_for_new_circs) {
- ++n_old;
- continue;
- }
- /* Never return a non-canonical connection using a recent link protocol
- * if the address is not what we wanted.
- *
- * (For old link protocols, we can't rely on is_canonical getting
- * set properly if we're talking to the right address, since we might
- * have an out-of-date descriptor, and we will get no NETINFO cell to
- * tell us about the right address.) */
- if (!conn->is_canonical && conn->link_proto >= 2 &&
- tor_addr_compare(&conn->real_addr, target_addr, CMP_EXACT)) {
- ++n_noncanonical;
- continue;
- }
-
- ++n_possible;
-
- if (!best) {
- best = conn; /* If we have no 'best' so far, this one is good enough. */
- continue;
- }
-
- if (connection_or_is_better(now, conn, best, 0))
- best = conn;
- }
+ tor_assert(or_conn);
- if (best) {
- *msg_out = "Connection is fine; using it.";
- *launch_out = 0;
- return best;
- } else if (n_inprogress_goodaddr) {
- *msg_out = "Connection in progress; waiting.";
- *launch_out = 0;
- return NULL;
- } else if (n_old || n_noncanonical) {
- *msg_out = "Connections all too old, or too non-canonical. "
- " Launching a new one.";
- *launch_out = 1;
- return NULL;
- } else {
- *msg_out = "Not connected. Connecting.";
- *launch_out = 1;
- return NULL;
- }
+ if (or_conn->chan)
+ channel_mark_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan));
}
/** How old do we let a connection to an OR get before deciding it's
@@ -874,8 +856,8 @@ connection_or_get_for_extend(const char *digest,
* - all open non-canonical connections for which a 'better' non-canonical
* connection exists to the same router at the same address.
*
- * See connection_or_is_better() for our idea of what makes one OR connection
- * better than another.
+ * See channel_is_better() in channel.c for our idea of what makes one OR
+ * connection better than another.
*/
static void
connection_or_group_set_badness(or_connection_t *head, int force)
@@ -887,23 +869,23 @@ connection_or_group_set_badness(or_connection_t *head, int force)
/* Pass 1: expire everything that's old, and see what the status of
* everything else is. */
for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) {
- if (or_conn->_base.marked_for_close ||
- or_conn->is_bad_for_new_circs)
+ if (or_conn->base_.marked_for_close ||
+ connection_or_is_bad_for_new_circs(or_conn))
continue;
if (force ||
- or_conn->_base.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD
+ or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD
< now) {
log_info(LD_OR,
"Marking OR conn to %s:%d as too old for new circuits "
- "(fd %d, %d secs old).",
- or_conn->_base.address, or_conn->_base.port, or_conn->_base.s,
- (int)(now - or_conn->_base.timestamp_created));
- or_conn->is_bad_for_new_circs = 1;
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old).",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
}
- if (or_conn->is_bad_for_new_circs) {
+ if (connection_or_is_bad_for_new_circs(or_conn)) {
++n_old;
- } else if (or_conn->_base.state != OR_CONN_STATE_OPEN) {
+ } else if (or_conn->base_.state != OR_CONN_STATE_OPEN) {
++n_inprogress;
} else if (or_conn->is_canonical) {
++n_canonical;
@@ -915,10 +897,10 @@ connection_or_group_set_badness(or_connection_t *head, int force)
/* Pass 2: We know how about how good the best connection is.
* expire everything that's worse, and find the very best if we can. */
for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) {
- if (or_conn->_base.marked_for_close ||
- or_conn->is_bad_for_new_circs)
+ if (or_conn->base_.marked_for_close ||
+ connection_or_is_bad_for_new_circs(or_conn))
continue; /* This one doesn't need to be marked bad. */
- if (or_conn->_base.state != OR_CONN_STATE_OPEN)
+ if (or_conn->base_.state != OR_CONN_STATE_OPEN)
continue; /* Don't mark anything bad until we have seen what happens
* when the connection finishes. */
if (n_canonical && !or_conn->is_canonical) {
@@ -926,16 +908,21 @@ connection_or_group_set_badness(or_connection_t *head, int force)
* and this one is open but not canonical. Mark it bad. */
log_info(LD_OR,
"Marking OR conn to %s:%d as unsuitable for new circuits: "
- "(fd %d, %d secs old). It is not canonical, and we have "
- "another connection to that OR that is.",
- or_conn->_base.address, or_conn->_base.port, or_conn->_base.s,
- (int)(now - or_conn->_base.timestamp_created));
- or_conn->is_bad_for_new_circs = 1;
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old). It is not "
+ "canonical, and we have another connection to that OR that is.",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
continue;
}
- if (!best || connection_or_is_better(now, or_conn, best, 0))
+ if (!best ||
+ channel_is_better(now,
+ TLS_CHAN_TO_BASE(or_conn->chan),
+ TLS_CHAN_TO_BASE(best->chan),
+ 0)) {
best = or_conn;
+ }
}
if (!best)
@@ -956,32 +943,37 @@ connection_or_group_set_badness(or_connection_t *head, int force)
* "mostly harmless", so a fix can wait until somebody is bored.
*/
for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) {
- if (or_conn->_base.marked_for_close ||
- or_conn->is_bad_for_new_circs ||
- or_conn->_base.state != OR_CONN_STATE_OPEN)
+ if (or_conn->base_.marked_for_close ||
+ connection_or_is_bad_for_new_circs(or_conn) ||
+ or_conn->base_.state != OR_CONN_STATE_OPEN)
continue;
- if (or_conn != best && connection_or_is_better(now, best, or_conn, 1)) {
+ if (or_conn != best &&
+ channel_is_better(now,
+ TLS_CHAN_TO_BASE(best->chan),
+ TLS_CHAN_TO_BASE(or_conn->chan), 1)) {
/* This isn't the best conn, _and_ the best conn is better than it,
even when we're being forgiving. */
if (best->is_canonical) {
log_info(LD_OR,
"Marking OR conn to %s:%d as unsuitable for new circuits: "
- "(fd %d, %d secs old). We have a better canonical one "
- "(fd %d; %d secs old).",
- or_conn->_base.address, or_conn->_base.port, or_conn->_base.s,
- (int)(now - or_conn->_base.timestamp_created),
- best->_base.s, (int)(now - best->_base.timestamp_created));
- or_conn->is_bad_for_new_circs = 1;
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old). "
+ "We have a better canonical one "
+ "(fd "TOR_SOCKET_T_FORMAT"; %d secs old).",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created),
+ best->base_.s, (int)(now - best->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
} else if (!tor_addr_compare(&or_conn->real_addr,
&best->real_addr, CMP_EXACT)) {
log_info(LD_OR,
"Marking OR conn to %s:%d as unsuitable for new circuits: "
- "(fd %d, %d secs old). We have a better one with the "
- "same address (fd %d; %d secs old).",
- or_conn->_base.address, or_conn->_base.port, or_conn->_base.s,
- (int)(now - or_conn->_base.timestamp_created),
- best->_base.s, (int)(now - best->_base.timestamp_created));
- or_conn->is_bad_for_new_circs = 1;
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old). We have a better "
+ "one with the "
+ "same address (fd "TOR_SOCKET_T_FORMAT"; %d secs old).",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created),
+ best->base_.s, (int)(now - best->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
}
}
}
@@ -1019,8 +1011,41 @@ connection_or_connect_failed(or_connection_t *conn,
control_event_bootstrap_problem(msg, reason);
}
+/** <b>conn</b> got an error in connection_handle_read_impl() or
+ * connection_handle_write_impl() and is going to die soon.
+ *
+ * <b>reason</b> specifies the or_conn_end_reason for the failure;
+ * <b>msg</b> specifies the strerror-style error message.
+ */
+void
+connection_or_notify_error(or_connection_t *conn,
+ int reason, const char *msg)
+{
+ channel_t *chan;
+
+ tor_assert(conn);
+
+ /* If we're connecting, call connect_failed() too */
+ if (TO_CONN(conn)->state == OR_CONN_STATE_CONNECTING)
+ connection_or_connect_failed(conn, reason, msg);
+
+ /* Tell the controlling channel if we have one */
+ if (conn->chan) {
+ chan = TLS_CHAN_TO_BASE(conn->chan);
+ /* Don't transition if we're already in closing, closed or error */
+ if (!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ channel_close_for_error(chan);
+ }
+ }
+
+ /* No need to mark for error because connection.c is about to do that */
+}
+
/** Launch a new OR connection to <b>addr</b>:<b>port</b> and expect to
- * handshake with an OR with identity digest <b>id_digest</b>.
+ * handshake with an OR with identity digest <b>id_digest</b>. Optionally,
+ * pass in a pointer to a channel using this connection.
*
* If <b>id_digest</b> is me, do nothing. If we're already connected to it,
* return that connection. If the connect() is in progress, set the
@@ -1035,7 +1060,8 @@ connection_or_connect_failed(or_connection_t *conn,
*/
or_connection_t *
connection_or_connect(const tor_addr_t *_addr, uint16_t port,
- const char *id_digest)
+ const char *id_digest,
+ channel_tls_t *chan)
{
or_connection_t *conn;
const or_options_t *options = get_options();
@@ -1058,9 +1084,17 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
conn = or_connection_new(tor_addr_family(&addr));
- /* set up conn so it's got all the data we need to remember */
+ /*
+ * Set up conn so it's got all the data we need to remember for channels
+ *
+ * This stuff needs to happen before connection_or_init_conn_from_address()
+ * so connection_or_set_identity_digest() and such know where to look to
+ * keep the channel up to date.
+ */
+ conn->chan = chan;
+ chan->conn = conn;
connection_or_init_conn_from_address(conn, &addr, port, id_digest, 1);
- conn->_base.state = OR_CONN_STATE_CONNECTING;
+ connection_or_change_state(conn, OR_CONN_STATE_CONNECTING);
control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED, 0);
conn->is_outgoing = 1;
@@ -1072,7 +1106,7 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
if (proxy_type != PROXY_NONE) {
tor_addr_copy(&addr, &proxy_addr);
port = proxy_port;
- conn->_base.proxy_state = PROXY_INFANT;
+ conn->base_.proxy_state = PROXY_INFANT;
}
} else {
/* get_proxy_addrport() might fail if we have a Bridge line that
@@ -1084,29 +1118,29 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
TO_CONN(conn)->port);
if (transport_name) {
- log_warn(LD_GENERAL, "We were supposed to connect to bridge '%s:%u' "
+ log_warn(LD_GENERAL, "We were supposed to connect to bridge '%s' "
"using pluggable transport '%s', but we can't find a pluggable "
"transport proxy supporting '%s'. This can happen if you "
"haven't provided a ClientTransportPlugin line, or if "
"your pluggable transport proxy stopped running.",
- fmt_addr(&TO_CONN(conn)->addr), TO_CONN(conn)->port,
+ fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port),
transport_name, transport_name);
} else {
- log_warn(LD_GENERAL, "Tried to connect to '%s:%u' through a proxy, but "
+ log_warn(LD_GENERAL, "Tried to connect to '%s' through a proxy, but "
"the proxy address could not be found.",
- fmt_addr(&TO_CONN(conn)->addr), TO_CONN(conn)->port);
+ fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port));
}
connection_free(TO_CONN(conn));
return NULL;
}
- switch (connection_connect(TO_CONN(conn), conn->_base.address,
+ switch (connection_connect(TO_CONN(conn), conn->base_.address,
&addr, port, &socket_error)) {
case -1:
/* If the connection failed immediately, and we're using
* a proxy, our proxy is down. Don't blame the Tor server. */
- if (conn->_base.proxy_state == PROXY_INFANT)
+ if (conn->base_.proxy_state == PROXY_INFANT)
entry_guard_register_connect_status(conn->identity_digest,
0, 1, time(NULL));
connection_or_connect_failed(conn,
@@ -1129,6 +1163,62 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
return conn;
}
+/** Mark orconn for close and transition the associated channel, if any, to
+ * the closing state.
+ *
+ * It's safe to call this and connection_or_close_for_error() any time, and
+ * channel layer will treat it as a connection closing for reasons outside
+ * its control, like the remote end closing it. It can also be a local
+ * reason that's specific to connection_t/or_connection_t rather than
+ * the channel mechanism, such as expiration of old connections in
+ * run_connection_housekeeping(). If you want to close a channel_t
+ * from somewhere that logically works in terms of generic channels
+ * rather than connections, use channel_mark_for_close(); see also
+ * the comment on that function in channel.c.
+ */
+
+void
+connection_or_close_normally(or_connection_t *orconn, int flush)
+{
+ channel_t *chan = NULL;
+
+ tor_assert(orconn);
+ if (flush) connection_mark_and_flush_internal(TO_CONN(orconn));
+ else connection_mark_for_close_internal(TO_CONN(orconn));
+ if (orconn->chan) {
+ chan = TLS_CHAN_TO_BASE(orconn->chan);
+ /* Don't transition if we're already in closing, closed or error */
+ if (!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ channel_close_from_lower_layer(chan);
+ }
+ }
+}
+
+/** Mark orconn for close and transition the associated channel, if any, to
+ * the error state.
+ */
+
+void
+connection_or_close_for_error(or_connection_t *orconn, int flush)
+{
+ channel_t *chan = NULL;
+
+ tor_assert(orconn);
+ if (flush) connection_mark_and_flush_internal(TO_CONN(orconn));
+ else connection_mark_for_close_internal(TO_CONN(orconn));
+ if (orconn->chan) {
+ chan = TLS_CHAN_TO_BASE(orconn->chan);
+ /* Don't transition if we're already in closing, closed or error */
+ if (!(chan->state == CHANNEL_STATE_CLOSING ||
+ chan->state == CHANNEL_STATE_CLOSED ||
+ chan->state == CHANNEL_STATE_ERROR)) {
+ channel_close_for_error(chan);
+ }
+ }
+}
+
/** Begin the tls handshake with <b>conn</b>. <b>receiving</b> is 0 if
* we initiated the connection, else it's 1.
*
@@ -1140,29 +1230,46 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
int
connection_tls_start_handshake(or_connection_t *conn, int receiving)
{
- conn->_base.state = OR_CONN_STATE_TLS_HANDSHAKING;
+ channel_listener_t *chan_listener;
+ channel_t *chan;
+
+ /* Incoming connections will need a new channel passed to the
+ * channel_tls_listener */
+ if (receiving) {
+ /* It shouldn't already be set */
+ tor_assert(!(conn->chan));
+ chan_listener = channel_tls_get_listener();
+ if (!chan_listener) {
+ chan_listener = channel_tls_start_listener();
+ command_setup_listener(chan_listener);
+ }
+ chan = channel_tls_handle_incoming(conn);
+ channel_listener_queue_incoming(chan_listener, chan);
+ }
+
+ connection_or_change_state(conn, OR_CONN_STATE_TLS_HANDSHAKING);
tor_assert(!conn->tls);
- conn->tls = tor_tls_new(conn->_base.s, receiving);
+ conn->tls = tor_tls_new(conn->base_.s, receiving);
if (!conn->tls) {
log_warn(LD_BUG,"tor_tls_new failed. Closing.");
return -1;
}
tor_tls_set_logged_address(conn->tls, // XXX client and relay?
- escaped_safe_str(conn->_base.address));
+ escaped_safe_str(conn->base_.address));
#ifdef USE_BUFFEREVENTS
if (connection_type_uses_bufferevent(TO_CONN(conn))) {
- const int filtering = get_options()->_UseFilteringSSLBufferevents;
+ const int filtering = get_options()->UseFilteringSSLBufferevents;
struct bufferevent *b =
- tor_tls_init_bufferevent(conn->tls, conn->_base.bufev, conn->_base.s,
+ tor_tls_init_bufferevent(conn->tls, conn->base_.bufev, conn->base_.s,
receiving, filtering);
if (!b) {
log_warn(LD_BUG,"tor_tls_init_bufferevent failed. Closing.");
return -1;
}
- conn->_base.bufev = b;
+ conn->base_.bufev = b;
if (conn->bucket_cfg)
- tor_set_bufferevent_rate_limit(conn->_base.bufev, conn->bucket_cfg);
+ tor_set_bufferevent_rate_limit(conn->base_.bufev, conn->bucket_cfg);
connection_enable_rate_limiting(TO_CONN(conn));
connection_configure_bufferevent_callbacks(TO_CONN(conn));
@@ -1174,7 +1281,8 @@ connection_tls_start_handshake(or_connection_t *conn, int receiving)
}
#endif
connection_start_reading(TO_CONN(conn));
- log_debug(LD_HANDSHAKE,"starting TLS handshake on fd %d", conn->_base.s);
+ log_debug(LD_HANDSHAKE,"starting TLS handshake on fd "TOR_SOCKET_T_FORMAT,
+ conn->base_.s);
note_crypto_pk_op(receiving ? TLS_HANDSHAKE_S : TLS_HANDSHAKE_C);
IF_HAS_BUFFEREVENT(TO_CONN(conn), {
@@ -1211,7 +1319,7 @@ connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn)
if (connection_tls_finish_handshake(conn) < 0) {
/* XXXX_TLS double-check that it's ok to do this from inside read. */
/* XXXX_TLS double-check that this verifies certificates. */
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
}
}
@@ -1226,12 +1334,12 @@ connection_tls_continue_handshake(or_connection_t *conn)
int result;
check_no_tls_errors();
again:
- if (conn->_base.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) {
+ if (conn->base_.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) {
// log_notice(LD_OR, "Renegotiate with %p", conn->tls);
result = tor_tls_renegotiate(conn->tls);
// log_notice(LD_OR, "Result: %d", result);
} else {
- tor_assert(conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING);
+ tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING);
// log_notice(LD_OR, "Continue handshake with %p", conn->tls);
result = tor_tls_handshake(conn->tls);
// log_notice(LD_OR, "Result: %d", result);
@@ -1244,19 +1352,21 @@ connection_tls_continue_handshake(or_connection_t *conn)
case TOR_TLS_DONE:
if (! tor_tls_used_v1_handshake(conn->tls)) {
if (!tor_tls_is_server(conn->tls)) {
- if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) {
+ if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_received_v3_certificate(conn->tls)) {
log_info(LD_OR, "Client got a v3 cert! Moving on to v3 "
- "handshake.");
+ "handshake with ciphersuite %s",
+ tor_tls_get_ciphersuite_name(conn->tls));
return connection_or_launch_v3_or_handshake(conn);
} else {
log_debug(LD_OR, "Done with initial SSL handshake (client-side)."
" Requesting renegotiation.");
- conn->_base.state = OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING;
+ connection_or_change_state(conn,
+ OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
goto again;
}
}
- // log_notice(LD_OR,"Done. state was %d.", conn->_base.state);
+ // log_notice(LD_OR,"Done. state was %d.", conn->base_.state);
} else {
/* v2/v3 handshake, but not a client. */
log_debug(LD_OR, "Done with initial SSL handshake (server-side). "
@@ -1264,7 +1374,8 @@ connection_tls_continue_handshake(or_connection_t *conn)
tor_tls_set_renegotiate_callback(conn->tls,
connection_or_tls_renegotiated_cb,
conn);
- conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING;
+ connection_or_change_state(conn,
+ OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
connection_stop_writing(TO_CONN(conn));
connection_start_reading(TO_CONN(conn));
return 0;
@@ -1294,28 +1405,29 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
/* XXXX cut-and-paste code; should become a function. */
if (event & BEV_EVENT_CONNECTED) {
- if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) {
+ if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_finish_handshake(conn->tls) < 0) {
log_warn(LD_OR, "Problem finishing handshake");
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
return;
}
}
if (! tor_tls_used_v1_handshake(conn->tls)) {
if (!tor_tls_is_server(conn->tls)) {
- if (conn->_base.state == OR_CONN_STATE_TLS_HANDSHAKING) {
+ if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) {
if (tor_tls_received_v3_certificate(conn->tls)) {
log_info(LD_OR, "Client got a v3 cert!");
if (connection_or_launch_v3_or_handshake(conn) < 0)
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
return;
} else {
- conn->_base.state = OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING;
+ connection_or_change_state(conn,
+ OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING);
tor_tls_unblock_renegotiation(conn->tls);
- if (bufferevent_ssl_renegotiate(conn->_base.bufev)<0) {
+ if (bufferevent_ssl_renegotiate(conn->base_.bufev)<0) {
log_warn(LD_OR, "Start_renegotiating went badly.");
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
}
tor_tls_unblock_renegotiation(conn->tls);
return; /* ???? */
@@ -1330,7 +1442,8 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
tor_tls_set_renegotiate_callback(conn->tls,
connection_or_tls_renegotiated_cb,
conn);
- conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING;
+ connection_or_change_state(conn,
+ OR_CONN_STATE_TLS_SERVER_RENEGOTIATING);
} else if (handshakes == 2) {
/* v2 handshake, as a server. Two handshakes happened already,
* so we treat renegotiation as done.
@@ -1339,18 +1452,18 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
} else if (handshakes > 2) {
log_warn(LD_OR, "More than two handshakes done on connection. "
"Closing.");
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
} else {
log_warn(LD_BUG, "We were unexpectedly told that a connection "
"got %d handshakes. Closing.", handshakes);
- connection_mark_for_close(TO_CONN(conn));
+ connection_or_close_for_error(conn, 0);
}
return;
}
}
connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT);
if (connection_tls_finish_handshake(conn) < 0)
- connection_mark_for_close(TO_CONN(conn)); /* ???? */
+ connection_or_close_for_error(conn, 0); /* ???? */
return;
}
@@ -1372,7 +1485,7 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
int
connection_or_nonopen_was_started_here(or_connection_t *conn)
{
- tor_assert(conn->_base.type == CONN_TYPE_OR);
+ tor_assert(conn->base_.type == CONN_TYPE_OR);
if (!conn->tls)
return 1; /* it's still in proxy states or something */
if (conn->handshake_state)
@@ -1380,29 +1493,6 @@ connection_or_nonopen_was_started_here(or_connection_t *conn)
return !tor_tls_is_server(conn->tls);
}
-/** Set the circid_type field of <b>conn</b> (which determines which part of
- * the circuit ID space we're willing to use) based on comparing our ID to
- * <b>identity_rcvd</b> */
-void
-connection_or_set_circid_type(or_connection_t *conn,
- crypto_pk_t *identity_rcvd)
-{
- const int started_here = connection_or_nonopen_was_started_here(conn);
- crypto_pk_t *our_identity =
- started_here ? get_tlsclient_identity_key() :
- get_server_identity_key();
-
- if (identity_rcvd) {
- if (crypto_pk_cmp_keys(our_identity, identity_rcvd)<0) {
- conn->circ_id_type = CIRC_ID_TYPE_LOWER;
- } else {
- conn->circ_id_type = CIRC_ID_TYPE_HIGHER;
- }
- } else {
- conn->circ_id_type = CIRC_ID_TYPE_NEITHER;
- }
-}
-
/** <b>Conn</b> just completed its handshake. Return 0 if all is well, and
* return -1 if he is lying, broken, or otherwise something is wrong.
*
@@ -1437,8 +1527,8 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
const or_options_t *options = get_options();
int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN;
const char *safe_address =
- started_here ? conn->_base.address :
- safe_str_client(conn->_base.address);
+ started_here ? conn->base_.address :
+ safe_str_client(conn->base_.address);
const char *conn_type = started_here ? "outgoing" : "incoming";
int has_cert = 0;
@@ -1447,7 +1537,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
if (started_here && !has_cert) {
log_info(LD_HANDSHAKE,"Tried connecting to router at %s:%d, but it didn't "
"send a cert! Closing.",
- safe_address, conn->_base.port);
+ safe_address, conn->base_.port);
return -1;
} else if (!has_cert) {
log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. "
@@ -1461,7 +1551,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
if (started_here && v<0) {
log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s:%d: It"
" has a cert but it's invalid. Closing.",
- safe_address, conn->_base.port);
+ safe_address, conn->base_.port);
return -1;
} else if (v<0) {
log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert "
@@ -1469,7 +1559,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
} else {
log_debug(LD_HANDSHAKE,
"The certificate seems to be valid on %s connection "
- "with %s:%d", conn_type, safe_address, conn->_base.port);
+ "with %s:%d", conn_type, safe_address, conn->base_.port);
}
check_no_tls_errors();
}
@@ -1480,7 +1570,9 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
memset(digest_rcvd_out, 0, DIGEST_LEN);
}
- connection_or_set_circid_type(conn, identity_rcvd);
+ tor_assert(conn->chan);
+ channel_set_circid_type(TLS_CHAN_TO_BASE(conn->chan), identity_rcvd, 1);
+
crypto_pk_free(identity_rcvd);
if (started_here)
@@ -1521,10 +1613,10 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
conn->identity_digest, DIGEST_LEN);
log_info(LD_HANDSHAKE, "Connected to router %s at %s:%d without knowing "
"its key. Hoping for the best.",
- conn->nickname, conn->_base.address, conn->_base.port);
+ conn->nickname, conn->base_.address, conn->base_.port);
/* if it's a bridge and we didn't know its identity fingerprint, now
* we do -- remember it for future attempts. */
- learned_router_identity(&conn->_base.addr, conn->_base.port,
+ learned_router_identity(&conn->base_.addr, conn->base_.port,
(const char*)peer_id);
}
@@ -1538,7 +1630,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
log_fn(severity, LD_HANDSHAKE,
"Tried connecting to router at %s:%d, but identity key was not "
"as expected: wanted %s but got %s.",
- conn->_base.address, conn->_base.port, expected, seen);
+ conn->base_.address, conn->base_.port, expected, seen);
entry_guard_register_connect_status(conn->identity_digest, 0, 1,
time(NULL));
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED,
@@ -1550,13 +1642,26 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
return -1;
}
if (authdir_mode_tests_reachability(options)) {
- dirserv_orconn_tls_done(conn->_base.address, conn->_base.port,
+ dirserv_orconn_tls_done(&conn->base_.addr, conn->base_.port,
(const char*)peer_id);
}
return 0;
}
+/** Return when a client used this, for connection.c, since client_used
+ * is now one of the timestamps of channel_t */
+
+time_t
+connection_or_client_used(or_connection_t *conn)
+{
+ tor_assert(conn);
+
+ if (conn->chan) {
+ return channel_when_last_client(TLS_CHAN_TO_BASE(conn->chan));
+ } else return 0;
+}
+
/** The v1/v2 TLS handshake is finished.
*
* Make sure we are happy with the person we just handshaked with.
@@ -1576,10 +1681,12 @@ connection_tls_finish_handshake(or_connection_t *conn)
char digest_rcvd[DIGEST_LEN];
int started_here = connection_or_nonopen_was_started_here(conn);
- log_debug(LD_HANDSHAKE,"%s tls handshake on %p with %s done. verifying.",
+ log_debug(LD_HANDSHAKE,"%s tls handshake on %p with %s done, using "
+ "ciphersuite %s. verifying.",
started_here?"outgoing":"incoming",
conn,
- safe_str_client(conn->_base.address));
+ safe_str_client(conn->base_.address),
+ tor_tls_get_ciphersuite_name(conn->tls));
directory_set_dirty();
@@ -1592,18 +1699,18 @@ connection_tls_finish_handshake(or_connection_t *conn)
if (tor_tls_used_v1_handshake(conn->tls)) {
conn->link_proto = 1;
if (!started_here) {
- connection_or_init_conn_from_address(conn, &conn->_base.addr,
- conn->_base.port, digest_rcvd, 0);
+ connection_or_init_conn_from_address(conn, &conn->base_.addr,
+ conn->base_.port, digest_rcvd, 0);
}
tor_tls_block_renegotiation(conn->tls);
return connection_or_set_state_open(conn);
} else {
- conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V2;
+ connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2);
if (connection_init_or_handshake_state(conn, started_here) < 0)
return -1;
if (!started_here) {
- connection_or_init_conn_from_address(conn, &conn->_base.addr,
- conn->_base.port, digest_rcvd, 0);
+ connection_or_init_conn_from_address(conn, &conn->base_.addr,
+ conn->base_.port, digest_rcvd, 0);
}
return connection_or_send_versions(conn, 0);
}
@@ -1623,7 +1730,7 @@ connection_or_launch_v3_or_handshake(or_connection_t *conn)
circuit_build_times_network_is_live(&circ_times);
- conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
if (connection_init_or_handshake_state(conn, 1) < 0)
return -1;
@@ -1671,10 +1778,12 @@ or_handshake_state_free(or_handshake_state_t *state)
* authenticate cell.)
*/
void
-or_handshake_state_record_cell(or_handshake_state_t *state,
+or_handshake_state_record_cell(or_connection_t *conn,
+ or_handshake_state_t *state,
const cell_t *cell,
int incoming)
{
+ size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids);
crypto_digest_t *d, **dptr;
packed_cell_t packed;
if (incoming) {
@@ -1696,8 +1805,8 @@ or_handshake_state_record_cell(or_handshake_state_t *state,
d = *dptr;
/* Re-packing like this is a little inefficient, but we don't have to do
this very often at all. */
- cell_pack(&packed, cell);
- crypto_digest_add_bytes(d, packed.body, sizeof(packed.body));
+ cell_pack(&packed, cell, conn->wide_circ_ids);
+ crypto_digest_add_bytes(d, packed.body, cell_network_size);
memwipe(&packed, 0, sizeof(packed));
}
@@ -1710,12 +1819,14 @@ or_handshake_state_record_cell(or_handshake_state_t *state,
* authenticate cell.)
*/
void
-or_handshake_state_record_var_cell(or_handshake_state_t *state,
+or_handshake_state_record_var_cell(or_connection_t *conn,
+ or_handshake_state_t *state,
const var_cell_t *cell,
int incoming)
{
crypto_digest_t *d, **dptr;
- char buf[VAR_CELL_HEADER_SIZE];
+ int n;
+ char buf[VAR_CELL_MAX_HEADER_SIZE];
if (incoming) {
if (!state->digest_received_data)
return;
@@ -1729,8 +1840,8 @@ or_handshake_state_record_var_cell(or_handshake_state_t *state,
d = *dptr;
- var_cell_pack_header(cell, buf);
- crypto_digest_add_bytes(d, buf, sizeof(buf));
+ n = var_cell_pack_header(cell, buf, conn->wide_circ_ids);
+ crypto_digest_add_bytes(d, buf, n);
crypto_digest_add_bytes(d, (const char *)cell->payload, cell->payload_len);
memwipe(buf, 0, sizeof(buf));
@@ -1742,35 +1853,9 @@ or_handshake_state_record_var_cell(or_handshake_state_t *state,
int
connection_or_set_state_open(or_connection_t *conn)
{
- int started_here = connection_or_nonopen_was_started_here(conn);
- time_t now = time(NULL);
- conn->_base.state = OR_CONN_STATE_OPEN;
+ connection_or_change_state(conn, OR_CONN_STATE_OPEN);
control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED, 0);
- if (started_here) {
- circuit_build_times_network_is_live(&circ_times);
- rep_hist_note_connect_succeeded(conn->identity_digest, now);
- if (entry_guard_register_connect_status(conn->identity_digest,
- 1, 0, now) < 0) {
- /* Close any circuits pending on this conn. We leave it in state
- * 'open' though, because it didn't actually *fail* -- we just
- * chose not to use it. (Otherwise
- * connection_about_to_close_connection() will call a big pile of
- * functions to indicate we shouldn't try it again.) */
- log_debug(LD_OR, "New entry guard was reachable, but closing this "
- "connection so we can retry the earlier entry guards.");
- circuit_n_conn_done(conn, 0);
- return -1;
- }
- router_set_status(conn->identity_digest, 1);
- } else {
- /* only report it to the geoip module if it's not a known router */
- if (!router_get_by_id_digest(conn->identity_digest)) {
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(conn)->addr,
- now);
- }
- }
-
or_handshake_state_free(conn->handshake_state);
conn->handshake_state = NULL;
IF_HAS_BUFFEREVENT(TO_CONN(conn), {
@@ -1779,8 +1864,6 @@ connection_or_set_state_open(or_connection_t *conn)
connection_start_reading(TO_CONN(conn));
}
- circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
-
return 0;
}
@@ -1792,16 +1875,21 @@ void
connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn)
{
packed_cell_t networkcell;
+ size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids);
tor_assert(cell);
tor_assert(conn);
- cell_pack(&networkcell, cell);
+ cell_pack(&networkcell, cell, conn->wide_circ_ids);
+
+ connection_write_to_buf(networkcell.body, cell_network_size, TO_CONN(conn));
- connection_write_to_buf(networkcell.body, CELL_NETWORK_SIZE, TO_CONN(conn));
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
- if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
- or_handshake_state_record_cell(conn->handshake_state, cell, 0);
+ if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
+ or_handshake_state_record_cell(conn, conn->handshake_state, cell, 0);
if (cell->command != CELL_PADDING)
conn->timestamp_last_added_nonpadding = approx_time();
@@ -1815,17 +1903,22 @@ void
connection_or_write_var_cell_to_buf(const var_cell_t *cell,
or_connection_t *conn)
{
- char hdr[VAR_CELL_HEADER_SIZE];
+ int n;
+ char hdr[VAR_CELL_MAX_HEADER_SIZE];
tor_assert(cell);
tor_assert(conn);
- var_cell_pack_header(cell, hdr);
- connection_write_to_buf(hdr, sizeof(hdr), TO_CONN(conn));
+ n = var_cell_pack_header(cell, hdr, conn->wide_circ_ids);
+ connection_write_to_buf(hdr, n, TO_CONN(conn));
connection_write_to_buf((char*)cell->payload,
cell->payload_len, TO_CONN(conn));
- if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
- or_handshake_state_record_var_cell(conn->handshake_state, cell, 0);
+ if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3)
+ or_handshake_state_record_var_cell(conn, conn->handshake_state, cell, 0);
if (cell->command != CELL_PADDING)
conn->timestamp_last_added_nonpadding = approx_time();
+
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
}
/** See whether there's a variable-length cell waiting on <b>or_conn</b>'s
@@ -1856,59 +1949,48 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn)
while (1) {
log_debug(LD_OR,
- "%d: starting, inbuf_datalen %d (%d pending in tls object).",
- conn->_base.s,(int)connection_get_inbuf_len(TO_CONN(conn)),
+ TOR_SOCKET_T_FORMAT": starting, inbuf_datalen %d "
+ "(%d pending in tls object).",
+ conn->base_.s,(int)connection_get_inbuf_len(TO_CONN(conn)),
tor_tls_get_pending_bytes(conn->tls));
if (connection_fetch_var_cell_from_buf(conn, &var_cell)) {
if (!var_cell)
return 0; /* not yet. */
+
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
+
circuit_build_times_network_is_live(&circ_times);
- command_process_var_cell(var_cell, conn);
+ channel_tls_handle_var_cell(var_cell, conn);
var_cell_free(var_cell);
} else {
- char buf[CELL_NETWORK_SIZE];
+ const int wide_circ_ids = conn->wide_circ_ids;
+ size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids);
+ char buf[CELL_MAX_NETWORK_SIZE];
cell_t cell;
if (connection_get_inbuf_len(TO_CONN(conn))
- < CELL_NETWORK_SIZE) /* whole response available? */
+ < cell_network_size) /* whole response available? */
return 0; /* not yet */
+ /* Touch the channel's active timestamp if there is one */
+ if (conn->chan)
+ channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
+
circuit_build_times_network_is_live(&circ_times);
- connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
+ connection_fetch_from_buf(buf, cell_network_size, TO_CONN(conn));
/* retrieve cell info from buf (create the host-order struct from the
* network-order string) */
- cell_unpack(&cell, buf);
+ cell_unpack(&cell, buf, wide_circ_ids);
- command_process_cell(&cell, conn);
+ channel_tls_handle_cell(&cell, conn);
}
}
}
-/** Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>
- * onto OR connection <b>conn</b>. Don't perform range-checking on reason:
- * we may want to propagate reasons from other cells.
- *
- * Return 0.
- */
-int
-connection_or_send_destroy(circid_t circ_id, or_connection_t *conn, int reason)
-{
- cell_t cell;
-
- tor_assert(conn);
-
- memset(&cell, 0, sizeof(cell_t));
- cell.circ_id = circ_id;
- cell.command = CELL_DESTROY;
- cell.payload[0] = (uint8_t) reason;
- log_debug(LD_OR,"Sending destroy (circID %d).", circ_id);
-
- connection_or_write_cell_to_buf(&cell, conn);
- return 0;
-}
-
/** Array of recognized link protocol versions. */
-static const uint16_t or_protocol_versions[] = { 1, 2, 3 };
+static const uint16_t or_protocol_versions[] = { 1, 2, 3, 4 };
/** Number of versions in <b>or_protocol_versions</b>. */
static const int n_or_protocol_versions =
(int)( sizeof(or_protocol_versions)/sizeof(uint16_t) );
@@ -1984,16 +2066,17 @@ connection_or_send_netinfo(or_connection_t *conn)
memset(&cell, 0, sizeof(cell_t));
cell.command = CELL_NETINFO;
- /* Timestamp. */
- set_uint32(cell.payload, htonl((uint32_t)now));
+ /* Timestamp, if we're a relay. */
+ if (public_server_mode(get_options()) || ! conn->is_outgoing)
+ set_uint32(cell.payload, htonl((uint32_t)now));
/* Their address. */
out = cell.payload + 4;
/* We use &conn->real_addr below, unless it hasn't yet been set. If it
- * hasn't yet been set, we know that _base.addr hasn't been tampered with
+ * hasn't yet been set, we know that base_.addr hasn't been tampered with
* yet either. */
len = append_address_to_payload(out, !tor_addr_is_null(&conn->real_addr)
- ? &conn->real_addr : &conn->_base.addr);
+ ? &conn->real_addr : &conn->base_.addr);
if (len<0)
return -1;
out += len;
@@ -2004,12 +2087,19 @@ connection_or_send_netinfo(or_connection_t *conn)
if ((public_server_mode(get_options()) || !conn->is_outgoing) &&
(me = router_get_my_routerinfo())) {
tor_addr_t my_addr;
- *out++ = 1; /* only one address is supported. */
+ *out++ = 1 + !tor_addr_is_null(&me->ipv6_addr);
tor_addr_from_ipv4h(&my_addr, me->addr);
len = append_address_to_payload(out, &my_addr);
if (len < 0)
return -1;
+ out += len;
+
+ if (!tor_addr_is_null(&me->ipv6_addr)) {
+ len = append_address_to_payload(out, &me->ipv6_addr);
+ if (len < 0)
+ return -1;
+ }
} else {
*out = 0;
}
@@ -2034,7 +2124,7 @@ connection_or_send_certs_cell(or_connection_t *conn)
ssize_t pos;
int server_mode;
- tor_assert(conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
+ tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
if (! conn->handshake_state)
return -1;
@@ -2081,7 +2171,7 @@ connection_or_send_auth_challenge_cell(or_connection_t *conn)
var_cell_t *cell;
uint8_t *cp;
uint8_t challenge[OR_AUTH_CHALLENGE_LEN];
- tor_assert(conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
+ tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
if (! conn->handshake_state)
return -1;
@@ -2212,19 +2302,11 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
if (server)
return V3_AUTH_FIXED_PART_LEN; // ptr-out
- /* Time: 8 octets. */
- {
- uint64_t now = time(NULL);
- if ((time_t)now < 0)
- return -1;
- set_uint32(ptr, htonl((uint32_t)(now>>32)));
- set_uint32(ptr+4, htonl((uint32_t)now));
- ptr += 8;
- }
-
- /* Nonce: 16 octets. */
- crypto_rand((char*)ptr, 16);
- ptr += 16;
+ /* 8 octets were reserved for the current time, but we're trying to get out
+ * of the habit of sending time around willynilly. Fortunately, nothing
+ * checks it. That's followed by 16 bytes of nonce. */
+ crypto_rand((char*)ptr, 24);
+ ptr += 24;
tor_assert(ptr - out == V3_AUTH_BODY_LEN);
diff --git a/src/or/connection_or.h b/src/or/connection_or.h
index b78c44492..85e68f1a3 100644
--- a/src/or/connection_or.h
+++ b/src/or/connection_or.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for connection_or.c.
**/
-#ifndef _TOR_CONNECTION_OR_H
-#define _TOR_CONNECTION_OR_H
+#ifndef TOR_CONNECTION_OR_H
+#define TOR_CONNECTION_OR_H
void connection_or_remove_from_identity_map(or_connection_t *conn);
void connection_or_clear_identity_map(void);
@@ -34,8 +34,14 @@ void connection_or_update_token_buckets(smartlist_t *conns,
void connection_or_connect_failed(or_connection_t *conn,
int reason, const char *msg);
+void connection_or_notify_error(or_connection_t *conn,
+ int reason, const char *msg);
or_connection_t *connection_or_connect(const tor_addr_t *addr, uint16_t port,
- const char *id_digest);
+ const char *id_digest,
+ channel_tls_t *chan);
+
+void connection_or_close_normally(or_connection_t *orconn, int flush);
+void connection_or_close_for_error(or_connection_t *orconn, int flush);
void connection_or_report_broken_states(int severity, int domain);
@@ -51,13 +57,15 @@ void connection_or_init_conn_from_address(or_connection_t *conn,
int started_here);
int connection_or_client_learned_peer_id(or_connection_t *conn,
const uint8_t *peer_id);
-void connection_or_set_circid_type(or_connection_t *conn,
- crypto_pk_t *identity_rcvd);
+time_t connection_or_client_used(or_connection_t *conn);
+int connection_or_get_num_circuits(or_connection_t *conn);
void or_handshake_state_free(or_handshake_state_t *state);
-void or_handshake_state_record_cell(or_handshake_state_t *state,
+void or_handshake_state_record_cell(or_connection_t *conn,
+ or_handshake_state_t *state,
const cell_t *cell,
int incoming);
-void or_handshake_state_record_var_cell(or_handshake_state_t *state,
+void or_handshake_state_record_var_cell(or_connection_t *conn,
+ or_handshake_state_t *state,
const var_cell_t *cell,
int incoming);
@@ -66,8 +74,6 @@ void connection_or_write_cell_to_buf(const cell_t *cell,
or_connection_t *conn);
void connection_or_write_var_cell_to_buf(const var_cell_t *cell,
or_connection_t *conn);
-int connection_or_send_destroy(circid_t circ_id, or_connection_t *conn,
- int reason);
int connection_or_send_versions(or_connection_t *conn, int v3_plus);
int connection_or_send_netinfo(or_connection_t *conn);
int connection_or_send_certs_cell(or_connection_t *conn);
@@ -80,10 +86,14 @@ int connection_or_send_authenticate_cell(or_connection_t *conn, int type);
int is_or_protocol_version_known(uint16_t version);
-void cell_pack(packed_cell_t *dest, const cell_t *src);
-void var_cell_pack_header(const var_cell_t *cell, char *hdr_out);
+void cell_pack(packed_cell_t *dest, const cell_t *src, int wide_circ_ids);
+int var_cell_pack_header(const var_cell_t *cell, char *hdr_out,
+ int wide_circ_ids);
var_cell_t *var_cell_new(uint16_t payload_len);
void var_cell_free(var_cell_t *cell);
+/** DOCDOC */
+#define MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS 4
+
#endif
diff --git a/src/or/control.c b/src/or/control.c
index 913d18a7f..a88de12d6 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,11 +11,16 @@
#define CONTROL_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuitstats.h"
#include "circuituse.h"
#include "config.h"
+#include "confparse.h"
#include "connection.h"
#include "connection_edge.h"
#include "connection_or.h"
@@ -23,6 +28,7 @@
#include "directory.h"
#include "dirserv.h"
#include "dnsserv.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
@@ -50,7 +56,7 @@
* because it is used both as a list of v0 event types, and as indices
* into the bitfield to determine which controllers want which events.
*/
-#define _EVENT_MIN 0x0001
+#define EVENT_MIN_ 0x0001
#define EVENT_CIRCUIT_STATUS 0x0001
#define EVENT_STREAM_STATUS 0x0002
#define EVENT_OR_CONN_STATUS 0x0003
@@ -76,8 +82,8 @@
#define EVENT_BUILDTIMEOUT_SET 0x0017
#define EVENT_SIGNAL 0x0018
#define EVENT_CONF_CHANGED 0x0019
-#define _EVENT_MAX 0x0019
-/* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */
+#define EVENT_MAX_ 0x0019
+/* If EVENT_MAX_ ever hits 0x0020, we need to make the mask wider. */
/** Bitfield: The bit 1&lt;&lt;e is set if <b>any</b> open control
* connection is interested in events of type <b>e</b>. We use this
@@ -592,7 +598,7 @@ send_control_event_string(uint16_t event, event_format_t which,
{
smartlist_t *conns = get_connection_array();
(void)which;
- tor_assert(event >= _EVENT_MIN && event <= _EVENT_MAX);
+ tor_assert(event >= EVENT_MIN_ && event <= EVENT_MAX_);
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
if (conn->type == CONN_TYPE_CONTROL &&
@@ -1215,9 +1221,10 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
connection_mark_for_close(TO_CONN(conn));
return 0;
ok:
- log_info(LD_CONTROL, "Authenticated control connection (%d)", conn->_base.s);
+ log_info(LD_CONTROL, "Authenticated control connection ("TOR_SOCKET_T_FORMAT
+ ")", conn->base_.s);
send_control_done(conn);
- conn->_base.state = CONTROL_CONN_STATE_OPEN;
+ conn->base_.state = CONTROL_CONN_STATE_OPEN;
tor_free(password);
if (sl) { /* clean up */
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
@@ -1243,6 +1250,27 @@ handle_control_saveconf(control_connection_t *conn, uint32_t len,
return 0;
}
+struct signal_t {
+ int sig;
+ const char *signal_name;
+};
+
+static const struct signal_t signal_table[] = {
+ { SIGHUP, "RELOAD" },
+ { SIGHUP, "HUP" },
+ { SIGINT, "SHUTDOWN" },
+ { SIGUSR1, "DUMP" },
+ { SIGUSR1, "USR1" },
+ { SIGUSR2, "DEBUG" },
+ { SIGUSR2, "USR2" },
+ { SIGTERM, "HALT" },
+ { SIGTERM, "TERM" },
+ { SIGTERM, "INT" },
+ { SIGNEWNYM, "NEWNYM" },
+ { SIGCLEARDNSCACHE, "CLEARDNSCACHE"},
+ { 0, NULL },
+};
+
/** Called when we get a SIGNAL command. React to the provided signal, and
* report success or failure. (If the signal results in a shutdown, success
* may not be reported.) */
@@ -1250,7 +1278,8 @@ static int
handle_control_signal(control_connection_t *conn, uint32_t len,
const char *body)
{
- int sig;
+ int sig = -1;
+ int i;
int n = 0;
char *s;
@@ -1259,27 +1288,19 @@ handle_control_signal(control_connection_t *conn, uint32_t len,
while (body[n] && ! TOR_ISSPACE(body[n]))
++n;
s = tor_strndup(body, n);
- if (!strcasecmp(s, "RELOAD") || !strcasecmp(s, "HUP"))
- sig = SIGHUP;
- else if (!strcasecmp(s, "SHUTDOWN") || !strcasecmp(s, "INT"))
- sig = SIGINT;
- else if (!strcasecmp(s, "DUMP") || !strcasecmp(s, "USR1"))
- sig = SIGUSR1;
- else if (!strcasecmp(s, "DEBUG") || !strcasecmp(s, "USR2"))
- sig = SIGUSR2;
- else if (!strcasecmp(s, "HALT") || !strcasecmp(s, "TERM"))
- sig = SIGTERM;
- else if (!strcasecmp(s, "NEWNYM"))
- sig = SIGNEWNYM;
- else if (!strcasecmp(s, "CLEARDNSCACHE"))
- sig = SIGCLEARDNSCACHE;
- else {
+
+ for (i = 0; signal_table[i].signal_name != NULL; ++i) {
+ if (!strcasecmp(s, signal_table[i].signal_name)) {
+ sig = signal_table[i].sig;
+ break;
+ }
+ }
+
+ if (sig < 0)
connection_printf_to_buf(conn, "552 Unrecognized signal code \"%s\"\r\n",
s);
- sig = -1;
- }
tor_free(s);
- if (sig<0)
+ if (sig < 0)
return 0;
send_control_done(conn);
@@ -1306,7 +1327,7 @@ handle_control_takeownership(control_connection_t *conn, uint32_t len,
log_info(LD_CONTROL, "Control connection %d has taken ownership of this "
"Tor instance.",
- (int)(conn->_base.s));
+ (int)(conn->base_.s));
send_control_done(conn);
return 0;
@@ -1352,10 +1373,13 @@ handle_control_mapaddress(control_connection_t *conn, uint32_t len,
"512-syntax error: invalid address '%s'", to);
log_warn(LD_CONTROL,
"Skipping invalid argument '%s' in MapAddress msg", to);
- } else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0")) {
+ } else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0") ||
+ !strcmp(from, "::")) {
+ const char type =
+ !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME :
+ (!strcmp(from, "0.0.0.0") ? RESOLVED_TYPE_IPV4 : RESOLVED_TYPE_IPV6);
const char *address = addressmap_register_virtual_address(
- !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : RESOLVED_TYPE_IPV4,
- tor_strdup(to));
+ type, tor_strdup(to));
if (!address) {
smartlist_add_asprintf(reply,
"451-resource exhausted: skipping '%s'", line);
@@ -1440,6 +1464,16 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
*answer = smartlist_join_strings(event_names, " ", 0, NULL);
smartlist_free(event_names);
+ } else if (!strcmp(question, "signal/names")) {
+ smartlist_t *signal_names = smartlist_new();
+ int j;
+ for (j = 0; signal_table[j].signal_name != NULL; ++j) {
+ smartlist_add(signal_names, (char*)signal_table[j].signal_name);
+ }
+
+ *answer = smartlist_join_strings(signal_names, " ", 0, NULL);
+
+ smartlist_free(signal_names);
} else if (!strcmp(question, "features/names")) {
*answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS");
} else if (!strcmp(question, "address")) {
@@ -1614,10 +1648,13 @@ getinfo_helper_dir(control_connection_t *control_conn,
const char *question, char **answer,
const char **errmsg)
{
- const routerinfo_t *ri;
+ const node_t *node;
+ const routerinfo_t *ri = NULL;
(void) control_conn;
if (!strcmpstart(question, "desc/id/")) {
- ri = router_get_by_hexdigest(question+strlen("desc/id/"));
+ node = node_get_by_hex_id(question+strlen("desc/id/"));
+ if (node)
+ ri = node->ri;
if (ri) {
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
@@ -1626,7 +1663,9 @@ getinfo_helper_dir(control_connection_t *control_conn,
} else if (!strcmpstart(question, "desc/name/")) {
/* XXX023 Setting 'warn_if_unnamed' here is a bit silly -- the
* warning goes to the user, not to the controller. */
- ri = router_get_by_nickname(question+strlen("desc/name/"),1);
+ node = node_get_by_nickname(question+strlen("desc/name/"), 1);
+ if (node)
+ ri = node->ri;
if (ri) {
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
@@ -1672,8 +1711,7 @@ getinfo_helper_dir(control_connection_t *control_conn,
const node_t *node = node_get_by_hex_id(question+strlen("md/id/"));
const microdesc_t *md = NULL;
if (node) md = node->md;
- if (md) {
- tor_assert(md->body);
+ if (md && md->body) {
*answer = tor_strndup(md->body, md->bodylen);
}
} else if (!strcmpstart(question, "md/name/")) {
@@ -1683,13 +1721,13 @@ getinfo_helper_dir(control_connection_t *control_conn,
/* XXXX duplicated code */
const microdesc_t *md = NULL;
if (node) md = node->md;
- if (md) {
- tor_assert(md->body);
+ if (md && md->body) {
*answer = tor_strndup(md->body, md->bodylen);
}
} else if (!strcmpstart(question, "desc-annotations/id/")) {
- ri = router_get_by_hexdigest(question+
- strlen("desc-annotations/id/"));
+ node = node_get_by_hex_id(question+strlen("desc-annotations/id/"));
+ if (node)
+ ri = node->ri;
if (ri) {
const char *annotations =
signed_descriptor_get_annotations(&ri->cache_info);
@@ -1847,11 +1885,11 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
}
smartlist_add_asprintf(descparts, "PURPOSE=%s",
- circuit_purpose_to_controller_string(circ->_base.purpose));
+ circuit_purpose_to_controller_string(circ->base_.purpose));
{
const char *hs_state =
- circuit_purpose_to_controller_hs_state_string(circ->_base.purpose);
+ circuit_purpose_to_controller_hs_state_string(circ->base_.purpose);
if (hs_state != NULL) {
smartlist_add_asprintf(descparts, "HS_STATE=%s", hs_state);
@@ -1865,7 +1903,7 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
{
char tbuf[ISO_TIME_USEC_LEN+1];
- format_iso_time_nospace_usec(tbuf, &circ->_base.timestamp_created);
+ format_iso_time_nospace_usec(tbuf, &circ->base_.timestamp_created);
smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf);
}
@@ -1889,7 +1927,7 @@ getinfo_helper_events(control_connection_t *control_conn,
if (!strcmp(question, "circuit-status")) {
circuit_t *circ_;
smartlist_t *status = smartlist_new();
- for (circ_ = _circuit_get_global_list(); circ_; circ_ = circ_->next) {
+ for (circ_ = circuit_get_global_list_(); circ_; circ_ = circ_->next) {
origin_circuit_t *circ;
char *circdesc;
const char *state;
@@ -1897,7 +1935,7 @@ getinfo_helper_events(control_connection_t *control_conn,
continue;
circ = TO_ORIGIN_CIRCUIT(circ_);
- if (circ->_base.state == CIRCUIT_STATE_OPEN)
+ if (circ->base_.state == CIRCUIT_STATE_OPEN)
state = "BUILT";
else if (circ->cpath)
state = "EXTENDED";
@@ -1974,7 +2012,7 @@ getinfo_helper_events(control_connection_t *control_conn,
if (base_conn->type != CONN_TYPE_OR || base_conn->marked_for_close)
continue;
conn = TO_OR_CONN(base_conn);
- if (conn->_base.state == OR_CONN_STATE_OPEN)
+ if (conn->base_.state == OR_CONN_STATE_OPEN)
state = "CONNECTED";
else if (conn->nickname)
state = "LAUNCHED";
@@ -2130,10 +2168,14 @@ static const getinfo_item_t getinfo_items[] = {
PREFIX("config/", config, "Current configuration values."),
DOC("config/names",
"List of configuration options, types, and documentation."),
+ DOC("config/defaults",
+ "List of default values for configuration options. "
+ "See also config/names"),
ITEM("info/names", misc,
"List of GETINFO options, types, and documentation."),
ITEM("events/names", misc,
"Events that the controller can ask for with SETEVENTS."),
+ ITEM("signal/names", misc, "Signal names recognized by the SIGNAL command"),
ITEM("features/names", misc, "What arguments can USEFEATURE take?"),
PREFIX("desc/id/", dir, "Router descriptors by ID."),
PREFIX("desc/name/", dir, "Router descriptors by nickname."),
@@ -2497,7 +2539,7 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
goto done;
}
} else {
- if (circ->_base.state == CIRCUIT_STATE_OPEN) {
+ if (circ->base_.state == CIRCUIT_STATE_OPEN) {
int err_reason = 0;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
@@ -2630,7 +2672,7 @@ handle_control_attachstream(control_connection_t *conn, uint32_t len,
TO_CONN(edge_conn)->state = AP_CONN_STATE_CONTROLLER_WAIT;
}
- if (circ && (circ->_base.state != CIRCUIT_STATE_OPEN)) {
+ if (circ && (circ->base_.state != CIRCUIT_STATE_OPEN)) {
connection_write_str_to_buf(
"551 Can't attach stream to non-open origin circuit\r\n",
conn);
@@ -2895,7 +2937,7 @@ handle_control_resolve(control_connection_t *conn, uint32_t len,
failed = smartlist_new();
SMARTLIST_FOREACH(args, const char *, arg, {
if (!is_keyval_pair(arg)) {
- if (dnsserv_launch_request(arg, is_reverse)<0)
+ if (dnsserv_launch_request(arg, is_reverse, conn)<0)
smartlist_add(failed, (char*)arg);
}
});
@@ -2903,7 +2945,7 @@ handle_control_resolve(control_connection_t *conn, uint32_t len,
send_control_done(conn);
SMARTLIST_FOREACH(failed, const char *, arg, {
control_event_address_mapped(arg, arg, time(NULL),
- "Unable to launch resolve request");
+ "internal", 0);
});
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
@@ -3099,6 +3141,8 @@ handle_control_authchallenge(control_connection_t *conn, uint32_t len,
"SERVERNONCE=%s\r\n",
server_hash_encoded,
server_nonce_encoded);
+
+ tor_free(client_nonce);
return 0;
}
@@ -3198,7 +3242,7 @@ connection_control_closed(control_connection_t *conn)
static int
is_valid_initial_command(control_connection_t *conn, const char *cmd)
{
- if (conn->_base.state == CONTROL_CONN_STATE_OPEN)
+ if (conn->base_.state == CONTROL_CONN_STATE_OPEN)
return 1;
if (!strcasecmp(cmd, "PROTOCOLINFO"))
return (!conn->have_sent_protocolinfo &&
@@ -3243,8 +3287,8 @@ connection_control_process_inbuf(control_connection_t *conn)
char *args;
tor_assert(conn);
- tor_assert(conn->_base.state == CONTROL_CONN_STATE_OPEN ||
- conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH);
+ tor_assert(conn->base_.state == CONTROL_CONN_STATE_OPEN ||
+ conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH);
if (!conn->incoming_cmd) {
conn->incoming_cmd = tor_malloc(1024);
@@ -3252,7 +3296,7 @@ connection_control_process_inbuf(control_connection_t *conn)
conn->incoming_cmd_cur_len = 0;
}
- if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH &&
+ if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
peek_connection_has_control0_command(TO_CONN(conn))) {
/* Detect v0 commands and send a "no more v0" message. */
size_t body_len;
@@ -3351,7 +3395,7 @@ connection_control_process_inbuf(control_connection_t *conn)
return 0;
}
- if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH &&
+ if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH &&
!is_valid_initial_command(conn, conn->incoming_cmd)) {
connection_write_str_to_buf("514 Authentication required.\r\n", conn);
connection_mark_for_close(TO_CONN(conn));
@@ -3538,9 +3582,9 @@ control_event_circuit_status_minor(origin_circuit_t *circ,
/* event_tail can currently be up to 130 chars long */
const char *hs_state_str =
circuit_purpose_to_controller_hs_state_string(purpose);
- const struct timeval *old_timestamp_created = tv;
+ const struct timeval *old_timestamp_began = tv;
char tbuf[ISO_TIME_USEC_LEN+1];
- format_iso_time_nospace_usec(tbuf, old_timestamp_created);
+ format_iso_time_nospace_usec(tbuf, old_timestamp_began);
tor_snprintf(event_tail, sizeof(event_tail),
" OLD_PURPOSE=%s%s%s OLD_TIME_CREATED=%s",
@@ -3696,9 +3740,22 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp,
}
}
- if (tp == STREAM_EVENT_NEW) {
- tor_snprintf(addrport_buf,sizeof(addrport_buf), " SOURCE_ADDR=%s:%d",
- ENTRY_TO_CONN(conn)->address, ENTRY_TO_CONN(conn)->port);
+ if (tp == STREAM_EVENT_NEW || tp == STREAM_EVENT_NEW_RESOLVE) {
+ /*
+ * When the control conn is an AF_UNIX socket and we have no address,
+ * it gets set to "(Tor_internal)"; see dnsserv_launch_request() in
+ * dnsserv.c.
+ */
+ if (strcmp(ENTRY_TO_CONN(conn)->address, "(Tor_internal)") != 0) {
+ tor_snprintf(addrport_buf,sizeof(addrport_buf), " SOURCE_ADDR=%s:%d",
+ ENTRY_TO_CONN(conn)->address, ENTRY_TO_CONN(conn)->port);
+ } else {
+ /*
+ * else leave it blank so control on AF_UNIX doesn't need to make
+ * something up.
+ */
+ addrport_buf[0] = '\0';
+ }
} else {
addrport_buf[0] = '\0';
}
@@ -3706,11 +3763,7 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp,
if (tp == STREAM_EVENT_NEW_RESOLVE) {
purpose = " PURPOSE=DNS_REQUEST";
} else if (tp == STREAM_EVENT_NEW) {
- if (ENTRY_TO_EDGE_CONN(conn)->is_dns_request ||
- (conn->socks_request &&
- SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)))
- purpose = " PURPOSE=DNS_REQUEST";
- else if (conn->use_begindir) {
+ if (conn->use_begindir) {
connection_t *linked = ENTRY_TO_CONN(conn)->linked_conn;
int linked_dir_purpose = -1;
if (linked && linked->type == CONN_TYPE_DIR)
@@ -3755,7 +3808,7 @@ orconn_target_get_name(char *name, size_t len, or_connection_t *conn)
DIGEST_LEN);
} else {
tor_snprintf(name, len, "%s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
}
}
@@ -3787,8 +3840,12 @@ control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t tp,
log_warn(LD_BUG, "Unrecognized status code %d", (int)tp);
return 0;
}
- ncircs = circuit_count_pending_on_or_conn(conn);
- ncircs += conn->n_circuits;
+ if (conn->chan) {
+ ncircs = circuit_count_pending_on_channel(TLS_CHAN_TO_BASE(conn->chan));
+ } else {
+ ncircs = 0;
+ }
+ ncircs += connection_or_get_num_circuits(conn);
if (ncircs && (tp == OR_CONN_EVENT_FAILED || tp == OR_CONN_EVENT_CLOSED)) {
tor_snprintf(ncircs_buf, sizeof(ncircs_buf), "%sNCIRCS=%d",
reason ? " " : "", ncircs);
@@ -3817,7 +3874,7 @@ control_event_stream_bandwidth(edge_connection_t *edge_conn)
send_control_event(EVENT_STREAM_BANDWIDTH_USED, ALL_FORMATS,
"650 STREAM_BW "U64_FORMAT" %lu %lu\r\n",
- U64_PRINTF_ARG(edge_conn->_base.global_identifier),
+ U64_PRINTF_ARG(edge_conn->base_.global_identifier),
(unsigned long)edge_conn->n_read,
(unsigned long)edge_conn->n_written);
@@ -3846,7 +3903,7 @@ control_event_stream_bandwidth_used(void)
send_control_event(EVENT_STREAM_BANDWIDTH_USED, ALL_FORMATS,
"650 STREAM_BW "U64_FORMAT" %lu %lu\r\n",
- U64_PRINTF_ARG(edge_conn->_base.global_identifier),
+ U64_PRINTF_ARG(edge_conn->base_.global_identifier),
(unsigned long)edge_conn->n_read,
(unsigned long)edge_conn->n_written);
@@ -3978,15 +4035,17 @@ control_event_descriptors_changed(smartlist_t *routers)
*/
int
control_event_address_mapped(const char *from, const char *to, time_t expires,
- const char *error)
+ const char *error, const int cached)
{
if (!EVENT_IS_INTERESTING(EVENT_ADDRMAP))
return 0;
if (expires < 3 || expires == TIME_MAX)
send_control_event(EVENT_ADDRMAP, ALL_FORMATS,
- "650 ADDRMAP %s %s NEVER %s\r\n", from, to,
- error?error:"");
+ "650 ADDRMAP %s %s NEVER %s%s"
+ "CACHED=\"%s\"\r\n",
+ from, to, error?error:"", error?" ":"",
+ cached?"YES":"NO");
else {
char buf[ISO_TIME_LEN+1];
char buf2[ISO_TIME_LEN+1];
@@ -3994,10 +4053,10 @@ control_event_address_mapped(const char *from, const char *to, time_t expires,
format_iso_time(buf2,expires);
send_control_event(EVENT_ADDRMAP, ALL_FORMATS,
"650 ADDRMAP %s %s \"%s\""
- " %s%sEXPIRES=\"%s\"\r\n",
+ " %s%sEXPIRES=\"%s\" CACHED=\"%s\"\r\n",
from, to, buf,
error?error:"", error?" ":"",
- buf2);
+ buf2, cached?"YES":"NO");
}
return 0;
@@ -4345,7 +4404,7 @@ control_event_guard(const char *nickname, const char *digest,
* a smartlist_t containing (key, value, ...) pairs in sequence.
* <b>value</b> can be NULL. */
int
-control_event_conf_changed(smartlist_t *elements)
+control_event_conf_changed(const smartlist_t *elements)
{
int i;
char *result;
@@ -4615,7 +4674,7 @@ control_event_bootstrap(bootstrap_status_t status, int progress)
if (status > bootstrap_percent ||
(progress && progress > bootstrap_percent)) {
bootstrap_status_to_string(status, &tag, &summary);
- log(status ? LOG_NOTICE : LOG_INFO, LD_CONTROL,
+ tor_log(status ? LOG_NOTICE : LOG_INFO, LD_CONTROL,
"Bootstrapped %d%%: %s.", progress ? progress : status, summary);
tor_snprintf(buf, sizeof(buf),
"BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\"",
@@ -4667,6 +4726,9 @@ control_event_bootstrap_problem(const char *warn, int reason)
!any_pending_bridge_descriptor_fetches())
recommendation = "warn";
+ if (we_are_hibernating())
+ recommendation = "ignore";
+
while (status>=0 && bootstrap_status_to_string(status, &tag, &summary) < 0)
status--; /* find a recognized status string based on current progress */
status = bootstrap_percent; /* set status back to the actual number */
diff --git a/src/or/control.h b/src/or/control.h
index f301ce91b..61062da2c 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for control.c.
**/
-#ifndef _TOR_CONTROL_H
-#define _TOR_CONTROL_H
+#ifndef TOR_CONTROL_H
+#define TOR_CONTROL_H
void control_update_global_event_mask(void);
void control_adjust_event_log_severity(void);
@@ -53,7 +53,8 @@ int control_event_stream_bandwidth_used(void);
void control_event_logmsg(int severity, uint32_t domain, const char *msg);
int control_event_descriptors_changed(smartlist_t *routers);
int control_event_address_mapped(const char *from, const char *to,
- time_t expires, const char *error);
+ time_t expires, const char *error,
+ const int cached);
int control_event_or_authdir_new_descriptor(const char *action,
const char *desc,
size_t desclen,
@@ -71,7 +72,7 @@ int control_event_server_status(int severity, const char *format, ...)
CHECK_PRINTF(2,3);
int control_event_guard(const char *nickname, const char *digest,
const char *status);
-int control_event_conf_changed(smartlist_t *elements);
+int control_event_conf_changed(const smartlist_t *elements);
int control_event_buildtimeout_set(const circuit_build_times_t *cbt,
buildtimeout_set_event_t type);
int control_event_signal(uintptr_t signal);
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index 0255227e7..ecf0d2035 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,16 +11,19 @@
*
* Right now, we only use this for processing onionskins.
**/
-
#include "or.h"
#include "buffers.h"
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "config.h"
#include "connection.h"
+#include "connection_or.h"
#include "cpuworker.h"
#include "main.h"
#include "onion.h"
+#include "rephist.h"
#include "router.h"
/** The maximum number of cpuworker processes we will keep around. */
@@ -29,10 +32,7 @@
#define MIN_CPUWORKERS 1
/** The tag specifies which circuit this onionskin was from. */
-#define TAG_LEN 10
-/** How many bytes are sent from the cpuworker back to tor? */
-#define LEN_ONION_RESPONSE \
- (1+TAG_LEN+ONIONSKIN_REPLY_LEN+CPATH_KEY_MATERIAL_LEN)
+#define TAG_LEN 12
/** How many cpuworkers we have running right now. */
static int num_cpuworkers=0;
@@ -68,22 +68,80 @@ connection_cpu_finished_flushing(connection_t *conn)
/** Pack global_id and circ_id; set *tag to the result. (See note on
* cpuworker_main for wire format.) */
static void
-tag_pack(char *tag, uint64_t conn_id, circid_t circ_id)
+tag_pack(uint8_t *tag, uint64_t chan_id, circid_t circ_id)
{
/*XXXX RETHINK THIS WHOLE MESS !!!! !NM NM NM NM*/
- set_uint64(tag, conn_id);
- set_uint16(tag+8, circ_id);
+ /*XXXX DOUBLEPLUSTHIS!!!! AS AS AS AS*/
+ set_uint64(tag, chan_id);
+ set_uint32(tag+8, circ_id);
}
/** Unpack <b>tag</b> into addr, port, and circ_id.
*/
static void
-tag_unpack(const char *tag, uint64_t *conn_id, circid_t *circ_id)
+tag_unpack(const uint8_t *tag, uint64_t *chan_id, circid_t *circ_id)
{
- *conn_id = get_uint64(tag);
- *circ_id = get_uint16(tag+8);
+ *chan_id = get_uint64(tag);
+ *circ_id = get_uint32(tag+8);
}
+/** Magic numbers to make sure our cpuworker_requests don't grow any
+ * mis-framing bugs. */
+#define CPUWORKER_REQUEST_MAGIC 0xda4afeed
+#define CPUWORKER_REPLY_MAGIC 0x5eedf00d
+
+/** A request sent to a cpuworker. */
+typedef struct cpuworker_request_t {
+ /** Magic number; must be CPUWORKER_REQUEST_MAGIC. */
+ uint32_t magic;
+ /** Opaque tag to identify the job */
+ uint8_t tag[TAG_LEN];
+ /** Task code. Must be one of CPUWORKER_TASK_* */
+ uint8_t task;
+
+ /** Flag: Are we timing this request? */
+ unsigned timed : 1;
+ /** If we're timing this request, when was it sent to the cpuworker? */
+ struct timeval started_at;
+
+ /** A create cell for the cpuworker to process. */
+ create_cell_t create_cell;
+
+ /* Turn the above into a tagged union if needed. */
+} cpuworker_request_t;
+
+/** A reply sent by a cpuworker. */
+typedef struct cpuworker_reply_t {
+ /** Magic number; must be CPUWORKER_REPLY_MAGIC. */
+ uint32_t magic;
+ /** Opaque tag to identify the job; matches the request's tag.*/
+ uint8_t tag[TAG_LEN];
+ /** True iff we got a successful request. */
+ uint8_t success;
+
+ /** Are we timing this request? */
+ unsigned int timed : 1;
+ /** What handshake type was the request? (Used for timing) */
+ uint16_t handshake_type;
+ /** When did we send the request to the cpuworker? */
+ struct timeval started_at;
+ /** Once the cpuworker received the request, how many microseconds did it
+ * take? (This shouldn't overflow; 4 billion micoseconds is over an hour,
+ * and we'll never have an onion handshake that takes so long.) */
+ uint32_t n_usec;
+
+ /** Output of processing a create cell
+ *
+ * @{
+ */
+ /** The created cell to send back. */
+ created_cell_t created_cell;
+ /** The keys to use on this circuit. */
+ uint8_t keys[CPATH_KEY_MATERIAL_LEN];
+ /** Input to use for authenticating introduce1 cells. */
+ uint8_t rend_auth_material[DIGEST_LEN];
+} cpuworker_reply_t;
+
/** Called when the onion key has changed and we need to spawn new
* cpuworkers. Close all currently idle cpuworkers, and mark the last
* rotation time as now.
@@ -122,6 +180,112 @@ connection_cpu_reached_eof(connection_t *conn)
return 0;
}
+/** Indexed by handshake type: how many onionskins have we processed and
+ * counted of that type? */
+static uint64_t onionskins_n_processed[MAX_ONION_HANDSHAKE_TYPE+1];
+/** Indexed by handshake type, corresponding to the onionskins counted in
+ * onionskins_n_processed: how many microseconds have we spent in cpuworkers
+ * processing that kind of onionskin? */
+static uint64_t onionskins_usec_internal[MAX_ONION_HANDSHAKE_TYPE+1];
+/** Indexed by handshake type, corresponding to onionskins counted in
+ * onionskins_n_processed: how many microseconds have we spent waiting for
+ * cpuworkers to give us answers for that kind of onionskin?
+ */
+static uint64_t onionskins_usec_roundtrip[MAX_ONION_HANDSHAKE_TYPE+1];
+
+/** If any onionskin takes longer than this, we clip them to this
+ * time. (microseconds) */
+#define MAX_BELIEVABLE_ONIONSKIN_DELAY (2*1000*1000)
+
+static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT;
+
+/** Return true iff we'd like to measure a handshake of type
+ * <b>onionskin_type</b>. Call only from the main thread. */
+static int
+should_time_request(uint16_t onionskin_type)
+{
+ /* If we've never heard of this type, we shouldn't even be here. */
+ if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE)
+ return 0;
+ /* Measure the first N handshakes of each type, to ensure we have a
+ * sample */
+ if (onionskins_n_processed[onionskin_type] < 4096)
+ return 1;
+ /** Otherwise, measure with P=1/128. We avoid doing this for every
+ * handshake, since the measurement itself can take a little time. */
+ return tor_weak_random_one_in_n(&request_sample_rng, 128);
+}
+
+/** Return an estimate of how many microseconds we will need for a single
+ * cpuworker to to process <b>n_requests</b> onionskins of type
+ * <b>onionskin_type</b>. */
+uint64_t
+estimated_usec_for_onionskins(uint32_t n_requests, uint16_t onionskin_type)
+{
+ if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) /* should be impossible */
+ return 1000 * (uint64_t)n_requests;
+ if (PREDICT_UNLIKELY(onionskins_n_processed[onionskin_type] < 100)) {
+ /* Until we have 100 data points, just asssume everything takes 1 msec. */
+ return 1000 * (uint64_t)n_requests;
+ } else {
+ /* This can't overflow: we'll never have more than 500000 onionskins
+ * measured in onionskin_usec_internal, and they won't take anything near
+ * 1 sec each, and we won't have anything like 1 million queued
+ * onionskins. But that's 5e5 * 1e6 * 1e6, which is still less than
+ * UINT64_MAX. */
+ return (onionskins_usec_internal[onionskin_type] * n_requests) /
+ onionskins_n_processed[onionskin_type];
+ }
+}
+
+/** Compute the absolute and relative overhead of using the cpuworker
+ * framework for onionskins of type <b>onionskin_type</b>.*/
+static int
+get_overhead_for_onionskins(uint32_t *usec_out, double *frac_out,
+ uint16_t onionskin_type)
+{
+ uint64_t overhead;
+
+ *usec_out = 0;
+ *frac_out = 0.0;
+
+ if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) /* should be impossible */
+ return -1;
+ if (onionskins_n_processed[onionskin_type] == 0 ||
+ onionskins_usec_internal[onionskin_type] == 0 ||
+ onionskins_usec_roundtrip[onionskin_type] == 0)
+ return -1;
+
+ overhead = onionskins_usec_roundtrip[onionskin_type] -
+ onionskins_usec_internal[onionskin_type];
+
+ *usec_out = (uint32_t)(overhead / onionskins_n_processed[onionskin_type]);
+ *frac_out = U64_TO_DBL(overhead) / onionskins_usec_internal[onionskin_type];
+
+ return 0;
+}
+
+/** If we've measured overhead for onionskins of type <b>onionskin_type</b>,
+ * log it. */
+void
+cpuworker_log_onionskin_overhead(int severity, int onionskin_type,
+ const char *onionskin_type_name)
+{
+ uint32_t overhead;
+ double relative_overhead;
+ int r;
+
+ r = get_overhead_for_onionskins(&overhead, &relative_overhead,
+ onionskin_type);
+ if (!overhead || r<0)
+ return;
+
+ log_fn(severity, LD_OR,
+ "%s onionskins have averaged %u usec overhead (%.2f%%) in "
+ "cpuworker code ",
+ onionskin_type_name, (unsigned)overhead, relative_overhead*100);
+}
+
/** Called when we get data from a cpuworker. If the answer is not complete,
* wait for a complete answer. If the answer is complete,
* process it as appropriate.
@@ -129,12 +293,9 @@ connection_cpu_reached_eof(connection_t *conn)
int
connection_cpu_process_inbuf(connection_t *conn)
{
- char success;
- char buf[LEN_ONION_RESPONSE];
- uint64_t conn_id;
+ uint64_t chan_id;
circid_t circ_id;
- connection_t *tmp_conn;
- or_connection_t *p_conn = NULL;
+ channel_t *p_chan = NULL;
circuit_t *circ;
tor_assert(conn);
@@ -144,25 +305,51 @@ connection_cpu_process_inbuf(connection_t *conn)
return 0;
if (conn->state == CPUWORKER_STATE_BUSY_ONION) {
- if (connection_get_inbuf_len(conn) < LEN_ONION_RESPONSE)
+ cpuworker_reply_t rpl;
+ if (connection_get_inbuf_len(conn) < sizeof(cpuworker_reply_t))
return 0; /* not yet */
- tor_assert(connection_get_inbuf_len(conn) == LEN_ONION_RESPONSE);
-
- connection_fetch_from_buf(&success,1,conn);
- connection_fetch_from_buf(buf,LEN_ONION_RESPONSE-1,conn);
-
+ tor_assert(connection_get_inbuf_len(conn) == sizeof(cpuworker_reply_t));
+
+ connection_fetch_from_buf((void*)&rpl,sizeof(cpuworker_reply_t),conn);
+
+ tor_assert(rpl.magic == CPUWORKER_REPLY_MAGIC);
+
+ if (rpl.timed && rpl.success &&
+ rpl.handshake_type <= MAX_ONION_HANDSHAKE_TYPE) {
+ /* Time how long this request took. The handshake_type check should be
+ needless, but let's leave it in to be safe. */
+ struct timeval tv_end, tv_diff;
+ int64_t usec_roundtrip;
+ tor_gettimeofday(&tv_end);
+ timersub(&tv_end, &rpl.started_at, &tv_diff);
+ usec_roundtrip = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
+ if (usec_roundtrip >= 0 &&
+ usec_roundtrip < MAX_BELIEVABLE_ONIONSKIN_DELAY) {
+ ++onionskins_n_processed[rpl.handshake_type];
+ onionskins_usec_internal[rpl.handshake_type] += rpl.n_usec;
+ onionskins_usec_roundtrip[rpl.handshake_type] += usec_roundtrip;
+ if (onionskins_n_processed[rpl.handshake_type] >= 500000) {
+ /* Scale down every 500000 handshakes. On a busy server, that's
+ * less impressive than it sounds. */
+ onionskins_n_processed[rpl.handshake_type] /= 2;
+ onionskins_usec_internal[rpl.handshake_type] /= 2;
+ onionskins_usec_roundtrip[rpl.handshake_type] /= 2;
+ }
+ }
+ }
/* parse out the circ it was talking about */
- tag_unpack(buf, &conn_id, &circ_id);
+ tag_unpack(rpl.tag, &chan_id, &circ_id);
circ = NULL;
- tmp_conn = connection_get_by_global_id(conn_id);
- if (tmp_conn && !tmp_conn->marked_for_close &&
- tmp_conn->type == CONN_TYPE_OR)
- p_conn = TO_OR_CONN(tmp_conn);
+ log_debug(LD_OR,
+ "Unpacking cpuworker reply, chan_id is " U64_FORMAT
+ ", circ_id is %u",
+ U64_PRINTF_ARG(chan_id), (unsigned)circ_id);
+ p_chan = channel_find_by_global_id(chan_id);
- if (p_conn)
- circ = circuit_get_by_circid_orconn(circ_id, p_conn);
+ if (p_chan)
+ circ = circuit_get_by_circid_channel(circ_id, p_chan);
- if (success == 0) {
+ if (rpl.success == 0) {
log_debug(LD_OR,
"decoding onionskin failed. "
"(Old key or bad software.) Closing.");
@@ -180,8 +367,10 @@ connection_cpu_process_inbuf(connection_t *conn)
goto done_processing;
}
tor_assert(! CIRCUIT_IS_ORIGIN(circ));
- if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
- buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
+ if (onionskin_answer(TO_OR_CIRCUIT(circ),
+ &rpl.created_cell,
+ (const char*)rpl.keys,
+ rpl.rend_auth_material) < 0) {
log_warn(LD_OR,"onionskin_answer failed. Closing.");
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
goto done_processing;
@@ -208,32 +397,21 @@ connection_cpu_process_inbuf(connection_t *conn)
* Read and writes from fdarray[1]. Reads requests, writes answers.
*
* Request format:
- * Task type [1 byte, always CPUWORKER_TASK_ONION]
- * Opaque tag TAG_LEN
- * Onionskin challenge ONIONSKIN_CHALLENGE_LEN
+ * cpuworker_request_t.
* Response format:
- * Success/failure [1 byte, boolean.]
- * Opaque tag TAG_LEN
- * Onionskin challenge ONIONSKIN_REPLY_LEN
- * Negotiated keys KEY_LEN*2+DIGEST_LEN*2
- *
- * (Note: this _should_ be by addr/port, since we're concerned with specific
- * connections, not with routers (where we'd use identity).)
+ * cpuworker_reply_t
*/
static void
cpuworker_main(void *data)
{
- char question[ONIONSKIN_CHALLENGE_LEN];
- uint8_t question_type;
+ /* For talking to the parent thread/process */
tor_socket_t *fdarray = data;
tor_socket_t fd;
/* variables for onion processing */
- char keys[CPATH_KEY_MATERIAL_LEN];
- char reply_to_proxy[ONIONSKIN_REPLY_LEN];
- char buf[LEN_ONION_RESPONSE];
- char tag[TAG_LEN];
- crypto_pk_t *onion_key = NULL, *last_onion_key = NULL;
+ server_onion_keys_t onion_keys;
+ cpuworker_request_t req;
+ cpuworker_reply_t rpl;
fd = fdarray[1]; /* this side is ours */
#ifndef TOR_IS_MULTITHREADED
@@ -244,68 +422,85 @@ cpuworker_main(void *data)
#endif
tor_free(data);
- dup_onion_keys(&onion_key, &last_onion_key);
+ setup_server_onion_keys(&onion_keys);
for (;;) {
- ssize_t r;
-
- if ((r = recv(fd, (void *)&question_type, 1, 0)) != 1) {
-// log_fn(LOG_ERR,"read type failed. Exiting.");
- if (r == 0) {
- log_info(LD_OR,
- "CPU worker exiting because Tor process closed connection "
- "(either rotated keys or died).");
- } else {
- log_info(LD_OR,
- "CPU worker exiting because of error on connection to Tor "
- "process.");
- log_info(LD_OR,"(Error on %d was %s)",
- fd, tor_socket_strerror(tor_socket_errno(fd)));
- }
- goto end;
- }
- tor_assert(question_type == CPUWORKER_TASK_ONION);
-
- if (read_all(fd, tag, TAG_LEN, 1) != TAG_LEN) {
- log_err(LD_BUG,"read tag failed. Exiting.");
+ if (read_all(fd, (void *)&req, sizeof(req), 1) != sizeof(req)) {
+ log_info(LD_OR, "read request failed. Exiting.");
goto end;
}
-
- if (read_all(fd, question, ONIONSKIN_CHALLENGE_LEN, 1) !=
- ONIONSKIN_CHALLENGE_LEN) {
- log_err(LD_BUG,"read question failed. Exiting.");
- goto end;
- }
-
- if (question_type == CPUWORKER_TASK_ONION) {
- if (onion_skin_server_handshake(question, onion_key, last_onion_key,
- reply_to_proxy, keys, CPATH_KEY_MATERIAL_LEN) < 0) {
+ tor_assert(req.magic == CPUWORKER_REQUEST_MAGIC);
+
+ memset(&rpl, 0, sizeof(rpl));
+
+ if (req.task == CPUWORKER_TASK_ONION) {
+ const create_cell_t *cc = &req.create_cell;
+ created_cell_t *cell_out = &rpl.created_cell;
+ struct timeval tv_start, tv_end;
+ int n;
+ rpl.timed = req.timed;
+ rpl.started_at = req.started_at;
+ rpl.handshake_type = cc->handshake_type;
+ if (req.timed)
+ tor_gettimeofday(&tv_start);
+ n = onion_skin_server_handshake(cc->handshake_type,
+ cc->onionskin, cc->handshake_len,
+ &onion_keys,
+ cell_out->reply,
+ rpl.keys, CPATH_KEY_MATERIAL_LEN,
+ rpl.rend_auth_material);
+ if (n < 0) {
/* failure */
log_debug(LD_OR,"onion_skin_server_handshake failed.");
- *buf = 0; /* indicate failure in first byte */
- memcpy(buf+1,tag,TAG_LEN);
- /* send all zeros as answer */
- memset(buf+1+TAG_LEN, 0, LEN_ONION_RESPONSE-(1+TAG_LEN));
+ memset(&rpl, 0, sizeof(rpl));
+ memcpy(rpl.tag, req.tag, TAG_LEN);
+ rpl.success = 0;
} else {
/* success */
log_debug(LD_OR,"onion_skin_server_handshake succeeded.");
- buf[0] = 1; /* 1 means success */
- memcpy(buf+1,tag,TAG_LEN);
- memcpy(buf+1+TAG_LEN,reply_to_proxy,ONIONSKIN_REPLY_LEN);
- memcpy(buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,keys,CPATH_KEY_MATERIAL_LEN);
+ memcpy(rpl.tag, req.tag, TAG_LEN);
+ cell_out->handshake_len = n;
+ switch (cc->cell_type) {
+ case CELL_CREATE:
+ cell_out->cell_type = CELL_CREATED; break;
+ case CELL_CREATE2:
+ cell_out->cell_type = CELL_CREATED2; break;
+ case CELL_CREATE_FAST:
+ cell_out->cell_type = CELL_CREATED_FAST; break;
+ default:
+ tor_assert(0);
+ goto end;
+ }
+ rpl.success = 1;
}
- if (write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) {
+ rpl.magic = CPUWORKER_REPLY_MAGIC;
+ if (req.timed) {
+ struct timeval tv_diff;
+ int64_t usec;
+ tor_gettimeofday(&tv_end);
+ timersub(&tv_end, &tv_start, &tv_diff);
+ usec = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
+ if (usec < 0 || usec > MAX_BELIEVABLE_ONIONSKIN_DELAY)
+ rpl.n_usec = MAX_BELIEVABLE_ONIONSKIN_DELAY;
+ else
+ rpl.n_usec = (uint32_t) usec;
+ }
+ if (write_all(fd, (void*)&rpl, sizeof(rpl), 1) != sizeof(rpl)) {
log_err(LD_BUG,"writing response buf failed. Exiting.");
goto end;
}
log_debug(LD_OR,"finished writing response.");
+ } else if (req.task == CPUWORKER_TASK_SHUTDOWN) {
+ log_info(LD_OR,"Clean shutdown: exiting");
+ goto end;
}
+ memwipe(&req, 0, sizeof(req));
+ memwipe(&rpl, 0, sizeof(req));
}
end:
- if (onion_key)
- crypto_pk_free(onion_key);
- if (last_onion_key)
- crypto_pk_free(last_onion_key);
+ memwipe(&req, 0, sizeof(req));
+ memwipe(&rpl, 0, sizeof(req));
+ release_server_onion_keys(&onion_keys);
tor_close_socket(fd);
crypto_thread_cleanup();
spawn_exit();
@@ -342,13 +537,16 @@ spawn_cpuworker(void)
conn = connection_new(CONN_TYPE_CPUWORKER, AF_UNIX);
- set_socket_nonblocking(fd);
-
/* set up conn so it's got all the data we need to remember */
conn->s = fd;
conn->address = tor_strdup("localhost");
tor_addr_make_unspec(&conn->addr);
+ if (set_socket_nonblocking(fd) == -1) {
+ connection_free(conn); /* this closes fd */
+ return -1;
+ }
+
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for cpuworker failed. Giving up.");
connection_free(conn); /* this closes fd */
@@ -368,6 +566,7 @@ static void
spawn_enough_cpuworkers(void)
{
int num_cpuworkers_needed = get_num_cpus(get_options());
+ int reseed = 0;
if (num_cpuworkers_needed < MIN_CPUWORKERS)
num_cpuworkers_needed = MIN_CPUWORKERS;
@@ -380,7 +579,11 @@ spawn_enough_cpuworkers(void)
return;
}
num_cpuworkers++;
+ reseed++;
}
+
+ if (reseed)
+ crypto_seed_weak_rng(&request_sample_rng);
}
/** Take a pending task from the queue and assign it to 'cpuworker'. */
@@ -388,7 +591,7 @@ static void
process_pending_task(connection_t *cpuworker)
{
or_circuit_t *circ;
- char *onionskin = NULL;
+ create_cell_t *onionskin = NULL;
tor_assert(cpuworker);
@@ -441,12 +644,13 @@ cull_wedged_cpuworkers(void)
*/
int
assign_onionskin_to_cpuworker(connection_t *cpuworker,
- or_circuit_t *circ, char *onionskin)
+ or_circuit_t *circ,
+ create_cell_t *onionskin)
{
- char qbuf[1];
- char tag[TAG_LEN];
+ cpuworker_request_t req;
time_t now = approx_time();
static time_t last_culled_cpuworkers = 0;
+ int should_time;
/* Checking for wedged cpuworkers requires a linear search over all
* connections, so let's do it only once a minute.
@@ -475,26 +679,39 @@ assign_onionskin_to_cpuworker(connection_t *cpuworker,
tor_assert(cpuworker);
- if (!circ->p_conn) {
- log_info(LD_OR,"circ->p_conn gone. Failing circ.");
+ if (!circ->p_chan) {
+ log_info(LD_OR,"circ->p_chan gone. Failing circ.");
tor_free(onionskin);
return -1;
}
- tag_pack(tag, circ->p_conn->_base.global_identifier,
+
+ if (connection_or_digest_is_known_relay(circ->p_chan->identity_digest))
+ rep_hist_note_circuit_handshake_completed(onionskin->handshake_type);
+
+ should_time = should_time_request(onionskin->handshake_type);
+ memset(&req, 0, sizeof(req));
+ req.magic = CPUWORKER_REQUEST_MAGIC;
+ tag_pack(req.tag, circ->p_chan->global_identifier,
circ->p_circ_id);
+ req.timed = should_time;
cpuworker->state = CPUWORKER_STATE_BUSY_ONION;
/* touch the lastwritten timestamp, since that's how we check to
* see how long it's been since we asked the question, and sometimes
* we check before the first call to connection_handle_write(). */
- cpuworker->timestamp_lastwritten = time(NULL);
+ cpuworker->timestamp_lastwritten = now;
num_cpuworkers_busy++;
- qbuf[0] = CPUWORKER_TASK_ONION;
- connection_write_to_buf(qbuf, 1, cpuworker);
- connection_write_to_buf(tag, sizeof(tag), cpuworker);
- connection_write_to_buf(onionskin, ONIONSKIN_CHALLENGE_LEN, cpuworker);
+ req.task = CPUWORKER_TASK_ONION;
+ memcpy(&req.create_cell, onionskin, sizeof(create_cell_t));
+
tor_free(onionskin);
+
+ if (should_time)
+ tor_gettimeofday(&req.started_at);
+
+ connection_write_to_buf((void*)&req, sizeof(req), cpuworker);
+ memwipe(&req, 0, sizeof(req));
}
return 0;
}
diff --git a/src/or/cpuworker.h b/src/or/cpuworker.h
index 91172caa5..317cef43b 100644
--- a/src/or/cpuworker.h
+++ b/src/or/cpuworker.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,17 +9,23 @@
* \brief Header file for cpuworker.c.
**/
-#ifndef _TOR_CPUWORKER_H
-#define _TOR_CPUWORKER_H
+#ifndef TOR_CPUWORKER_H
+#define TOR_CPUWORKER_H
void cpu_init(void);
void cpuworkers_rotate(void);
int connection_cpu_finished_flushing(connection_t *conn);
int connection_cpu_reached_eof(connection_t *conn);
int connection_cpu_process_inbuf(connection_t *conn);
+struct create_cell_t;
int assign_onionskin_to_cpuworker(connection_t *cpuworker,
or_circuit_t *circ,
- char *onionskin);
+ struct create_cell_t *onionskin);
+
+uint64_t estimated_usec_for_onionskins(uint32_t n_requests,
+ uint16_t onionskin_type);
+void cpuworker_log_onionskin_overhead(int severity, int onionskin_type,
+ const char *onionskin_type_name);
#endif
diff --git a/src/or/directory.c b/src/or/directory.c
index f235bf3b4..3752367c4 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -13,6 +13,7 @@
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "main.h"
#include "microdesc.h"
@@ -25,6 +26,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "routerset.h"
#if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
#ifndef OPENBSD
@@ -58,7 +60,6 @@
static void directory_send_command(dir_connection_t *conn,
int purpose, int direct, const char *resource,
const char *payload, size_t payload_len,
- int supports_conditional_consensus,
time_t if_modified_since);
static int directory_handle_command(dir_connection_t *conn);
static int body_is_plausible(const char *body, size_t body_len, int purpose);
@@ -89,12 +90,10 @@ static void directory_initiate_command_rend(const char *address,
const tor_addr_t *addr,
uint16_t or_port,
uint16_t dir_port,
- int supports_conditional_consensus,
- int supports_begindir,
const char *digest,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -227,16 +226,9 @@ router_supports_extrainfo(const char *identity_digest, int is_authority)
if (node && node->ri) {
if (node->ri->caches_extra_info)
return 1;
- if (is_authority && node->ri->platform &&
- tor_version_as_new_as(node->ri->platform,
- "Tor 0.2.0.0-alpha-dev (r10070)"))
- return 1;
}
if (is_authority) {
- const routerstatus_t *rs =
- router_get_consensus_status_by_id(identity_digest);
- if (rs && rs->version_supports_extrainfo_upload)
- return 1;
+ return 1;
}
return 0;
}
@@ -252,10 +244,10 @@ router_supports_extrainfo(const char *identity_digest, int is_authority)
int
directories_have_accepted_server_descriptor(void)
{
- smartlist_t *servers = router_get_trusted_dir_servers();
+ const smartlist_t *servers = router_get_trusted_dir_servers();
const or_options_t *options = get_options();
- SMARTLIST_FOREACH(servers, trusted_dir_server_t *, d, {
- if ((d->type & options->_PublishServerDescriptor) &&
+ SMARTLIST_FOREACH(servers, dir_server_t *, d, {
+ if ((d->type & options->PublishServerDescriptor_) &&
d->has_accepted_serverdesc) {
return 1;
}
@@ -288,7 +280,7 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
{
const or_options_t *options = get_options();
int post_via_tor;
- smartlist_t *dirservers = router_get_trusted_dir_servers();
+ const smartlist_t *dirservers = router_get_trusted_dir_servers();
int found = 0;
const int exclude_self = (dir_purpose == DIR_PURPOSE_UPLOAD_VOTE ||
dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES);
@@ -296,7 +288,7 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
/* This tries dirservers which we believe to be down, but ultimately, that's
* harmless, and we may as well err on the side of getting things uploaded.
*/
- SMARTLIST_FOREACH_BEGIN(dirservers, trusted_dir_server_t *, ds) {
+ SMARTLIST_FOREACH_BEGIN(dirservers, dir_server_t *, ds) {
routerstatus_t *rs = &(ds->fake_status);
size_t upload_len = payload_len;
tor_addr_t ds_addr;
@@ -342,6 +334,60 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
}
}
+/** Return true iff, according to the values in <b>options</b>, we should be
+ * using directory guards for direct downloads of directory information. */
+static int
+should_use_directory_guards(const or_options_t *options)
+{
+ /* Public (non-bridge) servers never use directory guards. */
+ if (public_server_mode(options))
+ return 0;
+ /* If guards are disabled, or directory guards are disabled, we can't
+ * use directory guards.
+ */
+ if (!options->UseEntryGuards || !options->UseEntryGuardsAsDirGuards)
+ return 0;
+ /* If we're configured to fetch directory info aggressively or of a
+ * nonstandard type, don't use directory guards. */
+ if (options->DownloadExtraInfo || options->FetchDirInfoEarly ||
+ options->FetchDirInfoExtraEarly || options->FetchUselessDescriptors ||
+ options->FetchV2Networkstatus)
+ return 0;
+ if (! options->PreferTunneledDirConns)
+ return 0;
+ return 1;
+}
+
+/** Pick an unconsetrained directory server from among our guards, the latest
+ * networkstatus, or the fallback dirservers, for use in downloading
+ * information of type <b>type</b>, and return its routerstatus. */
+static const routerstatus_t *
+directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags,
+ uint8_t dir_purpose)
+{
+ const routerstatus_t *rs = NULL;
+ const or_options_t *options = get_options();
+
+ if (options->UseBridges)
+ log_warn(LD_BUG, "Called when we have UseBridges set.");
+
+ if (should_use_directory_guards(options)) {
+ const node_t *node = choose_random_dirguard(type);
+ if (node)
+ rs = node->rs;
+ } else {
+ /* anybody with a non-zero dirport will do */
+ rs = router_pick_directory_server(type, pds_flags);
+ }
+ if (!rs) {
+ log_info(LD_DIR, "No router found for %s; falling back to "
+ "dirserver list.", dir_conn_purpose_to_string(dir_purpose));
+ rs = router_pick_fallback_dirserver(type, pds_flags);
+ }
+
+ return rs;
+}
+
/** Start a connection to a random running directory server, using
* connection purpose <b>dir_purpose</b>, intending to fetch descriptors
* of purpose <b>router_purpose</b>, and requesting <b>resource</b>.
@@ -426,26 +472,25 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
if (options->UseBridges && type != BRIDGE_DIRINFO) {
/* We want to ask a running bridge for which we have a descriptor.
*
- * Be careful here: we should only ask questions that we know our
- * bridges can answer. So far we're solving that by backing off to
- * the behavior supported by our oldest bridge; see for example
- * any_bridges_dont_support_microdescriptors().
+ * When we ask choose_random_entry() for a bridge, we specify what
+ * sort of dir fetch we'll be doing, so it won't return a bridge
+ * that can't answer our question.
*/
/* XXX024 Not all bridges handle conditional consensus downloading,
* so, for now, never assume the server supports that. -PP */
- const node_t *node = choose_random_entry(NULL);
+ const node_t *node = choose_random_dirguard(type);
if (node && node->ri) {
/* every bridge has a routerinfo. */
tor_addr_t addr;
routerinfo_t *ri = node->ri;
node_get_addr(node, &addr);
directory_initiate_command(ri->address, &addr,
- ri->or_port, 0,
- 0, /* don't use conditional consensus url */
- 1, ri->cache_info.identity_digest,
+ ri->or_port, 0/*no dirport*/,
+ ri->cache_info.identity_digest,
dir_purpose,
router_purpose,
- 0, resource, NULL, 0, if_modified_since);
+ DIRIND_ONEHOP,
+ resource, NULL, 0, if_modified_since);
} else
log_notice(LD_DIR, "Ignoring directory request, since no bridge "
"nodes are available yet.");
@@ -479,14 +524,13 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
}
}
if (!rs && type != BRIDGE_DIRINFO) {
- /* anybody with a non-zero dirport will do */
- rs = router_pick_directory_server(type, pds_flags);
+ /* */
+ rs = directory_pick_generic_dirserver(type, pds_flags,
+ dir_purpose);
if (!rs) {
- log_info(LD_DIR, "No router found for %s; falling back to "
- "dirserver list.", dir_conn_purpose_to_string(dir_purpose));
- rs = router_pick_trusteddirserver(type, pds_flags);
- if (!rs)
- get_via_tor = 1; /* last resort: try routing it via Tor */
+ /*XXXX024 I'm pretty sure this can never do any good, since
+ * rs isn't set. */
+ get_via_tor = 1; /* last resort: try routing it via Tor */
}
}
}
@@ -506,13 +550,15 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
}
}
- if (rs)
+ if (rs) {
+ const dir_indirection_t indirection =
+ get_via_tor ? DIRIND_ANONYMOUS : DIRIND_ONEHOP;
directory_initiate_command_routerstatus(rs, dir_purpose,
router_purpose,
- get_via_tor,
+ indirection,
resource, NULL, 0,
if_modified_since);
- else {
+ } else {
log_notice(LD_DIR,
"While fetching directory info, "
"no running dirservers known. Will try again later. "
@@ -536,7 +582,7 @@ directory_get_from_all_authorities(uint8_t dir_purpose,
dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES);
SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds) {
+ dir_server_t *, ds) {
routerstatus_t *rs;
if (router_digest_is_me(ds->digest))
continue;
@@ -544,17 +590,25 @@ directory_get_from_all_authorities(uint8_t dir_purpose,
continue;
rs = &ds->fake_status;
directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
- 0, resource, NULL, 0, 0);
+ DIRIND_ONEHOP, resource, NULL,
+ 0, 0);
} SMARTLIST_FOREACH_END(ds);
}
+/** Return true iff <b>ind</b> requires a multihop circuit. */
+static int
+dirind_is_anon(dir_indirection_t ind)
+{
+ return ind == DIRIND_ANON_DIRPORT || ind == DIRIND_ANONYMOUS;
+}
+
/** Same as directory_initiate_command_routerstatus(), but accepts
* rendezvous data to fetch a hidden service descriptor. */
void
directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -567,6 +621,7 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
struct in_addr in;
const char *address;
tor_addr_t addr;
+ const int anonymized_connection = dirind_is_anon(indirection);
node = node_get_by_id(status->identity_digest);
if (!node && anonymized_connection) {
@@ -596,11 +651,9 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
directory_initiate_command_rend(address, &addr,
status->or_port, status->dir_port,
- status->version_supports_conditional_consensus,
- status->version_supports_begindir,
status->identity_digest,
dir_purpose, router_purpose,
- anonymized_connection, resource,
+ indirection, resource,
payload, payload_len, if_modified_since,
rend_query);
}
@@ -623,7 +676,7 @@ void
directory_initiate_command_routerstatus(const routerstatus_t *status,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -631,7 +684,7 @@ directory_initiate_command_routerstatus(const routerstatus_t *status,
{
directory_initiate_command_routerstatus_rend(status, dir_purpose,
router_purpose,
- anonymized_connection, resource,
+ indirection, resource,
payload, payload_len,
if_modified_since, NULL);
}
@@ -647,8 +700,8 @@ directory_conn_is_self_reachability_test(dir_connection_t *conn)
const routerinfo_t *me = router_get_my_routerinfo();
if (me &&
router_digest_is_me(conn->identity_digest) &&
- tor_addr_eq_ipv4h(&conn->_base.addr, me->addr) && /*XXXX prop 118*/
- me->dir_port == conn->_base.port)
+ tor_addr_eq_ipv4h(&conn->base_.addr, me->addr) && /*XXXX prop 118*/
+ me->dir_port == conn->base_.port)
return 1;
}
return 0;
@@ -666,35 +719,35 @@ connection_dir_request_failed(dir_connection_t *conn)
}
if (!entry_list_is_constrained(get_options()))
router_set_status(conn->identity_digest, 0); /* don't try him again */
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
- conn->_base.address);
+ conn->base_.address);
connection_dir_download_v2_networkstatus_failed(conn, -1);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from "
"directory server at '%s'; retrying",
- conn->_base.address);
+ conn->base_.address);
if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE)
connection_dir_bridge_routerdesc_failed(conn);
connection_dir_download_routerdesc_failed(conn);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
if (conn->requested_resource)
networkstatus_consensus_download_failed(0, conn->requested_resource);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
log_info(LD_DIR, "Giving up on certificate fetch from directory server "
"at '%s'; retrying",
- conn->_base.address);
+ conn->base_.address);
connection_dir_download_cert_failed(conn, 0);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
log_info(LD_DIR, "Giving up downloading detached signatures from '%s'",
- conn->_base.address);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
+ conn->base_.address);
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
log_info(LD_DIR, "Giving up downloading votes from '%s'",
- conn->_base.address);
- } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
+ conn->base_.address);
+ } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
log_info(LD_DIR, "Giving up on downloading microdescriptors from "
- " directory server at '%s'; will retry", conn->_base.address);
+ " directory server at '%s'; will retry", conn->base_.address);
connection_dir_download_routerdesc_failed(conn);
}
}
@@ -717,10 +770,10 @@ connection_dir_download_v2_networkstatus_failed(dir_connection_t *conn,
/* We're a non-authoritative directory cache; try again. Ignore status
* code, since we don't want to keep trying forever in a tight loop
* if all the authorities are shutting us out. */
- smartlist_t *trusted_dirs = router_get_trusted_dir_servers();
- SMARTLIST_FOREACH(trusted_dirs, trusted_dir_server_t *, ds,
+ const smartlist_t *trusted_dirs = router_get_trusted_dir_servers();
+ SMARTLIST_FOREACH(trusted_dirs, dir_server_t *, ds,
download_status_failed(&ds->v2_ns_dl_status, 0));
- directory_get_from_dirserver(conn->_base.purpose, conn->router_purpose,
+ directory_get_from_dirserver(conn->base_.purpose, conn->router_purpose,
"all.z", 0 /* don't retry_if_no_servers */);
} else if (!strcmpstart(conn->requested_resource, "fp/")) {
/* We were trying to download by fingerprint; mark them all as having
@@ -765,9 +818,9 @@ connection_dir_download_routerdesc_failed(dir_connection_t *conn)
/* No need to relaunch descriptor downloads here: we already do it
* every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
- tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC);
+ tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
(void) conn;
}
@@ -791,7 +844,7 @@ connection_dir_bridge_routerdesc_failed(dir_connection_t *conn)
+ strlen("fp/"),
which, NULL, 0);
- tor_assert(conn->_base.purpose != DIR_PURPOSE_FETCH_EXTRAINFO);
+ tor_assert(conn->base_.purpose != DIR_PURPOSE_FETCH_EXTRAINFO);
if (smartlist_len(which)) {
connection_dir_retry_bridges(which);
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
@@ -803,19 +856,43 @@ connection_dir_bridge_routerdesc_failed(dir_connection_t *conn)
static void
connection_dir_download_cert_failed(dir_connection_t *conn, int status)
{
+ const char *fp_pfx = "fp/";
+ const char *fpsk_pfx = "fp-sk/";
smartlist_t *failed;
- tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
+ tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
if (!conn->requested_resource)
return;
failed = smartlist_new();
- dir_split_resource_into_fingerprints(conn->requested_resource+3,
- failed, NULL, DSR_HEX);
- SMARTLIST_FOREACH(failed, char *, cp,
- {
- authority_cert_dl_failed(cp, status);
- tor_free(cp);
- });
+ /*
+ * We have two cases download by fingerprint (resource starts
+ * with "fp/") or download by fingerprint/signing key pair
+ * (resource starts with "fp-sk/").
+ */
+ if (!strcmpstart(conn->requested_resource, fp_pfx)) {
+ /* Download by fingerprint case */
+ dir_split_resource_into_fingerprints(conn->requested_resource +
+ strlen(fp_pfx),
+ failed, NULL, DSR_HEX);
+ SMARTLIST_FOREACH_BEGIN(failed, char *, cp) {
+ /* Null signing key digest indicates download by fp only */
+ authority_cert_dl_failed(cp, NULL, status);
+ tor_free(cp);
+ } SMARTLIST_FOREACH_END(cp);
+ } else if (!strcmpstart(conn->requested_resource, fpsk_pfx)) {
+ /* Download by (fp,sk) pairs */
+ dir_split_resource_into_fingerprint_pairs(conn->requested_resource +
+ strlen(fpsk_pfx), failed);
+ SMARTLIST_FOREACH_BEGIN(failed, fp_pair_t *, cp) {
+ authority_cert_dl_failed(cp->first, cp->second, status);
+ tor_free(cp);
+ } SMARTLIST_FOREACH_END(cp);
+ } else {
+ log_warn(LD_DIR,
+ "Don't know what to do with failure for cert fetch %s",
+ conn->requested_resource);
+ }
+
smartlist_free(failed);
update_certificate_downloads(time(NULL));
@@ -833,11 +910,13 @@ static int
directory_command_should_use_begindir(const or_options_t *options,
const tor_addr_t *addr,
int or_port, uint8_t router_purpose,
- int anonymized_connection)
+ dir_indirection_t indirection)
{
if (!or_port)
return 0; /* We don't know an ORPort -- no chance. */
- if (!anonymized_connection)
+ if (indirection == DIRIND_DIRECT_CONN || indirection == DIRIND_ANON_DIRPORT)
+ return 0;
+ if (indirection == DIRIND_ONEHOP)
if (!fascist_firewall_allows_address_or(addr, or_port) ||
directory_fetches_from_authorities(options))
return 0; /* We're firewalled or are acting like a relay -- also no. */
@@ -855,17 +934,15 @@ directory_command_should_use_begindir(const or_options_t *options,
void
directory_initiate_command(const char *address, const tor_addr_t *_addr,
uint16_t or_port, uint16_t dir_port,
- int supports_conditional_consensus,
- int supports_begindir, const char *digest,
+ const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
- int anonymized_connection, const char *resource,
+ dir_indirection_t indirection, const char *resource,
const char *payload, size_t payload_len,
time_t if_modified_since)
{
directory_initiate_command_rend(address, _addr, or_port, dir_port,
- supports_conditional_consensus,
- supports_begindir, digest, dir_purpose,
- router_purpose, anonymized_connection,
+ digest, dir_purpose,
+ router_purpose, indirection,
resource, payload, payload_len,
if_modified_since, NULL);
}
@@ -889,10 +966,9 @@ is_sensitive_dir_purpose(uint8_t dir_purpose)
static void
directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
uint16_t or_port, uint16_t dir_port,
- int supports_conditional_consensus,
- int supports_begindir, const char *digest,
+ const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload, size_t payload_len,
time_t if_modified_since,
@@ -901,9 +977,9 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
dir_connection_t *conn;
const or_options_t *options = get_options();
int socket_error = 0;
- int use_begindir = supports_begindir &&
- directory_command_should_use_begindir(options, _addr,
- or_port, router_purpose, anonymized_connection);
+ int use_begindir = directory_command_should_use_begindir(options, _addr,
+ or_port, router_purpose, indirection);
+ const int anonymized_connection = dirind_is_anon(indirection);
tor_addr_t addr;
tor_assert(address);
@@ -937,18 +1013,19 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
conn = dir_connection_new(tor_addr_family(&addr));
/* set up conn so it's got all the data we need to remember */
- tor_addr_copy(&conn->_base.addr, &addr);
- conn->_base.port = use_begindir ? or_port : dir_port;
- conn->_base.address = tor_strdup(address);
+ tor_addr_copy(&conn->base_.addr, &addr);
+ conn->base_.port = use_begindir ? or_port : dir_port;
+ conn->base_.address = tor_strdup(address);
memcpy(conn->identity_digest, digest, DIGEST_LEN);
- conn->_base.purpose = dir_purpose;
+ conn->base_.purpose = dir_purpose;
conn->router_purpose = router_purpose;
/* give it an initial state */
- conn->_base.state = DIR_CONN_STATE_CONNECTING;
+ conn->base_.state = DIR_CONN_STATE_CONNECTING;
/* decide whether we can learn our IP address from this conn */
+ /* XXXX This is a bad name for this field now. */
conn->dirconn_direct = !anonymized_connection;
/* copy rendezvous data, if any */
@@ -963,7 +1040,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
dir_port = options->HTTPProxyPort;
}
- switch (connection_connect(TO_CONN(conn), conn->_base.address, &addr,
+ switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr,
dir_port, &socket_error)) {
case -1:
connection_dir_request_failed(conn); /* retry if we want */
@@ -973,13 +1050,12 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
return;
case 1:
/* start flushing conn */
- conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
+ conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING;
/* fall through */
case 0:
/* queue the command on the outbuf */
directory_send_command(conn, dir_purpose, 1, resource,
payload, payload_len,
- supports_conditional_consensus,
if_modified_since);
connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT);
/* writable indicates finish, readable indicates broken link,
@@ -997,7 +1073,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
if (anonymized_connection && use_begindir)
rep_hist_note_used_internal(time(NULL), 0, 1);
else if (anonymized_connection && !use_begindir)
- rep_hist_note_used_port(time(NULL), conn->_base.port);
+ rep_hist_note_used_port(time(NULL), conn->base_.port);
/* make an AP connection
* populate it and add it at the right state
@@ -1005,7 +1081,7 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
*/
linked_conn =
connection_ap_make_link(TO_CONN(conn),
- conn->_base.address, conn->_base.port,
+ conn->base_.address, conn->base_.port,
digest,
SESSION_GROUP_DIRCONN, iso_flags,
use_begindir, conn->dirconn_direct);
@@ -1020,11 +1096,10 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
connection_mark_for_close(TO_CONN(conn));
return;
}
- conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
+ conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING;
/* queue the command on the outbuf */
directory_send_command(conn, dir_purpose, 0, resource,
payload, payload_len,
- supports_conditional_consensus,
if_modified_since);
connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT);
@@ -1054,7 +1129,7 @@ connection_dir_is_encrypted(dir_connection_t *conn)
* sort strings alphabetically
*/
static int
-_compare_strs(const void **a, const void **b)
+compare_strs_(const void **a, const void **b)
{
const char *s1 = *a, *s2 = *b;
return strcmp(s1, s2);
@@ -1074,8 +1149,7 @@ _compare_strs(const void **a, const void **b)
* If 'resource' is provided, it is the name of a consensus flavor to request.
*/
static char *
-directory_get_consensus_url(int supports_conditional_consensus,
- const char *resource)
+directory_get_consensus_url(const char *resource)
{
char *url = NULL;
const char *hyphen, *flavor;
@@ -1087,12 +1161,12 @@ directory_get_consensus_url(int supports_conditional_consensus,
hyphen = "-";
}
- if (supports_conditional_consensus) {
+ {
char *authority_id_list;
smartlist_t *authority_digests = smartlist_new();
SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds) {
+ dir_server_t *, ds) {
char *hex;
if (!(ds->type & V3_DIRINFO))
continue;
@@ -1102,7 +1176,7 @@ directory_get_consensus_url(int supports_conditional_consensus,
ds->v3_identity_digest, CONDITIONAL_CONSENSUS_FPR_LEN);
smartlist_add(authority_digests, hex);
} SMARTLIST_FOREACH_END(ds);
- smartlist_sort(authority_digests, _compare_strs);
+ smartlist_sort(authority_digests, compare_strs_);
authority_id_list = smartlist_join_strings(authority_digests,
"+", 0, NULL);
@@ -1112,9 +1186,6 @@ directory_get_consensus_url(int supports_conditional_consensus,
SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp));
smartlist_free(authority_digests);
tor_free(authority_id_list);
- } else {
- tor_asprintf(&url, "/tor/status-vote/current/consensus%s%s.z",
- hyphen, flavor);
}
return url;
}
@@ -1126,7 +1197,6 @@ static void
directory_send_command(dir_connection_t *conn,
int purpose, int direct, const char *resource,
const char *payload, size_t payload_len,
- int supports_conditional_consensus,
time_t if_modified_since)
{
char proxystring[256];
@@ -1137,18 +1207,18 @@ directory_send_command(dir_connection_t *conn,
const char *httpcommand = NULL;
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
tor_free(conn->requested_resource);
if (resource)
conn->requested_resource = tor_strdup(resource);
/* come up with a string for which Host: we want */
- if (conn->_base.port == 80) {
- strlcpy(hoststring, conn->_base.address, sizeof(hoststring));
+ if (conn->base_.port == 80) {
+ strlcpy(hoststring, conn->base_.address, sizeof(hoststring));
} else {
tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
}
/* Format if-modified-since */
@@ -1189,8 +1259,7 @@ directory_send_command(dir_connection_t *conn,
/* resource is optional. If present, it's a flavor name */
tor_assert(!payload);
httpcommand = "GET";
- url = directory_get_consensus_url(supports_conditional_consensus,
- resource);
+ url = directory_get_consensus_url(resource);
log_info(LD_DIR, "Downloading consensus from %s using %s",
hoststring, url);
break;
@@ -1584,11 +1653,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
compress_method_t compression;
int plausible;
int skewed=0;
- int allow_partial = (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC);
+ int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
int was_compressed=0;
time_t now = time(NULL);
+ int src_code;
switch (connection_fetch_from_buf_http(TO_CONN(conn),
&headers, MAX_HEADERS_SIZE,
@@ -1597,7 +1667,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
case -1: /* overflow */
log_warn(LD_PROTOCOL,
"'fetch' response too large (server '%s:%d'). Closing.",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
return -1;
case 0:
log_info(LD_HTTP,
@@ -1610,7 +1680,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (parse_http_response(headers, &status_code, &date_header,
&compression, &reason) < 0) {
log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
tor_free(body); tor_free(headers);
return -1;
}
@@ -1619,9 +1689,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_debug(LD_DIR,
"Received response from directory server '%s:%d': %d %s "
"(purpose: %d)",
- conn->_base.address, conn->_base.port, status_code,
+ conn->base_.address, conn->base_.port, status_code,
escaped(reason),
- conn->_base.purpose);
+ conn->base_.purpose);
/* now check if it's got any hints for us about our IP address. */
if (conn->dirconn_direct) {
@@ -1638,7 +1708,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
* and the date header. (We used to check now-date_header, but that's
* inaccurate if we spend a lot of time downloading.)
*/
- delta = conn->_base.timestamp_lastwritten - date_header;
+ delta = conn->base_.timestamp_lastwritten - date_header;
if (labs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
char dbuf[64];
int trusted = router_digest_is_trusted_dir(conn->identity_digest);
@@ -1649,14 +1719,14 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"It seems that our clock is %s by %s, or that theirs is %s. "
"Tor requires an accurate clock to work: please check your time, "
"timezone, and date settings.",
- conn->_base.address, conn->_base.port,
+ conn->base_.address, conn->base_.port,
delta>0 ? "ahead" : "behind", dbuf,
delta>0 ? "behind" : "ahead");
skewed = 1; /* don't check the recommended-versions line */
if (trusted)
control_event_general_status(LOG_WARN,
"CLOCK_SKEW SKEW=%ld SOURCE=DIRSERV:%s:%d",
- delta, conn->_base.address, conn->_base.port);
+ delta, conn->base_.address, conn->base_.port);
} else {
log_debug(LD_HTTP, "Time on received directory is within tolerance; "
"we are %ld seconds skewed. (That's okay.)", delta);
@@ -1666,22 +1736,22 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (status_code == 503) {
routerstatus_t *rs;
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
const char *id_digest = conn->identity_digest;
log_info(LD_DIR,"Received http status code %d (%s) from server "
"'%s:%d'. I'll try again soon.",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
if ((rs = router_get_mutable_consensus_status_by_id(id_digest)))
rs->last_dir_503_at = now;
- if ((ds = router_get_trusteddirserver_by_digest(id_digest)))
+ if ((ds = router_get_fallback_dirserver_by_digest(id_digest)))
ds->fake_status.last_dir_503_at = now;
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
- plausible = body_is_plausible(body, body_len, conn->_base.purpose);
+ plausible = body_is_plausible(body, body_len, conn->base_.purpose);
if (compression != NO_METHOD || !plausible) {
char *new_body = NULL;
size_t new_len = 0;
@@ -1708,7 +1778,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, "
"but it seems to be %s.%s",
- conn->_base.address, conn->_base.port, description1,
+ conn->base_.address, conn->base_.port, description1,
description2,
(compression>0 && guessed>0)?" Trying both.":"");
}
@@ -1728,7 +1798,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (!plausible && !new_body) {
log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
"Unable to decompress HTTP body (server '%s:%d').",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
@@ -1740,12 +1810,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
smartlist_t *which = NULL;
v2_networkstatus_source_t source;
char *cp;
log_info(LD_DIR,"Received networkstatus objects (size %d) from server "
- "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
+ "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
if (status_code != 200) {
static ratelim_t warning_limit = RATELIM_INIT(3600);
char *m;
@@ -1754,8 +1824,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"Received http status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/status/%s\". "
"I'll try again soon.%s",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port, conn->requested_resource, m);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port, conn->requested_resource, m);
tor_free(m);
}
tor_free(body); tor_free(headers); tor_free(reason);
@@ -1773,7 +1843,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
source = NS_FROM_DIR_ALL;
which = smartlist_new();
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds,
+ dir_server_t *, ds,
{
char *hex = tor_malloc(HEX_DIGEST_LEN+1);
base16_encode(hex, HEX_DIGEST_LEN+1, ds->digest, DIGEST_LEN);
@@ -1811,27 +1881,27 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
int r;
const char *flavname = conn->requested_resource;
if (status_code != 200) {
int severity = (status_code == 304) ? LOG_INFO : LOG_WARN;
- log(severity, LD_DIR,
+ tor_log(severity, LD_DIR,
"Received http status code %d (%s) from server "
"'%s:%d' while fetching consensus directory.",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
tor_free(body); tor_free(headers); tor_free(reason);
networkstatus_consensus_download_failed(status_code, flavname);
return -1;
}
log_info(LD_DIR,"Received consensus directory (size %d) from server "
- "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
+ "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
if ((r=networkstatus_set_current_consensus(body, flavname, 0))<0) {
log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
"Unable to load %s consensus directory downloaded from "
"server '%s:%d'. I'll try again soon.",
- flavname, conn->_base.address, conn->_base.port);
+ flavname, conn->base_.address, conn->base_.port);
tor_free(body); tor_free(headers); tor_free(reason);
networkstatus_consensus_download_failed(0, flavname);
return -1;
@@ -1844,40 +1914,60 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_DIR, "Successfully loaded consensus.");
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
if (status_code != 200) {
log_warn(LD_DIR,
"Received http status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/keys/%s\".",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port, conn->requested_resource);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port, conn->requested_resource);
connection_dir_download_cert_failed(conn, status_code);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
log_info(LD_DIR,"Received authority certificates (size %d) from server "
- "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
- if (trusted_dirs_load_certs_from_string(body, 0, 1)<0) {
- log_warn(LD_DIR, "Unable to parse fetched certificates");
- /* if we fetched more than one and only some failed, the successful
- * ones got flushed to disk so it's safe to call this on them */
- connection_dir_download_cert_failed(conn, status_code);
+ "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
+
+ /*
+ * Tell trusted_dirs_load_certs_from_string() whether it was by fp
+ * or fp-sk pair.
+ */
+ src_code = -1;
+ if (!strcmpstart(conn->requested_resource, "fp/")) {
+ src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST;
+ } else if (!strcmpstart(conn->requested_resource, "fp-sk/")) {
+ src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST;
+ }
+
+ if (src_code != -1) {
+ if (trusted_dirs_load_certs_from_string(body, src_code, 1)<0) {
+ log_warn(LD_DIR, "Unable to parse fetched certificates");
+ /* if we fetched more than one and only some failed, the successful
+ * ones got flushed to disk so it's safe to call this on them */
+ connection_dir_download_cert_failed(conn, status_code);
+ } else {
+ directory_info_has_arrived(now, 0);
+ log_info(LD_DIR, "Successfully loaded certificates from fetch.");
+ }
} else {
- directory_info_has_arrived(now, 0);
- log_info(LD_DIR, "Successfully loaded certificates from fetch.");
+ log_warn(LD_DIR,
+ "Couldn't figure out what to do with fetched certificates for "
+ "unknown resource %s",
+ conn->requested_resource);
+ connection_dir_download_cert_failed(conn, status_code);
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
const char *msg;
int st;
log_info(LD_DIR,"Got votes (size %d) from server %s:%d",
- (int)body_len, conn->_base.address, conn->_base.port);
+ (int)body_len, conn->base_.address, conn->base_.port);
if (status_code != 200) {
log_warn(LD_DIR,
"Received http status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port, conn->requested_resource);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port, conn->requested_resource);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
@@ -1888,35 +1978,35 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_DIR, "Added vote(s) successfully [msg: %s]", msg);
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
const char *msg = NULL;
log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d",
- (int)body_len, conn->_base.address, conn->_base.port);
+ (int)body_len, conn->base_.address, conn->base_.port);
if (status_code != 200) {
log_warn(LD_DIR,
"Received http status code %d (%s) from server '%s:%d' while fetching "
"\"/tor/status-vote/next/consensus-signatures.z\".",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
- if (dirvote_add_signatures(body, conn->_base.address, &msg)<0) {
+ if (dirvote_add_signatures(body, conn->base_.address, &msg)<0) {
log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s",
- conn->_base.address, conn->_base.port, msg?msg:"???");
+ conn->base_.address, conn->base_.port, msg?msg:"???");
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
- conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
- int was_ei = conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO;
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
+ conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
+ int was_ei = conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO;
smartlist_t *which = NULL;
int n_asked_for = 0;
int descriptor_digests = conn->requested_resource &&
!strcmpstart(conn->requested_resource,"d/");
log_info(LD_DIR,"Received %s (size %d) from server '%s:%d'",
was_ei ? "extra server info" : "server info",
- (int)body_len, conn->_base.address, conn->_base.port);
+ (int)body_len, conn->base_.address, conn->base_.port);
if (conn->requested_resource &&
(!strcmpstart(conn->requested_resource,"d/") ||
!strcmpstart(conn->requested_resource,"fp/"))) {
@@ -1934,8 +2024,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR,
"Received http status code %d (%s) from server '%s:%d' "
"while fetching \"/tor/server/%s\". I'll try again soon.",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port, conn->requested_resource);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port, conn->requested_resource);
if (!which) {
connection_dir_download_routerdesc_failed(conn);
} else {
@@ -1969,7 +2059,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
// descriptor_digests, conn->router_purpose);
if (load_downloaded_routers(body, which, descriptor_digests,
conn->router_purpose,
- conn->_base.address))
+ conn->base_.address))
directory_info_has_arrived(now, 0);
}
}
@@ -1977,7 +2067,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_DIR, "Received %d/%d %s requested from %s:%d",
n_asked_for-smartlist_len(which), n_asked_for,
was_ei ? "extra-info documents" : "router descriptors",
- conn->_base.address, (int)conn->_base.port);
+ conn->base_.address, (int)conn->base_.port);
if (smartlist_len(which)) {
dir_routerdesc_download_failed(which, status_code,
conn->router_purpose,
@@ -1989,12 +2079,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (directory_conn_is_self_reachability_test(conn))
router_dirport_found_reachable();
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
smartlist_t *which = NULL;
log_info(LD_DIR,"Received answer to microdescriptor request (status %d, "
"size %d) from server '%s:%d'",
- status_code, (int)body_len, conn->_base.address,
- conn->_base.port);
+ status_code, (int)body_len, conn->base_.address,
+ conn->base_.port);
tor_assert(conn->requested_resource &&
!strcmpstart(conn->requested_resource, "d/"));
which = smartlist_new();
@@ -2005,8 +2095,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_DIR, "Received status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/micro/%s\". I'll try again "
"soon.",
- status_code, escaped(reason), conn->_base.address,
- (int)conn->_base.port, conn->requested_resource);
+ status_code, escaped(reason), conn->base_.address,
+ (int)conn->base_.port, conn->requested_resource);
dir_microdesc_download_failed(which, status_code);
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
smartlist_free(which);
@@ -2021,16 +2111,18 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
/* Mark remaining ones as failed. */
dir_microdesc_download_failed(which, status_code);
}
+ control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS,
+ count_loading_descriptors_progress());
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
smartlist_free(which);
smartlist_free(mds);
}
}
- if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
+ if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_DIR) {
switch (status_code) {
case 200: {
- trusted_dir_server_t *ds =
+ dir_server_t *ds =
router_get_trusteddirserver_by_digest(conn->identity_digest);
char *rejected_hdr = http_get_header(headers,
"X-Descriptor-Not-New: ");
@@ -2053,7 +2145,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"descriptor: finished.");
control_event_server_status(
LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
ds->has_accepted_serverdesc = 1;
if (directories_have_accepted_server_descriptor())
@@ -2063,72 +2155,72 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
case 400:
log_warn(LD_GENERAL,"http status 400 (%s) response from "
"dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->_base.address, conn->_base.port);
+ escaped(reason), conn->base_.address, conn->base_.port);
control_event_server_status(LOG_WARN,
"BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"",
- conn->_base.address, conn->_base.port, escaped(reason));
+ conn->base_.address, conn->base_.port, escaped(reason));
break;
default:
log_warn(LD_GENERAL,
"http status %d (%s) reason unexpected while uploading "
"descriptor to server '%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
/* return 0 in all cases, since we don't want to mark any
* dirservers down just because they don't like us. */
}
- if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_VOTE) {
+ if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_VOTE) {
switch (status_code) {
case 200: {
log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
}
break;
case 400:
log_warn(LD_DIR,"http status 400 (%s) response after uploading "
"vote to dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->_base.address, conn->_base.port);
+ escaped(reason), conn->base_.address, conn->base_.port);
break;
default:
log_warn(LD_GENERAL,
"http status %d (%s) reason unexpected while uploading "
"vote to server '%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
/* return 0 in all cases, since we don't want to mark any
* dirservers down just because they don't like us. */
}
- if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) {
+ if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) {
switch (status_code) {
case 200: {
log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d",
- conn->_base.address, conn->_base.port);
+ conn->base_.address, conn->base_.port);
}
break;
case 400:
log_warn(LD_DIR,"http status 400 (%s) response after uploading "
"signatures to dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->_base.address, conn->_base.port);
+ escaped(reason), conn->base_.address, conn->base_.port);
break;
default:
log_warn(LD_GENERAL,
"http status %d (%s) reason unexpected while uploading "
"signatures to server '%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
/* return 0 in all cases, since we don't want to mark any
* dirservers down just because they don't like us. */
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
tor_assert(conn->rend_data);
log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
"(%s))",
@@ -2146,7 +2238,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
} else {
/* Success, or at least there's a v2 descriptor already
* present. Notify pending connections about this. */
- conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
+ conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
rend_client_desc_trynow(conn->rend_data->onion_address);
}
break;
@@ -2162,13 +2254,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
default:
log_warn(LD_REND,"http status %d (%s) response unexpected while "
"fetching hidden service descriptor (server '%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
}
- if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
+ if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
tor_assert(conn->rend_data);
log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
"(%s))",
@@ -2187,13 +2279,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
* and _not_ performing another request. */
log_info(LD_REND, "Successfully fetched v2 rendezvous "
"descriptor, but we already have a v0 descriptor.");
- conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
+ conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
break;
default:
/* success. notify pending connections about this. */
log_info(LD_REND, "Successfully fetched v2 rendezvous "
"descriptor.");
- conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
+ conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
rend_client_desc_trynow(conn->rend_data->onion_address);
break;
}
@@ -2215,14 +2307,14 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"http status %d (%s) response unexpected while "
"fetching v2 hidden service descriptor (server '%s:%d'). "
"Retrying at another directory.",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
}
- if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC ||
- conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
+ if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC ||
+ conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
"(%s))",
status_code, escaped(reason));
@@ -2235,17 +2327,17 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
case 400:
log_warn(LD_REND,"http status 400 (%s) response from dirserver "
"'%s:%d'. Malformed rendezvous descriptor?",
- escaped(reason), conn->_base.address, conn->_base.port);
+ escaped(reason), conn->base_.address, conn->base_.port);
break;
default:
log_warn(LD_REND,"http status %d (%s) response unexpected (server "
"'%s:%d').",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
+ status_code, escaped(reason), conn->base_.address,
+ conn->base_.port);
break;
}
}
- note_client_request(conn->_base.purpose, was_compressed, orig_len);
+ note_client_request(conn->base_.purpose, was_compressed, orig_len);
tor_free(body); tor_free(headers); tor_free(reason);
return 0;
}
@@ -2255,9 +2347,9 @@ int
connection_dir_reached_eof(dir_connection_t *conn)
{
int retval;
- if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) {
+ if (conn->base_.state != DIR_CONN_STATE_CLIENT_READING) {
log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.",
- conn->_base.state);
+ conn->base_.state);
connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
connection_mark_for_close(TO_CONN(conn));
return -1;
@@ -2265,7 +2357,7 @@ connection_dir_reached_eof(dir_connection_t *conn)
retval = connection_dir_client_reached_eof(conn);
if (retval == 0) /* success */
- conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED;
+ conn->base_.state = DIR_CONN_STATE_CLIENT_FINISHED;
connection_mark_for_close(TO_CONN(conn));
return retval;
}
@@ -2283,7 +2375,7 @@ int
connection_dir_process_inbuf(dir_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
/* Directory clients write, then read data until they receive EOF;
* directory servers read data until they get an HTTP command, then
@@ -2292,7 +2384,7 @@ connection_dir_process_inbuf(dir_connection_t *conn)
*/
/* If we're on the dirserver side, look for a command. */
- if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
+ if (conn->base_.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
if (directory_handle_command(conn) < 0) {
connection_mark_for_close(TO_CONN(conn));
return -1;
@@ -2307,7 +2399,7 @@ connection_dir_process_inbuf(dir_connection_t *conn)
return -1;
}
- if (!conn->_base.inbuf_reached_eof)
+ if (!conn->base_.inbuf_reached_eof)
log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
return 0;
}
@@ -2380,12 +2472,12 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type);
cp += strlen(cp);
}
- if (!is_local_addr(&conn->_base.addr)) {
+ if (!is_local_addr(&conn->base_.addr)) {
/* Don't report the source address for a nearby/private connection.
* Otherwise we tend to mis-report in cases where incoming ports are
* being forwarded to a Tor server running behind the firewall. */
tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
- X_ADDRESS_HEADER "%s\r\n", conn->_base.address);
+ X_ADDRESS_HEADER "%s\r\n", conn->base_.address);
cp += strlen(cp);
}
if (encoding) {
@@ -2637,7 +2729,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
log_debug(LD_DIRSERV,"Received GET command.");
- conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
+ conn->base_.state = DIR_CONN_STATE_SERVER_WRITING;
if (parse_http_url(headers, &url) < 0) {
write_http_status_line(conn, 400, "Bad request");
@@ -2756,12 +2848,23 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
/* v2 or v3 network status fetch. */
smartlist_t *dir_fps = smartlist_new();
int is_v3 = !strcmpstart(url, "/tor/status-vote");
- geoip_client_action_t act =
- is_v3 ? GEOIP_CLIENT_NETWORKSTATUS : GEOIP_CLIENT_NETWORKSTATUS_V2;
const char *request_type = NULL;
const char *key = url + strlen("/tor/status/");
long lifetime = NETWORKSTATUS_CACHE_LIFETIME;
+ if (options->DisableV2DirectoryInfo_ && !is_v3) {
+ static ratelim_t reject_v2_ratelim = RATELIM_INIT(1800);
+ char *m;
+ write_http_status_line(conn, 404, "Not found");
+ smartlist_free(dir_fps);
+ geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND);
+ if ((m = rate_limit_log(&reject_v2_ratelim, approx_time()))) {
+ log_notice(LD_DIR, "Rejected a v2 networkstatus request.%s", m);
+ tor_free(m);
+ }
+ goto done;
+ }
+
if (!is_v3) {
dirserv_get_networkstatus_v2_fingerprints(dir_fps, key);
if (!strcmpstart(key, "fp/"))
@@ -2807,7 +2910,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
write_http_status_line(conn, 404, "Consensus not signed by sufficient "
"number of requested authorities");
smartlist_free(dir_fps);
- geoip_note_ns_response(act, GEOIP_REJECT_NOT_ENOUGH_SIGS);
+ geoip_note_ns_response(GEOIP_REJECT_NOT_ENOUGH_SIGS);
tor_free(flavor);
goto done;
}
@@ -2826,7 +2929,8 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */
write_http_status_line(conn, 503, "Network status object unavailable");
smartlist_free(dir_fps);
- geoip_note_ns_response(act, GEOIP_REJECT_UNAVAILABLE);
+ if (is_v3)
+ geoip_note_ns_response(GEOIP_REJECT_UNAVAILABLE);
goto done;
}
@@ -2834,13 +2938,15 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
write_http_status_line(conn, 404, "Not found");
SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
smartlist_free(dir_fps);
- geoip_note_ns_response(act, GEOIP_REJECT_NOT_FOUND);
+ if (is_v3)
+ geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND);
goto done;
} else if (!smartlist_len(dir_fps)) {
write_http_status_line(conn, 304, "Not modified");
SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
smartlist_free(dir_fps);
- geoip_note_ns_response(act, GEOIP_REJECT_NOT_MODIFIED);
+ if (is_v3)
+ geoip_note_ns_response(GEOIP_REJECT_NOT_MODIFIED);
goto done;
}
@@ -2852,24 +2958,24 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
write_http_status_line(conn, 503, "Directory busy, try again later");
SMARTLIST_FOREACH(dir_fps, char *, fp, tor_free(fp));
smartlist_free(dir_fps);
- geoip_note_ns_response(act, GEOIP_REJECT_BUSY);
+ if (is_v3)
+ geoip_note_ns_response(GEOIP_REJECT_BUSY);
goto done;
}
- {
+ if (is_v3) {
struct in_addr in;
tor_addr_t addr;
if (tor_inet_aton((TO_CONN(conn))->address, &in)) {
tor_addr_from_ipv4h(&addr, ntohl(in.s_addr));
- geoip_note_client_seen(act, &addr, time(NULL));
- geoip_note_ns_response(act, GEOIP_SUCCESS);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, time(NULL));
+ geoip_note_ns_response(GEOIP_SUCCESS);
/* Note that a request for a network status has started, so that we
* can measure the download time later on. */
- if (TO_CONN(conn)->dirreq_id)
- geoip_start_dirreq(TO_CONN(conn)->dirreq_id, dlen, act,
- DIRREQ_TUNNELED);
+ if (conn->dirreq_id)
+ geoip_start_dirreq(conn->dirreq_id, dlen, DIRREQ_TUNNELED);
else
- geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen, act,
+ geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen,
DIRREQ_DIRECT);
}
}
@@ -3231,7 +3337,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
}
if (options->BridgeAuthoritativeDir &&
- options->_BridgePassword_AuthDigest &&
+ options->BridgePassword_AuthDigest_ &&
connection_dir_is_encrypted(conn) &&
!strcmp(url,"/tor/networkstatus-bridges")) {
char *status;
@@ -3244,7 +3350,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
/* now make sure the password is there and right */
if (!header ||
tor_memneq(digest,
- options->_BridgePassword_AuthDigest, DIGEST256_LEN)) {
+ options->BridgePassword_AuthDigest_, DIGEST256_LEN)) {
write_http_status_line(conn, 404, "Not found");
tor_free(header);
goto done;
@@ -3300,7 +3406,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
}while(0);
if (!strcmp(url,"/tor/mallinfo.txt") &&
- (tor_addr_eq_ipv4h(&conn->_base.addr, 0x7f000001ul))) {
+ (tor_addr_eq_ipv4h(&conn->base_.addr, 0x7f000001ul))) {
char *result;
size_t len;
struct mallinfo mi;
@@ -3355,7 +3461,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
log_debug(LD_DIRSERV,"Received POST command.");
- conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
+ conn->base_.state = DIR_CONN_STATE_SERVER_WRITING;
if (parse_http_url(headers, &url) < 0) {
write_http_status_line(conn, 400, "Bad request");
@@ -3371,13 +3477,13 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
case -2:
log_info(LD_REND, "Rejected v2 rend descriptor (length %d) from %s "
"since we're not currently a hidden service directory.",
- (int)body_len, conn->_base.address);
+ (int)body_len, conn->base_.address);
write_http_status_line(conn, 503, "Currently not acting as v2 "
"hidden service directory");
break;
case -1:
log_warn(LD_REND, "Rejected v2 rend descriptor (length %d) from %s.",
- (int)body_len, conn->_base.address);
+ (int)body_len, conn->base_.address);
write_http_status_line(conn, 400,
"Invalid v2 service descriptor rejected");
break;
@@ -3402,7 +3508,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
uint8_t purpose = authdir_mode_bridge(options) ?
ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose,
- conn->_base.address, &msg);
+ conn->base_.address, &msg);
tor_assert(msg);
if (WRA_WAS_ADDED(r))
dirserv_get_directory(); /* rebuild and write to disk */
@@ -3412,7 +3518,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
log_info(LD_DIRSERV,
"Problematic router descriptor or extra-info from %s "
"(\"%s\").",
- conn->_base.address, msg);
+ conn->base_.address, msg);
write_http_status_line(conn, 400, msg);
} else if (r == ROUTER_ADDED_SUCCESSFULLY) {
write_http_status_line(conn, 200, msg);
@@ -3423,7 +3529,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
log_info(LD_DIRSERV,
"Rejected router descriptor or extra-info from %s "
"(\"%s\").",
- conn->_base.address, msg);
+ conn->base_.address, msg);
write_http_status_line(conn, 400, msg);
}
goto done;
@@ -3436,7 +3542,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
if (rend_cache_store(body, body_len, 1, NULL) < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV,
"Rejected rend descriptor (length %d) from %s.",
- (int)body_len, conn->_base.address);
+ (int)body_len, conn->base_.address);
write_http_status_line(conn, 400,
"Invalid v0 service descriptor rejected");
} else {
@@ -3454,7 +3560,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
} else {
tor_assert(msg);
log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").",
- conn->_base.address, msg);
+ conn->base_.address, msg);
write_http_status_line(conn, status, msg);
}
goto done;
@@ -3463,11 +3569,11 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
if (authdir_mode_v3(options) &&
!strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */
const char *msg = NULL;
- if (dirvote_add_signatures(body, conn->_base.address, &msg)>=0) {
+ if (dirvote_add_signatures(body, conn->base_.address, &msg)>=0) {
write_http_status_line(conn, 200, msg?msg:"Signatures stored");
} else {
log_warn(LD_DIR, "Unable to store signatures posted by %s: %s",
- conn->_base.address, msg?msg:"???");
+ conn->base_.address, msg?msg:"???");
write_http_status_line(conn, 400, msg?msg:"Unable to store signatures");
}
goto done;
@@ -3494,7 +3600,7 @@ directory_handle_command(dir_connection_t *conn)
int r;
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
switch (connection_fetch_from_buf_http(TO_CONN(conn),
&headers, MAX_HEADERS_SIZE,
@@ -3502,7 +3608,7 @@ directory_handle_command(dir_connection_t *conn)
case -1: /* overflow */
log_warn(LD_DIRSERV,
"Request too large from address '%s' to DirPort. Closing.",
- safe_str(conn->_base.address));
+ safe_str(conn->base_.address));
return -1;
case 0:
log_debug(LD_DIRSERV,"command not all here yet.");
@@ -3536,23 +3642,23 @@ int
connection_dir_finished_flushing(dir_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
/* Note that we have finished writing the directory response. For direct
* connections this means we're done, for tunneled connections its only
* an intermediate step. */
- if (TO_CONN(conn)->dirreq_id)
- geoip_change_dirreq_state(TO_CONN(conn)->dirreq_id, DIRREQ_TUNNELED,
+ if (conn->dirreq_id)
+ geoip_change_dirreq_state(conn->dirreq_id, DIRREQ_TUNNELED,
DIRREQ_FLUSHING_DIR_CONN_FINISHED);
else
geoip_change_dirreq_state(TO_CONN(conn)->global_identifier,
DIRREQ_DIRECT,
DIRREQ_FLUSHING_DIR_CONN_FINISHED);
- switch (conn->_base.state) {
+ switch (conn->base_.state) {
case DIR_CONN_STATE_CONNECTING:
case DIR_CONN_STATE_CLIENT_SENDING:
log_debug(LD_DIR,"client finished sending command.");
- conn->_base.state = DIR_CONN_STATE_CLIENT_READING;
+ conn->base_.state = DIR_CONN_STATE_CLIENT_READING;
return 0;
case DIR_CONN_STATE_SERVER_WRITING:
if (conn->dir_spool_src != DIR_SPOOL_NONE) {
@@ -3573,7 +3679,7 @@ connection_dir_finished_flushing(dir_connection_t *conn)
return 0;
default:
log_warn(LD_BUG,"called in unexpected state %d.",
- conn->_base.state);
+ conn->base_.state);
tor_fragile_assert();
return -1;
}
@@ -3586,13 +3692,13 @@ int
connection_dir_finished_connecting(dir_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->_base.type == CONN_TYPE_DIR);
- tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING);
+ tor_assert(conn->base_.type == CONN_TYPE_DIR);
+ tor_assert(conn->base_.state == DIR_CONN_STATE_CONNECTING);
log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
- conn->_base.address,conn->_base.port);
+ conn->base_.address,conn->base_.port);
- conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
+ conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
return 0;
}
@@ -3606,13 +3712,13 @@ dir_networkstatus_download_failed(smartlist_t *failed, int status_code)
return;
SMARTLIST_FOREACH_BEGIN(failed, const char *, fp) {
char digest[DIGEST_LEN];
- trusted_dir_server_t *dir;
+ dir_server_t *dir;
if (base16_decode(digest, DIGEST_LEN, fp, strlen(fp))<0) {
log_warn(LD_BUG, "Called with bad fingerprint in list: %s",
escaped(fp));
continue;
}
- dir = router_get_trusteddirserver_by_digest(digest);
+ dir = router_get_fallback_dirserver_by_digest(digest);
if (dir)
download_status_failed(&dir->v2_ns_dl_status, status_code);
@@ -3829,7 +3935,7 @@ dir_microdesc_download_failed(smartlist_t *failed,
/** Helper. Compare two fp_pair_t objects, and return negative, 0, or
* positive as appropriate. */
static int
-_compare_pairs(const void **a, const void **b)
+compare_pairs_(const void **a, const void **b)
{
const fp_pair_t *fp1 = *a, *fp2 = *b;
int r;
@@ -3880,8 +3986,8 @@ dir_split_resource_into_fingerprint_pairs(const char *res,
smartlist_free(pairs_tmp);
/* Uniq-and-sort */
- smartlist_sort(pairs_result, _compare_pairs);
- smartlist_uniq(pairs_result, _compare_pairs, _tor_free);
+ smartlist_sort(pairs_result, compare_pairs_);
+ smartlist_uniq(pairs_result, compare_pairs_, tor_free_);
smartlist_add_all(pairs_out, pairs_result);
smartlist_free(pairs_result);
diff --git a/src/or/directory.h b/src/or/directory.h
index 1ca1c5a6e..41f18a172 100644
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for directory.c.
**/
-#ifndef _TOR_DIRECTORY_H
-#define _TOR_DIRECTORY_H
+#ifndef TOR_DIRECTORY_H
+#define TOR_DIRECTORY_H
int directories_have_accepted_server_descriptor(void);
void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
@@ -22,10 +22,24 @@ void directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
void directory_get_from_all_authorities(uint8_t dir_purpose,
uint8_t router_purpose,
const char *resource);
+
+/** Enumeration of ways to connect to a directory server */
+typedef enum {
+ /** Default: connect over a one-hop Tor circuit but fall back to direct
+ * connection */
+ DIRIND_ONEHOP=0,
+ /** Connect over a multi-hop anonymizing Tor circuit */
+ DIRIND_ANONYMOUS=1,
+ /** Conncet to the DirPort directly */
+ DIRIND_DIRECT_CONN,
+ /** Connect over a multi-hop anonymizing Tor circuit to our dirport */
+ DIRIND_ANON_DIRPORT,
+} dir_indirection_t;
+
void directory_initiate_command_routerstatus(const routerstatus_t *status,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -33,7 +47,7 @@ void directory_initiate_command_routerstatus(const routerstatus_t *status,
void directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
uint8_t dir_purpose,
uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload,
size_t payload_len,
@@ -51,10 +65,9 @@ int connection_dir_finished_connecting(dir_connection_t *conn);
void connection_dir_about_to_close(dir_connection_t *dir_conn);
void directory_initiate_command(const char *address, const tor_addr_t *addr,
uint16_t or_port, uint16_t dir_port,
- int supports_conditional_consensus,
- int supports_begindir, const char *digest,
+ const char *digest,
uint8_t dir_purpose, uint8_t router_purpose,
- int anonymized_connection,
+ dir_indirection_t indirection,
const char *resource,
const char *payload, size_t payload_len,
time_t if_modified_since);
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index f1c9c6232..3e46153a5 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1,12 +1,16 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DIRSERV_PRIVATE
#include "or.h"
#include "buffers.h"
#include "config.h"
+#include "confparse.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "command.h"
#include "connection.h"
#include "connection_or.h"
#include "control.h"
@@ -62,6 +66,13 @@ static cached_dir_t *the_directory = NULL;
/** For authoritative directories: the current (v1) network status. */
static cached_dir_t the_runningrouters;
+/** Total number of routers with measured bandwidth; this is set by
+ * dirserv_count_measured_bws() before the loop in
+ * dirserv_generate_networkstatus_vote_obj() and checked by
+ * dirserv_get_credible_bandwidth() and
+ * dirserv_compute_performance_thresholds() */
+static int routers_with_measured_bw = 0;
+
static void directory_remove_invalid(void);
static cached_dir_t *dirserv_regenerate_directory(void);
static char *format_versions_list(config_line_t *ln);
@@ -79,10 +90,10 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp(
const char *fp,
int extrainfo,
time_t publish_cutoff);
-static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg);
-
-/************** Measured Bandwidth parsing code ******/
-#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
+static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
+ const char **msg);
+static uint32_t dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri);
+static uint32_t dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri);
/************** Fingerprint handling code ************/
@@ -388,18 +399,18 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
strmap_size(fingerprint_list->fp_by_name),
digestmap_size(fingerprint_list->status_by_digest));
- /* Versions before Tor 0.2.1.30 have known security issues that
+ /* Versions before Tor 0.2.2.35 have known security issues that
* make them unsuitable for the current network. */
- if (platform && !tor_version_as_new_as(platform,"0.2.1.30")) {
+ if (platform && !tor_version_as_new_as(platform,"0.2.2.35")) {
if (msg)
- *msg = "Tor version is insecure. Please upgrade!";
+ *msg = "Tor version is insecure or unsupported. Please upgrade!";
return FP_REJECT;
- } else if (platform && tor_version_as_new_as(platform,"0.2.2.1-alpha")) {
- /* Versions from 0.2.2.1-alpha...0.2.2.20-alpha have known security
+ } else if (platform && tor_version_as_new_as(platform,"0.2.3.0-alpha")) {
+ /* Versions from 0.2.3-alpha...0.2.3.9-alpha have known security
* issues that make them unusable for the current network */
- if (!tor_version_as_new_as(platform, "0.2.2.21-alpha")) {
+ if (!tor_version_as_new_as(platform, "0.2.3.10-alpha")) {
if (msg)
- *msg = "Tor version is insecure. Please upgrade!";
+ *msg = "Tor version is insecure or unsupported. Please upgrade!";
return FP_REJECT;
}
}
@@ -501,8 +512,8 @@ dirserv_free_fingerprint_list(void)
if (!fingerprint_list)
return;
- strmap_free(fingerprint_list->fp_by_name, _tor_free);
- digestmap_free(fingerprint_list->status_by_digest, _tor_free);
+ strmap_free(fingerprint_list->fp_by_name, tor_free_);
+ digestmap_free(fingerprint_list->status_by_digest, tor_free_);
tor_free(fingerprint_list);
}
@@ -717,7 +728,7 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
"MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.",
ri->nickname, source, (int)ri->cache_info.signed_descriptor_len,
MAX_DESCRIPTOR_UPLOAD_SIZE);
- *msg = "Router descriptor was too large";
+ *msg = "Router descriptor was too large.";
control_event_or_authdir_new_descriptor("REJECTED",
ri->cache_info.signed_descriptor_body,
ri->cache_info.signed_descriptor_len, *msg);
@@ -980,6 +991,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
unreachable.
*/
int answer;
+ const or_options_t *options = get_options();
node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest);
tor_assert(node);
@@ -988,17 +1000,27 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
answer = ! we_are_hibernating();
} else if (router->is_hibernating &&
(router->cache_info.published_on +
- HIBERNATION_PUBLICATION_SKEW) > router->last_reachable) {
+ HIBERNATION_PUBLICATION_SKEW) > node->last_reachable) {
/* A hibernating router is down unless we (somehow) had contact with it
* since it declared itself to be hibernating. */
answer = 0;
- } else if (get_options()->AssumeReachable) {
+ } else if (options->AssumeReachable) {
/* If AssumeReachable, everybody is up unless they say they are down! */
answer = 1;
} else {
- /* Otherwise, a router counts as up if we found it reachable in the last
- REACHABLE_TIMEOUT seconds. */
- answer = (now < router->last_reachable + REACHABLE_TIMEOUT);
+ /* Otherwise, a router counts as up if we found all announced OR
+ ports reachable in the last REACHABLE_TIMEOUT seconds.
+
+ XXX prop186 For now there's always one IPv4 and at most one
+ IPv6 OR port.
+
+ If we're not on IPv6, don't consider reachability of potential
+ IPv6 OR port since that'd kill all dual stack relays until a
+ majority of the dir auths have IPv6 connectivity. */
+ answer = (now < node->last_reachable + REACHABLE_TIMEOUT &&
+ (options->AuthDirHasIPv6Connectivity != 1 ||
+ tor_addr_is_null(&router->ipv6_addr) ||
+ now < node->last_reachable6 + REACHABLE_TIMEOUT));
}
if (!answer && running_long_enough_to_decide_unreachable()) {
@@ -1008,11 +1030,13 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
REACHABILITY_TEST_CYCLE_PERIOD seconds, then the router has probably
been down since at least that time after we last successfully reached
it.
+
+ XXX ipv6
*/
time_t when = now;
- if (router->last_reachable &&
- router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
- when = router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
+ if (node->last_reachable &&
+ node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
+ when = node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
rep_hist_note_router_unreachable(router->cache_info.identity_digest, when);
}
@@ -1117,6 +1141,8 @@ int
dirserv_dump_directory_to_string(char **dir_out,
crypto_pk_t *private_key)
{
+ /* XXXX 024 Get rid of this function if we can confirm that nobody's
+ * fetching these any longer */
char *cp;
char *identity_pkey; /* Identity key, DER64-encoded. */
char *recommended_versions;
@@ -1399,7 +1425,7 @@ clear_cached_dir(cached_dir_t *d)
/** Free all storage held by the cached_dir_t in <b>d</b>. */
static void
-_free_cached_dir(void *_d)
+free_cached_dir_(void *_d)
{
cached_dir_t *d;
if (!_d)
@@ -1417,21 +1443,12 @@ _free_cached_dir(void *_d)
* If <b>is_running_routers</b>, this is really a v1 running_routers
* document rather than a v1 directory.
*/
-void
-dirserv_set_cached_directory(const char *directory, time_t published,
- int is_running_routers)
+static void
+dirserv_set_cached_directory(const char *directory, time_t published)
{
- time_t now = time(NULL);
- if (is_running_routers) {
- if (published >= now - MAX_V1_RR_AGE)
- set_cached_dir(&cached_runningrouters, tor_strdup(directory), published);
- } else {
- if (published >= now - MAX_V1_DIRECTORY_AGE) {
- cached_dir_decref(cached_directory);
- cached_directory = new_cached_dir(tor_strdup(directory), published);
- }
- }
+ cached_dir_decref(cached_directory);
+ cached_directory = new_cached_dir(tor_strdup(directory), published);
}
/** If <b>networkstatus</b> is non-NULL, we've just received a v2
@@ -1448,7 +1465,6 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
time_t published)
{
cached_dir_t *d, *old_d;
- smartlist_t *trusted_dirs;
if (!cached_v2_networkstatus)
cached_v2_networkstatus = digestmap_new();
@@ -1471,9 +1487,9 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
}
/* Now purge old entries. */
- trusted_dirs = router_get_trusted_dir_servers();
+
if (digestmap_size(cached_v2_networkstatus) >
- smartlist_len(trusted_dirs) + MAX_UNTRUSTED_NETWORKSTATUSES) {
+ get_n_authorities(V2_DIRINFO) + MAX_UNTRUSTED_NETWORKSTATUSES) {
/* We need to remove the oldest untrusted networkstatus. */
const char *oldest = NULL;
time_t oldest_published = TIME_MAX;
@@ -1613,6 +1629,8 @@ dirserv_get_directory(void)
static cached_dir_t *
dirserv_regenerate_directory(void)
{
+ /* XXXX 024 Get rid of this function if we can confirm that nobody's
+ * fetching these any longer */
char *new_directory=NULL;
if (dirserv_dump_directory_to_string(&new_directory,
@@ -1632,7 +1650,7 @@ dirserv_regenerate_directory(void)
/* Save the directory to disk so we re-load it quickly on startup.
*/
- dirserv_set_cached_directory(the_directory->dir, time(NULL), 0);
+ dirserv_set_cached_directory(the_directory->dir, time(NULL));
return the_directory;
}
@@ -1758,17 +1776,13 @@ static double guard_wfu = 0.0;
* many seconds. */
static long guard_tk = 0;
/** Any router with a bandwidth at least this high is "Fast" */
-static uint32_t fast_bandwidth = 0;
+static uint32_t fast_bandwidth_kb = 0;
/** If exits can be guards, then all guards must have a bandwidth this
* high. */
-static uint32_t guard_bandwidth_including_exits = 0;
+static uint32_t guard_bandwidth_including_exits_kb = 0;
/** If exits can't be guards, then all guards must have a bandwidth this
* high. */
-static uint32_t guard_bandwidth_excluding_exits = 0;
-/** Total bandwidth of all the routers we're considering. */
-static uint64_t total_bandwidth = 0;
-/** Total bandwidth of all the exit routers we're considering. */
-static uint64_t total_exit_bandwidth = 0;
+static uint32_t guard_bandwidth_excluding_exits_kb = 0;
/** Helper: estimate the uptime of a router given its stated uptime and the
* amount of time since it last stated its stated uptime. */
@@ -1812,8 +1826,8 @@ dirserv_thinks_router_is_unreliable(time_t now,
}
}
if (need_capacity) {
- uint32_t bw = router_get_advertised_bandwidth(router);
- if (bw < fast_bandwidth)
+ uint32_t bw_kb = dirserv_get_credible_bandwidth_kb(router);
+ if (bw_kb < fast_bandwidth_kb)
return 1;
}
return 0;
@@ -1859,34 +1873,67 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
node->is_running);
}
+/** Don't consider routers with less bandwidth than this when computing
+ * thresholds. */
+#define ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB 4
+
+/** Helper for dirserv_compute_performance_thresholds(): Decide whether to
+ * include a router in our calculations, and return true iff we should; the
+ * require_mbw parameter is passed in by
+ * dirserv_compute_performance_thresholds() and controls whether we ever
+ * count routers with only advertised bandwidths */
+static int
+router_counts_toward_thresholds(const node_t *node, time_t now,
+ const digestmap_t *omit_as_sybil,
+ int require_mbw)
+{
+ /* Have measured bw? */
+ int have_mbw =
+ dirserv_has_measured_bw(node->identity);
+ uint64_t min_bw_kb = ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB;
+ const or_options_t *options = get_options();
+
+ if (options->TestingTorNetwork) {
+ min_bw_kb = (int64_t)options->TestingMinExitFlagThreshold / 1000;
+ }
+
+ return node->ri && router_is_active(node->ri, node, now) &&
+ !digestmap_get(omit_as_sybil, node->identity) &&
+ (dirserv_get_credible_bandwidth_kb(node->ri) >= min_bw_kb) &&
+ (have_mbw || !require_mbw);
+}
+
/** Look through the routerlist, the Mean Time Between Failure history, and
* the Weighted Fractional Uptime history, and use them to set thresholds for
* the Stable, Fast, and Guard flags. Update the fields stable_uptime,
* stable_mtbf, enough_mtbf_info, guard_wfu, guard_tk, fast_bandwidth,
* guard_bandwidh_including_exits, guard_bandwidth_excluding_exits,
- * total_bandwidth, and total_exit_bandwidth.
*
* Also, set the is_exit flag of each router appropriately. */
static void
-dirserv_compute_performance_thresholds(routerlist_t *rl)
+dirserv_compute_performance_thresholds(routerlist_t *rl,
+ digestmap_t *omit_as_sybil)
{
int n_active, n_active_nonexit, n_familiar;
- uint32_t *uptimes, *bandwidths, *bandwidths_excluding_exits;
+ uint32_t *uptimes, *bandwidths_kb, *bandwidths_excluding_exits_kb;
long *tks;
double *mtbfs, *wfus;
time_t now = time(NULL);
const or_options_t *options = get_options();
+ /* Require mbw? */
+ int require_mbw =
+ (routers_with_measured_bw >
+ options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0;
+
/* initialize these all here, in case there are no routers */
stable_uptime = 0;
stable_mtbf = 0;
- fast_bandwidth = 0;
- guard_bandwidth_including_exits = 0;
- guard_bandwidth_excluding_exits = 0;
+ fast_bandwidth_kb = 0;
+ guard_bandwidth_including_exits_kb = 0;
+ guard_bandwidth_excluding_exits_kb = 0;
guard_tk = 0;
guard_wfu = 0;
- total_bandwidth = 0;
- total_exit_bandwidth = 0;
/* Initialize arrays that will hold values for each router. We'll
* sort them and use that to compute thresholds. */
@@ -1894,9 +1941,9 @@ dirserv_compute_performance_thresholds(routerlist_t *rl)
/* Uptime for every active router. */
uptimes = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
/* Bandwidth for every active router. */
- bandwidths = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
+ bandwidths_kb = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
/* Bandwidth for every active non-exit router. */
- bandwidths_excluding_exits =
+ bandwidths_excluding_exits_kb =
tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
/* Weighted mean time between failure for each active router. */
mtbfs = tor_malloc(sizeof(double)*smartlist_len(rl->routers));
@@ -1909,21 +1956,19 @@ dirserv_compute_performance_thresholds(routerlist_t *rl)
/* Now, fill in the arrays. */
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) {
- routerinfo_t *ri = node->ri;
- if (ri && router_is_active(ri, node, now)) {
- const char *id = ri->cache_info.identity_digest;
- uint32_t bw;
+ if (router_counts_toward_thresholds(node, now, omit_as_sybil,
+ require_mbw)) {
+ routerinfo_t *ri = node->ri;
+ const char *id = node->identity;
+ uint32_t bw_kb;
node->is_exit = (!router_exit_policy_rejects_all(ri) &&
exit_policy_is_general_exit(ri->exit_policy));
uptimes[n_active] = (uint32_t)real_uptime(ri, now);
mtbfs[n_active] = rep_hist_get_stability(id, now);
tks [n_active] = rep_hist_get_weighted_time_known(id, now);
- bandwidths[n_active] = bw = router_get_advertised_bandwidth(ri);
- total_bandwidth += bw;
- if (node->is_exit && !node->is_bad_exit) {
- total_exit_bandwidth += bw;
- } else {
- bandwidths_excluding_exits[n_active_nonexit] = bw;
+ bandwidths_kb[n_active] = bw_kb = dirserv_get_credible_bandwidth_kb(ri);
+ if (!node->is_exit || node->is_bad_exit) {
+ bandwidths_excluding_exits_kb[n_active_nonexit] = bw_kb;
++n_active_nonexit;
}
++n_active;
@@ -1937,11 +1982,11 @@ dirserv_compute_performance_thresholds(routerlist_t *rl)
/* The median mtbf is stable, if we have enough mtbf info */
stable_mtbf = median_double(mtbfs, n_active);
/* The 12.5th percentile bandwidth is fast. */
- fast_bandwidth = find_nth_uint32(bandwidths, n_active, n_active/8);
+ fast_bandwidth_kb = find_nth_uint32(bandwidths_kb, n_active, n_active/8);
/* (Now bandwidths is sorted.) */
- if (fast_bandwidth < ROUTER_REQUIRED_MIN_BANDWIDTH/2)
- fast_bandwidth = bandwidths[n_active/4];
- guard_bandwidth_including_exits = bandwidths[(n_active-1)/2];
+ if (fast_bandwidth_kb < ROUTER_REQUIRED_MIN_BANDWIDTH/(2 * 1000))
+ fast_bandwidth_kb = bandwidths_kb[n_active/4];
+ guard_bandwidth_including_exits_kb = bandwidths_kb[(n_active-1)/2];
guard_tk = find_nth_long(tks, n_active, n_active/8);
}
@@ -1950,29 +1995,39 @@ dirserv_compute_performance_thresholds(routerlist_t *rl)
{
/* We can vote on a parameter for the minimum and maximum. */
- int32_t min_fast, max_fast;
+#define ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG 4
+ int32_t min_fast_kb, max_fast_kb, min_fast, max_fast;
min_fast = networkstatus_get_param(NULL, "FastFlagMinThreshold",
- 0, 0, INT32_MAX);
+ ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG,
+ ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG,
+ INT32_MAX);
+ if (options->TestingTorNetwork) {
+ min_fast = (int32_t)options->TestingMinFastFlagThreshold;
+ }
max_fast = networkstatus_get_param(NULL, "FastFlagMaxThreshold",
INT32_MAX, min_fast, INT32_MAX);
- if (fast_bandwidth < (uint32_t)min_fast)
- fast_bandwidth = min_fast;
- if (fast_bandwidth > (uint32_t)max_fast)
- fast_bandwidth = max_fast;
+ min_fast_kb = min_fast / 1000;
+ max_fast_kb = max_fast / 1000;
+
+ if (fast_bandwidth_kb < (uint32_t)min_fast_kb)
+ fast_bandwidth_kb = min_fast_kb;
+ if (fast_bandwidth_kb > (uint32_t)max_fast_kb)
+ fast_bandwidth_kb = max_fast_kb;
}
/* Protect sufficiently fast nodes from being pushed out of the set
* of Fast nodes. */
if (options->AuthDirFastGuarantee &&
- fast_bandwidth > options->AuthDirFastGuarantee)
- fast_bandwidth = (uint32_t)options->AuthDirFastGuarantee;
+ fast_bandwidth_kb > options->AuthDirFastGuarantee/1000)
+ fast_bandwidth_kb = (uint32_t)options->AuthDirFastGuarantee/1000;
/* Now that we have a time-known that 7/8 routers are known longer than,
* fill wfus with the wfu of every such "familiar" router. */
n_familiar = 0;
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) {
- routerinfo_t *ri = node->ri;
- if (ri && router_is_active(ri, node, now)) {
+ if (router_counts_toward_thresholds(node, now,
+ omit_as_sybil, require_mbw)) {
+ routerinfo_t *ri = node->ri;
const char *id = ri->cache_info.identity_digest;
long tk = rep_hist_get_weighted_time_known(id, now);
if (tk < guard_tk)
@@ -1988,32 +2043,259 @@ dirserv_compute_performance_thresholds(routerlist_t *rl)
enough_mtbf_info = rep_hist_have_measured_enough_stability();
if (n_active_nonexit) {
- guard_bandwidth_excluding_exits =
- median_uint32(bandwidths_excluding_exits, n_active_nonexit);
+ guard_bandwidth_excluding_exits_kb =
+ median_uint32(bandwidths_excluding_exits_kb, n_active_nonexit);
}
- log(LOG_INFO, LD_DIRSERV,
+ log_info(LD_DIRSERV,
"Cutoffs: For Stable, %lu sec uptime, %lu sec MTBF. "
- "For Fast: %lu bytes/sec. "
+ "For Fast: %lu kilobytes/sec. "
"For Guard: WFU %.03f%%, time-known %lu sec, "
- "and bandwidth %lu or %lu bytes/sec. We%s have enough stability data.",
+ "and bandwidth %lu or %lu kilobytes/sec. "
+ "We%s have enough stability data.",
(unsigned long)stable_uptime,
(unsigned long)stable_mtbf,
- (unsigned long)fast_bandwidth,
+ (unsigned long)fast_bandwidth_kb,
guard_wfu*100,
(unsigned long)guard_tk,
- (unsigned long)guard_bandwidth_including_exits,
- (unsigned long)guard_bandwidth_excluding_exits,
+ (unsigned long)guard_bandwidth_including_exits_kb,
+ (unsigned long)guard_bandwidth_excluding_exits_kb,
enough_mtbf_info ? "" : " don't ");
tor_free(uptimes);
tor_free(mtbfs);
- tor_free(bandwidths);
- tor_free(bandwidths_excluding_exits);
+ tor_free(bandwidths_kb);
+ tor_free(bandwidths_excluding_exits_kb);
tor_free(tks);
tor_free(wfus);
}
+/** Measured bandwidth cache entry */
+typedef struct mbw_cache_entry_s {
+ long mbw_kb;
+ time_t as_of;
+} mbw_cache_entry_t;
+
+/** Measured bandwidth cache - keys are identity_digests, values are
+ * mbw_cache_entry_t *. */
+static digestmap_t *mbw_cache = NULL;
+
+/** Store a measured bandwidth cache entry when reading the measured
+ * bandwidths file. */
+void
+dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
+ time_t as_of)
+{
+ mbw_cache_entry_t *e = NULL;
+
+ tor_assert(parsed_line);
+
+ /* Allocate a cache if we need */
+ if (!mbw_cache) mbw_cache = digestmap_new();
+
+ /* Check if we have an existing entry */
+ e = digestmap_get(mbw_cache, parsed_line->node_id);
+ /* If we do, we can re-use it */
+ if (e) {
+ /* Check that we really are newer, and update */
+ if (as_of > e->as_of) {
+ e->mbw_kb = parsed_line->bw_kb;
+ e->as_of = as_of;
+ }
+ } else {
+ /* We'll have to insert a new entry */
+ e = tor_malloc(sizeof(*e));
+ e->mbw_kb = parsed_line->bw_kb;
+ e->as_of = as_of;
+ digestmap_set(mbw_cache, parsed_line->node_id, e);
+ }
+}
+
+/** Clear and free the measured bandwidth cache */
+void
+dirserv_clear_measured_bw_cache(void)
+{
+ if (mbw_cache) {
+ /* Free the map and all entries */
+ digestmap_free(mbw_cache, tor_free_);
+ mbw_cache = NULL;
+ }
+}
+
+/** Scan the measured bandwidth cache and remove expired entries */
+void
+dirserv_expire_measured_bw_cache(time_t now)
+{
+
+ if (mbw_cache) {
+ /* Iterate through the cache and check each entry */
+ DIGESTMAP_FOREACH_MODIFY(mbw_cache, k, mbw_cache_entry_t *, e) {
+ if (now > e->as_of + MAX_MEASUREMENT_AGE) {
+ tor_free(e);
+ MAP_DEL_CURRENT(k);
+ }
+ } DIGESTMAP_FOREACH_END;
+
+ /* Check if we cleared the whole thing and free if so */
+ if (digestmap_size(mbw_cache) == 0) {
+ digestmap_free(mbw_cache, tor_free_);
+ mbw_cache = 0;
+ }
+ }
+}
+
+/** Get the current size of the measured bandwidth cache */
+int
+dirserv_get_measured_bw_cache_size(void)
+{
+ if (mbw_cache) return digestmap_size(mbw_cache);
+ else return 0;
+}
+
+/** Query the cache by identity digest, return value indicates whether
+ * we found it. The bw_out and as_of_out pointers receive the cached
+ * bandwidth value and the time it was cached if not NULL. */
+int
+dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out,
+ time_t *as_of_out)
+{
+ mbw_cache_entry_t *v = NULL;
+ int rv = 0;
+
+ if (mbw_cache && node_id) {
+ v = digestmap_get(mbw_cache, node_id);
+ if (v) {
+ /* Found something */
+ rv = 1;
+ if (bw_kb_out) *bw_kb_out = v->mbw_kb;
+ if (as_of_out) *as_of_out = v->as_of;
+ }
+ }
+
+ return rv;
+}
+
+/** Predicate wrapper for dirserv_query_measured_bw_cache() */
+int
+dirserv_has_measured_bw(const char *node_id)
+{
+ return dirserv_query_measured_bw_cache_kb(node_id, NULL, NULL);
+}
+
+/** Get the best estimate of a router's bandwidth for dirauth purposes,
+ * preferring measured to advertised values if available. */
+
+static uint32_t
+dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri)
+{
+ uint32_t bw_kb = 0;
+ /*
+ * Yeah, measured bandwidths in measured_bw_line_t are (implicitly
+ * signed) longs and the ones router_get_advertised_bandwidth() returns
+ * are uint32_t.
+ */
+ long mbw_kb = 0;
+
+ if (ri) {
+ /*
+ * * First try to see if we have a measured bandwidth; don't bother with
+ * as_of_out here, on the theory that a stale measured bandwidth is still
+ * better to trust than an advertised one.
+ */
+ if (dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest,
+ &mbw_kb, NULL)) {
+ /* Got one! */
+ bw_kb = (uint32_t)mbw_kb;
+ } else {
+ /* If not, fall back to advertised */
+ bw_kb = router_get_advertised_bandwidth(ri) / 1000;
+ }
+ }
+
+ return bw_kb;
+}
+
+/** Look through the routerlist, and using the measured bandwidth cache count
+ * how many measured bandwidths we know. This is used to decide whether we
+ * ever trust advertised bandwidths for purposes of assigning flags. */
+static void
+dirserv_count_measured_bws(routerlist_t *rl)
+{
+ /* Initialize this first */
+ routers_with_measured_bw = 0;
+
+ tor_assert(rl);
+ tor_assert(rl->routers);
+
+ /* Iterate over the routerlist and count measured bandwidths */
+ SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) {
+ /* Check if we know a measured bandwidth for this one */
+ if (dirserv_has_measured_bw(ri->cache_info.identity_digest)) {
+ ++routers_with_measured_bw;
+ }
+ } SMARTLIST_FOREACH_END(ri);
+}
+
+/** Return the bandwidth we believe for assigning flags; prefer measured
+ * over advertised, and if we have above a threshold quantity of measured
+ * bandwidths, we don't want to ever give flags to unmeasured routers, so
+ * return 0. */
+static uint32_t
+dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri)
+{
+ int threshold;
+ uint32_t bw_kb = 0;
+ long mbw_kb;
+
+ tor_assert(ri);
+ /* Check if we have a measured bandwidth, and check the threshold if not */
+ if (!(dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest,
+ &mbw_kb, NULL))) {
+ threshold = get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
+ if (routers_with_measured_bw > threshold) {
+ /* Return zero for unmeasured bandwidth if we are above threshold */
+ bw_kb = 0;
+ } else {
+ /* Return an advertised bandwidth otherwise */
+ bw_kb = router_get_advertised_bandwidth_capped(ri) / 1000;
+ }
+ } else {
+ /* We have the measured bandwidth in mbw */
+ bw_kb = (uint32_t)mbw_kb;
+ }
+
+ return bw_kb;
+}
+
+/** Give a statement of our current performance thresholds for inclusion
+ * in a vote document. */
+char *
+dirserv_get_flag_thresholds_line(void)
+{
+ char *result=NULL;
+ const int measured_threshold =
+ get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
+ const int enough_measured_bw = routers_with_measured_bw > measured_threshold;
+
+ tor_asprintf(&result,
+ "stable-uptime=%lu stable-mtbf=%lu "
+ "fast-speed=%lu "
+ "guard-wfu=%.03f%% guard-tk=%lu "
+ "guard-bw-inc-exits=%lu guard-bw-exc-exits=%lu "
+ "enough-mtbf=%d ignoring-advertised-bws=%d",
+ (unsigned long)stable_uptime,
+ (unsigned long)stable_mtbf,
+ (unsigned long)fast_bandwidth_kb*1000,
+ guard_wfu*100,
+ (unsigned long)guard_tk,
+ (unsigned long)guard_bandwidth_including_exits_kb*1000,
+ (unsigned long)guard_bandwidth_excluding_exits_kb*1000,
+ enough_mtbf_info ? 1 : 0,
+ enough_measured_bw ? 1 : 0);
+
+ return result;
+}
+
/** Given a platform string as in a routerinfo_t (possibly null), return a
* newly allocated version string for a networkstatus document, or NULL if the
* platform doesn't give a Tor version. */
@@ -2034,38 +2316,39 @@ version_from_platform(const char *platform)
return NULL;
}
-/** Helper: write the router-status information in <b>rs</b> into <b>buf</b>,
- * which has at least <b>buf_len</b> free characters. Do NUL-termination.
- * Use the same format as in network-status documents. If <b>version</b> is
- * non-NULL, add a "v" line for the platform. Return 0 on success, -1 on
- * failure.
+/** Helper: write the router-status information in <b>rs</b> into a newly
+ * allocated character buffer. Use the same format as in network-status
+ * documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
+ * Return 0 on success, -1 on failure.
*
- * The format argument has three possible values:
+ * The format argument has one of the following values:
* NS_V2 - Output an entry suitable for a V2 NS opinion document
* NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
* NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
* consensus entry.
- * NS_V3_VOTE - Output a complete V3 NS vote
+ * NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
+ * it contains additional information for the vote.
* NS_CONTROL_PORT - Output a NS document for the control port
*/
-int
-routerstatus_format_entry(char *buf, size_t buf_len,
- const routerstatus_t *rs, const char *version,
- routerstatus_format_type_t format)
+char *
+routerstatus_format_entry(const routerstatus_t *rs, const char *version,
+ routerstatus_format_type_t format,
+ const vote_routerstatus_t *vrs)
{
- int r;
- char *cp;
char *summary;
+ char *result = NULL;
char published[ISO_TIME_LEN+1];
char identity64[BASE64_DIGEST_LEN+1];
char digest64[BASE64_DIGEST_LEN+1];
+ smartlist_t *chunks = NULL;
format_iso_time(published, rs->published_on);
digest_to_base64(identity64, rs->identity_digest);
digest_to_base64(digest64, rs->descriptor_digest);
- r = tor_snprintf(buf, buf_len,
+ chunks = smartlist_new();
+ smartlist_add_asprintf(chunks,
"r %s %s %s%s%s %s %d %d\n",
rs->nickname,
identity64,
@@ -2075,21 +2358,26 @@ routerstatus_format_entry(char *buf, size_t buf_len,
fmt_addr32(rs->addr),
(int)rs->or_port,
(int)rs->dir_port);
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer.");
- return -1;
- }
/* TODO: Maybe we want to pass in what we need to build the rest of
* this here, instead of in the caller. Then we could use the
* networkstatus_type_t values, with an additional control port value
* added -MP */
- if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
- return 0;
- cp = buf + strlen(buf);
- /* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/
- r = tor_snprintf(cp, buf_len - (cp-buf),
+ /* V3 microdesc consensuses don't have "a" lines. */
+ if (format == NS_V3_CONSENSUS_MICRODESC)
+ goto done;
+
+ /* Possible "a" line. At most one for now. */
+ if (!tor_addr_is_null(&rs->ipv6_addr)) {
+ smartlist_add_asprintf(chunks, "a %s\n",
+ fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
+ }
+
+ if (format == NS_V3_CONSENSUS)
+ goto done;
+
+ smartlist_add_asprintf(chunks,
"s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
/* These must stay in alphabetical order. */
rs->is_authority?" Authority":"",
@@ -2105,25 +2393,16 @@ routerstatus_format_entry(char *buf, size_t buf_len,
rs->is_unnamed?" Unnamed":"",
rs->is_v2_dir?" V2Dir":"",
rs->is_valid?" Valid":"");
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer.");
- return -1;
- }
- cp += strlen(cp);
/* length of "opt v \n" */
#define V_LINE_OVERHEAD 7
if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
- if (tor_snprintf(cp, buf_len - (cp-buf), "opt v %s\n", version)<0) {
- log_warn(LD_BUG, "Unable to print router version.");
- return -1;
- }
- cp += strlen(cp);
+ smartlist_add_asprintf(chunks, "v %s\n", version);
}
if (format != NS_V2) {
const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
- uint32_t bw;
+ uint32_t bw_kb;
if (format != NS_CONTROL_PORT) {
/* Blow up more or less nicely if we didn't get anything or not the
@@ -2138,12 +2417,13 @@ routerstatus_format_entry(char *buf, size_t buf_len,
log_warn(LD_BUG, "Cannot get any descriptor for %s "
"(wanted descriptor %s).",
id, dd);
- return -1;
- };
+ goto err;
+ }
- /* This assert can fire for the control port, because
+ /* This assert could fire for the control port, because
* it can request NS documents before all descriptors
- * have been fetched. */
+ * have been fetched. Therefore, we only do this test when
+ * format != NS_CONTROL_PORT. */
if (tor_memneq(desc->cache_info.signed_descriptor_digest,
rs->descriptor_digest,
DIGEST_LEN)) {
@@ -2163,48 +2443,41 @@ routerstatus_format_entry(char *buf, size_t buf_len,
tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest,
rs->descriptor_digest,
DIGEST_LEN));
- };
+ }
}
if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
- bw = rs->bandwidth;
+ bw_kb = rs->bandwidth_kb;
} else {
tor_assert(desc);
- bw = router_get_advertised_bandwidth_capped(desc) / 1000;
+ bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
}
- r = tor_snprintf(cp, buf_len - (cp-buf),
- "w Bandwidth=%d\n", bw);
+ smartlist_add_asprintf(chunks,
+ "w Bandwidth=%d", bw_kb);
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer.");
- return -1;
- }
- cp += strlen(cp);
- if (format == NS_V3_VOTE && rs->has_measured_bw) {
- *--cp = '\0'; /* Kill "\n" */
- r = tor_snprintf(cp, buf_len - (cp-buf),
- " Measured=%d\n", rs->measured_bw);
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer for weight line.");
- return -1;
- }
- cp += strlen(cp);
+ if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
+ smartlist_add_asprintf(chunks,
+ " Measured=%d", vrs->measured_bw_kb);
}
+ smartlist_add(chunks, tor_strdup("\n"));
if (desc) {
- summary = policy_summarize(desc->exit_policy);
- r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary);
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer.");
- tor_free(summary);
- return -1;
- }
- cp += strlen(cp);
+ summary = policy_summarize(desc->exit_policy, AF_INET);
+ smartlist_add_asprintf(chunks, "p %s\n", summary);
tor_free(summary);
}
}
- return 0;
+ done:
+ result = smartlist_join_strings(chunks, "", 0, NULL);
+
+ err:
+ if (chunks) {
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+ }
+
+ return result;
}
/** Helper for sorting: compares two routerinfos first by address, and then by
@@ -2213,11 +2486,11 @@ routerstatus_format_entry(char *buf, size_t buf_len,
* and a router with more bandwidth is more useful than one with less.)
**/
static int
-_compare_routerinfo_by_ip_and_bw(const void **a, const void **b)
+compare_routerinfo_by_ip_and_bw_(const void **a, const void **b)
{
routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b;
int first_is_auth, second_is_auth;
- uint32_t bw_first, bw_second;
+ uint32_t bw_kb_first, bw_kb_second;
const node_t *node_first, *node_second;
int first_is_running, second_is_running;
@@ -2228,7 +2501,7 @@ _compare_routerinfo_by_ip_and_bw(const void **a, const void **b)
else if (first->addr > second->addr)
return 1;
- /* Potentially, this next bit could cause k n lg n memcmp calls. But in
+ /* Potentially, this next bit could cause k n lg n memeq calls. But in
* reality, we will almost never get here, since addresses will usually be
* different. */
@@ -2252,12 +2525,12 @@ _compare_routerinfo_by_ip_and_bw(const void **a, const void **b)
else if (!first_is_running && second_is_running)
return 1;
- bw_first = router_get_advertised_bandwidth(first);
- bw_second = router_get_advertised_bandwidth(second);
+ bw_kb_first = dirserv_get_bandwidth_for_router_kb(first);
+ bw_kb_second = dirserv_get_bandwidth_for_router_kb(second);
- if (bw_first > bw_second)
+ if (bw_kb_first > bw_kb_second)
return -1;
- else if (bw_first < bw_second)
+ else if (bw_kb_first < bw_kb_second)
return 1;
/* They're equal! Compare by identity digest, so there's a
@@ -2288,7 +2561,7 @@ get_possible_sybil_list(const smartlist_t *routers)
max_with_same_addr_on_authority = INT_MAX;
smartlist_add_all(routers_by_ip, routers);
- smartlist_sort(routers_by_ip, _compare_routerinfo_by_ip_and_bw);
+ smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_);
omit_as_sybil = digestmap_new();
last_addr = 0;
@@ -2393,9 +2666,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
int listbaddirs, int vote_on_hsdirs)
{
const or_options_t *options = get_options();
- int unstable_version =
- !tor_version_as_new_as(ri->platform,"0.1.1.16-rc-cvs");
- uint32_t routerbw = router_get_advertised_bandwidth(ri);
+ uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri);
memset(rs, 0, sizeof(routerstatus_t));
@@ -2406,8 +2677,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->is_exit = node->is_exit;
rs->is_stable = node->is_stable =
router_is_active(ri, node, now) &&
- !dirserv_thinks_router_is_unreliable(now, ri, 1, 0) &&
- !unstable_version;
+ !dirserv_thinks_router_is_unreliable(now, ri, 1, 0);
rs->is_fast = node->is_fast =
router_is_active(ri, node, now) &&
!dirserv_thinks_router_is_unreliable(now, ri, 0, 1);
@@ -2423,9 +2693,9 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
if (node->is_fast &&
((options->AuthDirGuardBWGuarantee &&
- routerbw >= options->AuthDirGuardBWGuarantee) ||
- routerbw >= MIN(guard_bandwidth_including_exits,
- guard_bandwidth_excluding_exits)) &&
+ routerbw_kb >= options->AuthDirGuardBWGuarantee/1000) ||
+ routerbw_kb >= MIN(guard_bandwidth_including_exits_kb,
+ guard_bandwidth_excluding_exits_kb)) &&
is_router_version_good_for_possible_guard(ri->platform)) {
long tk = rep_hist_get_weighted_time_known(
node->identity, now);
@@ -2453,6 +2723,14 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname));
rs->or_port = ri->or_port;
rs->dir_port = ri->dir_port;
+ if (options->AuthDirHasIPv6Connectivity == 1 &&
+ !tor_addr_is_null(&ri->ipv6_addr) &&
+ node->last_reachable6 >= now - REACHABLE_TIMEOUT) {
+ /* We're configured as having IPv6 connectivity. There's an IPv6
+ OR port and it's reachable so copy it to the routerstatus. */
+ tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr);
+ rs->ipv6_orport = ri->ipv6_orport;
+ }
}
/** Routerstatus <b>rs</b> is part of a group of routers that are on
@@ -2512,7 +2790,7 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
}
cp+=strlen("bw=");
- out->bw = tor_parse_long(cp, 0, 0, LONG_MAX, &parse_ok, &endptr);
+ out->bw_kb = tor_parse_long(cp, 0, 0, LONG_MAX, &parse_ok, &endptr);
if (!parse_ok || (*endptr && !TOR_ISSPACE(*endptr))) {
log_warn(LD_DIRSERV, "Invalid bandwidth in bandwidth file line: %s",
escaped(orig_line));
@@ -2561,16 +2839,16 @@ int
measured_bw_line_apply(measured_bw_line_t *parsed_line,
smartlist_t *routerstatuses)
{
- routerstatus_t *rs = NULL;
+ vote_routerstatus_t *rs = NULL;
if (!routerstatuses)
return 0;
rs = smartlist_bsearch(routerstatuses, parsed_line->node_id,
- compare_digest_to_routerstatus_entry);
+ compare_digest_to_vote_routerstatus_entry);
if (rs) {
rs->has_measured_bw = 1;
- rs->measured_bw = (uint32_t)parsed_line->bw;
+ rs->measured_bw_kb = (uint32_t)parsed_line->bw_kb;
} else {
log_info(LD_DIRSERV, "Node ID %s not found in routerstatus list",
parsed_line->node_hex);
@@ -2581,7 +2859,7 @@ measured_bw_line_apply(measured_bw_line_t *parsed_line,
/**
* Read the measured bandwidth file and apply it to the list of
- * routerstatuses. Returns -1 on error, 0 otherwise.
+ * vote_routerstatus_t. Returns -1 on error, 0 otherwise.
*/
int
dirserv_read_measured_bandwidths(const char *from_file,
@@ -2590,8 +2868,9 @@ dirserv_read_measured_bandwidths(const char *from_file,
char line[256];
FILE *fp = tor_fopen_cloexec(from_file, "r");
int applied_lines = 0;
- time_t file_time;
+ time_t file_time, now;
int ok;
+
if (fp == NULL) {
log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s",
from_file);
@@ -2615,7 +2894,8 @@ dirserv_read_measured_bandwidths(const char *from_file,
return -1;
}
- if ((time(NULL) - file_time) > MAX_MEASUREMENT_AGE) {
+ now = time(NULL);
+ if ((now - file_time) > MAX_MEASUREMENT_AGE) {
log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u",
(unsigned)(time(NULL) - file_time));
fclose(fp);
@@ -2623,18 +2903,23 @@ dirserv_read_measured_bandwidths(const char *from_file,
}
if (routerstatuses)
- smartlist_sort(routerstatuses, compare_routerstatus_entries);
+ smartlist_sort(routerstatuses, compare_vote_routerstatus_entries);
while (!feof(fp)) {
measured_bw_line_t parsed_line;
if (fgets(line, sizeof(line), fp) && strlen(line)) {
if (measured_bw_line_parse(&parsed_line, line) != -1) {
+ /* Also cache the line for dirserv_get_bandwidth_for_router() */
+ dirserv_cache_measured_bw(&parsed_line, file_time);
if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0)
applied_lines++;
}
}
}
+ /* Now would be a nice time to clean the cache, too */
+ dirserv_expire_measured_bw_cache(now);
+
fclose(fp);
log_info(LD_DIRSERV,
"Bandwidth measurement file successfully read. "
@@ -2672,11 +2957,11 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
tor_assert(private_key);
tor_assert(cert);
- if (resolve_my_address(LOG_WARN, options, &addr, &hostname)<0) {
+ if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) {
log_warn(LD_NET, "Couldn't resolve my hostname");
return NULL;
}
- if (!strchr(hostname, '.')) {
+ if (!hostname || !strchr(hostname, '.')) {
tor_free(hostname);
hostname = tor_dup_ip(addr);
}
@@ -2698,19 +2983,44 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
if (!contact)
contact = "(none)";
+ /*
+ * Do this so dirserv_compute_performance_thresholds() and
+ * set_routerstatus_from_routerinfo() see up-to-date bandwidth info.
+ */
+ if (options->V3BandwidthsFile) {
+ dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL);
+ } else {
+ /*
+ * No bandwidths file; clear the measured bandwidth cache in case we had
+ * one last time around.
+ */
+ if (dirserv_get_measured_bw_cache_size() > 0) {
+ dirserv_clear_measured_bw_cache();
+ }
+ }
+
/* precompute this part, since we need it to decide what "stable"
* means. */
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
dirserv_set_router_is_running(ri, now);
});
- dirserv_compute_performance_thresholds(rl);
-
routers = smartlist_new();
smartlist_add_all(routers, rl->routers);
routers_sort_by_identity(routers);
omit_as_sybil = get_possible_sybil_list(routers);
+ DIGESTMAP_FOREACH(omit_as_sybil, sybil_id, void *, ignore) {
+ (void) ignore;
+ rep_hist_make_router_pessimal(sybil_id, now);
+ } DIGESTMAP_FOREACH_END;
+
+ /* Count how many have measured bandwidths so we know how to assign flags;
+ * this must come before dirserv_compute_performance_thresholds() */
+ dirserv_count_measured_bws(rl);
+
+ dirserv_compute_performance_thresholds(rl, omit_as_sybil);
+
routerstatuses = smartlist_new();
microdescriptors = smartlist_new();
@@ -2718,7 +3028,6 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
if (ri->cache_info.published_on >= cutoff) {
routerstatus_t *rs;
vote_routerstatus_t *vrs;
- microdesc_t *md;
node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
if (!node)
continue;
@@ -2736,18 +3045,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
rs->is_flagged_running = 0;
vrs->version = version_from_platform(ri->platform);
- md = dirvote_create_microdescriptor(ri);
- if (md) {
- char buf[128];
- vote_microdesc_hash_t *h;
- dirvote_format_microdesc_vote_line(buf, sizeof(buf), md);
- h = tor_malloc(sizeof(vote_microdesc_hash_t));
- h->microdesc_hash_line = tor_strdup(buf);
- h->next = NULL;
- vrs->microdesc = h;
- md->last_listed = now;
- smartlist_add(microdescriptors, md);
- }
+ vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now,
+ microdescriptors);
smartlist_add(routerstatuses, vrs);
}
@@ -2764,9 +3063,18 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
smartlist_free(routers);
digestmap_free(omit_as_sybil, NULL);
+ /* This pass through applies the measured bw lines to the routerstatuses */
if (options->V3BandwidthsFile) {
dirserv_read_measured_bandwidths(options->V3BandwidthsFile,
routerstatuses);
+ } else {
+ /*
+ * No bandwidths file; clear the measured bandwidth cache in case we had
+ * one last time around.
+ */
+ if (dirserv_get_measured_bw_cache_size() > 0) {
+ dirserv_clear_measured_bw_cache();
+ }
}
v3_out = tor_malloc_zero(sizeof(networkstatus_t));
@@ -2859,14 +3167,13 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
/** For v2 authoritative directories only: Replace the contents of
* <b>the_v2_networkstatus</b> with a newly generated network status
* object. */
-static cached_dir_t *
+cached_dir_t *
generate_v2_networkstatus_opinion(void)
{
cached_dir_t *r = NULL;
- size_t len, identity_pkey_len;
+ size_t identity_pkey_len;
char *status = NULL, *client_versions = NULL, *server_versions = NULL,
*identity_pkey = NULL, *hostname = NULL;
- char *outp, *endp;
const or_options_t *options = get_options();
char fingerprint[FINGERPRINT_LEN+1];
char published[ISO_TIME_LEN+1];
@@ -2885,13 +3192,16 @@ generate_v2_networkstatus_opinion(void)
char *version_lines = NULL;
smartlist_t *routers = NULL;
digestmap_t *omit_as_sybil = NULL;
+ smartlist_t *chunks = NULL;
private_key = get_server_identity_key();
- if (resolve_my_address(LOG_WARN, options, &addr, &hostname)<0) {
+ if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) {
log_warn(LD_NET, "Couldn't resolve my hostname");
goto done;
}
+ if (!hostname)
+ hostname = tor_dup_ip(addr);
format_iso_time(published, now);
@@ -2921,12 +3231,8 @@ generate_v2_networkstatus_opinion(void)
version_lines = tor_strdup("");
}
- len = 4096+strlen(client_versions)+strlen(server_versions);
- len += identity_pkey_len*2;
- len += (RS_ENTRY_LEN)*smartlist_len(rl->routers);
-
- status = tor_malloc(len);
- tor_snprintf(status, len,
+ chunks = smartlist_new();
+ smartlist_add_asprintf(chunks,
"network-status-version 2\n"
"dir-source %s %s %d\n"
"fingerprint %s\n"
@@ -2946,8 +3252,6 @@ generate_v2_networkstatus_opinion(void)
versioning ? " Versions" : "",
version_lines,
identity_pkey);
- outp = status + strlen(status);
- endp = status + len;
/* precompute this part, since we need it to decide what "stable"
* means. */
@@ -2955,14 +3259,13 @@ generate_v2_networkstatus_opinion(void)
dirserv_set_router_is_running(ri, now);
});
- dirserv_compute_performance_thresholds(rl);
-
routers = smartlist_new();
smartlist_add_all(routers, rl->routers);
routers_sort_by_identity(routers);
-
omit_as_sybil = get_possible_sybil_list(routers);
+ dirserv_compute_performance_thresholds(rl, omit_as_sybil);
+
SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
if (ri->cache_info.published_on >= cutoff) {
routerstatus_t rs;
@@ -2979,34 +3282,33 @@ generate_v2_networkstatus_opinion(void)
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
clear_status_flags_on_sybil(&rs);
- if (routerstatus_format_entry(outp, endp-outp, &rs, version, NS_V2)) {
- log_warn(LD_BUG, "Unable to print router status.");
- tor_free(version);
- goto done;
+ {
+ char *rsf = routerstatus_format_entry(&rs, version, NS_V2, NULL);
+ if (rsf)
+ smartlist_add(chunks, rsf);
}
tor_free(version);
- outp += strlen(outp);
}
} SMARTLIST_FOREACH_END(ri);
- if (tor_snprintf(outp, endp-outp, "directory-signature %s\n",
- options->Nickname)<0) {
- log_warn(LD_BUG, "Unable to write signature line.");
- goto done;
- }
- if (router_get_networkstatus_v2_hash(status, digest)<0) {
- log_warn(LD_BUG, "Unable to hash network status");
- goto done;
- }
- outp += strlen(outp);
+ smartlist_add_asprintf(chunks, "directory-signature %s\n",
+ options->Nickname);
+
+ crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1);
note_crypto_pk_op(SIGN_DIR);
- if (router_append_dirobj_signature(outp,endp-outp,digest,DIGEST_LEN,
- private_key)<0) {
- log_warn(LD_BUG, "Unable to sign router status.");
- goto done;
+ {
+ char *sig;
+ if (!(sig = router_get_dirobj_signature(digest,DIGEST_LEN,
+ private_key))) {
+ log_warn(LD_BUG, "Unable to sign router status.");
+ goto done;
+ }
+ smartlist_add(chunks, sig);
}
+ status = smartlist_join_strings(chunks, "", 0, NULL);
+
{
networkstatus_v2_t *ns;
if (!(ns = networkstatus_v2_parse_from_string(status))) {
@@ -3028,6 +3330,10 @@ generate_v2_networkstatus_opinion(void)
}
done:
+ if (chunks) {
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+ }
tor_free(client_versions);
tor_free(server_versions);
tor_free(version_lines);
@@ -3074,7 +3380,7 @@ dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result,
}
} else {
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds,
+ dir_server_t *, ds,
if (ds->type & V2_DIRINFO)
smartlist_add(result, tor_memdup(ds->digest, DIGEST_LEN)));
}
@@ -3273,36 +3579,42 @@ dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
* Inform the reachability checker that we could get to this guy.
*/
void
-dirserv_orconn_tls_done(const char *address,
+dirserv_orconn_tls_done(const tor_addr_t *addr,
uint16_t or_port,
const char *digest_rcvd)
{
- routerinfo_t *ri;
+ node_t *node = NULL;
+ tor_addr_port_t orport;
+ routerinfo_t *ri = NULL;
time_t now = time(NULL);
- tor_assert(address);
+ tor_assert(addr);
tor_assert(digest_rcvd);
- ri = router_get_mutable_by_digest(digest_rcvd);
-
- if (ri == NULL)
+ node = node_get_mutable_by_id(digest_rcvd);
+ if (node == NULL || node->ri == NULL)
return;
+ ri = node->ri;
- if (!strcasecmp(address, ri->address) && or_port == ri->or_port) {
+ tor_addr_copy(&orport.addr, addr);
+ orport.port = or_port;
+ if (router_has_orport(ri, &orport)) {
/* Found the right router. */
if (!authdir_mode_bridge(get_options()) ||
ri->purpose == ROUTER_PURPOSE_BRIDGE) {
+ char addrstr[TOR_ADDR_BUF_LEN];
/* This is a bridge or we're not a bridge authorititative --
mark it as reachable. */
- tor_addr_t addr, *addrp=NULL;
log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.",
router_describe(ri),
- address, ri->or_port);
- if (tor_addr_parse(&addr, ri->address) != -1)
- addrp = &addr;
- else
- log_warn(LD_BUG, "Couldn't parse IP address \"%s\"", ri->address);
- rep_hist_note_router_reachable(digest_rcvd, addrp, or_port, now);
- ri->last_reachable = now;
+ tor_addr_to_str(addrstr, addr, sizeof(addrstr), 1),
+ ri->or_port);
+ if (tor_addr_family(addr) == AF_INET) {
+ rep_hist_note_router_reachable(digest_rcvd, addr, or_port, now);
+ node->last_reachable = now;
+ } else if (tor_addr_family(addr) == AF_INET6) {
+ /* No rephist for IPv6. */
+ node->last_reachable6 = now;
+ }
}
}
}
@@ -3325,7 +3637,7 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
/* It just came out of hibernation; launch a reachability test */
return 1;
}
- if (! routers_have_same_or_addr(ri, ri_old)) {
+ if (! routers_have_same_or_addrs(ri, ri_old)) {
/* Address or port changed; launch a reachability test */
return 1;
}
@@ -3338,15 +3650,35 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
void
dirserv_single_reachability_test(time_t now, routerinfo_t *router)
{
+ channel_t *chan = NULL;
+ node_t *node = NULL;
tor_addr_t router_addr;
+ (void) now;
+
+ tor_assert(router);
+ node = node_get_mutable_by_id(router->cache_info.identity_digest);
+ tor_assert(node);
+
+ /* IPv4. */
log_debug(LD_OR,"Testing reachability of %s at %s:%u.",
router->nickname, router->address, router->or_port);
- /* Remember when we started trying to determine reachability */
- if (!router->testing_since)
- router->testing_since = now;
tor_addr_from_ipv4h(&router_addr, router->addr);
- connection_or_connect(&router_addr, router->or_port,
- router->cache_info.identity_digest);
+ chan = channel_tls_connect(&router_addr, router->or_port,
+ router->cache_info.identity_digest);
+ if (chan) command_setup_channel(chan);
+
+ /* Possible IPv6. */
+ if (get_options()->AuthDirHasIPv6Connectivity == 1 &&
+ !tor_addr_is_null(&router->ipv6_addr)) {
+ char addrstr[TOR_ADDR_BUF_LEN];
+ log_debug(LD_OR, "Testing reachability of %s at %s:%u.",
+ router->nickname,
+ tor_addr_to_str(addrstr, &router->ipv6_addr, sizeof(addrstr), 1),
+ router->ipv6_orport);
+ chan = channel_tls_connect(&router->ipv6_addr, router->ipv6_orport,
+ router->cache_info.identity_digest);
+ if (chan) command_setup_channel(chan);
+ }
}
/** Auth dir server only: load balance such that we only
@@ -3649,7 +3981,7 @@ connection_dirserv_add_microdescs_to_outbuf(dir_connection_t *conn)
char *fp256 = smartlist_pop_last(conn->fingerprint_stack);
microdesc_t *md = microdesc_cache_lookup_by_digest256(cache, fp256);
tor_free(fp256);
- if (!md)
+ if (!md || !md->body)
continue;
if (conn->zlib_state) {
/* XXXX024 This 'last' business should actually happen on the last
@@ -3767,7 +4099,7 @@ connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn)
int
connection_dirserv_flushed_some(dir_connection_t *conn)
{
- tor_assert(conn->_base.state == DIR_CONN_STATE_SERVER_WRITING);
+ tor_assert(conn->base_.state == DIR_CONN_STATE_SERVER_WRITING);
if (connection_get_outbuf_len(TO_CONN(conn)) >= DIRSERV_BUFFER_MIN)
return 0;
@@ -3802,9 +4134,11 @@ dirserv_free_all(void)
cached_dir_decref(cached_directory);
clear_cached_dir(&cached_runningrouters);
- digestmap_free(cached_v2_networkstatus, _free_cached_dir);
+ digestmap_free(cached_v2_networkstatus, free_cached_dir_);
cached_v2_networkstatus = NULL;
- strmap_free(cached_consensuses, _free_cached_dir);
+ strmap_free(cached_consensuses, free_cached_dir_);
cached_consensuses = NULL;
+
+ dirserv_clear_measured_bw_cache();
}
diff --git a/src/or/dirserv.h b/src/or/dirserv.h
index 22269b200..f9d36d760 100644
--- a/src/or/dirserv.h
+++ b/src/or/dirserv.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for dirserv.c.
**/
-#ifndef _TOR_DIRSERV_H
-#define _TOR_DIRSERV_H
+#ifndef TOR_DIRSERV_H
+#define TOR_DIRSERV_H
/** What fraction (1 over this number) of the relay ID space do we
* (as a directory authority) launch connections to at each reachability
@@ -29,28 +29,6 @@
/** Maximum allowable length of a version line in a networkstatus. */
#define MAX_V_LINE_LEN 128
-/** Length of "r Authority BadDirectory BadExit Exit Fast Guard HSDir Named
- * Running Stable Unnamed V2Dir Valid\n". */
-#define MAX_FLAG_LINE_LEN 96
-/** Length of "w" line for weighting. Currently at most
- * "w Bandwidth=<uint32t> Measured=<uint32t>\n" */
-#define MAX_WEIGHT_LINE_LEN (12+10+10+10+1)
-/** Maximum length of an exit policy summary line. */
-#define MAX_POLICY_LINE_LEN (3+MAX_EXITPOLICY_SUMMARY_LEN)
-/** Amount of space to allocate for each entry: r, s, and v lines. */
-#define RS_ENTRY_LEN \
- ( /* first line */ \
- MAX_NICKNAME_LEN+BASE64_DIGEST_LEN*2+ISO_TIME_LEN+INET_NTOA_BUF_LEN+ \
- 5*2 /* ports */ + 10 /* punctuation */ + \
- /* second line */ \
- MAX_FLAG_LINE_LEN + \
- /* weight line */ \
- MAX_WEIGHT_LINE_LEN + \
- /* p line. */ \
- MAX_POLICY_LINE_LEN + \
- /* v line. */ \
- MAX_V_LINE_LEN \
- )
int connection_dirserv_flushed_some(dir_connection_t *conn);
@@ -70,12 +48,12 @@ int list_server_status_v1(smartlist_t *routers, char **router_status_out,
int for_controller);
int dirserv_dump_directory_to_string(char **dir_out,
crypto_pk_t *private_key);
+char *dirserv_get_flag_thresholds_line(void);
int directory_fetches_from_authorities(const or_options_t *options);
int directory_fetches_dir_info_early(const or_options_t *options);
int directory_fetches_dir_info_later(const or_options_t *options);
int directory_caches_v2_dir_info(const or_options_t *options);
-#define directory_caches_v1_dir_info(o) directory_caches_v2_dir_info(o)
int directory_caches_unknown_auth_certs(const or_options_t *options);
int directory_caches_dir_info(const or_options_t *options);
int directory_permits_begindir_requests(const or_options_t *options);
@@ -87,8 +65,6 @@ void directory_set_dirty(void);
cached_dir_t *dirserv_get_directory(void);
cached_dir_t *dirserv_get_runningrouters(void);
cached_dir_t *dirserv_get_consensus(const char *flavor_name);
-void dirserv_set_cached_directory(const char *directory, time_t when,
- int is_running_routers);
void dirserv_set_cached_networkstatus_v2(const char *directory,
const char *identity,
time_t published);
@@ -107,7 +83,7 @@ int dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key,
int is_extrainfo);
int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
const char **msg);
-void dirserv_orconn_tls_done(const char *address,
+void dirserv_orconn_tls_done(const tor_addr_t *addr,
uint16_t or_port,
const char *digest_rcvd);
int dirserv_should_launch_reachability_test(const routerinfo_t *ri,
@@ -130,18 +106,33 @@ size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs,
int compressed);
size_t dirserv_estimate_microdesc_size(const smartlist_t *fps, int compressed);
-int routerstatus_format_entry(char *buf, size_t buf_len,
+char *routerstatus_format_entry(
const routerstatus_t *rs, const char *platform,
- routerstatus_format_type_t format);
+ routerstatus_format_type_t format,
+ const vote_routerstatus_t *vrs);
void dirserv_free_all(void);
void cached_dir_decref(cached_dir_t *d);
cached_dir_t *new_cached_dir(char *s, time_t published);
#ifdef DIRSERV_PRIVATE
+
+/* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */
+#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
+
int measured_bw_line_parse(measured_bw_line_t *out, const char *line);
int measured_bw_line_apply(measured_bw_line_t *parsed_line,
smartlist_t *routerstatuses);
+
+void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
+ time_t as_of);
+void dirserv_clear_measured_bw_cache(void);
+void dirserv_expire_measured_bw_cache(time_t now);
+int dirserv_get_measured_bw_cache_size(void);
+int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_out,
+ time_t *as_of_out);
+int dirserv_has_measured_bw(const char *node_id);
+cached_dir_t *generate_v2_networkstatus_opinion(void);
#endif
int dirserv_read_measured_bandwidths(const char *from_file,
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 144859ae0..c6d124490 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DIRVOTE_PRIVATE
@@ -53,36 +53,10 @@ static int dirvote_compute_consensuses(void);
static int dirvote_publish_consensus(void);
static char *make_consensus_method_list(int low, int high, const char *sep);
-/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 13
-
-/** Lowest consensus method that contains a 'directory-footer' marker */
-#define MIN_METHOD_FOR_FOOTER 9
-
-/** Lowest consensus method that contains bandwidth weights */
-#define MIN_METHOD_FOR_BW_WEIGHTS 9
-
-/** Lowest consensus method that contains consensus params */
-#define MIN_METHOD_FOR_PARAMS 7
-
-/** Lowest consensus method that generates microdescriptors */
-#define MIN_METHOD_FOR_MICRODESC 8
-
-/** Lowest consensus method that ensures a majority of authorities voted
- * for a param. */
-#define MIN_METHOD_FOR_MAJORITY_PARAMS 12
-
-/** Lowest consensus method where microdesc consensuses omit any entry
- * with no microdesc. */
-#define MIN_METHOD_FOR_MANDATORY_MICRODESC 13
-
/* =====
* Voting
* =====*/
-/* Overestimated. */
-#define MICRODESC_LINE_LEN 80
-
/** Return a new string containing the string representation of the vote in
* <b>v3_ns</b>, signed with our v3 signing key <b>private_signing_key</b>.
* For v3 authorities. */
@@ -90,17 +64,14 @@ char *
format_networkstatus_vote(crypto_pk_t *private_signing_key,
networkstatus_t *v3_ns)
{
- size_t len;
- char *status = NULL;
+ smartlist_t *chunks;
const char *client_versions = NULL, *server_versions = NULL;
- char *outp, *endp;
char fingerprint[FINGERPRINT_LEN+1];
char digest[DIGEST_LEN];
uint32_t addr;
- routerlist_t *rl = router_get_routerlist();
- char *version_lines = NULL;
- int r;
+ char *client_versions_line = NULL, *server_versions_line = NULL;
networkstatus_voter_info_t *voter;
+ char *status = NULL;
tor_assert(private_signing_key);
tor_assert(v3_ns->type == NS_TYPE_VOTE || v3_ns->type == NS_TYPE_OPINION);
@@ -114,49 +85,28 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
client_versions = v3_ns->client_versions;
server_versions = v3_ns->server_versions;
- if (client_versions || server_versions) {
- size_t v_len = 64;
- char *cp;
- if (client_versions)
- v_len += strlen(client_versions);
- if (server_versions)
- v_len += strlen(server_versions);
- version_lines = tor_malloc(v_len);
- cp = version_lines;
- if (client_versions) {
- r = tor_snprintf(cp, v_len-(cp-version_lines),
- "client-versions %s\n", client_versions);
- if (r < 0) {
- log_err(LD_BUG, "Insufficient memory for client-versions line");
- tor_assert(0);
- }
- cp += strlen(cp);
- }
- if (server_versions) {
- r = tor_snprintf(cp, v_len-(cp-version_lines),
- "server-versions %s\n", server_versions);
- if (r < 0) {
- log_err(LD_BUG, "Insufficient memory for server-versions line");
- tor_assert(0);
- }
- }
+ if (client_versions) {
+ tor_asprintf(&client_versions_line, "client-versions %s\n",
+ client_versions);
} else {
- version_lines = tor_strdup("");
+ client_versions_line = tor_strdup("");
+ }
+ if (server_versions) {
+ tor_asprintf(&server_versions_line, "server-versions %s\n",
+ server_versions);
+ } else {
+ server_versions_line = tor_strdup("");
}
- len = 8192;
- len += strlen(version_lines);
- len += (RS_ENTRY_LEN+MICRODESC_LINE_LEN)*smartlist_len(rl->routers);
- len += strlen("\ndirectory-footer\n");
- len += v3_ns->cert->cache_info.signed_descriptor_len;
-
- status = tor_malloc(len);
+ chunks = smartlist_new();
{
char published[ISO_TIME_LEN+1];
char va[ISO_TIME_LEN+1];
char fu[ISO_TIME_LEN+1];
char vu[ISO_TIME_LEN+1];
char *flags = smartlist_join_strings(v3_ns->known_flags, " ", 0, NULL);
+ /* XXXX Abstraction violation: should be pulling a field out of v3_ns.*/
+ char *flag_thresholds = dirserv_get_flag_thresholds_line();
char *params;
authority_cert_t *cert = v3_ns->cert;
char *methods =
@@ -172,7 +122,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
params = tor_strdup("");
tor_assert(cert);
- r = tor_snprintf(status, len,
+ smartlist_add_asprintf(chunks,
"network-status-version 3\n"
"vote-status %s\n"
"consensus-methods %s\n"
@@ -181,8 +131,9 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
"fresh-until %s\n"
"valid-until %s\n"
"voting-delay %d %d\n"
- "%s" /* versions */
+ "%s%s" /* versions */
"known-flags %s\n"
+ "flag-thresholds %s\n"
"params %s\n"
"dir-source %s %s %s %s %d %d\n"
"contact %s\n",
@@ -190,99 +141,76 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
methods,
published, va, fu, vu,
v3_ns->vote_seconds, v3_ns->dist_seconds,
- version_lines,
+ client_versions_line,
+ server_versions_line,
flags,
+ flag_thresholds,
params,
voter->nickname, fingerprint, voter->address,
fmt_addr32(addr), voter->dir_port, voter->or_port,
voter->contact);
- if (r < 0) {
- log_err(LD_BUG, "Insufficient memory for network status line");
- tor_assert(0);
- }
-
tor_free(params);
tor_free(flags);
+ tor_free(flag_thresholds);
tor_free(methods);
- outp = status + strlen(status);
- endp = status + len;
if (!tor_digest_is_zero(voter->legacy_id_digest)) {
char fpbuf[HEX_DIGEST_LEN+1];
base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN);
- r = tor_snprintf(outp, endp-outp, "legacy-dir-key %s\n", fpbuf);
- if (r < 0) {
- log_err(LD_BUG, "Insufficient memory for legacy-dir-key line");
- tor_assert(0);
- }
- outp += strlen(outp);
+ smartlist_add_asprintf(chunks, "legacy-dir-key %s\n", fpbuf);
}
- tor_assert(outp + cert->cache_info.signed_descriptor_len < endp);
- memcpy(outp, cert->cache_info.signed_descriptor_body,
- cert->cache_info.signed_descriptor_len);
-
- outp += cert->cache_info.signed_descriptor_len;
+ smartlist_add(chunks, tor_strndup(cert->cache_info.signed_descriptor_body,
+ cert->cache_info.signed_descriptor_len));
}
SMARTLIST_FOREACH_BEGIN(v3_ns->routerstatus_list, vote_routerstatus_t *,
vrs) {
+ char *rsf;
vote_microdesc_hash_t *h;
- if (routerstatus_format_entry(outp, endp-outp, &vrs->status,
- vrs->version, NS_V3_VOTE) < 0) {
- log_warn(LD_BUG, "Unable to print router status.");
- goto err;
- }
- outp += strlen(outp);
+ rsf = routerstatus_format_entry(&vrs->status,
+ vrs->version, NS_V3_VOTE, vrs);
+ if (rsf)
+ smartlist_add(chunks, rsf);
for (h = vrs->microdesc; h; h = h->next) {
- size_t mlen = strlen(h->microdesc_hash_line);
- if (outp+mlen >= endp) {
- log_warn(LD_BUG, "Can't fit microdesc line in vote.");
- }
- memcpy(outp, h->microdesc_hash_line, mlen+1);
- outp += strlen(outp);
+ smartlist_add(chunks, tor_strdup(h->microdesc_hash_line));
}
} SMARTLIST_FOREACH_END(vrs);
- r = tor_snprintf(outp, endp-outp, "directory-footer\n");
- if (r < 0) {
- log_err(LD_BUG, "Insufficient memory for directory-footer line");
- tor_assert(0);
- }
- outp += strlen(outp);
+ smartlist_add(chunks, tor_strdup("directory-footer\n"));
+
+ /* The digest includes everything up through the space after
+ * directory-signature. (Yuck.) */
+ crypto_digest_smartlist(digest, DIGEST_LEN, chunks,
+ "directory-signature ", DIGEST_SHA1);
{
char signing_key_fingerprint[FINGERPRINT_LEN+1];
- if (tor_snprintf(outp, endp-outp, "directory-signature ")<0) {
- log_warn(LD_BUG, "Unable to start signature line.");
- goto err;
- }
- outp += strlen(outp);
-
if (crypto_pk_get_fingerprint(private_signing_key,
signing_key_fingerprint, 0)<0) {
log_warn(LD_BUG, "Unable to get fingerprint for signing key");
goto err;
}
- if (tor_snprintf(outp, endp-outp, "%s %s\n", fingerprint,
- signing_key_fingerprint)<0) {
- log_warn(LD_BUG, "Unable to end signature line.");
- goto err;
- }
- outp += strlen(outp);
+
+ smartlist_add_asprintf(chunks, "directory-signature %s %s\n", fingerprint,
+ signing_key_fingerprint);
}
- if (router_get_networkstatus_v3_hash(status, digest, DIGEST_SHA1)<0)
- goto err;
note_crypto_pk_op(SIGN_DIR);
- if (router_append_dirobj_signature(outp,endp-outp,digest, DIGEST_LEN,
- private_signing_key)<0) {
- log_warn(LD_BUG, "Unable to sign networkstatus vote.");
- goto err;
+ {
+ char *sig = router_get_dirobj_signature(digest, DIGEST_LEN,
+ private_signing_key);
+ if (!sig) {
+ log_warn(LD_BUG, "Unable to sign networkstatus vote.");
+ goto err;
+ }
+ smartlist_add(chunks, sig);
}
+ status = smartlist_join_strings(chunks, "", 0, NULL);
+
{
networkstatus_t *v;
if (!(v = networkstatus_parse_vote_from_string(status, NULL,
@@ -300,7 +228,12 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
err:
tor_free(status);
done:
- tor_free(version_lines);
+ tor_free(client_versions_line);
+ tor_free(server_versions_line);
+ if (chunks) {
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+ }
return status;
}
@@ -346,7 +279,7 @@ typedef struct dir_src_ent_t {
/** Helper for sorting networkstatus_t votes (not consensuses) by the
* hash of their voters' identity digests. */
static int
-_compare_votes_by_authority_id(const void **_a, const void **_b)
+compare_votes_by_authority_id_(const void **_a, const void **_b)
{
const networkstatus_t *a = *_a, *b = *_b;
return fast_memcmp(get_voter(a)->identity_digest,
@@ -357,7 +290,7 @@ _compare_votes_by_authority_id(const void **_a, const void **_b)
* their identity digests, and return -1, 0, or 1 depending on their
* ordering */
static int
-_compare_dir_src_ents_by_authority_id(const void **_a, const void **_b)
+compare_dir_src_ents_by_authority_id_(const void **_a, const void **_b)
{
const dir_src_ent_t *a = *_a, *b = *_b;
const networkstatus_voter_info_t *a_v = get_voter(a->v),
@@ -424,12 +357,27 @@ compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b)
/** Helper for sorting routerlists based on compare_vote_rs. */
static int
-_compare_vote_rs(const void **_a, const void **_b)
+compare_vote_rs_(const void **_a, const void **_b)
{
const vote_routerstatus_t *a = *_a, *b = *_b;
return compare_vote_rs(a,b);
}
+/** Helper for sorting OR ports. */
+static int
+compare_orports_(const void **_a, const void **_b)
+{
+ const tor_addr_port_t *a = *_a, *b = *_b;
+ int r;
+
+ if ((r = tor_addr_compare(&a->addr, &b->addr, CMP_EXACT)))
+ return r;
+ if ((r = (((int) b->port) - ((int) a->port))))
+ return r;
+
+ return 0;
+}
+
/** Given a list of vote_routerstatus_t, all for the same router identity,
* return whichever is most frequent, breaking ties in favor of more
* recently published vote_routerstatus_t and in case of ties there,
@@ -437,17 +385,18 @@ _compare_vote_rs(const void **_a, const void **_b)
*/
static vote_routerstatus_t *
compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
- char *microdesc_digest256_out)
+ char *microdesc_digest256_out,
+ tor_addr_port_t *best_alt_orport_out)
{
vote_routerstatus_t *most = NULL, *cur = NULL;
int most_n = 0, cur_n = 0;
time_t most_published = 0;
- /* _compare_vote_rs() sorts the items by identity digest (all the same),
+ /* compare_vote_rs_() sorts the items by identity digest (all the same),
* then by SD digest. That way, if we have a tie that the published_on
* date cannot tie, we use the descriptor with the smaller digest.
*/
- smartlist_sort(votes, _compare_vote_rs);
+ smartlist_sort(votes, compare_vote_rs_);
SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
if (cur && !compare_vote_rs(cur, rs)) {
++cur_n;
@@ -473,6 +422,38 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
tor_assert(most);
+ /* If we're producing "a" lines, vote on potential alternative (sets
+ * of) OR port(s) in the winning routerstatuses.
+ *
+ * XXX prop186 There's at most one alternative OR port (_the_ IPv6
+ * port) for now. */
+ if (consensus_method >= MIN_METHOD_FOR_A_LINES && best_alt_orport_out) {
+ smartlist_t *alt_orports = smartlist_new();
+ const tor_addr_port_t *most_alt_orport = NULL;
+
+ SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
+ if (compare_vote_rs(most, rs) == 0 &&
+ !tor_addr_is_null(&rs->status.ipv6_addr)
+ && rs->status.ipv6_orport) {
+ smartlist_add(alt_orports, tor_addr_port_new(&rs->status.ipv6_addr,
+ rs->status.ipv6_orport));
+ }
+ } SMARTLIST_FOREACH_END(rs);
+
+ smartlist_sort(alt_orports, compare_orports_);
+ most_alt_orport = smartlist_get_most_frequent(alt_orports,
+ compare_orports_);
+ if (most_alt_orport) {
+ memcpy(best_alt_orport_out, most_alt_orport, sizeof(tor_addr_port_t));
+ log_debug(LD_DIR, "\"a\" line winner for %s is %s",
+ most->status.nickname,
+ fmt_addrport(&most_alt_orport->addr, most_alt_orport->port));
+ }
+
+ SMARTLIST_FOREACH(alt_orports, tor_addr_port_t *, ap, tor_free(ap));
+ smartlist_free(alt_orports);
+ }
+
if (consensus_method >= MIN_METHOD_FOR_MICRODESC &&
microdesc_digest256_out) {
smartlist_t *digests = smartlist_new();
@@ -496,29 +477,11 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
return most;
}
-/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
- * at <b>digest_out</b> to the hash of the concatenation of those strings,
- * computed with the algorithm <b>alg</b>. */
-static void
-hash_list_members(char *digest_out, size_t len_out,
- smartlist_t *lst, digest_algorithm_t alg)
-{
- crypto_digest_t *d;
- if (alg == DIGEST_SHA1)
- d = crypto_digest_new();
- else
- d = crypto_digest256_new(alg);
- SMARTLIST_FOREACH(lst, const char *, cp,
- crypto_digest_add_bytes(d, cp, strlen(cp)));
- crypto_digest_get_digest(d, digest_out, len_out);
- crypto_digest_free(d);
-}
-
/** Sorting helper: compare two strings based on their values as base-ten
* positive integers. (Non-integers are treated as prior to all integers, and
* compared lexically.) */
static int
-_cmp_int_strings(const void **_a, const void **_b)
+cmp_int_strings_(const void **_a, const void **_b)
{
const char *a = *_a, *b = *_b;
int ai = (int)tor_parse_long(a, 10, 1, INT_MAX, NULL, NULL);
@@ -549,13 +512,13 @@ compute_consensus_method(smartlist_t *votes)
{
tor_assert(vote->supported_methods);
smartlist_add_all(tmp, vote->supported_methods);
- smartlist_sort(tmp, _cmp_int_strings);
- smartlist_uniq(tmp, _cmp_int_strings, NULL);
+ smartlist_sort(tmp, cmp_int_strings_);
+ smartlist_uniq(tmp, cmp_int_strings_, NULL);
smartlist_add_all(all_methods, tmp);
smartlist_clear(tmp);
});
- smartlist_sort(all_methods, _cmp_int_strings);
+ smartlist_sort(all_methods, cmp_int_strings_);
get_frequent_members(acceptable_methods, all_methods, min);
n_ok = smartlist_len(acceptable_methods);
if (n_ok) {
@@ -1358,6 +1321,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
char *client_versions = NULL, *server_versions = NULL;
smartlist_t *flags;
const char *flavor_name;
+ uint32_t max_unmeasured_bw_kb = DEFAULT_MAX_UNMEASURED_BW_KB;
int64_t G=0, M=0, E=0, D=0, T=0; /* For bandwidth weights */
const routerstatus_format_type_t rs_format =
flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC;
@@ -1504,7 +1468,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
/* Sort the votes. */
- smartlist_sort(votes, _compare_votes_by_authority_id);
+ smartlist_sort(votes, compare_votes_by_authority_id_);
/* Add the authority sections. */
{
smartlist_t *dir_sources = smartlist_new();
@@ -1523,7 +1487,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_add(dir_sources, e_legacy);
}
} SMARTLIST_FOREACH_END(v);
- smartlist_sort(dir_sources, _compare_dir_src_ents_by_authority_id);
+ smartlist_sort(dir_sources, compare_dir_src_ents_by_authority_id_);
SMARTLIST_FOREACH_BEGIN(dir_sources, const dir_src_ent_t *, e) {
char fingerprint[HEX_DIGEST_LEN+1];
@@ -1556,6 +1520,30 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_free(dir_sources);
}
+ if (consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW) {
+ char *max_unmeasured_param = NULL;
+ /* XXXX Extract this code into a common function */
+ if (params) {
+ if (strcmpstart(params, "maxunmeasuredbw=") == 0)
+ max_unmeasured_param = params;
+ else
+ max_unmeasured_param = strstr(params, " maxunmeasuredbw=");
+ }
+ if (max_unmeasured_param) {
+ int ok = 0;
+ char *eq = strchr(max_unmeasured_param, '=');
+ if (eq) {
+ max_unmeasured_bw_kb = (uint32_t)
+ tor_parse_ulong(eq+1, 10, 1, UINT32_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_DIR, "Bad element '%s' in max unmeasured bw param",
+ escaped(max_unmeasured_param));
+ max_unmeasured_bw_kb = DEFAULT_MAX_UNMEASURED_BW_KB;
+ }
+ }
+ }
+ }
+
/* Add the actual router entries. */
{
int *index; /* index[j] is the current index into votes[j]. */
@@ -1567,9 +1555,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_t *chosen_flags = smartlist_new();
smartlist_t *versions = smartlist_new();
smartlist_t *exitsummaries = smartlist_new();
- uint32_t *bandwidths = tor_malloc(sizeof(uint32_t) * smartlist_len(votes));
- uint32_t *measured_bws = tor_malloc(sizeof(uint32_t) *
- smartlist_len(votes));
+ uint32_t *bandwidths_kb = tor_malloc(sizeof(uint32_t) *
+ smartlist_len(votes));
+ uint32_t *measured_bws_kb = tor_malloc(sizeof(uint32_t) *
+ smartlist_len(votes));
int num_bandwidths;
int num_mbws;
@@ -1582,6 +1571,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
int *named_flag; /* Index of the flag "Named" for votes[j] */
int *unnamed_flag; /* Index of the flag "Unnamed" for votes[j] */
int chosen_named_idx;
+ int n_authorities_measuring_bandwidth;
strmap_t *name_to_id_map = strmap_new();
char conflict[DIGEST_LEN];
@@ -1600,10 +1590,19 @@ networkstatus_compute_consensus(smartlist_t *votes,
unnamed_flag[i] = named_flag[i] = -1;
chosen_named_idx = smartlist_string_pos(flags, "Named");
- /* Build the flag index. */
+ /* Build the flag indexes. Note that no vote can have more than 64 members
+ * for known_flags, so no value will be greater than 63, so it's safe to
+ * do U64_LITERAL(1) << index on these values. But note also that
+ * named_flag and unnamed_flag are initialized to -1, so we need to check
+ * that they're actually set before doing U64_LITERAL(1) << index with
+ * them.*/
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
flag_map[v_sl_idx] = tor_malloc_zero(
sizeof(int)*smartlist_len(v->known_flags));
+ if (smartlist_len(v->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) {
+ log_warn(LD_BUG, "Somehow, a vote has %d entries in known_flags",
+ smartlist_len(v->known_flags));
+ }
SMARTLIST_FOREACH_BEGIN(v->known_flags, const char *, fl) {
int p = smartlist_string_pos(flags, fl);
tor_assert(p >= 0);
@@ -1670,6 +1669,14 @@ networkstatus_compute_consensus(smartlist_t *votes,
} SMARTLIST_FOREACH_END(v);
}
+ /* We need to know how many votes measure bandwidth. */
+ n_authorities_measuring_bandwidth = 0;
+ SMARTLIST_FOREACH(votes, networkstatus_t *, v,
+ if (v->has_measured_bws) {
+ ++n_authorities_measuring_bandwidth;
+ }
+ );
+
/* Now go through all the votes */
flag_counts = tor_malloc(sizeof(int) * smartlist_len(flags));
while (1) {
@@ -1685,6 +1692,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
int n_listing = 0;
int i;
char microdesc_digest[DIGEST256_LEN];
+ tor_addr_port_t alt_orport = {TOR_ADDR_NULL, 0};
/* Of the next-to-be-considered digest in each voter, which is first? */
SMARTLIST_FOREACH(votes, networkstatus_t *, v, {
@@ -1728,7 +1736,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
if (rs->flags & (U64_LITERAL(1) << i))
++flag_counts[flag_map[v_sl_idx][i]];
}
- if (rs->flags & (U64_LITERAL(1) << named_flag[v_sl_idx])) {
+ if (named_flag[v_sl_idx] >= 0 &&
+ (rs->flags & (U64_LITERAL(1) << named_flag[v_sl_idx]))) {
if (chosen_name && strcmp(chosen_name, rs->status.nickname)) {
log_notice(LD_DIR, "Conflict on naming for router: %s vs %s",
chosen_name, rs->status.nickname);
@@ -1738,11 +1747,11 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
/* count bandwidths */
- if (rs->status.has_measured_bw)
- measured_bws[num_mbws++] = rs->status.measured_bw;
+ if (rs->has_measured_bw)
+ measured_bws_kb[num_mbws++] = rs->measured_bw_kb;
if (rs->status.has_bandwidth)
- bandwidths[num_bandwidths++] = rs->status.bandwidth;
+ bandwidths_kb[num_bandwidths++] = rs->status.bandwidth_kb;
} SMARTLIST_FOREACH_END(v);
/* We don't include this router at all unless more than half of
@@ -1754,7 +1763,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
* routerinfo and its contents are. */
memset(microdesc_digest, 0, sizeof(microdesc_digest));
rs = compute_routerstatus_consensus(matching_descs, consensus_method,
- microdesc_digest);
+ microdesc_digest, &alt_orport);
/* Copy bits of that into rs_out. */
memset(&rs_out, 0, sizeof(rs_out));
tor_assert(fast_memeq(lowest_id, rs->status.identity_digest,DIGEST_LEN));
@@ -1765,6 +1774,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
rs_out.published_on = rs->status.published_on;
rs_out.dir_port = rs->status.dir_port;
rs_out.or_port = rs->status.or_port;
+ if (consensus_method >= MIN_METHOD_FOR_A_LINES) {
+ tor_addr_copy(&rs_out.ipv6_addr, &alt_orport.addr);
+ rs_out.ipv6_orport = alt_orport.port;
+ }
rs_out.has_bandwidth = 0;
rs_out.has_exitsummary = 0;
@@ -1828,28 +1841,37 @@ networkstatus_compute_consensus(smartlist_t *votes,
/* Pick a bandwidth */
if (consensus_method >= 6 && num_mbws > 2) {
rs_out.has_bandwidth = 1;
- rs_out.bandwidth = median_uint32(measured_bws, num_mbws);
+ rs_out.bw_is_unmeasured = 0;
+ rs_out.bandwidth_kb = median_uint32(measured_bws_kb, num_mbws);
} else if (consensus_method >= 5 && num_bandwidths > 0) {
rs_out.has_bandwidth = 1;
- rs_out.bandwidth = median_uint32(bandwidths, num_bandwidths);
+ rs_out.bw_is_unmeasured = 1;
+ rs_out.bandwidth_kb = median_uint32(bandwidths_kb, num_bandwidths);
+ if (consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW &&
+ n_authorities_measuring_bandwidth > 2) {
+ /* Cap non-measured bandwidths. */
+ if (rs_out.bandwidth_kb > max_unmeasured_bw_kb) {
+ rs_out.bandwidth_kb = max_unmeasured_bw_kb;
+ }
+ }
}
/* Fix bug 2203: Do not count BadExit nodes as Exits for bw weights */
- if (consensus_method >= 11) {
+ if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) {
is_exit = is_exit && !is_bad_exit;
}
if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
if (rs_out.has_bandwidth) {
- T += rs_out.bandwidth;
+ T += rs_out.bandwidth_kb;
if (is_exit && is_guard)
- D += rs_out.bandwidth;
+ D += rs_out.bandwidth_kb;
else if (is_exit)
- E += rs_out.bandwidth;
+ E += rs_out.bandwidth_kb;
else if (is_guard)
- G += rs_out.bandwidth;
+ G += rs_out.bandwidth_kb;
else
- M += rs_out.bandwidth;
+ M += rs_out.bandwidth_kb;
} else {
log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
rs_out.nickname);
@@ -1862,7 +1884,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
* listed that descriptor will have the same summary. If not then
* something is fishy and we'll use the most common one (breaking
* ties in favor of lexicographically larger one (only because it
- * lets me reuse more existing code.
+ * lets me reuse more existing code)).
*
* The other case that can happen is that no authority that voted
* for that descriptor has an exit policy summary. That's
@@ -1948,12 +1970,12 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
{
- char buf[4096];
+ char *buf;
/* Okay!! Now we can write the descriptor... */
/* First line goes into "buf". */
- routerstatus_format_entry(buf, sizeof(buf), &rs_out, NULL,
- rs_format);
- smartlist_add(chunks, tor_strdup(buf));
+ buf = routerstatus_format_entry(&rs_out, NULL, rs_format, NULL);
+ if (buf)
+ smartlist_add(chunks, buf);
}
/* Now an m line, if applicable. */
if (flavor == FLAV_MICRODESC &&
@@ -1973,7 +1995,11 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_add(chunks, tor_strdup("\n"));
/* Now the weight line. */
if (rs_out.has_bandwidth) {
- smartlist_add_asprintf(chunks, "w Bandwidth=%d\n", rs_out.bandwidth);
+ int unmeasured = rs_out.bw_is_unmeasured &&
+ consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW;
+ smartlist_add_asprintf(chunks, "w Bandwidth=%d%s\n",
+ rs_out.bandwidth_kb,
+ unmeasured?" Unmeasured=1":"");
}
/* Now the exitpolicy summary line. */
@@ -1999,8 +2025,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_free(chosen_flags);
smartlist_free(versions);
smartlist_free(exitsummaries);
- tor_free(bandwidths);
- tor_free(measured_bws);
+ tor_free(bandwidths_kb);
+ tor_free(measured_bws_kb);
}
if (consensus_method >= MIN_METHOD_FOR_FOOTER) {
@@ -2016,6 +2042,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
// Parse params, extract BW_WEIGHT_SCALE if present
// DO NOT use consensus_param_bw_weight_scale() in this code!
// The consensus is not formed yet!
+ /* XXXX Extract this code into a common function */
if (params) {
if (strcmpstart(params, "bwweightscale=") == 0)
bw_weight_param = params;
@@ -2060,12 +2087,12 @@ networkstatus_compute_consensus(smartlist_t *votes,
size_t digest_len =
flavor == FLAV_NS ? DIGEST_LEN : DIGEST256_LEN;
const char *algname = crypto_digest_algorithm_get_name(digest_alg);
- char sigbuf[4096];
+ char *signature;
smartlist_add(chunks, tor_strdup("directory-signature "));
/* Compute the hash of the chunks. */
- hash_list_members(digest, digest_len, chunks, digest_alg);
+ crypto_digest_smartlist(digest, digest_len, chunks, "", digest_alg);
/* Get the fingerprints */
crypto_pk_get_fingerprint(identity_key, fingerprint, 0);
@@ -2081,14 +2108,12 @@ networkstatus_compute_consensus(smartlist_t *votes,
signing_key_fingerprint);
}
/* And the signature. */
- sigbuf[0] = '\0';
- if (router_append_dirobj_signature(sigbuf, sizeof(sigbuf),
- digest, digest_len,
- signing_key)) {
+ if (!(signature = router_get_dirobj_signature(digest, digest_len,
+ signing_key))) {
log_warn(LD_BUG, "Couldn't sign consensus networkstatus.");
- return NULL; /* This leaks, but it should never happen. */
+ goto done;
}
- smartlist_add(chunks, tor_strdup(sigbuf));
+ smartlist_add(chunks, signature);
if (legacy_id_key_digest && legacy_signing_key && consensus_method >= 3) {
smartlist_add(chunks, tor_strdup("directory-signature "));
@@ -2104,26 +2129,18 @@ networkstatus_compute_consensus(smartlist_t *votes,
algname, fingerprint,
signing_key_fingerprint);
}
- sigbuf[0] = '\0';
- if (router_append_dirobj_signature(sigbuf, sizeof(sigbuf),
- digest, digest_len,
- legacy_signing_key)) {
+
+ if (!(signature = router_get_dirobj_signature(digest, digest_len,
+ legacy_signing_key))) {
log_warn(LD_BUG, "Couldn't sign consensus networkstatus.");
- return NULL; /* This leaks, but it should never happen. */
+ goto done;
}
- smartlist_add(chunks, tor_strdup(sigbuf));
+ smartlist_add(chunks, signature);
}
}
result = smartlist_join_strings(chunks, "", 0, NULL);
- tor_free(client_versions);
- tor_free(server_versions);
- SMARTLIST_FOREACH(flags, char *, cp, tor_free(cp));
- smartlist_free(flags);
- SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
- smartlist_free(chunks);
-
{
networkstatus_t *c;
if (!(c = networkstatus_parse_vote_from_string(result, NULL,
@@ -2131,15 +2148,24 @@ networkstatus_compute_consensus(smartlist_t *votes,
log_err(LD_BUG, "Generated a networkstatus consensus we couldn't "
"parse.");
tor_free(result);
- return NULL;
+ goto done;
}
// Verify balancing parameters
if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS && added_weights) {
- networkstatus_verify_bw_weights(c);
+ networkstatus_verify_bw_weights(c, consensus_method);
}
networkstatus_vote_free(c);
}
+ done:
+
+ tor_free(client_versions);
+ tor_free(server_versions);
+ SMARTLIST_FOREACH(flags, char *, cp, tor_free(cp));
+ smartlist_free(flags);
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+
return result;
}
@@ -2193,7 +2219,7 @@ networkstatus_add_detached_signatures(networkstatus_t *target,
{
digests_t *digests = strmap_get(sigs->digests, flavor);
int n_matches = 0;
- digest_algorithm_t alg;
+ int alg;
if (!digests) {
*msg_out = "No digests for given consensus flavor";
return -1;
@@ -2258,7 +2284,7 @@ networkstatus_add_detached_signatures(networkstatus_t *target,
if (sig->good_signature || !old_sig || old_sig->bad_signature) {
log_info(LD_DIR, "Adding signature from %s with %s", voter_identity,
algorithm);
- log(severity, LD_DIR, "Added a signature for %s from %s.",
+ tor_log(severity, LD_DIR, "Added a signature for %s from %s.",
target_voter->nickname, source);
++r;
if (old_sig) {
@@ -2457,7 +2483,7 @@ ns_detached_signatures_free(ns_detached_signatures_t *s)
smartlist_free(sigs);
} STRMAP_FOREACH_END;
strmap_free(s->signatures, NULL);
- strmap_free(s->digests, _tor_free);
+ strmap_free(s->digests, tor_free_);
}
tor_free(s);
@@ -2757,7 +2783,7 @@ dirvote_fetch_missing_votes(void)
char *resource;
SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds) {
+ dir_server_t *, ds) {
if (!(ds->type & V3_DIRINFO))
continue;
if (!dirvote_get_vote(ds->v3_identity_digest,
@@ -2875,7 +2901,7 @@ list_v3_auth_ids(void)
smartlist_t *known_v3_keys = smartlist_new();
char *keys;
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds,
+ dir_server_t *, ds,
if ((ds->type & V3_DIRINFO) &&
!tor_digest_is_zero(ds->v3_identity_digest))
smartlist_add(known_v3_keys,
@@ -2896,7 +2922,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
{
networkstatus_t *vote;
networkstatus_voter_info_t *vi;
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
pending_vote_t *pending_vote = NULL;
const char *end_of_vote = NULL;
int any_failed = 0;
@@ -2947,7 +2973,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
/* Hey, it's a new cert! */
trusted_dirs_load_certs_from_string(
vote->cert->cache_info.signed_descriptor_body,
- 0 /* from_store */, 1 /*flush*/);
+ TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/);
if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest,
vote->cert->signing_key_digest)) {
log_warn(LD_BUG, "We added a cert, but still couldn't find it.");
@@ -3080,7 +3106,7 @@ dirvote_compute_consensuses(void)
}
tor_assert(pending_vote_list);
SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, {
- if (smartlist_string_isin(v->vote->known_flags, "Running"))
+ if (smartlist_contains_string(v->vote->known_flags, "Running"))
n_vote_running++;
});
if (!n_vote_running) {
@@ -3441,7 +3467,7 @@ dirvote_free_all(void)
const char *
dirvote_get_pending_consensus(consensus_flavor_t flav)
{
- tor_assert(((int)flav) >= 0 && flav < N_CONSENSUS_FLAVORS);
+ tor_assert(((int)flav) >= 0 && (int)flav < N_CONSENSUS_FLAVORS);
return pending_consensuses[flav].body;
}
@@ -3504,15 +3530,11 @@ dirvote_get_vote(const char *fp, int flags)
return NULL;
}
-/** Construct and return a new microdescriptor from a routerinfo <b>ri</b>.
- *
- * XXX Right now, there is only one way to generate microdescriptors from
- * router descriptors. This may change in future consensus methods. If so,
- * we'll need an internal way to remember which method we used, and ask for a
- * particular method.
+/** Construct and return a new microdescriptor from a routerinfo <b>ri</b>
+ * according to <b>consensus_method</b>.
**/
microdesc_t *
-dirvote_create_microdescriptor(const routerinfo_t *ri)
+dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
{
microdesc_t *result = NULL;
char *key = NULL, *summary = NULL, *family = NULL;
@@ -3522,23 +3544,49 @@ dirvote_create_microdescriptor(const routerinfo_t *ri)
if (crypto_pk_write_public_key_to_string(ri->onion_pkey, &key, &keylen)<0)
goto done;
- summary = policy_summarize(ri->exit_policy);
+ summary = policy_summarize(ri->exit_policy, AF_INET);
if (ri->declared_family)
family = smartlist_join_strings(ri->declared_family, " ", 0, NULL);
smartlist_add_asprintf(chunks, "onion-key\n%s", key);
+ if (consensus_method >= MIN_METHOD_FOR_NTOR_KEY &&
+ ri->onion_curve25519_pkey) {
+ char kbuf[128];
+ base64_encode(kbuf, sizeof(kbuf),
+ (const char*)ri->onion_curve25519_pkey->public_key,
+ CURVE25519_PUBKEY_LEN);
+ smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
+ }
+
+ if (consensus_method >= MIN_METHOD_FOR_A_LINES &&
+ !tor_addr_is_null(&ri->ipv6_addr) && ri->ipv6_orport)
+ smartlist_add_asprintf(chunks, "a %s\n",
+ fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport));
+
if (family)
smartlist_add_asprintf(chunks, "family %s\n", family);
if (summary && strcmp(summary, "reject 1-65535"))
smartlist_add_asprintf(chunks, "p %s\n", summary);
+ if (consensus_method >= MIN_METHOD_FOR_P6_LINES &&
+ ri->ipv6_exit_policy) {
+ /* XXXX024 This doesn't match proposal 208, which says these should
+ * be taken unchanged from the routerinfo. That's bogosity, IMO:
+ * the proposal should have said to do this instead.*/
+ char *p6 = write_short_policy(ri->ipv6_exit_policy);
+ if (p6 && strcmp(p6, "reject 1-65535"))
+ smartlist_add_asprintf(chunks, "p6 %s\n", p6);
+ tor_free(p6);
+ }
+
output = smartlist_join_strings(chunks, "", 0, NULL);
{
smartlist_t *lst = microdescs_parse_from_string(output,
- output+strlen(output), 0, 1);
+ output+strlen(output), 0,
+ SAVED_NOWHERE);
if (smartlist_len(lst) != 1) {
log_warn(LD_DIR, "We generated a microdescriptor we couldn't parse.");
SMARTLIST_FOREACH(lst, microdesc_t *, md, microdesc_free(md));
@@ -3561,33 +3609,117 @@ dirvote_create_microdescriptor(const routerinfo_t *ri)
return result;
}
-/** Cached space-separated string to hold */
-static char *microdesc_consensus_methods = NULL;
-
/** Format the appropriate vote line to describe the microdescriptor <b>md</b>
* in a consensus vote document. Write it into the <b>out_len</b>-byte buffer
* in <b>out</b>. Return -1 on failure and the number of characters written
* on success. */
ssize_t
-dirvote_format_microdesc_vote_line(char *out, size_t out_len,
- const microdesc_t *md)
+dirvote_format_microdesc_vote_line(char *out_buf, size_t out_buf_len,
+ const microdesc_t *md,
+ int consensus_method_low,
+ int consensus_method_high)
{
+ ssize_t ret = -1;
char d64[BASE64_DIGEST256_LEN+1];
- if (!microdesc_consensus_methods) {
- microdesc_consensus_methods =
- make_consensus_method_list(MIN_METHOD_FOR_MICRODESC,
- MAX_SUPPORTED_CONSENSUS_METHOD,
- ",");
- tor_assert(microdesc_consensus_methods);
- }
+ char *microdesc_consensus_methods =
+ make_consensus_method_list(consensus_method_low,
+ consensus_method_high,
+ ",");
+ tor_assert(microdesc_consensus_methods);
+
if (digest256_to_base64(d64, md->digest)<0)
- return -1;
+ goto out;
- if (tor_snprintf(out, out_len, "m %s sha256=%s\n",
+ if (tor_snprintf(out_buf, out_buf_len, "m %s sha256=%s\n",
microdesc_consensus_methods, d64)<0)
- return -1;
+ goto out;
+
+ ret = strlen(out_buf);
+
+ out:
+ tor_free(microdesc_consensus_methods);
+ return ret;
+}
+
+/** Array of start and end of consensus methods used for supported
+ microdescriptor formats. */
+static const struct consensus_method_range_t {
+ int low;
+ int high;
+} microdesc_consensus_methods[] = {
+ {MIN_METHOD_FOR_MICRODESC, MIN_METHOD_FOR_A_LINES - 1},
+ {MIN_METHOD_FOR_A_LINES, MIN_METHOD_FOR_P6_LINES - 1},
+ {MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1},
+ {MIN_METHOD_FOR_NTOR_KEY, MAX_SUPPORTED_CONSENSUS_METHOD},
+ {-1, -1}
+};
+
+/** Helper type used when generating the microdescriptor lines in a directory
+ * vote. */
+typedef struct microdesc_vote_line_t {
+ int low;
+ int high;
+ microdesc_t *md;
+ struct microdesc_vote_line_t *next;
+} microdesc_vote_line_t;
+
+/** Generate and return a linked list of all the lines that should appear to
+ * describe a router's microdescriptor versions in a directory vote.
+ * Add the generated microdescriptors to <b>microdescriptors_out</b>. */
+vote_microdesc_hash_t *
+dirvote_format_all_microdesc_vote_lines(const routerinfo_t *ri, time_t now,
+ smartlist_t *microdescriptors_out)
+{
+ const struct consensus_method_range_t *cmr;
+ microdesc_vote_line_t *entries = NULL, *ep;
+ vote_microdesc_hash_t *result = NULL;
+
+ /* Generate the microdescriptors. */
+ for (cmr = microdesc_consensus_methods;
+ cmr->low != -1 && cmr->high != -1;
+ cmr++) {
+ microdesc_t *md = dirvote_create_microdescriptor(ri, cmr->low);
+ if (md) {
+ microdesc_vote_line_t *e =
+ tor_malloc_zero(sizeof(microdesc_vote_line_t));
+ e->md = md;
+ e->low = cmr->low;
+ e->high = cmr->high;
+ e->next = entries;
+ entries = e;
+ }
+ }
+
+ /* Compress adjacent identical ones */
+ for (ep = entries; ep; ep = ep->next) {
+ while (ep->next &&
+ fast_memeq(ep->md->digest, ep->next->md->digest, DIGEST256_LEN) &&
+ ep->low == ep->next->high + 1) {
+ microdesc_vote_line_t *next = ep->next;
+ ep->low = next->low;
+ microdesc_free(next->md);
+ ep->next = next->next;
+ tor_free(next);
+ }
+ }
- return strlen(out);
+ /* Format them into vote_microdesc_hash_t, and add to microdescriptors_out.*/
+ while ((ep = entries)) {
+ char buf[128];
+ vote_microdesc_hash_t *h;
+ dirvote_format_microdesc_vote_line(buf, sizeof(buf), ep->md,
+ ep->low, ep->high);
+ h = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
+ h->microdesc_hash_line = tor_strdup(buf);
+ h->next = result;
+ result = h;
+ ep->md->last_listed = now;
+ smartlist_add(microdescriptors_out, ep->md);
+ entries = ep->next;
+ tor_free(ep);
+ }
+
+ return result;
}
/** If <b>vrs</b> has a hash made for the consensus method <b>method</b> with
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index e6f970061..b23645212 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for dirvote.c.
**/
-#ifndef _TOR_DIRVOTE_H
-#define _TOR_DIRVOTE_H
+#ifndef TOR_DIRVOTE_H
+#define TOR_DIRVOTE_H
/** Lowest allowable value for VoteSeconds. */
#define MIN_VOTE_SECONDS 20
@@ -19,6 +19,50 @@
/** Smallest allowable voting interval. */
#define MIN_VOTE_INTERVAL 300
+/** The highest consensus method that we currently support. */
+#define MAX_SUPPORTED_CONSENSUS_METHOD 17
+
+/** Lowest consensus method that contains a 'directory-footer' marker */
+#define MIN_METHOD_FOR_FOOTER 9
+
+/** Lowest consensus method that contains bandwidth weights */
+#define MIN_METHOD_FOR_BW_WEIGHTS 9
+
+/** Lowest consensus method that contains consensus params */
+#define MIN_METHOD_FOR_PARAMS 7
+
+/** Lowest consensus method that generates microdescriptors */
+#define MIN_METHOD_FOR_MICRODESC 8
+
+/** Lowest consensus method that doesn't count bad exits as exits for weight */
+#define MIN_METHOD_TO_CUT_BADEXIT_WEIGHT 11
+
+/** Lowest consensus method that ensures a majority of authorities voted
+ * for a param. */
+#define MIN_METHOD_FOR_MAJORITY_PARAMS 12
+
+/** Lowest consensus method where microdesc consensuses omit any entry
+ * with no microdesc. */
+#define MIN_METHOD_FOR_MANDATORY_MICRODESC 13
+
+/** Lowest consensus method that contains "a" lines. */
+#define MIN_METHOD_FOR_A_LINES 14
+
+/** Lowest consensus method where microdescs may include a "p6" line. */
+#define MIN_METHOD_FOR_P6_LINES 15
+
+/** Lowest consensus method where microdescs may include an onion-key-ntor
+ * line */
+#define MIN_METHOD_FOR_NTOR_KEY 16
+
+/** Lowest consensus method that ensures that authorities output an
+ * Unmeasured=1 flag for unmeasured bandwidths */
+#define MIN_METHOD_TO_CLIP_UNMEASURED_BW 17
+
+/** Default bandwidth to clip unmeasured bandwidths to using method >=
+ * MIN_METHOD_TO_CLIP_UNMEASURED_BW */
+#define DEFAULT_MAX_UNMEASURED_BW_KB 20
+
void dirvote_free_all(void);
/* vote manipulation */
@@ -70,9 +114,16 @@ networkstatus_t *
dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
authority_cert_t *cert);
-microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri);
+microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri,
+ int consensus_method);
ssize_t dirvote_format_microdesc_vote_line(char *out, size_t out_len,
- const microdesc_t *md);
+ const microdesc_t *md,
+ int consensus_method_low,
+ int consensus_method_high);
+vote_microdesc_hash_t *dirvote_format_all_microdesc_vote_lines(
+ const routerinfo_t *ri,
+ time_t now,
+ smartlist_t *microdescriptors_out);
int vote_routerstatus_find_microdesc_hash(char *digest256_out,
const vote_routerstatus_t *vrs,
diff --git a/src/or/dns.c b/src/or/dns.c
index 78893bfbe..f2b7eecc3 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -61,6 +61,9 @@ struct evdns_request;
#define evdns_base_resolve_ipv4(base, addr, options, cb, ptr) \
((evdns_resolve_ipv4((addr), (options), (cb), (ptr))!=0) \
? NULL : ((void*)1))
+#define evdns_base_resolve_ipv6(base, addr, options, cb, ptr) \
+ ((evdns_resolve_ipv6((addr), (options), (cb), (ptr))!=0) \
+ ? NULL : ((void*)1))
#define evdns_base_resolve_reverse(base, addr, options, cb, ptr) \
((evdns_resolve_reverse((addr), (options), (cb), (ptr))!=0) \
? NULL : ((void*)1))
@@ -84,12 +87,6 @@ struct evdns_request;
* that the resolver is wedged? */
#define RESOLVE_MAX_TIMEOUT 300
-/** Possible outcomes from hostname lookup: permanent failure,
- * transient (retryable) failure, and success. */
-#define DNS_RESOLVE_FAILED_TRANSIENT 1
-#define DNS_RESOLVE_FAILED_PERMANENT 2
-#define DNS_RESOLVE_SUCCEEDED 3
-
/** Our evdns_base; this structure handles all our name lookups. */
static struct evdns_base *the_evdns_base = NULL;
@@ -117,7 +114,7 @@ typedef struct pending_connection_t {
/* Possible states for a cached resolve_t */
/** We are waiting for the resolver system to tell us an answer here.
* When we get one, or when we time out, the state of this cached_resolve_t
- * will become "DONE" and we'll possibly add a CACHED_VALID or a CACHED_FAILED
+ * will become "DONE" and we'll possibly add a CACHED
* entry. This cached_resolve_t will be in the hash table so that we will
* know not to launch more requests for this addr, but rather to add more
* connections to the pending list for the addr. */
@@ -128,10 +125,18 @@ typedef struct pending_connection_t {
#define CACHE_STATE_DONE 1
/** We are caching an answer for this address. This should have no pending
* connections, and should appear in the hash table. */
-#define CACHE_STATE_CACHED_VALID 2
-/** We are caching a failure for this address. This should have no pending
- * connections, and should appear in the hash table */
-#define CACHE_STATE_CACHED_FAILED 3
+#define CACHE_STATE_CACHED 2
+
+/** @name status values for a single DNS request.
+ *
+ * @{ */
+/** The DNS request is in progress. */
+#define RES_STATUS_INFLIGHT 1
+/** The DNS request finished and gave an answer */
+#define RES_STATUS_DONE_OK 2
+/** The DNS request finished and gave an error */
+#define RES_STATUS_DONE_ERR 3
+/**@}*/
/** A DNS request: possibly completed, possibly pending; cached_resolve
* structs are stored at the OR side in a hash table, and as a linked
@@ -139,19 +144,39 @@ typedef struct pending_connection_t {
*/
typedef struct cached_resolve_t {
HT_ENTRY(cached_resolve_t) node;
- uint32_t magic;
+ uint32_t magic; /**< Must be CACHED_RESOLVE_MAGIC */
char address[MAX_ADDRESSLEN]; /**< The hostname to be resolved. */
+
+ union {
+ uint32_t addr_ipv4; /**< IPv4 addr for <b>address</b>, if successful.
+ * (In host order.) */
+ int err_ipv4; /**< One of DNS_ERR_*, if IPv4 lookup failed. */
+ } result_ipv4; /**< Outcome of IPv4 lookup */
+ union {
+ struct in6_addr addr_ipv6; /**< IPv6 addr for <b>address</b>, if
+ * successful */
+ int err_ipv6; /**< One of DNS_ERR_*, if IPv6 lookup failed. */
+ } result_ipv6; /**< Outcome of IPv6 lookup, if any */
union {
- struct {
- struct in6_addr addr6; /**< IPv6 addr for <b>address</b>. */
- uint32_t addr; /**< IPv4 addr for <b>address</b>. */
- } a;
- char *hostname; /**< Hostname for <b>address</b> (if a reverse lookup) */
- } result;
- uint8_t state; /**< Is this cached entry pending/done/valid/failed? */
- uint8_t is_reverse; /**< Is this a reverse (addr-to-hostname) lookup? */
+ char *hostname; /** A hostname, if PTR lookup happened successfully*/
+ int err_hostname; /** One of DNS_ERR_*, if PTR lookup failed. */
+ } result_ptr;
+ /** @name Status fields
+ *
+ * These take one of the RES_STATUS_* values, depending on the state
+ * of the corresponding lookup.
+ *
+ * @{ */
+ unsigned int res_status_ipv4 : 2;
+ unsigned int res_status_ipv6 : 2;
+ unsigned int res_status_hostname : 2;
+ /**@}*/
+ uint8_t state; /**< Is this cached entry pending/done/informative? */
+
time_t expire; /**< Remove items from cache after this time. */
- uint32_t ttl; /**< What TTL did the nameserver tell us? */
+ uint32_t ttl_ipv4; /**< What TTL did the nameserver tell us? */
+ uint32_t ttl_ipv6; /**< What TTL did the nameserver tell us? */
+ uint32_t ttl_hostname; /**< What TTL did the nameserver tell us? */
/** Connections that want to know when we get an answer for this resolve. */
pending_connection_t *pending_connections;
/** Position of this element in the heap*/
@@ -159,20 +184,31 @@ typedef struct cached_resolve_t {
} cached_resolve_t;
static void purge_expired_resolves(time_t now);
-static void dns_found_answer(const char *address, uint8_t is_reverse,
- uint32_t addr, const char *hostname, char outcome,
+static void dns_found_answer(const char *address, uint8_t query_type,
+ int dns_answer,
+ const tor_addr_t *addr,
+ const char *hostname,
uint32_t ttl);
-static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type);
-static int launch_resolve(edge_connection_t *exitconn);
+static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
+ const cached_resolve_t *resolve);
+static int launch_resolve(cached_resolve_t *resolve);
static void add_wildcarded_test_address(const char *address);
static int configure_nameservers(int force);
static int answer_is_wildcarded(const char *ip);
static int dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
or_circuit_t *oncirc, char **resolved_to_hostname,
- int *made_connection_pending_out);
+ int *made_connection_pending_out,
+ cached_resolve_t **resolve_out);
+static int set_exitconn_info_from_resolve(edge_connection_t *exitconn,
+ const cached_resolve_t *resolve,
+ char **hostname_out);
+static int evdns_err_is_transient(int err);
+static void inform_pending_connections(cached_resolve_t *resolve);
+static void make_pending_resolve_cached(cached_resolve_t *cached);
+
#ifdef DEBUG_DNS_CACHE
-static void _assert_cache_ok(void);
-#define assert_cache_ok() _assert_cache_ok()
+static void assert_cache_ok_(void);
+#define assert_cache_ok() assert_cache_ok_()
#else
#define assert_cache_ok() STMT_NIL
#endif
@@ -181,6 +217,13 @@ static void assert_resolve_ok(cached_resolve_t *resolve);
/** Hash table of cached_resolve objects. */
static HT_HEAD(cache_map, cached_resolve_t) cache_root;
+/** Global: how many IPv6 requests have we made in all? */
+static uint64_t n_ipv6_requests_made = 0;
+/** Global: how many IPv6 requests have timed out? */
+static uint64_t n_ipv6_timeouts = 0;
+/** Global: Do we think that IPv6 DNS is broken? */
+static int dns_is_broken_for_ipv6 = 0;
+
/** Function to compare hashed resolves on their addresses; used to
* implement hash tables. */
static INLINE int
@@ -219,7 +262,7 @@ evdns_log_cb(int warn, const char *msg)
int severity = warn ? LOG_WARN : LOG_INFO;
if (!strcmpstart(msg, "Resolve requested for") &&
get_options()->SafeLogging) {
- log(LOG_INFO, LD_EXIT, "eventdns: Resolve requested.");
+ log_info(LD_EXIT, "eventdns: Resolve requested.");
return;
} else if (!strcmpstart(msg, "Search: ")) {
return;
@@ -248,13 +291,13 @@ evdns_log_cb(int warn, const char *msg)
control_event_server_status(LOG_WARN, "NAMESERVER_ALL_DOWN");
all_down = 1;
}
- log(severity, LD_EXIT, "eventdns: %s", msg);
+ tor_log(severity, LD_EXIT, "eventdns: %s", msg);
}
/** Helper: passed to eventdns.c as a callback so it can generate random
* numbers for transaction IDs and 0x20-hack coding. */
static void
-_dns_randfn(char *b, size_t n)
+dns_randfn_(char *b, size_t n)
{
crypto_rand(b,n);
}
@@ -264,7 +307,7 @@ int
dns_init(void)
{
init_cache_map();
- evdns_set_random_bytes_fn(_dns_randfn);
+ evdns_set_random_bytes_fn(dns_randfn_);
if (server_mode(get_options())) {
int r = configure_nameservers(1);
return r;
@@ -336,7 +379,7 @@ dns_get_expiry_ttl(uint32_t ttl)
/** Helper: free storage held by an entry in the DNS cache. */
static void
-_free_cached_resolve(cached_resolve_t *r)
+free_cached_resolve_(cached_resolve_t *r)
{
if (!r)
return;
@@ -345,8 +388,8 @@ _free_cached_resolve(cached_resolve_t *r)
r->pending_connections = victim->next;
tor_free(victim);
}
- if (r->is_reverse)
- tor_free(r->result.hostname);
+ if (r->res_status_hostname == RES_STATUS_DONE_OK)
+ tor_free(r->result_ptr.hostname);
r->magic = 0xFF00FF00;
tor_free(r);
}
@@ -355,7 +398,7 @@ _free_cached_resolve(cached_resolve_t *r)
* less-than-zero, zero, or greater-than-zero as appropriate. Used for
* the priority queue implementation. */
static int
-_compare_cached_resolves_by_expiry(const void *_a, const void *_b)
+compare_cached_resolves_by_expiry_(const void *_a, const void *_b)
{
const cached_resolve_t *a = _a, *b = _b;
if (a->expire < b->expire)
@@ -370,6 +413,65 @@ _compare_cached_resolves_by_expiry(const void *_a, const void *_b)
* will expire. */
static smartlist_t *cached_resolve_pqueue = NULL;
+static void
+cached_resolve_add_answer(cached_resolve_t *resolve,
+ int query_type,
+ int dns_result,
+ const tor_addr_t *answer_addr,
+ const char *answer_hostname,
+ uint32_t ttl)
+{
+ if (query_type == DNS_PTR) {
+ if (resolve->res_status_hostname != RES_STATUS_INFLIGHT)
+ return;
+
+ if (dns_result == DNS_ERR_NONE && answer_hostname) {
+ resolve->result_ptr.hostname = tor_strdup(answer_hostname);
+ resolve->res_status_hostname = RES_STATUS_DONE_OK;
+ } else {
+ resolve->result_ptr.err_hostname = dns_result;
+ resolve->res_status_hostname = RES_STATUS_DONE_ERR;
+ }
+ resolve->ttl_hostname = ttl;
+ } else if (query_type == DNS_IPv4_A) {
+ if (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT)
+ return;
+
+ if (dns_result == DNS_ERR_NONE && answer_addr &&
+ tor_addr_family(answer_addr) == AF_INET) {
+ resolve->result_ipv4.addr_ipv4 = tor_addr_to_ipv4h(answer_addr);
+ resolve->res_status_ipv4 = RES_STATUS_DONE_OK;
+ } else {
+ resolve->result_ipv4.err_ipv4 = dns_result;
+ resolve->res_status_ipv4 = RES_STATUS_DONE_ERR;
+ }
+
+ } else if (query_type == DNS_IPv6_AAAA) {
+ if (resolve->res_status_ipv6 != RES_STATUS_INFLIGHT)
+ return;
+
+ if (dns_result == DNS_ERR_NONE && answer_addr &&
+ tor_addr_family(answer_addr) == AF_INET6) {
+ memcpy(&resolve->result_ipv6.addr_ipv6,
+ tor_addr_to_in6(answer_addr),
+ sizeof(struct in6_addr));
+ resolve->res_status_ipv6 = RES_STATUS_DONE_OK;
+ } else {
+ resolve->result_ipv6.err_ipv6 = dns_result;
+ resolve->res_status_ipv6 = RES_STATUS_DONE_ERR;
+ }
+ }
+}
+
+/** Return true iff there are no in-flight requests for <b>resolve</b>. */
+static int
+cached_resolve_have_all_answers(const cached_resolve_t *resolve)
+{
+ return (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT &&
+ resolve->res_status_ipv6 != RES_STATUS_INFLIGHT &&
+ resolve->res_status_hostname != RES_STATUS_INFLIGHT);
+}
+
/** Set an expiry time for a cached_resolve_t, and add it to the expiry
* priority queue */
static void
@@ -380,7 +482,7 @@ set_expiry(cached_resolve_t *resolve, time_t expires)
cached_resolve_pqueue = smartlist_new();
resolve->expire = expires;
smartlist_pqueue_add(cached_resolve_pqueue,
- _compare_cached_resolves_by_expiry,
+ compare_cached_resolves_by_expiry_,
STRUCT_OFFSET(cached_resolve_t, minheap_idx),
resolve);
}
@@ -395,13 +497,13 @@ dns_free_all(void)
SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res,
{
if (res->state == CACHE_STATE_DONE)
- _free_cached_resolve(res);
+ free_cached_resolve_(res);
});
}
for (ptr = HT_START(cache_map, &cache_root); ptr != NULL; ptr = next) {
item = *ptr;
next = HT_NEXT_RMV(cache_map, &cache_root, ptr);
- _free_cached_resolve(item);
+ free_cached_resolve_(item);
}
HT_CLEAR(cache_map, &cache_root);
smartlist_free(cached_resolve_pqueue);
@@ -427,7 +529,7 @@ purge_expired_resolves(time_t now)
if (resolve->expire > now)
break;
smartlist_pqueue_pop(cached_resolve_pqueue,
- _compare_cached_resolves_by_expiry,
+ compare_cached_resolves_by_expiry_,
STRUCT_OFFSET(cached_resolve_t, minheap_idx));
if (resolve->state == CACHE_STATE_PENDING) {
@@ -435,8 +537,7 @@ purge_expired_resolves(time_t now)
"Expiring a dns resolve %s that's still pending. Forgot to "
"cull it? DNS resolve didn't tell us about the timeout?",
escaped_safe_str(resolve->address));
- } else if (resolve->state == CACHE_STATE_CACHED_VALID ||
- resolve->state == CACHE_STATE_CACHED_FAILED) {
+ } else if (resolve->state == CACHE_STATE_CACHED) {
log_debug(LD_EXIT,
"Forgetting old cached resolve (address %s, expires %lu)",
escaped_safe_str(resolve->address),
@@ -454,9 +555,9 @@ purge_expired_resolves(time_t now)
pend = resolve->pending_connections;
resolve->pending_connections = pend->next;
/* Connections should only be pending if they have no socket. */
- tor_assert(!SOCKET_OK(pend->conn->_base.s));
+ tor_assert(!SOCKET_OK(pend->conn->base_.s));
pendconn = pend->conn;
- if (!pendconn->_base.marked_for_close) {
+ if (!pendconn->base_.marked_for_close) {
connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT);
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
connection_free(TO_CONN(pendconn));
@@ -465,8 +566,7 @@ purge_expired_resolves(time_t now)
}
}
- if (resolve->state == CACHE_STATE_CACHED_VALID ||
- resolve->state == CACHE_STATE_CACHED_FAILED ||
+ if (resolve->state == CACHE_STATE_CACHED ||
resolve->state == CACHE_STATE_PENDING) {
removed = HT_REMOVE(cache_map, &cache_root, resolve);
if (removed != resolve) {
@@ -481,8 +581,8 @@ purge_expired_resolves(time_t now)
cached_resolve_t *tmp = HT_FIND(cache_map, &cache_root, resolve);
tor_assert(tmp != resolve);
}
- if (resolve->is_reverse)
- tor_free(resolve->result.hostname);
+ if (resolve->res_status_hostname == RES_STATUS_DONE_OK)
+ tor_free(resolve->result_ptr.hostname);
resolve->magic = 0xF0BBF0BB;
tor_free(resolve);
}
@@ -490,19 +590,24 @@ purge_expired_resolves(time_t now)
assert_cache_ok();
}
+/* argument for send_resolved_cell only, meaning "let the answer type be ipv4
+ * or ipv6 depending on the connection's address". */
+#define RESOLVED_TYPE_AUTO 0xff
+
/** Send a response to the RESOLVE request of a connection.
* <b>answer_type</b> must be one of
- * RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT).
+ * RESOLVED_TYPE_(AUTO|ERROR|ERROR_TRANSIENT|).
*
* If <b>circ</b> is provided, and we have a cached answer, send the
* answer back along circ; otherwise, send the answer back along
* <b>conn</b>'s attached circuit.
*/
static void
-send_resolved_cell(edge_connection_t *conn, uint8_t answer_type)
+send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
+ const cached_resolve_t *resolved)
{
- char buf[RELAY_PAYLOAD_SIZE];
- size_t buflen;
+ char buf[RELAY_PAYLOAD_SIZE], *cp = buf;
+ size_t buflen = 0;
uint32_t ttl;
buf[0] = answer_type;
@@ -510,19 +615,36 @@ send_resolved_cell(edge_connection_t *conn, uint8_t answer_type)
switch (answer_type)
{
- case RESOLVED_TYPE_IPV4:
- buf[1] = 4;
- set_uint32(buf+2, tor_addr_to_ipv4n(&conn->_base.addr));
- set_uint32(buf+6, htonl(ttl));
- buflen = 10;
- break;
- /*XXXX IP6 need ipv6 implementation */
+ case RESOLVED_TYPE_AUTO:
+ if (resolved && resolved->res_status_ipv4 == RES_STATUS_DONE_OK) {
+ cp[0] = RESOLVED_TYPE_IPV4;
+ cp[1] = 4;
+ set_uint32(cp+2, htonl(resolved->result_ipv4.addr_ipv4));
+ set_uint32(cp+6, htonl(ttl));
+ cp += 10;
+ }
+ if (resolved && resolved->res_status_ipv6 == RES_STATUS_DONE_OK) {
+ const uint8_t *bytes = resolved->result_ipv6.addr_ipv6.s6_addr;
+ cp[0] = RESOLVED_TYPE_IPV6;
+ cp[1] = 16;
+ memcpy(cp+2, bytes, 16);
+ set_uint32(cp+18, htonl(ttl));
+ cp += 22;
+ }
+ if (cp != buf) {
+ buflen = cp - buf;
+ break;
+ } else {
+ answer_type = RESOLVED_TYPE_ERROR;
+ /* fall through. */
+ }
case RESOLVED_TYPE_ERROR_TRANSIENT:
case RESOLVED_TYPE_ERROR:
{
const char *errmsg = "Error resolving hostname";
size_t msglen = strlen(errmsg);
+ buf[0] = answer_type;
buf[1] = msglen;
strlcpy(buf+2, errmsg, sizeof(buf)-2);
set_uint32(buf+2+msglen, htonl(ttl));
@@ -600,10 +722,11 @@ dns_resolve(edge_connection_t *exitconn)
int is_resolve, r;
int made_connection_pending = 0;
char *hostname = NULL;
- is_resolve = exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE;
+ cached_resolve_t *resolve = NULL;
+ is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE;
r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname,
- &made_connection_pending);
+ &made_connection_pending, &resolve);
switch (r) {
case 1:
@@ -614,7 +737,7 @@ dns_resolve(edge_connection_t *exitconn)
if (hostname)
send_resolved_hostname_cell(exitconn, hostname);
else
- send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
+ send_resolved_cell(exitconn, RESOLVED_TYPE_AUTO, resolve);
exitconn->on_circuit = NULL;
} else {
/* Add to the n_streams list; the calling function will send back a
@@ -626,7 +749,7 @@ dns_resolve(edge_connection_t *exitconn)
case 0:
/* The request is pending: add the connection into the linked list of
* resolving_streams on this circuit. */
- exitconn->_base.state = EXIT_CONN_STATE_RESOLVING;
+ exitconn->base_.state = EXIT_CONN_STATE_RESOLVING;
exitconn->next_stream = oncirc->resolving_streams;
oncirc->resolving_streams = exitconn;
break;
@@ -636,14 +759,15 @@ dns_resolve(edge_connection_t *exitconn)
* and stop everybody waiting for the same connection. */
if (is_resolve) {
send_resolved_cell(exitconn,
- (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT);
+ (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT,
+ NULL);
}
exitconn->on_circuit = NULL;
- dns_cancel_pending_resolve(exitconn->_base.address);
+ dns_cancel_pending_resolve(exitconn->base_.address);
- if (!made_connection_pending && !exitconn->_base.marked_for_close) {
+ if (!made_connection_pending && !exitconn->base_.marked_for_close) {
/* If we made the connection pending, then we freed it already in
* dns_cancel_pending_resolve(). If we marked it for close, it'll
* get freed from the main loop. Otherwise, can free it now. */
@@ -670,48 +794,50 @@ dns_resolve(edge_connection_t *exitconn)
* Set *<b>made_connection_pending_out</b> to true if we have placed
* <b>exitconn</b> on the list of pending connections for some resolve; set it
* to false otherwise.
+ *
+ * Set *<b>resolve_out</b> to a cached resolve, if we found one.
*/
static int
dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
or_circuit_t *oncirc, char **hostname_out,
- int *made_connection_pending_out)
+ int *made_connection_pending_out,
+ cached_resolve_t **resolve_out)
{
cached_resolve_t *resolve;
cached_resolve_t search;
pending_connection_t *pending_connection;
- const routerinfo_t *me;
+ int is_reverse = 0;
tor_addr_t addr;
time_t now = time(NULL);
- uint8_t is_reverse = 0;
int r;
assert_connection_ok(TO_CONN(exitconn), 0);
- tor_assert(!SOCKET_OK(exitconn->_base.s));
+ tor_assert(!SOCKET_OK(exitconn->base_.s));
assert_cache_ok();
tor_assert(oncirc);
*made_connection_pending_out = 0;
- /* first check if exitconn->_base.address is an IP. If so, we already
+ /* first check if exitconn->base_.address is an IP. If so, we already
* know the answer. */
- if (tor_addr_parse(&addr, exitconn->_base.address) >= 0) {
- if (tor_addr_family(&addr) == AF_INET) {
- tor_addr_copy(&exitconn->_base.addr, &addr);
+ if (tor_addr_parse(&addr, exitconn->base_.address) >= 0) {
+ if (tor_addr_family(&addr) == AF_INET ||
+ tor_addr_family(&addr) == AF_INET6) {
+ tor_addr_copy(&exitconn->base_.addr, &addr);
exitconn->address_ttl = DEFAULT_DNS_TTL;
return 1;
} else {
- /* XXXX IPv6 */
+ /* XXXX unspec? Bogus? */
return -1;
}
}
/* If we're a non-exit, don't even do DNS lookups. */
- if (!(me = router_get_my_routerinfo()) ||
- policy_is_reject_star(me->exit_policy)) {
+ if (router_my_exit_policy_is_reject_star())
return -1;
- }
- if (address_is_invalid_destination(exitconn->_base.address, 0)) {
- log(LOG_PROTOCOL_WARN, LD_EXIT,
+
+ if (address_is_invalid_destination(exitconn->base_.address, 0)) {
+ tor_log(LOG_PROTOCOL_WARN, LD_EXIT,
"Rejecting invalid destination address %s",
- escaped_safe_str(exitconn->_base.address));
+ escaped_safe_str(exitconn->base_.address));
return -1;
}
@@ -719,14 +845,14 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
* resolves in the hash table. */
purge_expired_resolves(now);
- /* lower-case exitconn->_base.address, so it's in canonical form */
- tor_strlower(exitconn->_base.address);
+ /* lower-case exitconn->base_.address, so it's in canonical form */
+ tor_strlower(exitconn->base_.address);
/* Check whether this is a reverse lookup. If it's malformed, or it's a
* .in-addr.arpa address but this isn't a resolve request, kill the
* connection.
*/
- if ((r = tor_addr_parse_PTR_name(&addr, exitconn->_base.address,
+ if ((r = tor_addr_parse_PTR_name(&addr, exitconn->base_.address,
AF_UNSPEC, 0)) != 0) {
if (r == 1) {
is_reverse = 1;
@@ -737,21 +863,22 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
if (!is_reverse || !is_resolve) {
if (!is_reverse)
log_info(LD_EXIT, "Bad .in-addr.arpa address \"%s\"; sending error.",
- escaped_safe_str(exitconn->_base.address));
+ escaped_safe_str(exitconn->base_.address));
else if (!is_resolve)
log_info(LD_EXIT,
"Attempt to connect to a .in-addr.arpa address \"%s\"; "
"sending error.",
- escaped_safe_str(exitconn->_base.address));
+ escaped_safe_str(exitconn->base_.address));
return -1;
}
//log_notice(LD_EXIT, "Looks like an address %s",
- //exitconn->_base.address);
+ //exitconn->base_.address);
}
+ exitconn->is_reverse_dns_lookup = is_reverse;
/* now check the hash table to see if 'address' is already there. */
- strlcpy(search.address, exitconn->_base.address, sizeof(search.address));
+ strlcpy(search.address, exitconn->base_.address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
if (resolve && resolve->expire > now) { /* already there */
switch (resolve->state) {
@@ -763,27 +890,19 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
pending_connection->next = resolve->pending_connections;
resolve->pending_connections = pending_connection;
*made_connection_pending_out = 1;
- log_debug(LD_EXIT,"Connection (fd %d) waiting for pending DNS "
- "resolve of %s", exitconn->_base.s,
- escaped_safe_str(exitconn->_base.address));
+ log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") waiting "
+ "for pending DNS resolve of %s", exitconn->base_.s,
+ escaped_safe_str(exitconn->base_.address));
return 0;
- case CACHE_STATE_CACHED_VALID:
- log_debug(LD_EXIT,"Connection (fd %d) found cached answer for %s",
- exitconn->_base.s,
+ case CACHE_STATE_CACHED:
+ log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") found "
+ "cached answer for %s",
+ exitconn->base_.s,
escaped_safe_str(resolve->address));
- exitconn->address_ttl = resolve->ttl;
- if (resolve->is_reverse) {
- tor_assert(is_resolve);
- *hostname_out = tor_strdup(resolve->result.hostname);
- } else {
- tor_addr_from_ipv4h(&exitconn->_base.addr, resolve->result.a.addr);
- }
- return 1;
- case CACHE_STATE_CACHED_FAILED:
- log_debug(LD_EXIT,"Connection (fd %d) found cached error for %s",
- exitconn->_base.s,
- escaped_safe_str(exitconn->_base.address));
- return -1;
+
+ *resolve_out = resolve;
+
+ return set_exitconn_info_from_resolve(exitconn, resolve, hostname_out);
case CACHE_STATE_DONE:
log_err(LD_BUG, "Found a 'DONE' dns resolve still in the cache.");
tor_fragile_assert();
@@ -796,8 +915,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
resolve->magic = CACHED_RESOLVE_MAGIC;
resolve->state = CACHE_STATE_PENDING;
resolve->minheap_idx = -1;
- resolve->is_reverse = is_reverse;
- strlcpy(resolve->address, exitconn->_base.address, sizeof(resolve->address));
+ strlcpy(resolve->address, exitconn->base_.address, sizeof(resolve->address));
/* add this connection to the pending list */
pending_connection = tor_malloc_zero(sizeof(pending_connection_t));
@@ -810,10 +928,115 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
set_expiry(resolve, now + RESOLVE_MAX_TIMEOUT);
log_debug(LD_EXIT,"Launching %s.",
- escaped_safe_str(exitconn->_base.address));
+ escaped_safe_str(exitconn->base_.address));
assert_cache_ok();
- return launch_resolve(exitconn);
+ return launch_resolve(resolve);
+}
+
+/** Given an exit connection <b>exitconn</b>, and a cached_resolve_t
+ * <b>resolve</b> whose DNS lookups have all succeeded or failed, update the
+ * appropriate fields (address_ttl and addr) of <b>exitconn</b>.
+ *
+ * If this is a reverse lookup, set *<b>hostname_out</b> to a newly allocated
+ * copy of the name resulting hostname.
+ *
+ * Return -2 on a transient error, -1 on a permenent error, and 1 on
+ * a successful lookup.
+ */
+static int
+set_exitconn_info_from_resolve(edge_connection_t *exitconn,
+ const cached_resolve_t *resolve,
+ char **hostname_out)
+{
+ int ipv4_ok, ipv6_ok, answer_with_ipv4, r;
+ uint32_t begincell_flags;
+ const int is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE;
+ tor_assert(exitconn);
+ tor_assert(resolve);
+
+ if (exitconn->is_reverse_dns_lookup) {
+ exitconn->address_ttl = resolve->ttl_hostname;
+ if (resolve->res_status_hostname == RES_STATUS_DONE_OK) {
+ *hostname_out = tor_strdup(resolve->result_ptr.hostname);
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ /* If we're here then the connection wants one or either of ipv4, ipv6, and
+ * we can give it one or both. */
+ if (is_resolve) {
+ begincell_flags = BEGIN_FLAG_IPV6_OK;
+ } else {
+ begincell_flags = exitconn->begincell_flags;
+ }
+
+ ipv4_ok = (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) &&
+ ! (begincell_flags & BEGIN_FLAG_IPV4_NOT_OK);
+ ipv6_ok = (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) &&
+ (begincell_flags & BEGIN_FLAG_IPV6_OK) &&
+ get_options()->IPv6Exit;
+
+ /* Now decide which one to actually give. */
+ if (ipv4_ok && ipv6_ok && is_resolve) {
+ answer_with_ipv4 = 1;
+ } else if (ipv4_ok && ipv6_ok) {
+ /* If we have both, see if our exit policy has an opinion. */
+ const uint16_t port = exitconn->base_.port;
+ int ipv4_allowed, ipv6_allowed;
+ tor_addr_t a4, a6;
+ tor_addr_from_ipv4h(&a4, resolve->result_ipv4.addr_ipv4);
+ tor_addr_from_in6(&a6, &resolve->result_ipv6.addr_ipv6);
+ ipv4_allowed = !router_compare_to_my_exit_policy(&a4, port);
+ ipv6_allowed = !router_compare_to_my_exit_policy(&a6, port);
+ if (ipv4_allowed && !ipv6_allowed) {
+ answer_with_ipv4 = 1;
+ } else if (ipv6_allowed && !ipv4_allowed) {
+ answer_with_ipv4 = 0;
+ } else {
+ /* Our exit policy would permit both. Answer with whichever the user
+ * prefers */
+ answer_with_ipv4 = !(begincell_flags &
+ BEGIN_FLAG_IPV6_PREFERRED);
+ }
+ } else {
+ /* Otherwise if one is okay, send it back. */
+ if (ipv4_ok) {
+ answer_with_ipv4 = 1;
+ } else if (ipv6_ok) {
+ answer_with_ipv4 = 0;
+ } else {
+ /* Neither one was okay. Choose based on user preference. */
+ answer_with_ipv4 = !(begincell_flags &
+ BEGIN_FLAG_IPV6_PREFERRED);
+ }
+ }
+
+ /* Finally, we write the answer back. */
+ r = 1;
+ if (answer_with_ipv4) {
+ if (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) {
+ tor_addr_from_ipv4h(&exitconn->base_.addr,
+ resolve->result_ipv4.addr_ipv4);
+ } else {
+ r = evdns_err_is_transient(resolve->result_ipv4.err_ipv4) ? -2 : -1;
+ }
+
+ exitconn->address_ttl = resolve->ttl_ipv4;
+ } else {
+ if (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) {
+ tor_addr_from_in6(&exitconn->base_.addr,
+ &resolve->result_ipv6.addr_ipv6);
+ } else {
+ r = evdns_err_is_transient(resolve->result_ipv6.err_ipv6) ? -2 : -1;
+ }
+
+ exitconn->address_ttl = resolve->ttl_ipv6;
+ }
+
+ return r;
}
/** Log an error and abort if conn is waiting for a DNS resolve.
@@ -826,7 +1049,7 @@ assert_connection_edge_not_dns_pending(edge_connection_t *conn)
#if 1
cached_resolve_t *resolve;
- strlcpy(search.address, conn->_base.address, sizeof(search.address));
+ strlcpy(search.address, conn->base_.address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
if (!resolve)
return;
@@ -856,7 +1079,7 @@ assert_all_pending_dns_resolves_ok(void)
pend;
pend = pend->next) {
assert_connection_ok(TO_CONN(pend->conn), 0);
- tor_assert(!SOCKET_OK(pend->conn->_base.s));
+ tor_assert(!SOCKET_OK(pend->conn->base_.s));
tor_assert(!connection_in_array(TO_CONN(pend->conn)));
}
}
@@ -871,15 +1094,15 @@ connection_dns_remove(edge_connection_t *conn)
cached_resolve_t search;
cached_resolve_t *resolve;
- tor_assert(conn->_base.type == CONN_TYPE_EXIT);
- tor_assert(conn->_base.state == EXIT_CONN_STATE_RESOLVING);
+ tor_assert(conn->base_.type == CONN_TYPE_EXIT);
+ tor_assert(conn->base_.state == EXIT_CONN_STATE_RESOLVING);
- strlcpy(search.address, conn->_base.address, sizeof(search.address));
+ strlcpy(search.address, conn->base_.address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
if (!resolve) {
log_notice(LD_BUG, "Address %s is not pending. Dropping.",
- escaped_safe_str(conn->_base.address));
+ escaped_safe_str(conn->base_.address));
return;
}
@@ -891,10 +1114,10 @@ connection_dns_remove(edge_connection_t *conn)
if (pend->conn == conn) {
resolve->pending_connections = pend->next;
tor_free(pend);
- log_debug(LD_EXIT, "First connection (fd %d) no longer waiting "
- "for resolve of %s",
- conn->_base.s,
- escaped_safe_str(conn->_base.address));
+ log_debug(LD_EXIT, "First connection (fd "TOR_SOCKET_T_FORMAT") no "
+ "longer waiting for resolve of %s",
+ conn->base_.s,
+ escaped_safe_str(conn->base_.address));
return;
} else {
for ( ; pend->next; pend = pend->next) {
@@ -903,8 +1126,9 @@ connection_dns_remove(edge_connection_t *conn)
pend->next = victim->next;
tor_free(victim);
log_debug(LD_EXIT,
- "Connection (fd %d) no longer waiting for resolve of %s",
- conn->_base.s, escaped_safe_str(conn->_base.address));
+ "Connection (fd "TOR_SOCKET_T_FORMAT") no longer waiting "
+ "for resolve of %s",
+ conn->base_.s, escaped_safe_str(conn->base_.address));
return; /* more are pending */
}
}
@@ -959,17 +1183,17 @@ dns_cancel_pending_resolve(const char *address)
escaped_safe_str(address));
while (resolve->pending_connections) {
pend = resolve->pending_connections;
- pend->conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ pend->conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
pendconn = pend->conn;
assert_connection_ok(TO_CONN(pendconn), 0);
- tor_assert(!SOCKET_OK(pendconn->_base.s));
- if (!pendconn->_base.marked_for_close) {
+ tor_assert(!SOCKET_OK(pendconn->base_.s));
+ if (!pendconn->base_.marked_for_close) {
connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED);
}
circ = circuit_get_by_edge_conn(pendconn);
if (circ)
circuit_detach_stream(circ, pendconn);
- if (!pendconn->_base.marked_for_close)
+ if (!pendconn->base_.marked_for_close)
connection_free(TO_CONN(pendconn));
resolve->pending_connections = pend->next;
tor_free(pend);
@@ -987,47 +1211,6 @@ dns_cancel_pending_resolve(const char *address)
resolve->state = CACHE_STATE_DONE;
}
-/** Helper: adds an entry to the DNS cache mapping <b>address</b> to the ipv4
- * address <b>addr</b> (if is_reverse is 0) or the hostname <b>hostname</b> (if
- * is_reverse is 1). <b>ttl</b> is a cache ttl; <b>outcome</b> is one of
- * DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
- **/
-static void
-add_answer_to_cache(const char *address, uint8_t is_reverse, uint32_t addr,
- const char *hostname, char outcome, uint32_t ttl)
-{
- cached_resolve_t *resolve;
- if (outcome == DNS_RESOLVE_FAILED_TRANSIENT)
- return;
-
- //log_notice(LD_EXIT, "Adding to cache: %s -> %s (%lx, %s), %d",
- // address, is_reverse?"(reverse)":"", (unsigned long)addr,
- // hostname?hostname:"NULL",(int)outcome);
-
- resolve = tor_malloc_zero(sizeof(cached_resolve_t));
- resolve->magic = CACHED_RESOLVE_MAGIC;
- resolve->state = (outcome == DNS_RESOLVE_SUCCEEDED) ?
- CACHE_STATE_CACHED_VALID : CACHE_STATE_CACHED_FAILED;
- strlcpy(resolve->address, address, sizeof(resolve->address));
- resolve->is_reverse = is_reverse;
- if (is_reverse) {
- if (outcome == DNS_RESOLVE_SUCCEEDED) {
- tor_assert(hostname);
- resolve->result.hostname = tor_strdup(hostname);
- } else {
- tor_assert(! hostname);
- resolve->result.hostname = NULL;
- }
- } else {
- tor_assert(!hostname);
- resolve->result.a.addr = addr;
- }
- resolve->ttl = ttl;
- assert_resolve_ok(resolve);
- HT_INSERT(cache_map, &cache_root, resolve);
- set_expiry(resolve, time(NULL) + dns_get_expiry_ttl(ttl));
-}
-
/** Return true iff <b>address</b> is one of the addresses we use to verify
* that well-known sites aren't being hijacked by our DNS servers. */
static INLINE int
@@ -1035,25 +1218,26 @@ is_test_address(const char *address)
{
const or_options_t *options = get_options();
return options->ServerDNSTestAddresses &&
- smartlist_string_isin_case(options->ServerDNSTestAddresses, address);
+ smartlist_contains_string_case(options->ServerDNSTestAddresses, address);
}
-/** Called on the OR side when a DNS worker or the eventdns library tells us
- * the outcome of a DNS resolve: tell all pending connections about the result
- * of the lookup, and cache the value. (<b>address</b> is a NUL-terminated
- * string containing the address to look up; <b>addr</b> is an IPv4 address in
- * host order; <b>outcome</b> is one of
- * DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
+/** Called on the OR side when the eventdns library tells us the outcome of a
+ * single DNS resolve: remember the answer, and tell all pending connections
+ * about the result of the lookup if the lookup is now done. (<b>address</b>
+ * is a NUL-terminated string containing the address to look up;
+ * <b>query_type</b> is one of DNS_{IPv4_A,IPv6_AAAA,PTR}; <b>dns_answer</b>
+ * is DNS_OK or one of DNS_ERR_*, <b>addr</b> is an IPv4 or IPv6 address if we
+ * got one; <b>hostname</b> is a hostname fora PTR request if we got one, and
+ * <b>ttl</b> is the time-to-live of this answer, in seconds.)
*/
static void
-dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
- const char *hostname, char outcome, uint32_t ttl)
+dns_found_answer(const char *address, uint8_t query_type,
+ int dns_answer,
+ const tor_addr_t *addr,
+ const char *hostname, uint32_t ttl)
{
- pending_connection_t *pend;
cached_resolve_t search;
- cached_resolve_t *resolve, *removed;
- edge_connection_t *pendconn;
- circuit_t *circ;
+ cached_resolve_t *resolve;
assert_cache_ok();
@@ -1063,9 +1247,8 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
if (!resolve) {
int is_test_addr = is_test_address(address);
if (!is_test_addr)
- log_info(LD_EXIT,"Resolved unasked address %s; caching anyway.",
+ log_info(LD_EXIT,"Resolved unasked address %s; ignoring.",
escaped_safe_str(address));
- add_answer_to_cache(address, is_reverse, addr, hostname, outcome, ttl);
return;
}
assert_resolve_ok(resolve);
@@ -1081,46 +1264,66 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
tor_assert(resolve->pending_connections == NULL);
return;
}
- /* Removed this assertion: in fact, we'll sometimes get a double answer
- * to the same question. This can happen when we ask one worker to resolve
- * X.Y.Z., then we cancel the request, and then we ask another worker to
- * resolve X.Y.Z. */
- /* tor_assert(resolve->state == CACHE_STATE_PENDING); */
+
+ cached_resolve_add_answer(resolve, query_type, dns_answer,
+ addr, hostname, ttl);
+
+ if (cached_resolve_have_all_answers(resolve)) {
+ inform_pending_connections(resolve);
+
+ make_pending_resolve_cached(resolve);
+ }
+}
+
+/** Given a pending cached_resolve_t that we just finished resolving,
+ * inform every connection that was waiting for the outcome of that
+ * resolution. */
+static void
+inform_pending_connections(cached_resolve_t *resolve)
+{
+ pending_connection_t *pend;
+ edge_connection_t *pendconn;
+ int r;
while (resolve->pending_connections) {
+ char *hostname = NULL;
pend = resolve->pending_connections;
pendconn = pend->conn; /* don't pass complex things to the
connection_mark_for_close macro */
assert_connection_ok(TO_CONN(pendconn),time(NULL));
- if (pendconn->_base.marked_for_close) {
+
+ if (pendconn->base_.marked_for_close) {
/* prevent double-remove. */
- pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
resolve->pending_connections = pend->next;
tor_free(pend);
continue;
}
- tor_addr_from_ipv4h(&pendconn->_base.addr, addr);
- pendconn->address_ttl = ttl;
- if (outcome != DNS_RESOLVE_SUCCEEDED) {
+ r = set_exitconn_info_from_resolve(pendconn,
+ resolve,
+ &hostname);
+
+ if (r < 0) {
/* prevent double-remove. */
- pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
- if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
+ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) {
connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED);
/* This detach must happen after we send the end cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
} else {
- send_resolved_cell(pendconn, outcome == DNS_RESOLVE_FAILED_PERMANENT ?
- RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT);
+ send_resolved_cell(pendconn, r == -1 ?
+ RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT,
+ NULL);
/* This detach must happen after we send the resolved cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
}
connection_free(TO_CONN(pendconn));
} else {
- if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
- tor_assert(!is_reverse);
+ circuit_t *circ;
+ if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) {
/* prevent double-remove. */
- pend->conn->_base.state = EXIT_CONN_STATE_CONNECTING;
+ pend->conn->base_.state = EXIT_CONN_STATE_CONNECTING;
circ = circuit_get_by_edge_conn(pend->conn);
tor_assert(circ);
@@ -1136,11 +1339,11 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
} else {
/* prevent double-remove. This isn't really an accurate state,
* but it does the right thing. */
- pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
- if (is_reverse)
+ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ if (pendconn->is_reverse_dns_lookup)
send_resolved_hostname_cell(pendconn, hostname);
else
- send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4);
+ send_resolved_cell(pendconn, RESOLVED_TYPE_AUTO, resolve);
circ = circuit_get_by_edge_conn(pendconn);
tor_assert(circ);
circuit_detach_stream(circ, pendconn);
@@ -1150,9 +1353,21 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
resolve->pending_connections = pend->next;
tor_free(pend);
}
+}
+
+/** Remove a pending cached_resolve_t from the hashtable, and add a
+ * corresponding cached cached_resolve_t.
+ *
+ * This function is only necessary because of the perversity of our
+ * cache timeout code; see inline comment for ideas on eliminating it.
+ **/
+static void
+make_pending_resolve_cached(cached_resolve_t *resolve)
+{
+ cached_resolve_t *removed;
resolve->state = CACHE_STATE_DONE;
- removed = HT_REMOVE(cache_map, &cache_root, &search);
+ removed = HT_REMOVE(cache_map, &cache_root, resolve);
if (removed != resolve) {
log_err(LD_BUG, "The pending resolve we found wasn't removable from"
" the cache. Tried to purge %s (%p); instead got %s (%p).",
@@ -1161,8 +1376,42 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
}
assert_resolve_ok(resolve);
assert_cache_ok();
+ /* The resolve will eventually just hit the time-out in the expiry queue and
+ * expire. See fd0bafb0dedc7e2 for a brief explanation of how this got that
+ * way. XXXXX we could do better!*/
+
+ {
+ cached_resolve_t *new_resolve = tor_memdup(resolve,
+ sizeof(cached_resolve_t));
+ uint32_t ttl = UINT32_MAX;
+ new_resolve->expire = 0; /* So that set_expiry won't croak. */
+ if (resolve->res_status_hostname == RES_STATUS_DONE_OK)
+ new_resolve->result_ptr.hostname =
+ tor_strdup(resolve->result_ptr.hostname);
+
+ new_resolve->state = CACHE_STATE_CACHED;
+
+ assert_resolve_ok(new_resolve);
+ HT_INSERT(cache_map, &cache_root, new_resolve);
+
+ if ((resolve->res_status_ipv4 == RES_STATUS_DONE_OK ||
+ resolve->res_status_ipv4 == RES_STATUS_DONE_ERR) &&
+ resolve->ttl_ipv4 < ttl)
+ ttl = resolve->ttl_ipv4;
+
+ if ((resolve->res_status_ipv6 == RES_STATUS_DONE_OK ||
+ resolve->res_status_ipv6 == RES_STATUS_DONE_ERR) &&
+ resolve->ttl_ipv6 < ttl)
+ ttl = resolve->ttl_ipv6;
+
+ if ((resolve->res_status_hostname == RES_STATUS_DONE_OK ||
+ resolve->res_status_hostname == RES_STATUS_DONE_ERR) &&
+ resolve->ttl_hostname < ttl)
+ ttl = resolve->ttl_hostname;
+
+ set_expiry(new_resolve, time(NULL) + dns_get_expiry_ttl(ttl));
+ }
- add_answer_to_cache(address, is_reverse, addr, hostname, outcome, ttl);
assert_cache_ok();
}
@@ -1210,24 +1459,18 @@ configure_nameservers(int force)
}
#ifdef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS
- if (options->OutboundBindAddress) {
- tor_addr_t addr;
- if (tor_addr_parse(&addr, options->OutboundBindAddress) < 0) {
- log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
- options->OutboundBindAddress);
+ if (! tor_addr_is_null(&options->OutboundBindAddressIPv4_)) {
+ int socklen;
+ struct sockaddr_storage ss;
+ socklen = tor_addr_to_sockaddr(&options->OutboundBindAddressIPv4_, 0,
+ (struct sockaddr *)&ss, sizeof(ss));
+ if (socklen <= 0) {
+ log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr."
+ " Ignoring.");
} else {
- int socklen;
- struct sockaddr_storage ss;
- socklen = tor_addr_to_sockaddr(&addr, 0,
- (struct sockaddr *)&ss, sizeof(ss));
- if (socklen <= 0) {
- log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr."
- " Ignoring.");
- } else {
- evdns_base_set_default_outgoing_bind_address(the_evdns_base,
- (struct sockaddr *)&ss,
- socklen);
- }
+ evdns_base_set_default_outgoing_bind_address(the_evdns_base,
+ (struct sockaddr *)&ss,
+ socklen);
}
}
#endif
@@ -1331,23 +1574,40 @@ static void
evdns_callback(int result, char type, int count, int ttl, void *addresses,
void *arg)
{
- char *string_address = arg;
- uint8_t is_reverse = 0;
- int status = DNS_RESOLVE_FAILED_PERMANENT;
- uint32_t addr = 0;
+ char *arg_ = arg;
+ uint8_t orig_query_type = arg_[0];
+ char *string_address = arg_ + 1;
+ tor_addr_t addr;
const char *hostname = NULL;
int was_wildcarded = 0;
+ tor_addr_make_unspec(&addr);
+
+ /* Keep track of whether IPv6 is working */
+ if (type == DNS_IPv6_AAAA) {
+ if (result == DNS_ERR_TIMEOUT) {
+ ++n_ipv6_timeouts;
+ }
+
+ if (n_ipv6_timeouts > 10 &&
+ n_ipv6_timeouts > n_ipv6_requests_made / 2) {
+ if (! dns_is_broken_for_ipv6) {
+ log_notice(LD_EXIT, "More than half of our IPv6 requests seem to "
+ "have timed out. I'm going to assume I can't get AAAA "
+ "responses.");
+ dns_is_broken_for_ipv6 = 1;
+ }
+ }
+ }
+
if (result == DNS_ERR_NONE) {
if (type == DNS_IPv4_A && count) {
char answer_buf[INET_NTOA_BUF_LEN+1];
- struct in_addr in;
char *escaped_address;
uint32_t *addrs = addresses;
- in.s_addr = addrs[0];
- addr = ntohl(addrs[0]);
- status = DNS_RESOLVE_SUCCEEDED;
- tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
+ tor_addr_from_ipv4n(&addr, addrs[0]);
+
+ tor_addr_to_str(answer_buf, &addr, sizeof(answer_buf), 0);
escaped_address = esc_for_log(string_address);
if (answer_is_wildcarded(answer_buf)) {
@@ -1356,8 +1616,30 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
safe_str(escaped_address),
escaped_safe_str(answer_buf));
was_wildcarded = 1;
- addr = 0;
- status = DNS_RESOLVE_FAILED_PERMANENT;
+ tor_addr_make_unspec(&addr);
+ result = DNS_ERR_NOTEXIST;
+ } else {
+ log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
+ safe_str(escaped_address),
+ escaped_safe_str(answer_buf));
+ }
+ tor_free(escaped_address);
+ } else if (type == DNS_IPv6_AAAA && count) {
+ char answer_buf[TOR_ADDR_BUF_LEN];
+ char *escaped_address;
+ struct in6_addr *addrs = addresses;
+ tor_addr_from_in6(&addr, &addrs[0]);
+ tor_inet_ntop(AF_INET6, &addrs[0], answer_buf, sizeof(answer_buf));
+ escaped_address = esc_for_log(string_address);
+
+ if (answer_is_wildcarded(answer_buf)) {
+ log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked "
+ "address %s; treating as a failure.",
+ safe_str(escaped_address),
+ escaped_safe_str(answer_buf));
+ was_wildcarded = 1;
+ tor_addr_make_unspec(&addr);
+ result = DNS_ERR_NOTEXIST;
} else {
log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
safe_str(escaped_address),
@@ -1366,9 +1648,7 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
tor_free(escaped_address);
} else if (type == DNS_PTR && count) {
char *escaped_address;
- is_reverse = 1;
hostname = ((char**)addresses)[0];
- status = DNS_RESOLVE_SUCCEEDED;
escaped_address = esc_for_log(string_address);
log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
safe_str(escaped_address),
@@ -1381,9 +1661,6 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
log_warn(LD_BUG, "eventdns returned no addresses or error for %s!",
escaped_safe_str(string_address));
}
- } else {
- if (evdns_err_is_transient(result))
- status = DNS_RESOLVE_FAILED_TRANSIENT;
}
if (was_wildcarded) {
if (is_test_address(string_address)) {
@@ -1392,23 +1669,78 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
add_wildcarded_test_address(string_address);
}
}
+
+ if (orig_query_type && type && orig_query_type != type) {
+ log_warn(LD_BUG, "Weird; orig_query_type == %d but type == %d",
+ (int)orig_query_type, (int)type);
+ }
if (result != DNS_ERR_SHUTDOWN)
- dns_found_answer(string_address, is_reverse, addr, hostname, status, ttl);
- tor_free(string_address);
+ dns_found_answer(string_address, orig_query_type,
+ result, &addr, hostname, ttl);
+
+ tor_free(arg_);
+}
+
+/** Start a single DNS resolve for <b>address</b> (if <b>query_type</b> is
+ * DNS_IPv4_A or DNS_IPv6_AAAA) <b>ptr_address</b> (if <b>query_type</b> is
+ * DNS_PTR). Return 0 if we launched the request, -1 otherwise. */
+static int
+launch_one_resolve(const char *address, uint8_t query_type,
+ const tor_addr_t *ptr_address)
+{
+ const int options = get_options()->ServerDNSSearchDomains ? 0
+ : DNS_QUERY_NO_SEARCH;
+ const size_t addr_len = strlen(address);
+ struct evdns_request *req = 0;
+ char *addr = tor_malloc(addr_len + 2);
+ addr[0] = (char) query_type;
+ memcpy(addr+1, address, addr_len + 1);
+
+ switch (query_type) {
+ case DNS_IPv4_A:
+ req = evdns_base_resolve_ipv4(the_evdns_base,
+ address, options, evdns_callback, addr);
+ break;
+ case DNS_IPv6_AAAA:
+ req = evdns_base_resolve_ipv6(the_evdns_base,
+ address, options, evdns_callback, addr);
+ ++n_ipv6_requests_made;
+ break;
+ case DNS_PTR:
+ if (tor_addr_family(ptr_address) == AF_INET)
+ req = evdns_base_resolve_reverse(the_evdns_base,
+ tor_addr_to_in(ptr_address),
+ DNS_QUERY_NO_SEARCH,
+ evdns_callback, addr);
+ else if (tor_addr_family(ptr_address) == AF_INET6)
+ req = evdns_base_resolve_reverse_ipv6(the_evdns_base,
+ tor_addr_to_in6(ptr_address),
+ DNS_QUERY_NO_SEARCH,
+ evdns_callback, addr);
+ else
+ log_warn(LD_BUG, "Called with PTR query and unexpected address family");
+ break;
+ default:
+ log_warn(LD_BUG, "Called with unexpectd query type %d", (int)query_type);
+ break;
+ }
+
+ if (req) {
+ return 0;
+ } else {
+ tor_free(addr);
+ return -1;
+ }
}
/** For eventdns: start resolving as necessary to find the target for
* <b>exitconn</b>. Returns -1 on error, -2 on transient error,
* 0 on "resolve launched." */
static int
-launch_resolve(edge_connection_t *exitconn)
+launch_resolve(cached_resolve_t *resolve)
{
- char *addr;
- struct evdns_request *req = NULL;
tor_addr_t a;
int r;
- int options = get_options()->ServerDNSSearchDomains ? 0
- : DNS_QUERY_NO_SEARCH;
if (get_options()->DisableNetwork)
return -1;
@@ -1422,40 +1754,45 @@ launch_resolve(edge_connection_t *exitconn)
}
}
- addr = tor_strdup(exitconn->_base.address);
-
r = tor_addr_parse_PTR_name(
- &a, exitconn->_base.address, AF_UNSPEC, 0);
+ &a, resolve->address, AF_UNSPEC, 0);
tor_assert(the_evdns_base);
if (r == 0) {
log_info(LD_EXIT, "Launching eventdns request for %s",
- escaped_safe_str(exitconn->_base.address));
- req = evdns_base_resolve_ipv4(the_evdns_base,
- exitconn->_base.address, options,
- evdns_callback, addr);
+ escaped_safe_str(resolve->address));
+ resolve->res_status_ipv4 = RES_STATUS_INFLIGHT;
+ if (get_options()->IPv6Exit)
+ resolve->res_status_ipv6 = RES_STATUS_INFLIGHT;
+
+ if (launch_one_resolve(resolve->address, DNS_IPv4_A, NULL) < 0) {
+ resolve->res_status_ipv4 = 0;
+ r = -1;
+ }
+
+ if (r==0 && get_options()->IPv6Exit) {
+ /* We ask for an IPv6 address for *everything*. */
+ if (launch_one_resolve(resolve->address, DNS_IPv6_AAAA, NULL) < 0) {
+ resolve->res_status_ipv6 = 0;
+ r = -1;
+ }
+ }
} else if (r == 1) {
+ r = 0;
log_info(LD_EXIT, "Launching eventdns reverse request for %s",
- escaped_safe_str(exitconn->_base.address));
- if (tor_addr_family(&a) == AF_INET)
- req = evdns_base_resolve_reverse(the_evdns_base,
- tor_addr_to_in(&a), DNS_QUERY_NO_SEARCH,
- evdns_callback, addr);
- else
- req = evdns_base_resolve_reverse_ipv6(the_evdns_base,
- tor_addr_to_in6(&a), DNS_QUERY_NO_SEARCH,
- evdns_callback, addr);
+ escaped_safe_str(resolve->address));
+ resolve->res_status_hostname = RES_STATUS_INFLIGHT;
+ if (launch_one_resolve(resolve->address, DNS_PTR, &a) < 0) {
+ resolve->res_status_hostname = 0;
+ r = -1;
+ }
} else if (r == -1) {
log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here.");
}
- r = 0;
- if (!req) {
+ if (r < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_EXIT, "eventdns rejected address %s.",
- escaped_safe_str(addr));
- r = -1;
- tor_free(addr); /* There is no evdns request in progress; stop
- * addr from getting leaked. */
+ escaped_safe_str(resolve->address));
}
return r;
}
@@ -1488,8 +1825,8 @@ static int dns_wildcarded_test_address_notice_given = 0;
/** True iff all addresses seem to be getting wildcarded. */
static int dns_is_completely_invalid = 0;
-/** Called when we see <b>id</b> (a dotted quad) in response to a request for
- * a hopefully bogus address. */
+/** Called when we see <b>id</b> (a dotted quad or IPv6 address) in response
+ * to a request for a hopefully bogus address. */
static void
wildcard_increment_answer(const char *id)
{
@@ -1506,8 +1843,8 @@ wildcard_increment_answer(const char *id)
if (*ip > 5 && n_wildcard_requests > 10) {
if (!dns_wildcard_list) dns_wildcard_list = smartlist_new();
- if (!smartlist_string_isin(dns_wildcard_list, id)) {
- log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
+ if (!smartlist_contains_string(dns_wildcard_list, id)) {
+ tor_log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
"Your DNS provider has given \"%s\" as an answer for %d different "
"invalid addresses. Apparently they are hijacking DNS failures. "
"I'll try to correct for this by treating future occurrences of "
@@ -1529,7 +1866,8 @@ add_wildcarded_test_address(const char *address)
if (!dns_wildcarded_test_address_list)
dns_wildcarded_test_address_list = smartlist_new();
- if (smartlist_string_isin_case(dns_wildcarded_test_address_list, address))
+ if (smartlist_contains_string_case(dns_wildcarded_test_address_list,
+ address))
return;
n_test_addrs = get_options()->ServerDNSTestAddresses ?
@@ -1538,7 +1876,7 @@ add_wildcarded_test_address(const char *address)
smartlist_add(dns_wildcarded_test_address_list, tor_strdup(address));
n = smartlist_len(dns_wildcarded_test_address_list);
if (n > n_test_addrs/2) {
- log(dns_wildcarded_test_address_notice_given ? LOG_INFO : LOG_NOTICE,
+ tor_log(dns_wildcarded_test_address_notice_given ? LOG_INFO : LOG_NOTICE,
LD_EXIT, "Your DNS provider tried to redirect \"%s\" to a junk "
"address. It has done this with %d test addresses so far. I'm "
"going to stop being an exit node for now, since our DNS seems so "
@@ -1561,18 +1899,28 @@ evdns_wildcard_check_callback(int result, char type, int count, int ttl,
{
(void)ttl;
++n_wildcard_requests;
- if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count) {
- uint32_t *addrs = addresses;
- int i;
+ if (result == DNS_ERR_NONE && count) {
char *string_address = arg;
- for (i = 0; i < count; ++i) {
- char answer_buf[INET_NTOA_BUF_LEN+1];
- struct in_addr in;
- in.s_addr = addrs[i];
- tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
- wildcard_increment_answer(answer_buf);
+ int i;
+ if (type == DNS_IPv4_A) {
+ const uint32_t *addrs = addresses;
+ for (i = 0; i < count; ++i) {
+ char answer_buf[INET_NTOA_BUF_LEN+1];
+ struct in_addr in;
+ in.s_addr = addrs[i];
+ tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
+ wildcard_increment_answer(answer_buf);
+ }
+ } else if (type == DNS_IPv6_AAAA) {
+ const struct in6_addr *addrs = addresses;
+ for (i = 0; i < count; ++i) {
+ char answer_buf[TOR_ADDR_BUF_LEN+1];
+ tor_inet_ntop(AF_INET6, &addrs[i], answer_buf, sizeof(answer_buf));
+ wildcard_increment_answer(answer_buf);
+ }
}
- log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
+
+ tor_log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
"Your DNS provider gave an answer for \"%s\", which "
"is not supposed to exist. Apparently they are hijacking "
"DNS failures. Trying to correct for this. We've noticed %d "
@@ -1588,7 +1936,8 @@ evdns_wildcard_check_callback(int result, char type, int count, int ttl,
* <b>min_len</b> and <b>max_len</b> random (plausible) characters followed by
* <b>suffix</b> */
static void
-launch_wildcard_check(int min_len, int max_len, const char *suffix)
+launch_wildcard_check(int min_len, int max_len, int is_ipv6,
+ const char *suffix)
{
char *addr;
struct evdns_request *req;
@@ -1598,7 +1947,15 @@ launch_wildcard_check(int min_len, int max_len, const char *suffix)
"domains with request for bogus hostname \"%s\"", addr);
tor_assert(the_evdns_base);
- req = evdns_base_resolve_ipv4(
+ if (is_ipv6)
+ req = evdns_base_resolve_ipv6(
+ the_evdns_base,
+ /* This "addr" tells us which address to resolve */
+ addr,
+ DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback,
+ /* This "addr" is an argument to the callback*/ addr);
+ else
+ req = evdns_base_resolve_ipv4(
the_evdns_base,
/* This "addr" tells us which address to resolve */
addr,
@@ -1613,10 +1970,9 @@ launch_wildcard_check(int min_len, int max_len, const char *suffix)
/** Launch attempts to resolve a bunch of known-good addresses (configured in
* ServerDNSTestAddresses). [Callback for a libevent timer] */
static void
-launch_test_addresses(int fd, short event, void *args)
+launch_test_addresses(evutil_socket_t fd, short event, void *args)
{
const or_options_t *options = get_options();
- struct evdns_request *req;
(void)fd;
(void)event;
(void)args;
@@ -1629,21 +1985,22 @@ launch_test_addresses(int fd, short event, void *args)
/* This situation is worse than the failure-hijacking situation. When this
* happens, we're no good for DNS requests at all, and we shouldn't really
* be an exit server.*/
- if (!options->ServerDNSTestAddresses)
- return;
- tor_assert(the_evdns_base);
- SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses,
- const char *, address) {
- char *a = tor_strdup(address);
- req = evdns_base_resolve_ipv4(the_evdns_base,
- address, DNS_QUERY_NO_SEARCH, evdns_callback, a);
+ if (options->ServerDNSTestAddresses) {
- if (!req) {
- log_info(LD_EXIT, "eventdns rejected test address %s",
- escaped_safe_str(address));
- tor_free(a);
- }
- } SMARTLIST_FOREACH_END(address);
+ tor_assert(the_evdns_base);
+ SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses,
+ const char *, address) {
+ if (launch_one_resolve(address, DNS_IPv4_A, NULL) < 0) {
+ log_info(LD_EXIT, "eventdns rejected test address %s",
+ escaped_safe_str(address));
+ }
+
+ if (launch_one_resolve(address, DNS_IPv6_AAAA, NULL) < 0) {
+ log_info(LD_EXIT, "eventdns rejected test address %s",
+ escaped_safe_str(address));
+ }
+ } SMARTLIST_FOREACH_END(address);
+ }
}
#define N_WILDCARD_CHECKS 2
@@ -1655,27 +2012,29 @@ launch_test_addresses(int fd, short event, void *args)
static void
dns_launch_wildcard_checks(void)
{
- int i;
+ int i, ipv6;
log_info(LD_EXIT, "Launching checks to see whether our nameservers like "
"to hijack DNS failures.");
- for (i = 0; i < N_WILDCARD_CHECKS; ++i) {
- /* RFC2606 reserves these. Sadly, some DNS hijackers, in a silly attempt
- * to 'comply' with rfc2606, refrain from giving A records for these.
- * This is the standards-compliance equivalent of making sure that your
- * crackhouse's elevator inspection certificate is up to date.
- */
- launch_wildcard_check(2, 16, ".invalid");
- launch_wildcard_check(2, 16, ".test");
-
- /* These will break specs if there are ever any number of
- * 8+-character top-level domains. */
- launch_wildcard_check(8, 16, "");
-
- /* Try some random .com/org/net domains. This will work fine so long as
- * not too many resolve to the same place. */
- launch_wildcard_check(8, 16, ".com");
- launch_wildcard_check(8, 16, ".org");
- launch_wildcard_check(8, 16, ".net");
+ for (ipv6 = 0; ipv6 <= 1; ++ipv6) {
+ for (i = 0; i < N_WILDCARD_CHECKS; ++i) {
+ /* RFC2606 reserves these. Sadly, some DNS hijackers, in a silly
+ * attempt to 'comply' with rfc2606, refrain from giving A records for
+ * these. This is the standards-compliance equivalent of making sure
+ * that your crackhouse's elevator inspection certificate is up to date.
+ */
+ launch_wildcard_check(2, 16, ipv6, ".invalid");
+ launch_wildcard_check(2, 16, ipv6, ".test");
+
+ /* These will break specs if there are ever any number of
+ * 8+-character top-level domains. */
+ launch_wildcard_check(8, 16, ipv6, "");
+
+ /* Try some random .com/org/net domains. This will work fine so long as
+ * not too many resolve to the same place. */
+ launch_wildcard_check(8, 16, ipv6, ".com");
+ launch_wildcard_check(8, 16, ipv6, ".org");
+ launch_wildcard_check(8, 16, ipv6, ".net");
+ }
}
}
@@ -1709,15 +2068,24 @@ dns_seems_to_be_broken(void)
return dns_is_completely_invalid;
}
+/** Return true iff we think that IPv6 hostname lookup is broken */
+int
+dns_seems_to_be_broken_for_ipv6(void)
+{
+ return dns_is_broken_for_ipv6;
+}
+
/** Forget what we've previously learned about our DNS servers' correctness. */
void
dns_reset_correctness_checks(void)
{
- strmap_free(dns_wildcard_response_count, _tor_free);
+ strmap_free(dns_wildcard_response_count, tor_free_);
dns_wildcard_response_count = NULL;
n_wildcard_requests = 0;
+ n_ipv6_requests_made = n_ipv6_timeouts = 0;
+
if (dns_wildcard_list) {
SMARTLIST_FOREACH(dns_wildcard_list, char *, cp, tor_free(cp));
smartlist_clear(dns_wildcard_list);
@@ -1728,7 +2096,8 @@ dns_reset_correctness_checks(void)
smartlist_clear(dns_wildcarded_test_address_list);
}
dns_wildcard_one_notice_given = dns_wildcard_notice_given =
- dns_wildcarded_test_address_notice_given = dns_is_completely_invalid = 0;
+ dns_wildcarded_test_address_notice_given = dns_is_completely_invalid =
+ dns_is_broken_for_ipv6 = 0;
}
/** Return true iff we have noticed that the dotted-quad <b>ip</b> has been
@@ -1736,7 +2105,7 @@ dns_reset_correctness_checks(void)
static int
answer_is_wildcarded(const char *ip)
{
- return dns_wildcard_list && smartlist_string_isin(dns_wildcard_list, ip);
+ return dns_wildcard_list && smartlist_contains_string(dns_wildcard_list, ip);
}
/** Exit with an assertion if <b>resolve</b> is corrupt. */
@@ -1752,11 +2121,14 @@ assert_resolve_ok(cached_resolve_t *resolve)
}
if (resolve->state == CACHE_STATE_PENDING ||
resolve->state == CACHE_STATE_DONE) {
+#if 0
tor_assert(!resolve->ttl);
if (resolve->is_reverse)
- tor_assert(!resolve->result.hostname);
+ tor_assert(!resolve->hostname);
else
- tor_assert(!resolve->result.a.addr);
+ tor_assert(!resolve->result_ipv4.addr_ipv4);
+#endif
+ /*XXXXX ADD MORE */
}
}
@@ -1779,15 +2151,15 @@ dump_dns_mem_usage(int severity)
/* Print out the count and estimated size of our &cache_root. It undercounts
hostnames in cached reverse resolves.
*/
- log(severity, LD_MM, "Our DNS cache has %d entries.", hash_count);
- log(severity, LD_MM, "Our DNS cache size is approximately %u bytes.",
+ tor_log(severity, LD_MM, "Our DNS cache has %d entries.", hash_count);
+ tor_log(severity, LD_MM, "Our DNS cache size is approximately %u bytes.",
(unsigned)hash_mem);
}
#ifdef DEBUG_DNS_CACHE
/** Exit with an assertion if the DNS cache is corrupt. */
static void
-_assert_cache_ok(void)
+assert_cache_ok_(void)
{
cached_resolve_t **resolve;
int bad_rep = _cache_map_HT_REP_IS_BAD(&cache_root);
@@ -1804,7 +2176,7 @@ _assert_cache_ok(void)
return;
smartlist_pqueue_assert_ok(cached_resolve_pqueue,
- _compare_cached_resolves_by_expiry,
+ compare_cached_resolves_by_expiry_,
STRUCT_OFFSET(cached_resolve_t, minheap_idx));
SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res,
diff --git a/src/or/dns.h b/src/or/dns.h
index 8c8b476ac..022cd4ac6 100644
--- a/src/or/dns.h
+++ b/src/or/dns.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for dns.c.
**/
-#ifndef _TOR_DNS_H
-#define _TOR_DNS_H
+#ifndef TOR_DNS_H
+#define TOR_DNS_H
int dns_init(void);
int has_dns_init_failed(void);
@@ -24,6 +24,7 @@ void dns_cancel_pending_resolve(const char *question);
int dns_resolve(edge_connection_t *exitconn);
void dns_launch_correctness_checks(void);
int dns_seems_to_be_broken(void);
+int dns_seems_to_be_broken_for_ipv6(void);
void dns_reset_correctness_checks(void);
void dump_dns_mem_usage(int severity);
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 69adcef9e..ebff7b524 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -89,6 +89,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
continue;
switch (req->questions[i]->type) {
case EVDNS_TYPE_A:
+ case EVDNS_TYPE_AAAA:
case EVDNS_TYPE_PTR:
q = req->questions[i];
default:
@@ -101,7 +102,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
evdns_server_request_respond(req, DNS_ERR_NOTIMPL);
return;
}
- if (q->type != EVDNS_TYPE_A) {
+ if (q->type != EVDNS_TYPE_A && q->type != EVDNS_TYPE_AAAA) {
tor_assert(q->type == EVDNS_TYPE_PTR);
}
@@ -125,7 +126,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
TO_CONN(conn)->port = port;
TO_CONN(conn)->address = tor_dup_addr(&tor_addr);
- if (q->type == EVDNS_TYPE_A)
+ if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA)
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE;
else
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
@@ -133,7 +134,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
strlcpy(entry_conn->socks_request->address, q->name,
sizeof(entry_conn->socks_request->address));
- entry_conn->socks_request->listener_type = listener->_base.type;
+ entry_conn->socks_request->listener_type = listener->base_.type;
entry_conn->dns_server_request = req;
entry_conn->isolation_flags = listener->isolation_flags;
entry_conn->session_group = listener->session_group;
@@ -146,7 +147,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
return;
}
- control_event_stream_status(entry_conn, STREAM_EVENT_NEW, 0);
+ control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0);
/* Now, unless a controller asked us to leave streams unattached,
* throw the connection over to get rewritten (which will
@@ -169,7 +170,8 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
* response; -1 if we couldn't launch the request.
*/
int
-dnsserv_launch_request(const char *name, int reverse)
+dnsserv_launch_request(const char *name, int reverse,
+ control_connection_t *control_conn)
{
entry_connection_t *entry_conn;
edge_connection_t *conn;
@@ -178,7 +180,26 @@ dnsserv_launch_request(const char *name, int reverse)
/* Make a new dummy AP connection, and attach the request to it. */
entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET);
conn = ENTRY_TO_EDGE_CONN(entry_conn);
- conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT;
+ conn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
+
+ tor_addr_copy(&TO_CONN(conn)->addr, &control_conn->base_.addr);
+#ifdef AF_UNIX
+ /*
+ * The control connection can be AF_UNIX and if so tor_dup_addr will
+ * unhelpfully say "<unknown address type>"; say "(Tor_internal)"
+ * instead.
+ */
+ if (control_conn->base_.socket_family == AF_UNIX) {
+ TO_CONN(conn)->port = 0;
+ TO_CONN(conn)->address = tor_strdup("(Tor_internal)");
+ } else {
+ TO_CONN(conn)->port = control_conn->base_.port;
+ TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr);
+ }
+#else
+ TO_CONN(conn)->port = control_conn->base_.port;
+ TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr);
+#endif
if (reverse)
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
@@ -202,6 +223,8 @@ dnsserv_launch_request(const char *name, int reverse)
return -1;
}
+ control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0);
+
/* Now, unless a controller asked us to leave streams unattached,
* throw the connection over to get rewritten (which will
* answer it immediately if it's in the cache, or completely bogus, or
@@ -289,8 +312,9 @@ dnsserv_resolved(entry_connection_t *conn,
* or more of the questions in the request); then, call
* evdns_server_request_respond. */
if (answer_type == RESOLVED_TYPE_IPV6) {
- log_info(LD_APP, "Got an IPv6 answer; that's not implemented.");
- err = DNS_ERR_NOTIMPL;
+ evdns_server_request_add_aaaa_reply(req,
+ name,
+ 1, answer, ttl);
} else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4 &&
conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
evdns_server_request_add_a_reply(req,
diff --git a/src/or/dnsserv.h b/src/or/dnsserv.h
index 3aaa038d2..687a77e59 100644
--- a/src/or/dnsserv.h
+++ b/src/or/dnsserv.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for dnsserv.c.
**/
-#ifndef _TOR_DNSSERV_H
-#define _TOR_DNSSERV_H
+#ifndef TOR_DNSSERV_H
+#define TOR_DNSSERV_H
void dnsserv_configure_listener(connection_t *conn);
void dnsserv_close_listener(connection_t *conn);
@@ -20,7 +20,8 @@ void dnsserv_resolved(entry_connection_t *conn,
const char *answer,
int ttl);
void dnsserv_reject_request(entry_connection_t *conn);
-int dnsserv_launch_request(const char *name, int is_reverse);
+int dnsserv_launch_request(const char *name, int is_reverse,
+ control_connection_t *control_conn);
#endif
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
new file mode 100644
index 000000000..2aa063cda
--- /dev/null
+++ b/src/or/entrynodes.c
@@ -0,0 +1,2255 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file entrynodes.c
+ * \brief Code to manage our fixed first nodes for various functions.
+ *
+ * Entry nodes can be guards (for general use) or bridges (for censorship
+ * circumvention).
+ **/
+
+#include "or.h"
+#include "circuitbuild.h"
+#include "circuitstats.h"
+#include "config.h"
+#include "confparse.h"
+#include "connection.h"
+#include "connection_or.h"
+#include "control.h"
+#include "directory.h"
+#include "entrynodes.h"
+#include "main.h"
+#include "microdesc.h"
+#include "networkstatus.h"
+#include "nodelist.h"
+#include "policies.h"
+#include "router.h"
+#include "routerlist.h"
+#include "routerparse.h"
+#include "routerset.h"
+#include "transports.h"
+#include "statefile.h"
+
+/** Information about a configured bridge. Currently this just matches the
+ * ones in the torrc file, but one day we may be able to learn about new
+ * bridges on our own, and remember them in the state file. */
+typedef struct {
+ /** Address of the bridge. */
+ tor_addr_t addr;
+ /** TLS port for the bridge. */
+ uint16_t port;
+ /** Boolean: We are re-parsing our bridge list, and we are going to remove
+ * this one if we don't find it in the list of configured bridges. */
+ unsigned marked_for_removal : 1;
+ /** Expected identity digest, or all zero bytes if we don't know what the
+ * digest should be. */
+ char identity[DIGEST_LEN];
+
+ /** Name of pluggable transport protocol taken from its config line. */
+ char *transport_name;
+
+ /** When should we next try to fetch a descriptor for this bridge? */
+ download_status_t fetch_status;
+} bridge_info_t;
+
+/** A list of our chosen entry guards. */
+static smartlist_t *entry_guards = NULL;
+/** A value of 1 means that the entry_guards list has changed
+ * and those changes need to be flushed to disk. */
+static int entry_guards_dirty = 0;
+
+static void bridge_free(bridge_info_t *bridge);
+static const node_t *choose_random_entry_impl(cpath_build_state_t *state,
+ int for_directory,
+ dirinfo_type_t dirtype);
+
+/** Return the list of entry guards, creating it if necessary. */
+const smartlist_t *
+get_entry_guards(void)
+{
+ if (! entry_guards)
+ entry_guards = smartlist_new();
+ return entry_guards;
+}
+
+/** Check whether the entry guard <b>e</b> is usable, given the directory
+ * authorities' opinion about the router (stored in <b>ri</b>) and the user's
+ * configuration (in <b>options</b>). Set <b>e</b>-&gt;bad_since
+ * accordingly. Return true iff the entry guard's status changes.
+ *
+ * If it's not usable, set *<b>reason</b> to a static string explaining why.
+ */
+static int
+entry_guard_set_status(entry_guard_t *e, const node_t *node,
+ time_t now, const or_options_t *options,
+ const char **reason)
+{
+ char buf[HEX_DIGEST_LEN+1];
+ int changed = 0;
+
+ *reason = NULL;
+
+ /* Do we want to mark this guard as bad? */
+ if (!node)
+ *reason = "unlisted";
+ else if (!node->is_running)
+ *reason = "down";
+ else if (options->UseBridges && (!node->ri ||
+ node->ri->purpose != ROUTER_PURPOSE_BRIDGE))
+ *reason = "not a bridge";
+ else if (options->UseBridges && !node_is_a_configured_bridge(node))
+ *reason = "not a configured bridge";
+ else if (!options->UseBridges && !node->is_possible_guard &&
+ !routerset_contains_node(options->EntryNodes,node))
+ *reason = "not recommended as a guard";
+ else if (routerset_contains_node(options->ExcludeNodes, node))
+ *reason = "excluded";
+ else if (e->path_bias_disabled)
+ *reason = "path-biased";
+
+ if (*reason && ! e->bad_since) {
+ /* Router is newly bad. */
+ base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
+ log_info(LD_CIRC, "Entry guard %s (%s) is %s: marking as unusable.",
+ e->nickname, buf, *reason);
+
+ e->bad_since = now;
+ control_event_guard(e->nickname, e->identity, "BAD");
+ changed = 1;
+ } else if (!*reason && e->bad_since) {
+ /* There's nothing wrong with the router any more. */
+ base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
+ log_info(LD_CIRC, "Entry guard %s (%s) is no longer unusable: "
+ "marking as ok.", e->nickname, buf);
+
+ e->bad_since = 0;
+ control_event_guard(e->nickname, e->identity, "GOOD");
+ changed = 1;
+ }
+
+ if (node) {
+ int is_dir = node_is_dir(node) && node->rs &&
+ node->rs->version_supports_microdesc_cache;
+ if (options->UseBridges && node_is_a_configured_bridge(node))
+ is_dir = 1;
+ if (e->is_dir_cache != is_dir) {
+ e->is_dir_cache = is_dir;
+ changed = 1;
+ }
+ }
+
+ return changed;
+}
+
+/** Return true iff enough time has passed since we last tried to connect
+ * to the unreachable guard <b>e</b> that we're willing to try again. */
+static int
+entry_is_time_to_retry(entry_guard_t *e, time_t now)
+{
+ long diff;
+ if (e->last_attempted < e->unreachable_since)
+ return 1;
+ diff = now - e->unreachable_since;
+ if (diff < 6*60*60)
+ return now > (e->last_attempted + 60*60);
+ else if (diff < 3*24*60*60)
+ return now > (e->last_attempted + 4*60*60);
+ else if (diff < 7*24*60*60)
+ return now > (e->last_attempted + 18*60*60);
+ else
+ return now > (e->last_attempted + 36*60*60);
+}
+
+/** Return the node corresponding to <b>e</b>, if <b>e</b> is
+ * working well enough that we are willing to use it as an entry
+ * right now. (Else return NULL.) In particular, it must be
+ * - Listed as either up or never yet contacted;
+ * - Present in the routerlist;
+ * - Listed as 'stable' or 'fast' by the current dirserver consensus,
+ * if demanded by <b>need_uptime</b> or <b>need_capacity</b>
+ * (unless it's a configured EntryNode);
+ * - Allowed by our current ReachableORAddresses config option; and
+ * - Currently thought to be reachable by us (unless <b>assume_reachable</b>
+ * is true).
+ *
+ * If the answer is no, set *<b>msg</b> to an explanation of why.
+ *
+ * If need_descriptor is true, only return the node if we currently have
+ * a descriptor (routerinfo or microdesc) for it.
+ */
+static INLINE const node_t *
+entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity,
+ int assume_reachable, int need_descriptor, const char **msg)
+{
+ const node_t *node;
+ const or_options_t *options = get_options();
+ tor_assert(msg);
+
+ if (e->path_bias_disabled) {
+ *msg = "path-biased";
+ return NULL;
+ }
+ if (e->bad_since) {
+ *msg = "bad";
+ return NULL;
+ }
+ /* no good if it's unreachable, unless assume_unreachable or can_retry. */
+ if (!assume_reachable && !e->can_retry &&
+ e->unreachable_since && !entry_is_time_to_retry(e, time(NULL))) {
+ *msg = "unreachable";
+ return NULL;
+ }
+ node = node_get_by_id(e->identity);
+ if (!node) {
+ *msg = "no node info";
+ return NULL;
+ }
+ if (need_descriptor && !node_has_descriptor(node)) {
+ *msg = "no descriptor";
+ return NULL;
+ }
+ if (get_options()->UseBridges) {
+ if (node_get_purpose(node) != ROUTER_PURPOSE_BRIDGE) {
+ *msg = "not a bridge";
+ return NULL;
+ }
+ if (!node_is_a_configured_bridge(node)) {
+ *msg = "not a configured bridge";
+ return NULL;
+ }
+ } else { /* !get_options()->UseBridges */
+ if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) {
+ *msg = "not general-purpose";
+ return NULL;
+ }
+ }
+ if (routerset_contains_node(options->EntryNodes, node)) {
+ /* they asked for it, they get it */
+ need_uptime = need_capacity = 0;
+ }
+ if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
+ *msg = "not fast/stable";
+ return NULL;
+ }
+ if (!fascist_firewall_allows_node(node)) {
+ *msg = "unreachable by config";
+ return NULL;
+ }
+ return node;
+}
+
+/** Return the number of entry guards that we think are usable. */
+int
+num_live_entry_guards(int for_directory)
+{
+ int n = 0;
+ const char *msg;
+ if (! entry_guards)
+ return 0;
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
+ if (for_directory && !entry->is_dir_cache)
+ continue;
+ if (entry_is_live(entry, 0, 1, 0, !for_directory, &msg))
+ ++n;
+ } SMARTLIST_FOREACH_END(entry);
+ return n;
+}
+
+/** If <b>digest</b> matches the identity of any node in the
+ * entry_guards list, return that node. Else return NULL. */
+entry_guard_t *
+entry_guard_get_by_id_digest(const char *digest)
+{
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
+ if (tor_memeq(digest, entry->identity, DIGEST_LEN))
+ return entry;
+ );
+ return NULL;
+}
+
+/** Dump a description of our list of entry guards to the log at level
+ * <b>severity</b>. */
+static void
+log_entry_guards(int severity)
+{
+ smartlist_t *elements = smartlist_new();
+ char *s;
+
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e)
+ {
+ const char *msg = NULL;
+ if (entry_is_live(e, 0, 1, 0, 0, &msg))
+ smartlist_add_asprintf(elements, "%s [%s] (up %s)",
+ e->nickname,
+ hex_str(e->identity, DIGEST_LEN),
+ e->made_contact ? "made-contact" : "never-contacted");
+ else
+ smartlist_add_asprintf(elements, "%s [%s] (%s, %s)",
+ e->nickname,
+ hex_str(e->identity, DIGEST_LEN),
+ msg,
+ e->made_contact ? "made-contact" : "never-contacted");
+ }
+ SMARTLIST_FOREACH_END(e);
+
+ s = smartlist_join_strings(elements, ",", 0, NULL);
+ SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp));
+ smartlist_free(elements);
+ log_fn(severity,LD_CIRC,"%s",s);
+ tor_free(s);
+}
+
+/** Called when one or more guards that we would previously have used for some
+ * purpose are no longer in use because a higher-priority guard has become
+ * usable again. */
+static void
+control_event_guard_deferred(void)
+{
+ /* XXXX We don't actually have a good way to figure out _how many_ entries
+ * are live for some purpose. We need an entry_is_even_slightly_live()
+ * function for this to work right. NumEntryGuards isn't reliable: if we
+ * need guards with weird properties, we can have more than that number
+ * live.
+ **/
+#if 0
+ int n = 0;
+ const char *msg;
+ const or_options_t *options = get_options();
+ if (!entry_guards)
+ return;
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
+ {
+ if (entry_is_live(entry, 0, 1, 0, &msg)) {
+ if (n++ == options->NumEntryGuards) {
+ control_event_guard(entry->nickname, entry->identity, "DEFERRED");
+ return;
+ }
+ }
+ });
+#endif
+}
+
+/** Largest amount that we'll backdate chosen_on_date */
+#define CHOSEN_ON_DATE_SLOP (30*86400)
+
+/** Add a new (preferably stable and fast) router to our
+ * entry_guards list. Return a pointer to the router if we succeed,
+ * or NULL if we can't find any more suitable entries.
+ *
+ * If <b>chosen</b> is defined, use that one, and if it's not
+ * already in our entry_guards list, put it at the *beginning*.
+ * Else, put the one we pick at the end of the list. */
+static const node_t *
+add_an_entry_guard(const node_t *chosen, int reset_status, int prepend,
+ int for_discovery, int for_directory)
+{
+ const node_t *node;
+ entry_guard_t *entry;
+
+ if (chosen) {
+ node = chosen;
+ entry = entry_guard_get_by_id_digest(node->identity);
+ if (entry) {
+ if (reset_status) {
+ entry->bad_since = 0;
+ entry->can_retry = 1;
+ }
+ entry->is_dir_cache = node->rs &&
+ node->rs->version_supports_microdesc_cache;
+ if (get_options()->UseBridges && node_is_a_configured_bridge(node))
+ entry->is_dir_cache = 1;
+ return NULL;
+ }
+ } else if (!for_directory) {
+ node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL);
+ if (!node)
+ return NULL;
+ } else {
+ const routerstatus_t *rs;
+ rs = router_pick_directory_server(MICRODESC_DIRINFO|V3_DIRINFO,
+ PDS_PREFER_TUNNELED_DIR_CONNS_|PDS_FOR_GUARD);
+ if (!rs)
+ return NULL;
+ node = node_get_by_id(rs->identity_digest);
+ if (!node)
+ return NULL;
+ }
+ if (node->using_as_guard)
+ return NULL;
+ if (entry_guard_get_by_id_digest(node->identity) != NULL) {
+ log_info(LD_CIRC, "I was about to add a duplicate entry guard.");
+ /* This can happen if we choose a guard, then the node goes away, then
+ * comes back. */
+ ((node_t*) node)->using_as_guard = 1;
+ return NULL;
+ }
+ entry = tor_malloc_zero(sizeof(entry_guard_t));
+ log_info(LD_CIRC, "Chose %s as new entry guard.",
+ node_describe(node));
+ strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname));
+ memcpy(entry->identity, node->identity, DIGEST_LEN);
+ entry->is_dir_cache = node_is_dir(node) &&
+ node->rs && node->rs->version_supports_microdesc_cache;
+ if (get_options()->UseBridges && node_is_a_configured_bridge(node))
+ entry->is_dir_cache = 1;
+
+ /* Choose expiry time smudged over the past month. The goal here
+ * is to a) spread out when Tor clients rotate their guards, so they
+ * don't all select them on the same day, and b) avoid leaving a
+ * precise timestamp in the state file about when we first picked
+ * this guard. For details, see the Jan 2010 or-dev thread. */
+ entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
+ entry->chosen_by_version = tor_strdup(VERSION);
+
+ /* Are we picking this guard because all of our current guards are
+ * down so we need another one (for_discovery is 1), or because we
+ * decided we need more variety in our guard list (for_discovery is 0)?
+ *
+ * Currently we hack this behavior into place by setting "made_contact"
+ * for guards of the latter variety, so we'll be willing to use any of
+ * them right off the bat.
+ */
+ if (!for_discovery)
+ entry->made_contact = 1;
+
+ ((node_t*)node)->using_as_guard = 1;
+ if (prepend)
+ smartlist_insert(entry_guards, 0, entry);
+ else
+ smartlist_add(entry_guards, entry);
+ control_event_guard(entry->nickname, entry->identity, "NEW");
+ control_event_guard_deferred();
+ log_entry_guards(LOG_INFO);
+ return node;
+}
+
+/** Choose how many entry guards or directory guards we'll use. If
+ * <b>for_directory</b> is true, we return how many directory guards to
+ * use; else we return how many entry guards to use. */
+static int
+decide_num_guards(const or_options_t *options, int for_directory)
+{
+ if (for_directory && options->NumDirectoryGuards != 0)
+ return options->NumDirectoryGuards;
+ return options->NumEntryGuards;
+}
+
+/** If the use of entry guards is configured, choose more entry guards
+ * until we have enough in the list. */
+static void
+pick_entry_guards(const or_options_t *options, int for_directory)
+{
+ int changed = 0;
+ const int num_needed = decide_num_guards(options, for_directory);
+
+ tor_assert(entry_guards);
+
+ while (num_live_entry_guards(for_directory) < num_needed) {
+ if (!add_an_entry_guard(NULL, 0, 0, 0, for_directory))
+ break;
+ changed = 1;
+ }
+ if (changed)
+ entry_guards_changed();
+}
+
+/** How long (in seconds) do we allow an entry guard to be nonfunctional,
+ * unlisted, excluded, or otherwise nonusable before we give up on it? */
+#define ENTRY_GUARD_REMOVE_AFTER (30*24*60*60)
+
+/** Release all storage held by <b>e</b>. */
+static void
+entry_guard_free(entry_guard_t *e)
+{
+ if (!e)
+ return;
+ tor_free(e->chosen_by_version);
+ tor_free(e);
+}
+
+/**
+ * Return the minimum lifetime of working entry guard, in seconds,
+ * as given in the consensus networkstatus. (Plus CHOSEN_ON_DATE_SLOP,
+ * so that we can do the chosen_on_date randomization while achieving the
+ * desired minimum lifetime.)
+ */
+static int32_t
+guards_get_lifetime(void)
+{
+ const or_options_t *options = get_options();
+#define DFLT_GUARD_LIFETIME (86400 * 60) /* Two months. */
+#define MIN_GUARD_LIFETIME (86400 * 30) /* One months. */
+#define MAX_GUARD_LIFETIME (86400 * 1826) /* Five years. */
+
+ if (options->GuardLifetime >= 1) {
+ return CLAMP(MIN_GUARD_LIFETIME,
+ options->GuardLifetime,
+ MAX_GUARD_LIFETIME) + CHOSEN_ON_DATE_SLOP;
+ }
+
+ return networkstatus_get_param(NULL, "GuardLifetime",
+ DFLT_GUARD_LIFETIME,
+ MIN_GUARD_LIFETIME,
+ MAX_GUARD_LIFETIME) + CHOSEN_ON_DATE_SLOP;
+}
+
+/** Remove any entry guard which was selected by an unknown version of Tor,
+ * or which was selected by a version of Tor that's known to select
+ * entry guards badly, or which was selected more 2 months ago. */
+/* XXXX The "obsolete guards" and "chosen long ago guards" things should
+ * probably be different functions. */
+static int
+remove_obsolete_entry_guards(time_t now)
+{
+ int changed = 0, i;
+ int32_t guard_lifetime = guards_get_lifetime();
+
+ for (i = 0; i < smartlist_len(entry_guards); ++i) {
+ entry_guard_t *entry = smartlist_get(entry_guards, i);
+ const char *ver = entry->chosen_by_version;
+ const char *msg = NULL;
+ tor_version_t v;
+ int version_is_bad = 0, date_is_bad = 0;
+ if (!ver) {
+ msg = "does not say what version of Tor it was selected by";
+ version_is_bad = 1;
+ } else if (tor_version_parse(ver, &v)) {
+ msg = "does not seem to be from any recognized version of Tor";
+ version_is_bad = 1;
+ } else {
+ char *tor_ver = NULL;
+ tor_asprintf(&tor_ver, "Tor %s", ver);
+ if ((tor_version_as_new_as(tor_ver, "0.1.0.10-alpha") &&
+ !tor_version_as_new_as(tor_ver, "0.1.2.16-dev")) ||
+ (tor_version_as_new_as(tor_ver, "0.2.0.0-alpha") &&
+ !tor_version_as_new_as(tor_ver, "0.2.0.6-alpha")) ||
+ /* above are bug 440; below are bug 1217 */
+ (tor_version_as_new_as(tor_ver, "0.2.1.3-alpha") &&
+ !tor_version_as_new_as(tor_ver, "0.2.1.23")) ||
+ (tor_version_as_new_as(tor_ver, "0.2.2.0-alpha") &&
+ !tor_version_as_new_as(tor_ver, "0.2.2.7-alpha"))) {
+ msg = "was selected without regard for guard bandwidth";
+ version_is_bad = 1;
+ }
+ tor_free(tor_ver);
+ }
+ if (!version_is_bad && entry->chosen_on_date + guard_lifetime < now) {
+ /* It's been too long since the date listed in our state file. */
+ msg = "was selected several months ago";
+ date_is_bad = 1;
+ }
+
+ if (version_is_bad || date_is_bad) { /* we need to drop it */
+ char dbuf[HEX_DIGEST_LEN+1];
+ tor_assert(msg);
+ base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
+ log_fn(version_is_bad ? LOG_NOTICE : LOG_INFO, LD_CIRC,
+ "Entry guard '%s' (%s) %s. (Version=%s.) Replacing it.",
+ entry->nickname, dbuf, msg, ver?escaped(ver):"none");
+ control_event_guard(entry->nickname, entry->identity, "DROPPED");
+ entry_guard_free(entry);
+ smartlist_del_keeporder(entry_guards, i--);
+ log_entry_guards(LOG_INFO);
+ changed = 1;
+ }
+ }
+
+ return changed ? 1 : 0;
+}
+
+/** Remove all entry guards that have been down or unlisted for so
+ * long that we don't think they'll come up again. Return 1 if we
+ * removed any, or 0 if we did nothing. */
+static int
+remove_dead_entry_guards(time_t now)
+{
+ char dbuf[HEX_DIGEST_LEN+1];
+ char tbuf[ISO_TIME_LEN+1];
+ int i;
+ int changed = 0;
+
+ for (i = 0; i < smartlist_len(entry_guards); ) {
+ entry_guard_t *entry = smartlist_get(entry_guards, i);
+ if (entry->bad_since &&
+ ! entry->path_bias_disabled &&
+ entry->bad_since + ENTRY_GUARD_REMOVE_AFTER < now) {
+
+ base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
+ format_local_iso_time(tbuf, entry->bad_since);
+ log_info(LD_CIRC, "Entry guard '%s' (%s) has been down or unlisted "
+ "since %s local time; removing.",
+ entry->nickname, dbuf, tbuf);
+ control_event_guard(entry->nickname, entry->identity, "DROPPED");
+ entry_guard_free(entry);
+ smartlist_del_keeporder(entry_guards, i);
+ log_entry_guards(LOG_INFO);
+ changed = 1;
+ } else
+ ++i;
+ }
+ return changed ? 1 : 0;
+}
+
+/** A new directory or router-status has arrived; update the down/listed
+ * status of the entry guards.
+ *
+ * An entry is 'down' if the directory lists it as nonrunning.
+ * An entry is 'unlisted' if the directory doesn't include it.
+ *
+ * Don't call this on startup; only on a fresh download. Otherwise we'll
+ * think that things are unlisted.
+ */
+void
+entry_guards_compute_status(const or_options_t *options, time_t now)
+{
+ int changed = 0;
+ digestmap_t *reasons;
+
+ if (! entry_guards)
+ return;
+
+ if (options->EntryNodes) /* reshuffle the entry guard list if needed */
+ entry_nodes_should_be_added();
+
+ reasons = digestmap_new();
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry)
+ {
+ const node_t *r = node_get_by_id(entry->identity);
+ const char *reason = NULL;
+ if (entry_guard_set_status(entry, r, now, options, &reason))
+ changed = 1;
+
+ if (entry->bad_since)
+ tor_assert(reason);
+ if (reason)
+ digestmap_set(reasons, entry->identity, (char*)reason);
+ }
+ SMARTLIST_FOREACH_END(entry);
+
+ if (remove_dead_entry_guards(now))
+ changed = 1;
+ if (remove_obsolete_entry_guards(now))
+ changed = 1;
+
+ if (changed) {
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
+ const char *reason = digestmap_get(reasons, entry->identity);
+ const char *live_msg = "";
+ const node_t *r = entry_is_live(entry, 0, 1, 0, 0, &live_msg);
+ log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.",
+ entry->nickname,
+ hex_str(entry->identity, DIGEST_LEN),
+ entry->unreachable_since ? "unreachable" : "reachable",
+ entry->bad_since ? "unusable" : "usable",
+ reason ? ", ": "",
+ reason ? reason : "",
+ r ? "live" : "not live / ",
+ r ? "" : live_msg);
+ } SMARTLIST_FOREACH_END(entry);
+ log_info(LD_CIRC, " (%d/%d entry guards are usable/new)",
+ num_live_entry_guards(0), smartlist_len(entry_guards));
+ log_entry_guards(LOG_INFO);
+ entry_guards_changed();
+ }
+
+ digestmap_free(reasons, NULL);
+}
+
+/** Called when a connection to an OR with the identity digest <b>digest</b>
+ * is established (<b>succeeded</b>==1) or has failed (<b>succeeded</b>==0).
+ * If the OR is an entry, change that entry's up/down status.
+ * Return 0 normally, or -1 if we want to tear down the new connection.
+ *
+ * If <b>mark_relay_status</b>, also call router_set_status() on this
+ * relay.
+ *
+ * XXX024 change succeeded and mark_relay_status into 'int flags'.
+ */
+int
+entry_guard_register_connect_status(const char *digest, int succeeded,
+ int mark_relay_status, time_t now)
+{
+ int changed = 0;
+ int refuse_conn = 0;
+ int first_contact = 0;
+ entry_guard_t *entry = NULL;
+ int idx = -1;
+ char buf[HEX_DIGEST_LEN+1];
+
+ if (! entry_guards)
+ return 0;
+
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ tor_assert(e);
+ if (tor_memeq(e->identity, digest, DIGEST_LEN)) {
+ entry = e;
+ idx = e_sl_idx;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(e);
+
+ if (!entry)
+ return 0;
+
+ base16_encode(buf, sizeof(buf), entry->identity, DIGEST_LEN);
+
+ if (succeeded) {
+ if (entry->unreachable_since) {
+ log_info(LD_CIRC, "Entry guard '%s' (%s) is now reachable again. Good.",
+ entry->nickname, buf);
+ entry->can_retry = 0;
+ entry->unreachable_since = 0;
+ entry->last_attempted = now;
+ control_event_guard(entry->nickname, entry->identity, "UP");
+ changed = 1;
+ }
+ if (!entry->made_contact) {
+ entry->made_contact = 1;
+ first_contact = changed = 1;
+ }
+ } else { /* ! succeeded */
+ if (!entry->made_contact) {
+ /* We've never connected to this one. */
+ log_info(LD_CIRC,
+ "Connection to never-contacted entry guard '%s' (%s) failed. "
+ "Removing from the list. %d/%d entry guards usable/new.",
+ entry->nickname, buf,
+ num_live_entry_guards(0)-1, smartlist_len(entry_guards)-1);
+ control_event_guard(entry->nickname, entry->identity, "DROPPED");
+ entry_guard_free(entry);
+ smartlist_del_keeporder(entry_guards, idx);
+ log_entry_guards(LOG_INFO);
+ changed = 1;
+ } else if (!entry->unreachable_since) {
+ log_info(LD_CIRC, "Unable to connect to entry guard '%s' (%s). "
+ "Marking as unreachable.", entry->nickname, buf);
+ entry->unreachable_since = entry->last_attempted = now;
+ control_event_guard(entry->nickname, entry->identity, "DOWN");
+ changed = 1;
+ entry->can_retry = 0; /* We gave it an early chance; no good. */
+ } else {
+ char tbuf[ISO_TIME_LEN+1];
+ format_iso_time(tbuf, entry->unreachable_since);
+ log_debug(LD_CIRC, "Failed to connect to unreachable entry guard "
+ "'%s' (%s). It has been unreachable since %s.",
+ entry->nickname, buf, tbuf);
+ entry->last_attempted = now;
+ entry->can_retry = 0; /* We gave it an early chance; no good. */
+ }
+ }
+
+ /* if the caller asked us to, also update the is_running flags for this
+ * relay */
+ if (mark_relay_status)
+ router_set_status(digest, succeeded);
+
+ if (first_contact) {
+ /* We've just added a new long-term entry guard. Perhaps the network just
+ * came back? We should give our earlier entries another try too,
+ * and close this connection so we don't use it before we've given
+ * the others a shot. */
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ if (e == entry)
+ break;
+ if (e->made_contact) {
+ const char *msg;
+ const node_t *r = entry_is_live(e, 0, 1, 1, 0, &msg);
+ if (r && e->unreachable_since) {
+ refuse_conn = 1;
+ e->can_retry = 1;
+ }
+ }
+ } SMARTLIST_FOREACH_END(e);
+ if (refuse_conn) {
+ log_info(LD_CIRC,
+ "Connected to new entry guard '%s' (%s). Marking earlier "
+ "entry guards up. %d/%d entry guards usable/new.",
+ entry->nickname, buf,
+ num_live_entry_guards(0), smartlist_len(entry_guards));
+ log_entry_guards(LOG_INFO);
+ changed = 1;
+ }
+ }
+
+ if (changed)
+ entry_guards_changed();
+ return refuse_conn ? -1 : 0;
+}
+
+/** When we try to choose an entry guard, should we parse and add
+ * config's EntryNodes first? */
+static int should_add_entry_nodes = 0;
+
+/** Called when the value of EntryNodes changes in our configuration. */
+void
+entry_nodes_should_be_added(void)
+{
+ log_info(LD_CIRC, "EntryNodes config option set. Putting configured "
+ "relays at the front of the entry guard list.");
+ should_add_entry_nodes = 1;
+}
+
+/** Update the using_as_guard fields of all the nodes. We do this after we
+ * remove entry guards from the list: This is the only function that clears
+ * the using_as_guard field. */
+static void
+update_node_guard_status(void)
+{
+ smartlist_t *nodes = nodelist_get_list();
+ SMARTLIST_FOREACH(nodes, node_t *, node, node->using_as_guard = 0);
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
+ node_t *node = node_get_mutable_by_id(entry->identity);
+ if (node)
+ node->using_as_guard = 1;
+ } SMARTLIST_FOREACH_END(entry);
+}
+
+/** Adjust the entry guards list so that it only contains entries from
+ * EntryNodes, adding new entries from EntryNodes to the list as needed. */
+static void
+entry_guards_set_from_config(const or_options_t *options)
+{
+ smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps;
+ smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list;
+ tor_assert(entry_guards);
+
+ should_add_entry_nodes = 0;
+
+ if (!options->EntryNodes) {
+ /* It's possible that a controller set EntryNodes, thus making
+ * should_add_entry_nodes set, then cleared it again, all before the
+ * call to choose_random_entry() that triggered us. If so, just return.
+ */
+ return;
+ }
+
+ {
+ char *string = routerset_to_string(options->EntryNodes);
+ log_info(LD_CIRC,"Adding configured EntryNodes '%s'.", string);
+ tor_free(string);
+ }
+
+ entry_nodes = smartlist_new();
+ worse_entry_nodes = smartlist_new();
+ entry_fps = smartlist_new();
+ old_entry_guards_on_list = smartlist_new();
+ old_entry_guards_not_on_list = smartlist_new();
+
+ /* Split entry guards into those on the list and those not. */
+
+ routerset_get_all_nodes(entry_nodes, options->EntryNodes,
+ options->ExcludeNodes, 0);
+ SMARTLIST_FOREACH(entry_nodes, const node_t *,node,
+ smartlist_add(entry_fps, (void*)node->identity));
+
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, {
+ if (smartlist_contains_digest(entry_fps, e->identity))
+ smartlist_add(old_entry_guards_on_list, e);
+ else
+ smartlist_add(old_entry_guards_not_on_list, e);
+ });
+
+ /* Remove all currently configured guard nodes, excluded nodes, unreachable
+ * nodes, or non-Guard nodes from entry_nodes. */
+ SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
+ if (entry_guard_get_by_id_digest(node->identity)) {
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ continue;
+ } else if (routerset_contains_node(options->ExcludeNodes, node)) {
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ continue;
+ } else if (!fascist_firewall_allows_node(node)) {
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ continue;
+ } else if (! node->is_possible_guard) {
+ smartlist_add(worse_entry_nodes, (node_t*)node);
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ }
+ } SMARTLIST_FOREACH_END(node);
+
+ /* Now build the new entry_guards list. */
+ smartlist_clear(entry_guards);
+ /* First, the previously configured guards that are in EntryNodes. */
+ smartlist_add_all(entry_guards, old_entry_guards_on_list);
+ /* Next, scramble the rest of EntryNodes, putting the guards first. */
+ smartlist_shuffle(entry_nodes);
+ smartlist_shuffle(worse_entry_nodes);
+ smartlist_add_all(entry_nodes, worse_entry_nodes);
+
+ /* Next, the rest of EntryNodes */
+ SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
+ add_an_entry_guard(node, 0, 0, 1, 0);
+ if (smartlist_len(entry_guards) > options->NumEntryGuards * 10)
+ break;
+ } SMARTLIST_FOREACH_END(node);
+ log_notice(LD_GENERAL, "%d entries in guards", smartlist_len(entry_guards));
+ /* Finally, free the remaining previously configured guards that are not in
+ * EntryNodes. */
+ SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
+ entry_guard_free(e));
+
+ update_node_guard_status();
+
+ smartlist_free(entry_nodes);
+ smartlist_free(worse_entry_nodes);
+ smartlist_free(entry_fps);
+ smartlist_free(old_entry_guards_on_list);
+ smartlist_free(old_entry_guards_not_on_list);
+ entry_guards_changed();
+}
+
+/** Return 0 if we're fine adding arbitrary routers out of the
+ * directory to our entry guard list, or return 1 if we have a
+ * list already and we must stick to it.
+ */
+int
+entry_list_is_constrained(const or_options_t *options)
+{
+ if (options->EntryNodes)
+ return 1;
+ if (options->UseBridges)
+ return 1;
+ return 0;
+}
+
+/** Return true iff this node can answer directory questions about
+ * microdescriptors. */
+static int
+node_understands_microdescriptors(const node_t *node)
+{
+ tor_assert(node);
+ if (node->rs && node->rs->version_supports_microdesc_cache)
+ return 1;
+ if (node->ri && tor_version_supports_microdescriptors(node->ri->platform))
+ return 1;
+ return 0;
+}
+
+/** Return true iff <b>node</b> is able to answer directory questions
+ * of type <b>dirinfo</b>. */
+static int
+node_can_handle_dirinfo(const node_t *node, dirinfo_type_t dirinfo)
+{
+ /* Checking dirinfo for any type other than microdescriptors isn't required
+ yet, since we only choose directory guards that can support microdescs,
+ routerinfos, and networkstatuses, AND we don't use directory guards if
+ we're configured to do direct downloads of anything else. The only case
+ where we might have a guard that doesn't know about a type of directory
+ information is when we're retrieving directory information from a
+ bridge. */
+
+ if ((dirinfo & MICRODESC_DIRINFO) &&
+ !node_understands_microdescriptors(node))
+ return 0;
+ return 1;
+}
+
+/** Pick a live (up and listed) entry guard from entry_guards. If
+ * <b>state</b> is non-NULL, this is for a specific circuit --
+ * make sure not to pick this circuit's exit or any node in the
+ * exit's family. If <b>state</b> is NULL, we're looking for a random
+ * guard (likely a bridge). If <b>dirinfo</b> is not NO_DIRINFO, then
+ * only select from nodes that know how to answer directory questions
+ * of that type. */
+const node_t *
+choose_random_entry(cpath_build_state_t *state)
+{
+ return choose_random_entry_impl(state, 0, 0);
+}
+
+/** Pick a live (up and listed) directory guard from entry_guards for
+ * downloading information of type <b>type</b>. */
+const node_t *
+choose_random_dirguard(dirinfo_type_t type)
+{
+ return choose_random_entry_impl(NULL, 1, type);
+}
+
+/** Helper for choose_random{entry,dirguard}. */
+static const node_t *
+choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
+ dirinfo_type_t dirinfo_type)
+{
+ const or_options_t *options = get_options();
+ smartlist_t *live_entry_guards = smartlist_new();
+ smartlist_t *exit_family = smartlist_new();
+ const node_t *chosen_exit =
+ state?build_state_get_exit_node(state) : NULL;
+ const node_t *node = NULL;
+ int need_uptime = state ? state->need_uptime : 0;
+ int need_capacity = state ? state->need_capacity : 0;
+ int preferred_min, consider_exit_family = 0;
+ int need_descriptor = !for_directory;
+ const int num_needed = decide_num_guards(options, for_directory);
+
+ if (chosen_exit) {
+ nodelist_add_node_and_family(exit_family, chosen_exit);
+ consider_exit_family = 1;
+ }
+
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+
+ if (should_add_entry_nodes)
+ entry_guards_set_from_config(options);
+
+ if (!entry_list_is_constrained(options) &&
+ smartlist_len(entry_guards) < num_needed)
+ pick_entry_guards(options, for_directory);
+
+ retry:
+ smartlist_clear(live_entry_guards);
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
+ const char *msg;
+ node = entry_is_live(entry, need_uptime, need_capacity, 0,
+ need_descriptor, &msg);
+ if (!node)
+ continue; /* down, no point */
+ if (for_directory) {
+ if (!entry->is_dir_cache)
+ continue; /* We need a directory and didn't get one. */
+ }
+ if (node == chosen_exit)
+ continue; /* don't pick the same node for entry and exit */
+ if (consider_exit_family && smartlist_contains(exit_family, node))
+ continue; /* avoid relays that are family members of our exit */
+ if (dirinfo_type != NO_DIRINFO &&
+ !node_can_handle_dirinfo(node, dirinfo_type))
+ continue; /* this node won't be able to answer our dir questions */
+#if 0 /* since EntryNodes is always strict now, this clause is moot */
+ if (options->EntryNodes &&
+ !routerset_contains_node(options->EntryNodes, node)) {
+ /* We've come to the end of our preferred entry nodes. */
+ if (smartlist_len(live_entry_guards))
+ goto choose_and_finish; /* only choose from the ones we like */
+ if (options->StrictNodes) {
+ /* in theory this case should never happen, since
+ * entry_guards_set_from_config() drops unwanted relays */
+ tor_fragile_assert();
+ } else {
+ log_info(LD_CIRC,
+ "No relays from EntryNodes available. Using others.");
+ }
+ }
+#endif
+ smartlist_add(live_entry_guards, (void*)node);
+ if (!entry->made_contact) {
+ /* Always start with the first not-yet-contacted entry
+ * guard. Otherwise we might add several new ones, pick
+ * the second new one, and now we've expanded our entry
+ * guard list without needing to. */
+ goto choose_and_finish;
+ }
+ if (smartlist_len(live_entry_guards) >= num_needed)
+ goto choose_and_finish; /* we have enough */
+ } SMARTLIST_FOREACH_END(entry);
+
+ if (entry_list_is_constrained(options)) {
+ /* If we prefer the entry nodes we've got, and we have at least
+ * one choice, that's great. Use it. */
+ preferred_min = 1;
+ } else {
+ /* Try to have at least 2 choices available. This way we don't
+ * get stuck with a single live-but-crummy entry and just keep
+ * using him.
+ * (We might get 2 live-but-crummy entry guards, but so be it.) */
+ preferred_min = 2;
+ }
+
+ if (smartlist_len(live_entry_guards) < preferred_min) {
+ if (!entry_list_is_constrained(options)) {
+ /* still no? try adding a new entry then */
+ /* XXX if guard doesn't imply fast and stable, then we need
+ * to tell add_an_entry_guard below what we want, or it might
+ * be a long time til we get it. -RD */
+ node = add_an_entry_guard(NULL, 0, 0, 1, for_directory);
+ if (node) {
+ entry_guards_changed();
+ /* XXX we start over here in case the new node we added shares
+ * a family with our exit node. There's a chance that we'll just
+ * load up on entry guards here, if the network we're using is
+ * one big family. Perhaps we should teach add_an_entry_guard()
+ * to understand nodes-to-avoid-if-possible? -RD */
+ goto retry;
+ }
+ }
+ if (!node && need_uptime) {
+ need_uptime = 0; /* try without that requirement */
+ goto retry;
+ }
+ if (!node && need_capacity) {
+ /* still no? last attempt, try without requiring capacity */
+ need_capacity = 0;
+ goto retry;
+ }
+#if 0
+ /* Removing this retry logic: if we only allow one exit, and it is in the
+ same family as all our entries, then we are just plain not going to win
+ here. */
+ if (!node && entry_list_is_constrained(options) && consider_exit_family) {
+ /* still no? if we're using bridges or have strictentrynodes
+ * set, and our chosen exit is in the same family as all our
+ * bridges/entry guards, then be flexible about families. */
+ consider_exit_family = 0;
+ goto retry;
+ }
+#endif
+ /* live_entry_guards may be empty below. Oh well, we tried. */
+ }
+
+ choose_and_finish:
+ if (entry_list_is_constrained(options)) {
+ /* We need to weight by bandwidth, because our bridges or entryguards
+ * were not already selected proportional to their bandwidth. */
+ node = node_sl_choose_by_bandwidth(live_entry_guards, WEIGHT_FOR_GUARD);
+ } else {
+ /* We choose uniformly at random here, because choose_good_entry_server()
+ * already weights its choices by bandwidth, so we don't want to
+ * *double*-weight our guard selection. */
+ node = smartlist_choose(live_entry_guards);
+ }
+ smartlist_free(live_entry_guards);
+ smartlist_free(exit_family);
+ return node;
+}
+
+/** Parse <b>state</b> and learn about the entry guards it describes.
+ * If <b>set</b> is true, and there are no errors, replace the global
+ * entry_list with what we find.
+ * On success, return 0. On failure, alloc into *<b>msg</b> a string
+ * describing the error, and return -1.
+ */
+int
+entry_guards_parse_state(or_state_t *state, int set, char **msg)
+{
+ entry_guard_t *node = NULL;
+ smartlist_t *new_entry_guards = smartlist_new();
+ config_line_t *line;
+ time_t now = time(NULL);
+ const char *state_version = state->TorVersion;
+ digestmap_t *added_by = digestmap_new();
+
+ *msg = NULL;
+ for (line = state->EntryGuards; line; line = line->next) {
+ if (!strcasecmp(line->key, "EntryGuard")) {
+ smartlist_t *args = smartlist_new();
+ node = tor_malloc_zero(sizeof(entry_guard_t));
+ /* all entry guards on disk have been contacted */
+ node->made_contact = 1;
+ smartlist_add(new_entry_guards, node);
+ smartlist_split_string(args, line->value, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ if (smartlist_len(args)<2) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "Too few arguments to EntryGuard");
+ } else if (!is_legal_nickname(smartlist_get(args,0))) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "Bad nickname for EntryGuard");
+ } else {
+ strlcpy(node->nickname, smartlist_get(args,0), MAX_NICKNAME_LEN+1);
+ if (base16_decode(node->identity, DIGEST_LEN, smartlist_get(args,1),
+ strlen(smartlist_get(args,1)))<0) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "Bad hex digest for EntryGuard");
+ }
+ }
+ if (smartlist_len(args) >= 3) {
+ const char *is_cache = smartlist_get(args, 2);
+ if (!strcasecmp(is_cache, "DirCache")) {
+ node->is_dir_cache = 1;
+ } else if (!strcasecmp(is_cache, "NoDirCache")) {
+ node->is_dir_cache = 0;
+ } else {
+ log_warn(LD_CONFIG, "Bogus third argument to EntryGuard line: %s",
+ escaped(is_cache));
+ }
+ }
+ SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
+ smartlist_free(args);
+ if (*msg)
+ break;
+ } else if (!strcasecmp(line->key, "EntryGuardDownSince") ||
+ !strcasecmp(line->key, "EntryGuardUnlistedSince")) {
+ time_t when;
+ time_t last_try = 0;
+ if (!node) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "EntryGuardDownSince/UnlistedSince without EntryGuard");
+ break;
+ }
+ if (parse_iso_time(line->value, &when)<0) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "Bad time in EntryGuardDownSince/UnlistedSince");
+ break;
+ }
+ if (when > now) {
+ /* It's a bad idea to believe info in the future: you can wind
+ * up with timeouts that aren't allowed to happen for years. */
+ continue;
+ }
+ if (strlen(line->value) >= ISO_TIME_LEN+ISO_TIME_LEN+1) {
+ /* ignore failure */
+ (void) parse_iso_time(line->value+ISO_TIME_LEN+1, &last_try);
+ }
+ if (!strcasecmp(line->key, "EntryGuardDownSince")) {
+ node->unreachable_since = when;
+ node->last_attempted = last_try;
+ } else {
+ node->bad_since = when;
+ }
+ } else if (!strcasecmp(line->key, "EntryGuardAddedBy")) {
+ char d[DIGEST_LEN];
+ /* format is digest version date */
+ if (strlen(line->value) < HEX_DIGEST_LEN+1+1+1+ISO_TIME_LEN) {
+ log_warn(LD_BUG, "EntryGuardAddedBy line is not long enough.");
+ continue;
+ }
+ if (base16_decode(d, sizeof(d), line->value, HEX_DIGEST_LEN)<0 ||
+ line->value[HEX_DIGEST_LEN] != ' ') {
+ log_warn(LD_BUG, "EntryGuardAddedBy line %s does not begin with "
+ "hex digest", escaped(line->value));
+ continue;
+ }
+ digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1));
+ } else if (!strcasecmp(line->key, "EntryGuardPathUseBias")) {
+ const or_options_t *options = get_options();
+ double use_cnt, success_cnt;
+
+ if (!node) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "EntryGuardPathUseBias without EntryGuard");
+ break;
+ }
+
+ if (tor_sscanf(line->value, "%lf %lf",
+ &use_cnt, &success_cnt) != 2) {
+ log_info(LD_GENERAL, "Malformed path use bias line for node %s",
+ node->nickname);
+ continue;
+ }
+
+ if (use_cnt < success_cnt) {
+ int severity = LOG_INFO;
+ /* If this state file was written by a Tor that would have
+ * already fixed it, then the overcounting bug is still there.. */
+ if (tor_version_as_new_as(state_version, "0.2.4.13-alpha")) {
+ severity = LOG_NOTICE;
+ }
+ log_fn(severity, LD_BUG,
+ "State file contains unexpectedly high usage success "
+ "counts %lf/%lf for Guard %s ($%s)",
+ success_cnt, use_cnt,
+ node->nickname, hex_str(node->identity, DIGEST_LEN));
+ success_cnt = use_cnt;
+ }
+
+ node->use_attempts = use_cnt;
+ node->use_successes = success_cnt;
+
+ log_info(LD_GENERAL, "Read %f/%f path use bias for node %s",
+ node->use_successes, node->use_attempts, node->nickname);
+
+ /* Note: We rely on the < comparison here to allow us to set a 0
+ * rate and disable the feature entirely. If refactoring, don't
+ * change to <= */
+ if (pathbias_get_use_success_count(node)/node->use_attempts
+ < pathbias_get_extreme_use_rate(options) &&
+ pathbias_get_dropguards(options)) {
+ node->path_bias_disabled = 1;
+ log_info(LD_GENERAL,
+ "Path use bias is too high (%f/%f); disabling node %s",
+ node->circ_successes, node->circ_attempts, node->nickname);
+ }
+ } else if (!strcasecmp(line->key, "EntryGuardPathBias")) {
+ const or_options_t *options = get_options();
+ double hop_cnt, success_cnt, timeouts, collapsed, successful_closed,
+ unusable;
+
+ if (!node) {
+ *msg = tor_strdup("Unable to parse entry nodes: "
+ "EntryGuardPathBias without EntryGuard");
+ break;
+ }
+
+ /* First try 3 params, then 2. */
+ /* In the long run: circuit_success ~= successful_circuit_close +
+ * collapsed_circuits +
+ * unusable_circuits */
+ if (tor_sscanf(line->value, "%lf %lf %lf %lf %lf %lf",
+ &hop_cnt, &success_cnt, &successful_closed,
+ &collapsed, &unusable, &timeouts) != 6) {
+ int old_success, old_hops;
+ if (tor_sscanf(line->value, "%u %u", &old_success, &old_hops) != 2) {
+ continue;
+ }
+ log_info(LD_GENERAL, "Reading old-style EntryGuardPathBias %s",
+ escaped(line->value));
+
+ success_cnt = old_success;
+ successful_closed = old_success;
+ hop_cnt = old_hops;
+ timeouts = 0;
+ collapsed = 0;
+ unusable = 0;
+ }
+
+ if (hop_cnt < success_cnt) {
+ int severity = LOG_INFO;
+ /* If this state file was written by a Tor that would have
+ * already fixed it, then the overcounting bug is still there.. */
+ if (tor_version_as_new_as(state_version, "0.2.4.13-alpha")) {
+ severity = LOG_NOTICE;
+ }
+ log_fn(severity, LD_BUG,
+ "State file contains unexpectedly high success counts "
+ "%lf/%lf for Guard %s ($%s)",
+ success_cnt, hop_cnt,
+ node->nickname, hex_str(node->identity, DIGEST_LEN));
+ success_cnt = hop_cnt;
+ }
+
+ node->circ_attempts = hop_cnt;
+ node->circ_successes = success_cnt;
+
+ node->successful_circuits_closed = successful_closed;
+ node->timeouts = timeouts;
+ node->collapsed_circuits = collapsed;
+ node->unusable_circuits = unusable;
+
+ log_info(LD_GENERAL, "Read %f/%f path bias for node %s",
+ node->circ_successes, node->circ_attempts, node->nickname);
+ /* Note: We rely on the < comparison here to allow us to set a 0
+ * rate and disable the feature entirely. If refactoring, don't
+ * change to <= */
+ if (pathbias_get_close_success_count(node)/node->circ_attempts
+ < pathbias_get_extreme_rate(options) &&
+ pathbias_get_dropguards(options)) {
+ node->path_bias_disabled = 1;
+ log_info(LD_GENERAL,
+ "Path bias is too high (%f/%f); disabling node %s",
+ node->circ_successes, node->circ_attempts, node->nickname);
+ }
+
+ } else {
+ log_warn(LD_BUG, "Unexpected key %s", line->key);
+ }
+ }
+
+ SMARTLIST_FOREACH_BEGIN(new_entry_guards, entry_guard_t *, e) {
+ char *sp;
+ char *val = digestmap_get(added_by, e->identity);
+ if (val && (sp = strchr(val, ' '))) {
+ time_t when;
+ *sp++ = '\0';
+ if (parse_iso_time(sp, &when)<0) {
+ log_warn(LD_BUG, "Can't read time %s in EntryGuardAddedBy", sp);
+ } else {
+ e->chosen_by_version = tor_strdup(val);
+ e->chosen_on_date = when;
+ }
+ } else {
+ if (state_version) {
+ e->chosen_by_version = tor_strdup(state_version);
+ e->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
+ }
+ }
+ if (e->path_bias_disabled && !e->bad_since)
+ e->bad_since = time(NULL);
+ }
+ SMARTLIST_FOREACH_END(e);
+
+ if (*msg || !set) {
+ SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e,
+ entry_guard_free(e));
+ smartlist_free(new_entry_guards);
+ } else { /* !err && set */
+ if (entry_guards) {
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
+ entry_guard_free(e));
+ smartlist_free(entry_guards);
+ }
+ entry_guards = new_entry_guards;
+ entry_guards_dirty = 0;
+ /* XXX024 hand new_entry_guards to this func, and move it up a
+ * few lines, so we don't have to re-dirty it */
+ if (remove_obsolete_entry_guards(now))
+ entry_guards_dirty = 1;
+
+ update_node_guard_status();
+ }
+ digestmap_free(added_by, tor_free_);
+ return *msg ? -1 : 0;
+}
+
+/** Our list of entry guards has changed, or some element of one
+ * of our entry guards has changed. Write the changes to disk within
+ * the next few minutes.
+ */
+void
+entry_guards_changed(void)
+{
+ time_t when;
+ entry_guards_dirty = 1;
+
+ /* or_state_save() will call entry_guards_update_state(). */
+ when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600;
+ or_state_mark_dirty(get_or_state(), when);
+}
+
+/** If the entry guard info has not changed, do nothing and return.
+ * Otherwise, free the EntryGuards piece of <b>state</b> and create
+ * a new one out of the global entry_guards list, and then mark
+ * <b>state</b> dirty so it will get saved to disk.
+ */
+void
+entry_guards_update_state(or_state_t *state)
+{
+ config_line_t **next, *line;
+ if (! entry_guards_dirty)
+ return;
+
+ config_free_lines(state->EntryGuards);
+ next = &state->EntryGuards;
+ *next = NULL;
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ char dbuf[HEX_DIGEST_LEN+1];
+ if (!e->made_contact)
+ continue; /* don't write this one to disk */
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuard");
+ base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN);
+ tor_asprintf(&line->value, "%s %s %sDirCache", e->nickname, dbuf,
+ e->is_dir_cache ? "" : "No");
+ next = &(line->next);
+ if (e->unreachable_since) {
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardDownSince");
+ line->value = tor_malloc(ISO_TIME_LEN+1+ISO_TIME_LEN+1);
+ format_iso_time(line->value, e->unreachable_since);
+ if (e->last_attempted) {
+ line->value[ISO_TIME_LEN] = ' ';
+ format_iso_time(line->value+ISO_TIME_LEN+1, e->last_attempted);
+ }
+ next = &(line->next);
+ }
+ if (e->bad_since) {
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardUnlistedSince");
+ line->value = tor_malloc(ISO_TIME_LEN+1);
+ format_iso_time(line->value, e->bad_since);
+ next = &(line->next);
+ }
+ if (e->chosen_on_date && e->chosen_by_version &&
+ !strchr(e->chosen_by_version, ' ')) {
+ char d[HEX_DIGEST_LEN+1];
+ char t[ISO_TIME_LEN+1];
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardAddedBy");
+ base16_encode(d, sizeof(d), e->identity, DIGEST_LEN);
+ format_iso_time(t, e->chosen_on_date);
+ tor_asprintf(&line->value, "%s %s %s",
+ d, e->chosen_by_version, t);
+ next = &(line->next);
+ }
+ if (e->circ_attempts > 0) {
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardPathBias");
+ /* In the long run: circuit_success ~= successful_circuit_close +
+ * collapsed_circuits +
+ * unusable_circuits */
+ tor_asprintf(&line->value, "%f %f %f %f %f %f",
+ e->circ_attempts, e->circ_successes,
+ pathbias_get_close_success_count(e),
+ e->collapsed_circuits,
+ e->unusable_circuits, e->timeouts);
+ next = &(line->next);
+ }
+ if (e->use_attempts > 0) {
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardPathUseBias");
+
+ tor_asprintf(&line->value, "%f %f",
+ e->use_attempts,
+ pathbias_get_use_success_count(e));
+ next = &(line->next);
+ }
+
+ } SMARTLIST_FOREACH_END(e);
+ if (!get_options()->AvoidDiskWrites)
+ or_state_mark_dirty(get_or_state(), 0);
+ entry_guards_dirty = 0;
+}
+
+/** If <b>question</b> is the string "entry-guards", then dump
+ * to *<b>answer</b> a newly allocated string describing all of
+ * the nodes in the global entry_guards list. See control-spec.txt
+ * for details.
+ * For backward compatibility, we also handle the string "helper-nodes".
+ * */
+int
+getinfo_helper_entry_guards(control_connection_t *conn,
+ const char *question, char **answer,
+ const char **errmsg)
+{
+ (void) conn;
+ (void) errmsg;
+
+ if (!strcmp(question,"entry-guards") ||
+ !strcmp(question,"helper-nodes")) {
+ smartlist_t *sl = smartlist_new();
+ char tbuf[ISO_TIME_LEN+1];
+ char nbuf[MAX_VERBOSE_NICKNAME_LEN+1];
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ const char *status = NULL;
+ time_t when = 0;
+ const node_t *node;
+
+ if (!e->made_contact) {
+ status = "never-connected";
+ } else if (e->bad_since) {
+ when = e->bad_since;
+ status = "unusable";
+ } else {
+ status = "up";
+ }
+
+ node = node_get_by_id(e->identity);
+ if (node) {
+ node_get_verbose_nickname(node, nbuf);
+ } else {
+ nbuf[0] = '$';
+ base16_encode(nbuf+1, sizeof(nbuf)-1, e->identity, DIGEST_LEN);
+ /* e->nickname field is not very reliable if we don't know about
+ * this router any longer; don't include it. */
+ }
+
+ if (when) {
+ format_iso_time(tbuf, when);
+ smartlist_add_asprintf(sl, "%s %s %s\n", nbuf, status, tbuf);
+ } else {
+ smartlist_add_asprintf(sl, "%s %s\n", nbuf, status);
+ }
+ } SMARTLIST_FOREACH_END(e);
+ *answer = smartlist_join_strings(sl, "", 0, NULL);
+ SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
+ smartlist_free(sl);
+ }
+ return 0;
+}
+
+/** A list of configured bridges. Whenever we actually get a descriptor
+ * for one, we add it as an entry guard. Note that the order of bridges
+ * in this list does not necessarily correspond to the order of bridges
+ * in the torrc. */
+static smartlist_t *bridge_list = NULL;
+
+/** Mark every entry of the bridge list to be removed on our next call to
+ * sweep_bridge_list unless it has first been un-marked. */
+void
+mark_bridge_list(void)
+{
+ if (!bridge_list)
+ bridge_list = smartlist_new();
+ SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b,
+ b->marked_for_removal = 1);
+}
+
+/** Remove every entry of the bridge list that was marked with
+ * mark_bridge_list if it has not subsequently been un-marked. */
+void
+sweep_bridge_list(void)
+{
+ if (!bridge_list)
+ bridge_list = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
+ if (b->marked_for_removal) {
+ SMARTLIST_DEL_CURRENT(bridge_list, b);
+ bridge_free(b);
+ }
+ } SMARTLIST_FOREACH_END(b);
+}
+
+/** Initialize the bridge list to empty, creating it if needed. */
+static void
+clear_bridge_list(void)
+{
+ if (!bridge_list)
+ bridge_list = smartlist_new();
+ SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, bridge_free(b));
+ smartlist_clear(bridge_list);
+}
+
+/** Free the bridge <b>bridge</b>. */
+static void
+bridge_free(bridge_info_t *bridge)
+{
+ if (!bridge)
+ return;
+
+ tor_free(bridge->transport_name);
+ tor_free(bridge);
+}
+
+/** If we have a bridge configured whose digest matches <b>digest</b>, or a
+ * bridge with no known digest whose address matches any of the
+ * tor_addr_port_t's in <b>orports</b>, return that bridge. Else return
+ * NULL. */
+static bridge_info_t *
+get_configured_bridge_by_orports_digest(const char *digest,
+ const smartlist_t *orports)
+{
+ if (!bridge_list)
+ return NULL;
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
+ {
+ if (tor_digest_is_zero(bridge->identity)) {
+ SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, ap)
+ {
+ if (tor_addr_compare(&bridge->addr, &ap->addr, CMP_EXACT) == 0 &&
+ bridge->port == ap->port)
+ return bridge;
+ }
+ SMARTLIST_FOREACH_END(ap);
+ }
+ if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN))
+ return bridge;
+ }
+ SMARTLIST_FOREACH_END(bridge);
+ return NULL;
+}
+
+/** If we have a bridge configured whose digest matches <b>digest</b>, or a
+ * bridge with no known digest whose address matches <b>addr</b>:<b>/port</b>,
+ * return that bridge. Else return NULL. */
+static bridge_info_t *
+get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr,
+ uint16_t port,
+ const char *digest)
+{
+ if (!bridge_list)
+ return NULL;
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
+ {
+ if (tor_digest_is_zero(bridge->identity) &&
+ !tor_addr_compare(&bridge->addr, addr, CMP_EXACT) &&
+ bridge->port == port)
+ return bridge;
+ if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN))
+ return bridge;
+ }
+ SMARTLIST_FOREACH_END(bridge);
+ return NULL;
+}
+
+/** Wrapper around get_configured_bridge_by_addr_port_digest() to look
+ * it up via router descriptor <b>ri</b>. */
+static bridge_info_t *
+get_configured_bridge_by_routerinfo(const routerinfo_t *ri)
+{
+ bridge_info_t *bi = NULL;
+ smartlist_t *orports = router_get_all_orports(ri);
+ bi = get_configured_bridge_by_orports_digest(ri->cache_info.identity_digest,
+ orports);
+ SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p));
+ smartlist_free(orports);
+ return bi;
+}
+
+/** Return 1 if <b>ri</b> is one of our known bridges, else 0. */
+int
+routerinfo_is_a_configured_bridge(const routerinfo_t *ri)
+{
+ return get_configured_bridge_by_routerinfo(ri) ? 1 : 0;
+}
+
+/** Return 1 if <b>node</b> is one of our configured bridges, else 0. */
+int
+node_is_a_configured_bridge(const node_t *node)
+{
+ int retval = 0;
+ smartlist_t *orports = node_get_all_orports(node);
+ retval = get_configured_bridge_by_orports_digest(node->identity,
+ orports) != NULL;
+ SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p));
+ smartlist_free(orports);
+ return retval;
+}
+
+/** We made a connection to a router at <b>addr</b>:<b>port</b>
+ * without knowing its digest. Its digest turned out to be <b>digest</b>.
+ * If it was a bridge, and we still don't know its digest, record it.
+ */
+void
+learned_router_identity(const tor_addr_t *addr, uint16_t port,
+ const char *digest)
+{
+ bridge_info_t *bridge =
+ get_configured_bridge_by_addr_port_digest(addr, port, digest);
+ if (bridge && tor_digest_is_zero(bridge->identity)) {
+ char *transport_info = NULL;
+ const char *transport_name =
+ find_transport_name_by_bridge_addrport(addr, port);
+ if (transport_name)
+ tor_asprintf(&transport_info, " (with transport '%s')", transport_name);
+
+ memcpy(bridge->identity, digest, DIGEST_LEN);
+ log_notice(LD_DIR, "Learned fingerprint %s for bridge %s%s.",
+ hex_str(digest, DIGEST_LEN), fmt_addrport(addr, port),
+ transport_info ? transport_info : "");
+ tor_free(transport_info);
+ }
+}
+
+/** Return true if <b>bridge</b> has the same identity digest as
+ * <b>digest</b>. If <b>digest</b> is NULL, it matches
+ * bridges with unspecified identity digests. */
+static int
+bridge_has_digest(const bridge_info_t *bridge, const char *digest)
+{
+ if (digest)
+ return tor_memeq(digest, bridge->identity, DIGEST_LEN);
+ else
+ return tor_digest_is_zero(bridge->identity);
+}
+
+/** We are about to add a new bridge at <b>addr</b>:<b>port</b>, with optional
+ * <b>digest</b> and <b>transport_name</b>. Mark for removal any previously
+ * existing bridge with the same address and port, and warn the user as
+ * appropriate.
+ */
+static void
+bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
+ const char *digest, const char *transport_name)
+{
+ /* Iterate the already-registered bridge list:
+
+ If you find a bridge with the same adress and port, mark it for
+ removal. It doesn't make sense to have two active bridges with
+ the same IP:PORT. If the bridge in question has a different
+ digest or transport than <b>digest</b>/<b>transport_name</b>,
+ it's probably a misconfiguration and we should warn the user.
+ */
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) {
+ if (bridge->marked_for_removal)
+ continue;
+
+ if (tor_addr_eq(&bridge->addr, addr) && (bridge->port == port)) {
+
+ bridge->marked_for_removal = 1;
+
+ if (!bridge_has_digest(bridge, digest) ||
+ strcmp_opt(bridge->transport_name, transport_name)) {
+ /* warn the user */
+ char *bridge_description_new, *bridge_description_old;
+ tor_asprintf(&bridge_description_new, "%s:%s:%s",
+ fmt_addrport(addr, port),
+ digest ? hex_str(digest, DIGEST_LEN) : "",
+ transport_name ? transport_name : "");
+ tor_asprintf(&bridge_description_old, "%s:%s:%s",
+ fmt_addrport(&bridge->addr, bridge->port),
+ tor_digest_is_zero(bridge->identity) ?
+ "" : hex_str(bridge->identity,DIGEST_LEN),
+ bridge->transport_name ? bridge->transport_name : "");
+
+ log_warn(LD_GENERAL,"Tried to add bridge '%s', but we found a conflict"
+ " with the already registered bridge '%s'. We will discard"
+ " the old bridge and keep '%s'. If this is not what you"
+ " wanted, please change your configuration file accordingly.",
+ bridge_description_new, bridge_description_old,
+ bridge_description_new);
+
+ tor_free(bridge_description_new);
+ tor_free(bridge_description_old);
+ }
+ }
+ } SMARTLIST_FOREACH_END(bridge);
+}
+
+/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
+ * is set, it tells us the identity key too. If we already had the
+ * bridge in our list, unmark it, and don't actually add anything new.
+ * If <b>transport_name</b> is non-NULL - the bridge is associated with a
+ * pluggable transport - we assign the transport to the bridge. */
+void
+bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
+ const char *digest, const char *transport_name)
+{
+ bridge_info_t *b;
+
+ bridge_resolve_conflicts(addr, port, digest, transport_name);
+
+ b = tor_malloc_zero(sizeof(bridge_info_t));
+ tor_addr_copy(&b->addr, addr);
+ b->port = port;
+ if (digest)
+ memcpy(b->identity, digest, DIGEST_LEN);
+ if (transport_name)
+ b->transport_name = tor_strdup(transport_name);
+ b->fetch_status.schedule = DL_SCHED_BRIDGE;
+ if (!bridge_list)
+ bridge_list = smartlist_new();
+
+ smartlist_add(bridge_list, b);
+}
+
+/** Return true iff <b>routerset</b> contains the bridge <b>bridge</b>. */
+static int
+routerset_contains_bridge(const routerset_t *routerset,
+ const bridge_info_t *bridge)
+{
+ int result;
+ extend_info_t *extinfo;
+ tor_assert(bridge);
+ if (!routerset)
+ return 0;
+
+ extinfo = extend_info_new(
+ NULL, bridge->identity, NULL, NULL, &bridge->addr, bridge->port);
+ result = routerset_contains_extendinfo(routerset, extinfo);
+ extend_info_free(extinfo);
+ return result;
+}
+
+/** If <b>digest</b> is one of our known bridges, return it. */
+static bridge_info_t *
+find_bridge_by_digest(const char *digest)
+{
+ SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge,
+ {
+ if (tor_memeq(bridge->identity, digest, DIGEST_LEN))
+ return bridge;
+ });
+ return NULL;
+}
+
+/** Given the <b>addr</b> and <b>port</b> of a bridge, if that bridge
+ * supports a pluggable transport, return its name. Otherwise, return
+ * NULL. */
+const char *
+find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port)
+{
+ if (!bridge_list)
+ return NULL;
+
+ SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
+ if (tor_addr_eq(&bridge->addr, addr) &&
+ (bridge->port == port))
+ return bridge->transport_name;
+ } SMARTLIST_FOREACH_END(bridge);
+
+ return NULL;
+}
+
+/** If <b>addr</b> and <b>port</b> match the address and port of a
+ * bridge of ours that uses pluggable transports, place its transport
+ * in <b>transport</b>.
+ *
+ * Return 0 on success (found a transport, or found a bridge with no
+ * transport, or found no bridge); return -1 if we should be using a
+ * transport, but the transport could not be found.
+ */
+int
+find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
+ const transport_t **transport)
+{
+ *transport = NULL;
+ if (!bridge_list)
+ return 0;
+
+ SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
+ if (tor_addr_eq(&bridge->addr, addr) &&
+ (bridge->port == port)) { /* bridge matched */
+ if (bridge->transport_name) { /* it also uses pluggable transports */
+ *transport = transport_get_by_name(bridge->transport_name);
+ if (*transport == NULL) { /* it uses pluggable transports, but
+ the transport could not be found! */
+ return -1;
+ }
+ return 0;
+ } else { /* bridge matched, but it doesn't use transports. */
+ break;
+ }
+ }
+ } SMARTLIST_FOREACH_END(bridge);
+
+ *transport = NULL;
+ return 0;
+}
+
+/** We need to ask <b>bridge</b> for its server descriptor. */
+static void
+launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
+{
+ char *address;
+ const or_options_t *options = get_options();
+
+ if (connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR, &bridge->addr, bridge->port,
+ DIR_PURPOSE_FETCH_SERVERDESC))
+ return; /* it's already on the way */
+
+ if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
+ download_status_mark_impossible(&bridge->fetch_status);
+ log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
+ safe_str_client(fmt_and_decorate_addr(&bridge->addr)));
+ return;
+ }
+
+ address = tor_dup_addr(&bridge->addr);
+
+ directory_initiate_command(address, &bridge->addr,
+ bridge->port, 0/*no dirport*/,
+ bridge->identity,
+ DIR_PURPOSE_FETCH_SERVERDESC,
+ ROUTER_PURPOSE_BRIDGE,
+ DIRIND_ONEHOP, "authority.z", NULL, 0, 0);
+ tor_free(address);
+}
+
+/** Fetching the bridge descriptor from the bridge authority returned a
+ * "not found". Fall back to trying a direct fetch. */
+void
+retry_bridge_descriptor_fetch_directly(const char *digest)
+{
+ bridge_info_t *bridge = find_bridge_by_digest(digest);
+ if (!bridge)
+ return; /* not found? oh well. */
+
+ launch_direct_bridge_descriptor_fetch(bridge);
+}
+
+/** For each bridge in our list for which we don't currently have a
+ * descriptor, fetch a new copy of its descriptor -- either directly
+ * from the bridge or via a bridge authority. */
+void
+fetch_bridge_descriptors(const or_options_t *options, time_t now)
+{
+ int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO);
+ int ask_bridge_directly;
+ int can_use_bridge_authority;
+
+ if (!bridge_list)
+ return;
+
+ /* If we still have unconfigured managed proxies, don't go and
+ connect to a bridge. */
+ if (pt_proxies_configuration_pending())
+ return;
+
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
+ {
+ if (!download_status_is_ready(&bridge->fetch_status, now,
+ IMPOSSIBLE_TO_DOWNLOAD))
+ continue; /* don't bother, no need to retry yet */
+ if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
+ download_status_mark_impossible(&bridge->fetch_status);
+ log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
+ safe_str_client(fmt_and_decorate_addr(&bridge->addr)));
+ continue;
+ }
+
+ /* schedule another fetch as if this one will fail, in case it does */
+ download_status_failed(&bridge->fetch_status, 0);
+
+ can_use_bridge_authority = !tor_digest_is_zero(bridge->identity) &&
+ num_bridge_auths;
+ ask_bridge_directly = !can_use_bridge_authority ||
+ !options->UpdateBridgesFromAuthority;
+ log_debug(LD_DIR, "ask_bridge_directly=%d (%d, %d, %d)",
+ ask_bridge_directly, tor_digest_is_zero(bridge->identity),
+ !options->UpdateBridgesFromAuthority, !num_bridge_auths);
+
+ if (ask_bridge_directly &&
+ !fascist_firewall_allows_address_or(&bridge->addr, bridge->port)) {
+ log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our "
+ "firewall policy. %s.",
+ fmt_addrport(&bridge->addr, bridge->port),
+ can_use_bridge_authority ?
+ "Asking bridge authority instead" : "Skipping");
+ if (can_use_bridge_authority)
+ ask_bridge_directly = 0;
+ else
+ continue;
+ }
+
+ if (ask_bridge_directly) {
+ /* we need to ask the bridge itself for its descriptor. */
+ launch_direct_bridge_descriptor_fetch(bridge);
+ } else {
+ /* We have a digest and we want to ask an authority. We could
+ * combine all the requests into one, but that may give more
+ * hints to the bridge authority than we want to give. */
+ char resource[10 + HEX_DIGEST_LEN];
+ memcpy(resource, "fp/", 3);
+ base16_encode(resource+3, HEX_DIGEST_LEN+1,
+ bridge->identity, DIGEST_LEN);
+ memcpy(resource+3+HEX_DIGEST_LEN, ".z", 3);
+ log_info(LD_DIR, "Fetching bridge info '%s' from bridge authority.",
+ resource);
+ directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,
+ ROUTER_PURPOSE_BRIDGE, resource, 0);
+ }
+ }
+ SMARTLIST_FOREACH_END(bridge);
+}
+
+/** If our <b>bridge</b> is configured to be a different address than
+ * the bridge gives in <b>node</b>, rewrite the routerinfo
+ * we received to use the address we meant to use. Now we handle
+ * multihomed bridges better.
+ */
+static void
+rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
+{
+ /* XXXX move this function. */
+ /* XXXX overridden addresses should really live in the node_t, so that the
+ * routerinfo_t and the microdesc_t can be immutable. But we can only
+ * do that safely if we know that no function that connects to an OR
+ * does so through an address from any source other than node_get_addr().
+ */
+ tor_addr_t addr;
+
+ if (node->ri) {
+ routerinfo_t *ri = node->ri;
+ tor_addr_from_ipv4h(&addr, ri->addr);
+
+ if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
+ bridge->port == ri->or_port) ||
+ (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) &&
+ bridge->port == ri->ipv6_orport)) {
+ /* they match, so no need to do anything */
+ } else {
+ if (tor_addr_family(&bridge->addr) == AF_INET) {
+ ri->addr = tor_addr_to_ipv4h(&bridge->addr);
+ tor_free(ri->address);
+ ri->address = tor_dup_ip(ri->addr);
+ ri->or_port = bridge->port;
+ log_info(LD_DIR,
+ "Adjusted bridge routerinfo for '%s' to match configured "
+ "address %s:%d.",
+ ri->nickname, ri->address, ri->or_port);
+ } else if (tor_addr_family(&bridge->addr) == AF_INET6) {
+ tor_addr_copy(&ri->ipv6_addr, &bridge->addr);
+ ri->ipv6_orport = bridge->port;
+ log_info(LD_DIR,
+ "Adjusted bridge routerinfo for '%s' to match configured "
+ "address %s.",
+ ri->nickname, fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport));
+ } else {
+ log_err(LD_BUG, "Address family not supported: %d.",
+ tor_addr_family(&bridge->addr));
+ return;
+ }
+ }
+
+ /* Mark which address to use based on which bridge_t we got. */
+ node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 &&
+ !tor_addr_is_null(&node->ri->ipv6_addr));
+
+ /* XXXipv6 we lack support for falling back to another address for
+ the same relay, warn the user */
+ if (!tor_addr_is_null(&ri->ipv6_addr)) {
+ tor_addr_port_t ap;
+ node_get_pref_orport(node, &ap);
+ log_notice(LD_CONFIG,
+ "Bridge '%s' has both an IPv4 and an IPv6 address. "
+ "Will prefer using its %s address (%s).",
+ ri->nickname,
+ tor_addr_family(&ap.addr) == AF_INET6 ? "IPv6" : "IPv4",
+ fmt_addrport(&ap.addr, ap.port));
+ }
+ }
+ if (node->rs) {
+ routerstatus_t *rs = node->rs;
+ tor_addr_from_ipv4h(&addr, rs->addr);
+
+ if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
+ bridge->port == rs->or_port) {
+ /* they match, so no need to do anything */
+ } else {
+ rs->addr = tor_addr_to_ipv4h(&bridge->addr);
+ rs->or_port = bridge->port;
+ log_info(LD_DIR,
+ "Adjusted bridge routerstatus for '%s' to match "
+ "configured address %s.",
+ rs->nickname, fmt_addrport(&bridge->addr, rs->or_port));
+ }
+ }
+}
+
+/** We just learned a descriptor for a bridge. See if that
+ * digest is in our entry guard list, and add it if not. */
+void
+learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
+{
+ tor_assert(ri);
+ tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE);
+ if (get_options()->UseBridges) {
+ int first = !any_bridge_descriptors_known();
+ bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri);
+ time_t now = time(NULL);
+ router_set_status(ri->cache_info.identity_digest, 1);
+
+ if (bridge) { /* if we actually want to use this one */
+ node_t *node;
+ /* it's here; schedule its re-fetch for a long time from now. */
+ if (!from_cache)
+ download_status_reset(&bridge->fetch_status);
+
+ node = node_get_mutable_by_id(ri->cache_info.identity_digest);
+ tor_assert(node);
+ rewrite_node_address_for_bridge(bridge, node);
+ add_an_entry_guard(node, 1, 1, 0, 0);
+
+ log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname,
+ from_cache ? "cached" : "fresh", router_describe(ri));
+ /* set entry->made_contact so if it goes down we don't drop it from
+ * our entry node list */
+ entry_guard_register_connect_status(ri->cache_info.identity_digest,
+ 1, 0, now);
+ if (first)
+ routerlist_retry_directory_downloads(now);
+ }
+ }
+}
+
+/** Return 1 if any of our entry guards have descriptors that
+ * are marked with purpose 'bridge' and are running. Else return 0.
+ *
+ * We use this function to decide if we're ready to start building
+ * circuits through our bridges, or if we need to wait until the
+ * directory "server/authority" requests finish. */
+int
+any_bridge_descriptors_known(void)
+{
+ tor_assert(get_options()->UseBridges);
+ return choose_random_entry(NULL) != NULL;
+}
+
+/** Return 1 if there are any directory conns fetching bridge descriptors
+ * that aren't marked for close. We use this to guess if we should tell
+ * the controller that we have a problem. */
+int
+any_pending_bridge_descriptor_fetches(void)
+{
+ smartlist_t *conns = get_connection_array();
+ SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
+ if (conn->type == CONN_TYPE_DIR &&
+ conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
+ TO_DIR_CONN(conn)->router_purpose == ROUTER_PURPOSE_BRIDGE &&
+ !conn->marked_for_close &&
+ conn->linked &&
+ conn->linked_conn && !conn->linked_conn->marked_for_close) {
+ log_debug(LD_DIR, "found one: %s", conn->address);
+ return 1;
+ }
+ } SMARTLIST_FOREACH_END(conn);
+ return 0;
+}
+
+/** Return 1 if we have at least one descriptor for an entry guard
+ * (bridge or member of EntryNodes) and all descriptors we know are
+ * down. Else return 0. If <b>act</b> is 1, then mark the down guards
+ * up; else just observe and report. */
+static int
+entries_retry_helper(const or_options_t *options, int act)
+{
+ const node_t *node;
+ int any_known = 0;
+ int any_running = 0;
+ int need_bridges = options->UseBridges != 0;
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ node = node_get_by_id(e->identity);
+ if (node && node_has_descriptor(node) &&
+ node_is_bridge(node) == need_bridges) {
+ any_known = 1;
+ if (node->is_running)
+ any_running = 1; /* some entry is both known and running */
+ else if (act) {
+ /* Mark all current connections to this OR as unhealthy, since
+ * otherwise there could be one that started 30 seconds
+ * ago, and in 30 seconds it will time out, causing us to mark
+ * the node down and undermine the retry attempt. We mark even
+ * the established conns, since if the network just came back
+ * we'll want to attach circuits to fresh conns. */
+ connection_or_set_bad_connections(node->identity, 1);
+
+ /* mark this entry node for retry */
+ router_set_status(node->identity, 1);
+ e->can_retry = 1;
+ e->bad_since = 0;
+ }
+ }
+ } SMARTLIST_FOREACH_END(e);
+ log_debug(LD_DIR, "%d: any_known %d, any_running %d",
+ act, any_known, any_running);
+ return any_known && !any_running;
+}
+
+/** Do we know any descriptors for our bridges / entrynodes, and are
+ * all the ones we have descriptors for down? */
+int
+entries_known_but_down(const or_options_t *options)
+{
+ tor_assert(entry_list_is_constrained(options));
+ return entries_retry_helper(options, 0);
+}
+
+/** Mark all down known bridges / entrynodes up. */
+void
+entries_retry_all(const or_options_t *options)
+{
+ tor_assert(entry_list_is_constrained(options));
+ entries_retry_helper(options, 1);
+}
+
+/** Return true if at least one of our bridges runs a Tor version that can
+ * provide microdescriptors to us. If not, we'll fall back to asking for
+ * full descriptors. */
+int
+any_bridge_supports_microdescriptors(void)
+{
+ const node_t *node;
+ if (!get_options()->UseBridges || !entry_guards)
+ return 0;
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ node = node_get_by_id(e->identity);
+ if (node && node->is_running &&
+ node_is_bridge(node) && node_is_a_configured_bridge(node) &&
+ node_understands_microdescriptors(node)) {
+ /* This is one of our current bridges, and we know enough about
+ * it to know that it will be able to answer our microdescriptor
+ * questions. */
+ return 1;
+ }
+ } SMARTLIST_FOREACH_END(e);
+ return 0;
+}
+
+/** Release all storage held by the list of entry guards and related
+ * memory structs. */
+void
+entry_guards_free_all(void)
+{
+ if (entry_guards) {
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
+ entry_guard_free(e));
+ smartlist_free(entry_guards);
+ entry_guards = NULL;
+ }
+ clear_bridge_list();
+ smartlist_free(bridge_list);
+ bridge_list = NULL;
+ circuit_build_times_free_timeouts(&circ_times);
+}
+
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
new file mode 100644
index 000000000..52b8dc00e
--- /dev/null
+++ b/src/or/entrynodes.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file guardnodes.h
+ * \brief Header file for circuitbuild.c.
+ **/
+
+#ifndef TOR_ENTRYNODES_H
+#define TOR_ENTRYNODES_H
+
+#if 1
+/* XXXX NM I would prefer that all of this stuff be private to
+ * entrynodes.c. */
+
+/** An entry_guard_t represents our information about a chosen long-term
+ * first hop, known as a "helper" node in the literature. We can't just
+ * use a node_t, since we want to remember these even when we
+ * don't have any directory info. */
+typedef struct entry_guard_t {
+ char nickname[MAX_NICKNAME_LEN+1];
+ char identity[DIGEST_LEN];
+ time_t chosen_on_date; /**< Approximately when was this guard added?
+ * "0" if we don't know. */
+ char *chosen_by_version; /**< What tor version added this guard? NULL
+ * if we don't know. */
+ unsigned int made_contact : 1; /**< 0 if we have never connected to this
+ * router, 1 if we have. */
+ unsigned int can_retry : 1; /**< Should we retry connecting to this entry,
+ * in spite of having it marked as unreachable?*/
+ unsigned int path_bias_noticed : 1; /**< Did we alert the user about path
+ * bias for this node already? */
+ unsigned int path_bias_warned : 1; /**< Did we alert the user about path bias
+ * for this node already? */
+ unsigned int path_bias_extreme : 1; /**< Did we alert the user about path
+ * bias for this node already? */
+ unsigned int path_bias_disabled : 1; /**< Have we disabled this node because
+ * of path bias issues? */
+ unsigned int path_bias_use_noticed : 1; /**< Did we alert the user about path
+ * use bias for this node already? */
+ unsigned int path_bias_use_extreme : 1; /**< Did we alert the user about path
+ * use bias for this node already? */
+ unsigned int is_dir_cache : 1; /**< Is this node a directory cache? */
+ time_t bad_since; /**< 0 if this guard is currently usable, or the time at
+ * which it was observed to become (according to the
+ * directory or the user configuration) unusable. */
+ time_t unreachable_since; /**< 0 if we can connect to this guard, or the
+ * time at which we first noticed we couldn't
+ * connect to it. */
+ time_t last_attempted; /**< 0 if we can connect to this guard, or the time
+ * at which we last failed to connect to it. */
+
+ double circ_attempts; /**< Number of circuits this guard has "attempted" */
+ double circ_successes; /**< Number of successfully built circuits using
+ * this guard as first hop. */
+ double successful_circuits_closed; /**< Number of circuits that carried
+ * streams successfully. */
+ double collapsed_circuits; /**< Number of fully built circuits that were
+ * remotely closed before any streams were
+ * attempted. */
+ double unusable_circuits; /**< Number of circuits for which streams were
+ * attempted, but none succeeded. */
+ double timeouts; /**< Number of 'right-censored' circuit timeouts for this
+ * guard. */
+ double use_attempts; /**< Number of circuits we tried to use with streams */
+ double use_successes; /**< Number of successfully used circuits using
+ * this guard as first hop. */
+} entry_guard_t;
+
+entry_guard_t *entry_guard_get_by_id_digest(const char *digest);
+void entry_guards_changed(void);
+const smartlist_t *get_entry_guards(void);
+int num_live_entry_guards(int for_directory);
+
+#endif
+
+void entry_guards_compute_status(const or_options_t *options, time_t now);
+int entry_guard_register_connect_status(const char *digest, int succeeded,
+ int mark_relay_status, time_t now);
+void entry_nodes_should_be_added(void);
+int entry_list_is_constrained(const or_options_t *options);
+const node_t *choose_random_entry(cpath_build_state_t *state);
+const node_t *choose_random_dirguard(dirinfo_type_t t);
+int entry_guards_parse_state(or_state_t *state, int set, char **msg);
+void entry_guards_update_state(or_state_t *state);
+int getinfo_helper_entry_guards(control_connection_t *conn,
+ const char *question, char **answer,
+ const char **errmsg);
+
+void mark_bridge_list(void);
+void sweep_bridge_list(void);
+
+int routerinfo_is_a_configured_bridge(const routerinfo_t *ri);
+int node_is_a_configured_bridge(const node_t *node);
+void learned_router_identity(const tor_addr_t *addr, uint16_t port,
+ const char *digest);
+void bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
+ const char *digest,
+ const char *transport_name);
+void retry_bridge_descriptor_fetch_directly(const char *digest);
+void fetch_bridge_descriptors(const or_options_t *options, time_t now);
+void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);
+int any_bridge_descriptors_known(void);
+int any_pending_bridge_descriptor_fetches(void);
+int entries_known_but_down(const or_options_t *options);
+void entries_retry_all(const or_options_t *options);
+
+int any_bridge_supports_microdescriptors(void);
+
+void entry_guards_free_all(void);
+
+const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr,
+ uint16_t port);
+struct transport_t;
+int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
+ const struct transport_t **transport);
+
+int validate_pluggable_transports_config(void);
+
+double pathbias_get_close_success_count(entry_guard_t *guard);
+double pathbias_get_use_success_count(entry_guard_t *guard);
+
+#endif
+
diff --git a/src/or/eventdns_tor.h b/src/or/eventdns_tor.h
index 4c40b3524..69662281b 100644
--- a/src/or/eventdns_tor.h
+++ b/src/or/eventdns_tor.h
@@ -1,6 +1,9 @@
-/* Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#ifndef TOR_EVENTDNS_TOR_H
+#define TOR_EVENTDNS_TOR_H
+
#include "orconfig.h"
#define DNS_USE_OPENSSL_FOR_ID
#ifndef HAVE_UINT
@@ -18,3 +21,5 @@ typedef unsigned char u_char;
#include "util.h"
#include "compat.h"
+#endif
+
diff --git a/src/or/fp_pair.c b/src/or/fp_pair.c
new file mode 100644
index 000000000..4d8a835c8
--- /dev/null
+++ b/src/or/fp_pair.c
@@ -0,0 +1,308 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "fp_pair.h"
+
+/* Define fp_pair_map_t structures */
+
+struct fp_pair_map_entry_s {
+ HT_ENTRY(fp_pair_map_entry_s) node;
+ void *val;
+ fp_pair_t key;
+};
+
+struct fp_pair_map_s {
+ HT_HEAD(fp_pair_map_impl, fp_pair_map_entry_s) head;
+};
+
+/*
+ * Hash function and equality checker for fp_pair_map_t
+ */
+
+/** Compare fp_pair_entry_t objects by key value. */
+static INLINE int
+fp_pair_map_entries_eq(const fp_pair_map_entry_t *a,
+ const fp_pair_map_entry_t *b)
+{
+ return tor_memeq(&(a->key), &(b->key), sizeof(fp_pair_t));
+}
+
+/** Return a hash value for an fp_pair_entry_t. */
+static INLINE unsigned int
+fp_pair_map_entry_hash(const fp_pair_map_entry_t *a)
+{
+ const uint32_t *p;
+ unsigned int hash;
+
+ p = (const uint32_t *)(a->key.first);
+ /* Hashes are 20 bytes long, so 5 times uint32_t */
+ hash = p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4];
+ /* Now XOR in the second fingerprint */
+ p = (const uint32_t *)(a->key.second);
+ hash ^= p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4];
+
+ return hash;
+}
+
+/*
+ * Hash table functions for fp_pair_map_t
+ */
+
+HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_s, node,
+ fp_pair_map_entry_hash, fp_pair_map_entries_eq)
+HT_GENERATE(fp_pair_map_impl, fp_pair_map_entry_s, node,
+ fp_pair_map_entry_hash, fp_pair_map_entries_eq,
+ 0.6, tor_malloc, tor_realloc, tor_free)
+
+/** Constructor to create a new empty map from fp_pair_t to void *
+ */
+
+fp_pair_map_t *
+fp_pair_map_new(void)
+{
+ fp_pair_map_t *result;
+
+ result = tor_malloc(sizeof(fp_pair_map_t));
+ HT_INIT(fp_pair_map_impl, &result->head);
+ return result;
+}
+
+/** Set the current value for key to val; returns the previous
+ * value for key if one was set, or NULL if one was not.
+ */
+
+void *
+fp_pair_map_set(fp_pair_map_t *map, const fp_pair_t *key, void *val)
+{
+ fp_pair_map_entry_t *resolve;
+ fp_pair_map_entry_t search;
+ void *oldval;
+
+ tor_assert(map);
+ tor_assert(key);
+ tor_assert(val);
+
+ memcpy(&(search.key), key, sizeof(*key));
+ resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search);
+ if (resolve) {
+ oldval = resolve->val;
+ resolve->val = val;
+ } else {
+ resolve = tor_malloc_zero(sizeof(fp_pair_map_entry_t));
+ memcpy(&(resolve->key), key, sizeof(*key));
+ resolve->val = val;
+ HT_INSERT(fp_pair_map_impl, &(map->head), resolve);
+ oldval = NULL;
+ }
+
+ return oldval;
+}
+
+/** Set the current value for the key (first, second) to val; returns
+ * the previous value for key if one was set, or NULL if one was not.
+ */
+
+void *
+fp_pair_map_set_by_digests(fp_pair_map_t *map,
+ const char *first, const char *second,
+ void *val)
+{
+ fp_pair_t k;
+
+ tor_assert(first);
+ tor_assert(second);
+
+ memcpy(k.first, first, DIGEST_LEN);
+ memcpy(k.second, second, DIGEST_LEN);
+
+ return fp_pair_map_set(map, &k, val);
+}
+
+/** Return the current value associated with key, or NULL if no value is set.
+ */
+
+void *
+fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key)
+{
+ fp_pair_map_entry_t *resolve;
+ fp_pair_map_entry_t search;
+ void *val = NULL;
+
+ tor_assert(map);
+ tor_assert(key);
+
+ memcpy(&(search.key), key, sizeof(*key));
+ resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search);
+ if (resolve) val = resolve->val;
+
+ return val;
+}
+
+/** Return the current value associated the key (first, second), or
+ * NULL if no value is set.
+ */
+
+void *
+fp_pair_map_get_by_digests(const fp_pair_map_t *map,
+ const char *first, const char *second)
+{
+ fp_pair_t k;
+
+ tor_assert(first);
+ tor_assert(second);
+
+ memcpy(k.first, first, DIGEST_LEN);
+ memcpy(k.second, second, DIGEST_LEN);
+
+ return fp_pair_map_get(map, &k);
+}
+
+/** Remove the value currently associated with key from the map.
+ * Return the value if one was set, or NULL if there was no entry for
+ * key. The caller must free any storage associated with the
+ * returned value.
+ */
+
+void *
+fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key)
+{
+ fp_pair_map_entry_t *resolve;
+ fp_pair_map_entry_t search;
+ void *val = NULL;
+
+ tor_assert(map);
+ tor_assert(key);
+
+ memcpy(&(search.key), key, sizeof(*key));
+ resolve = HT_REMOVE(fp_pair_map_impl, &(map->head), &search);
+ if (resolve) {
+ val = resolve->val;
+ tor_free(resolve);
+ }
+
+ return val;
+}
+
+/** Remove all entries from map, and deallocate storage for those entries.
+ * If free_val is provided, it is invoked on every value in map.
+ */
+
+void
+fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*))
+{
+ fp_pair_map_entry_t **ent, **next, *this;
+
+ if (map) {
+ for (ent = HT_START(fp_pair_map_impl, &(map->head));
+ ent != NULL; ent = next) {
+ this = *ent;
+ next = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), ent);
+ if (free_val) free_val(this->val);
+ tor_free(this);
+ }
+ tor_assert(HT_EMPTY(&(map->head)));
+ HT_CLEAR(fp_pair_map_impl, &(map->head));
+ tor_free(map);
+ }
+}
+
+/** Return true iff map has no entries.
+ */
+
+int
+fp_pair_map_isempty(const fp_pair_map_t *map)
+{
+ tor_assert(map);
+
+ return HT_EMPTY(&(map->head));
+}
+
+/** Return the number of items in map.
+ */
+
+int
+fp_pair_map_size(const fp_pair_map_t *map)
+{
+ tor_assert(map);
+
+ return HT_SIZE(&(map->head));
+}
+
+/** return an iterator pointing to the start of map.
+ */
+
+fp_pair_map_iter_t *
+fp_pair_map_iter_init(fp_pair_map_t *map)
+{
+ tor_assert(map);
+
+ return HT_START(fp_pair_map_impl, &(map->head));
+}
+
+/** Advance iter a single step to the next entry of map, and return
+ * its new value.
+ */
+
+fp_pair_map_iter_t *
+fp_pair_map_iter_next(fp_pair_map_t *map, fp_pair_map_iter_t *iter)
+{
+ tor_assert(map);
+ tor_assert(iter);
+
+ return HT_NEXT(fp_pair_map_impl, &(map->head), iter);
+}
+
+/** Advance iter a single step to the next entry of map, removing the current
+ * entry, and return its new value.
+ */
+
+fp_pair_map_iter_t *
+fp_pair_map_iter_next_rmv(fp_pair_map_t *map, fp_pair_map_iter_t *iter)
+{
+ fp_pair_map_entry_t *rmv;
+
+ tor_assert(map);
+ tor_assert(iter);
+ tor_assert(*iter);
+
+ rmv = *iter;
+ iter = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), iter);
+ tor_free(rmv);
+
+ return iter;
+}
+
+/** Set *key_out and *val_out to the current entry pointed to by iter.
+ */
+
+void
+fp_pair_map_iter_get(fp_pair_map_iter_t *iter,
+ fp_pair_t *key_out, void **val_out)
+{
+ tor_assert(iter);
+ tor_assert(*iter);
+
+ if (key_out) memcpy(key_out, &((*iter)->key), sizeof(fp_pair_t));
+ if (val_out) *val_out = (*iter)->val;
+}
+
+/** Return true iff iter has advanced past the last entry of its map.
+ */
+
+int
+fp_pair_map_iter_done(fp_pair_map_iter_t *iter)
+{
+ return (iter == NULL);
+}
+
+/** Assert if anything has gone wrong with the internal
+ * representation of map.
+ */
+
+void
+fp_pair_map_assert_ok(const fp_pair_map_t *map)
+{
+ tor_assert(!fp_pair_map_impl_HT_REP_IS_BAD_(&(map->head)));
+}
+
diff --git a/src/or/fp_pair.h b/src/or/fp_pair.h
new file mode 100644
index 000000000..89f664a81
--- /dev/null
+++ b/src/or/fp_pair.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file fp_pair.h
+ * \brief Header file for fp_pair.c.
+ **/
+
+#ifndef _TOR_FP_PAIR_H
+#define _TOR_FP_PAIR_H
+
+/*
+ * Declare fp_pair_map_t functions and structs
+ */
+
+typedef struct fp_pair_map_entry_s fp_pair_map_entry_t;
+typedef struct fp_pair_map_s fp_pair_map_t;
+typedef fp_pair_map_entry_t *fp_pair_map_iter_t;
+
+fp_pair_map_t * fp_pair_map_new(void);
+void * fp_pair_map_set(fp_pair_map_t *map, const fp_pair_t *key, void *val);
+void * fp_pair_map_set_by_digests(fp_pair_map_t *map,
+ const char *first, const char *second,
+ void *val);
+void * fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key);
+void * fp_pair_map_get_by_digests(const fp_pair_map_t *map,
+ const char *first, const char *second);
+void * fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key);
+void fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*));
+int fp_pair_map_isempty(const fp_pair_map_t *map);
+int fp_pair_map_size(const fp_pair_map_t *map);
+fp_pair_map_iter_t * fp_pair_map_iter_init(fp_pair_map_t *map);
+fp_pair_map_iter_t * fp_pair_map_iter_next(fp_pair_map_t *map,
+ fp_pair_map_iter_t *iter);
+fp_pair_map_iter_t * fp_pair_map_iter_next_rmv(fp_pair_map_t *map,
+ fp_pair_map_iter_t *iter);
+void fp_pair_map_iter_get(fp_pair_map_iter_t *iter,
+ fp_pair_t *key_out, void **val_out);
+int fp_pair_map_iter_done(fp_pair_map_iter_t *iter);
+void fp_pair_map_assert_ok(const fp_pair_map_t *map);
+
+#undef DECLARE_MAP_FNS
+
+#endif
+
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 6b7cc82b8..e2e98e8ec 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,17 +21,23 @@
static void clear_geoip_db(void);
static void init_geoip_countries(void);
-/** An entry from the GeoIP file: maps an IP range to a country. */
-typedef struct geoip_entry_t {
+/** An entry from the GeoIP IPv4 file: maps an IPv4 range to a country. */
+typedef struct geoip_ipv4_entry_t {
uint32_t ip_low; /**< The lowest IP in the range, in host order */
uint32_t ip_high; /**< The highest IP in the range, in host order */
intptr_t country; /**< An index into geoip_countries */
-} geoip_entry_t;
+} geoip_ipv4_entry_t;
+
+/** An entry from the GeoIP IPv6 file: maps an IPv6 range to a country. */
+typedef struct geoip_ipv6_entry_t {
+ struct in6_addr ip_low; /**< The lowest IP in the range, in host order */
+ struct in6_addr ip_high; /**< The highest IP in the range, in host order */
+ intptr_t country; /**< An index into geoip_countries */
+} geoip_ipv6_entry_t;
/** A per-country record for GeoIP request history. */
typedef struct geoip_country_t {
char countrycode[3];
- uint32_t n_v2_ns_requests;
uint32_t n_v3_ns_requests;
} geoip_country_t;
@@ -41,45 +47,48 @@ static smartlist_t *geoip_countries = NULL;
* The index is encoded in the pointer, and 1 is added so that NULL can mean
* not found. */
static strmap_t *country_idxplus1_by_lc_code = NULL;
-/** A list of all known geoip_entry_t, sorted by ip_low. */
-static smartlist_t *geoip_entries = NULL;
+/** Lists of all known geoip_ipv4_entry_t and geoip_ipv6_entry_t, sorted
+ * by their respective ip_low. */
+static smartlist_t *geoip_ipv4_entries = NULL, *geoip_ipv6_entries = NULL;
-/** SHA1 digest of the GeoIP file to include in extra-info descriptors. */
+/** SHA1 digest of the GeoIP files to include in extra-info descriptors. */
static char geoip_digest[DIGEST_LEN];
+static char geoip6_digest[DIGEST_LEN];
-/** Return the index of the <b>country</b>'s entry in the GeoIP DB
- * if it is a valid 2-letter country code, otherwise return -1.
- */
+/** Return the index of the <b>country</b>'s entry in the GeoIP
+ * country list if it is a valid 2-letter country code, otherwise
+ * return -1. */
country_t
geoip_get_country(const char *country)
{
- void *_idxplus1;
+ void *idxplus1_;
intptr_t idx;
- _idxplus1 = strmap_get_lc(country_idxplus1_by_lc_code, country);
- if (!_idxplus1)
+ idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country);
+ if (!idxplus1_)
return -1;
- idx = ((uintptr_t)_idxplus1)-1;
+ idx = ((uintptr_t)idxplus1_)-1;
return (country_t)idx;
}
-/** Add an entry to the GeoIP table, mapping all IPs between <b>low</b> and
- * <b>high</b>, inclusive, to the 2-letter country code <b>country</b>.
- */
+/** Add an entry to a GeoIP table, mapping all IP addresses between <b>low</b>
+ * and <b>high</b>, inclusive, to the 2-letter country code <b>country</b>. */
static void
-geoip_add_entry(uint32_t low, uint32_t high, const char *country)
+geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high,
+ const char *country)
{
intptr_t idx;
- geoip_entry_t *ent;
- void *_idxplus1;
+ void *idxplus1_;
- if (high < low)
+ if (tor_addr_family(low) != tor_addr_family(high))
+ return;
+ if (tor_addr_compare(high, low, CMP_EXACT) < 0)
return;
- _idxplus1 = strmap_get_lc(country_idxplus1_by_lc_code, country);
+ idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country);
- if (!_idxplus1) {
+ if (!idxplus1_) {
geoip_country_t *c = tor_malloc_zero(sizeof(geoip_country_t));
strlcpy(c->countrycode, country, sizeof(c->countrycode));
tor_strlower(c->countrycode);
@@ -87,54 +96,103 @@ geoip_add_entry(uint32_t low, uint32_t high, const char *country)
idx = smartlist_len(geoip_countries) - 1;
strmap_set_lc(country_idxplus1_by_lc_code, country, (void*)(idx+1));
} else {
- idx = ((uintptr_t)_idxplus1)-1;
+ idx = ((uintptr_t)idxplus1_)-1;
}
{
geoip_country_t *c = smartlist_get(geoip_countries, idx);
tor_assert(!strcasecmp(c->countrycode, country));
}
- ent = tor_malloc_zero(sizeof(geoip_entry_t));
- ent->ip_low = low;
- ent->ip_high = high;
- ent->country = idx;
- smartlist_add(geoip_entries, ent);
+
+ if (tor_addr_family(low) == AF_INET) {
+ geoip_ipv4_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv4_entry_t));
+ ent->ip_low = tor_addr_to_ipv4h(low);
+ ent->ip_high = tor_addr_to_ipv4h(high);
+ ent->country = idx;
+ smartlist_add(geoip_ipv4_entries, ent);
+ } else if (tor_addr_family(low) == AF_INET6) {
+ geoip_ipv6_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv6_entry_t));
+ ent->ip_low = *tor_addr_to_in6(low);
+ ent->ip_high = *tor_addr_to_in6(high);
+ ent->country = idx;
+ smartlist_add(geoip_ipv6_entries, ent);
+ }
}
-/** Add an entry to the GeoIP table, parsing it from <b>line</b>. The
- * format is as for geoip_load_file(). */
+/** Add an entry to the GeoIP table indicated by <b>family</b>,
+ * parsing it from <b>line</b>. The format is as for geoip_load_file(). */
/*private*/ int
-geoip_parse_entry(const char *line)
+geoip_parse_entry(const char *line, sa_family_t family)
{
- unsigned int low, high;
- char b[3];
+ tor_addr_t low_addr, high_addr;
+ char c[3];
+ char *country = NULL;
+
if (!geoip_countries)
init_geoip_countries();
- if (!geoip_entries)
- geoip_entries = smartlist_new();
+ if (family == AF_INET) {
+ if (!geoip_ipv4_entries)
+ geoip_ipv4_entries = smartlist_new();
+ } else if (family == AF_INET6) {
+ if (!geoip_ipv6_entries)
+ geoip_ipv6_entries = smartlist_new();
+ } else {
+ log_warn(LD_GENERAL, "Unsupported family: %d", family);
+ return -1;
+ }
while (TOR_ISSPACE(*line))
++line;
if (*line == '#')
return 0;
- if (tor_sscanf(line,"%u,%u,%2s", &low, &high, b) == 3) {
- geoip_add_entry(low, high, b);
- return 0;
- } else if (tor_sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, b) == 3) {
- geoip_add_entry(low, high, b);
- return 0;
- } else {
- log_warn(LD_GENERAL, "Unable to parse line from GEOIP file: %s",
- escaped(line));
- return -1;
+
+ if (family == AF_INET) {
+ unsigned int low, high;
+ if (tor_sscanf(line,"%u,%u,%2s", &low, &high, c) == 3 ||
+ tor_sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, c) == 3) {
+ tor_addr_from_ipv4h(&low_addr, low);
+ tor_addr_from_ipv4h(&high_addr, high);
+ } else
+ goto fail;
+ country = c;
+ } else { /* AF_INET6 */
+ char buf[512];
+ char *low_str, *high_str;
+ struct in6_addr low, high;
+ char *strtok_state;
+ strlcpy(buf, line, sizeof(buf));
+ low_str = tor_strtok_r(buf, ",", &strtok_state);
+ if (!low_str)
+ goto fail;
+ high_str = tor_strtok_r(NULL, ",", &strtok_state);
+ if (!high_str)
+ goto fail;
+ country = tor_strtok_r(NULL, "\n", &strtok_state);
+ if (!country)
+ goto fail;
+ if (strlen(country) != 2)
+ goto fail;
+ if (tor_inet_pton(AF_INET6, low_str, &low) <= 0)
+ goto fail;
+ tor_addr_from_in6(&low_addr, &low);
+ if (tor_inet_pton(AF_INET6, high_str, &high) <= 0)
+ goto fail;
+ tor_addr_from_in6(&high_addr, &high);
}
+ geoip_add_entry(&low_addr, &high_addr, country);
+ return 0;
+
+ fail:
+ log_warn(LD_GENERAL, "Unable to parse line from GEOIP %s file: %s",
+ family == AF_INET ? "IPv4" : "IPv6", escaped(line));
+ return -1;
}
/** Sorting helper: return -1, 1, or 0 based on comparison of two
- * geoip_entry_t */
+ * geoip_ipv4_entry_t */
static int
-_geoip_compare_entries(const void **_a, const void **_b)
+geoip_ipv4_compare_entries_(const void **_a, const void **_b)
{
- const geoip_entry_t *a = *_a, *b = *_b;
+ const geoip_ipv4_entry_t *a = *_a, *b = *_b;
if (a->ip_low < b->ip_low)
return -1;
else if (a->ip_low > b->ip_low)
@@ -144,13 +202,13 @@ _geoip_compare_entries(const void **_a, const void **_b)
}
/** bsearch helper: return -1, 1, or 0 based on comparison of an IP (a pointer
- * to a uint32_t in host order) to a geoip_entry_t */
+ * to a uint32_t in host order) to a geoip_ipv4_entry_t */
static int
-_geoip_compare_key_to_entry(const void *_key, const void **_member)
+geoip_ipv4_compare_key_to_entry_(const void *_key, const void **_member)
{
/* No alignment issue here, since _key really is a pointer to uint32_t */
const uint32_t addr = *(uint32_t *)_key;
- const geoip_entry_t *entry = *_member;
+ const geoip_ipv4_entry_t *entry = *_member;
if (addr < entry->ip_low)
return -1;
else if (addr > entry->ip_high)
@@ -159,6 +217,34 @@ _geoip_compare_key_to_entry(const void *_key, const void **_member)
return 0;
}
+/** Sorting helper: return -1, 1, or 0 based on comparison of two
+ * geoip_ipv6_entry_t */
+static int
+geoip_ipv6_compare_entries_(const void **_a, const void **_b)
+{
+ const geoip_ipv6_entry_t *a = *_a, *b = *_b;
+ return fast_memcmp(a->ip_low.s6_addr, b->ip_low.s6_addr,
+ sizeof(struct in6_addr));
+}
+
+/** bsearch helper: return -1, 1, or 0 based on comparison of an IPv6
+ * (a pointer to a in6_addr) to a geoip_ipv6_entry_t */
+static int
+geoip_ipv6_compare_key_to_entry_(const void *_key, const void **_member)
+{
+ const struct in6_addr *addr = (struct in6_addr *)_key;
+ const geoip_ipv6_entry_t *entry = *_member;
+
+ if (fast_memcmp(addr->s6_addr, entry->ip_low.s6_addr,
+ sizeof(struct in6_addr)) < 0)
+ return -1;
+ else if (fast_memcmp(addr->s6_addr, entry->ip_high.s6_addr,
+ sizeof(struct in6_addr)) > 0)
+ return 1;
+ else
+ return 0;
+}
+
/** Return 1 if we should collect geoip stats on bridge users, and
* include them in our extrainfo descriptor. Else return 0. */
int
@@ -185,27 +271,35 @@ init_geoip_countries(void)
strmap_set_lc(country_idxplus1_by_lc_code, "??", (void*)(1));
}
-/** Clear the GeoIP database and reload it from the file
- * <b>filename</b>. Return 0 on success, -1 on failure.
+/** Clear appropriate GeoIP database, based on <b>family</b>, and
+ * reload it from the file <b>filename</b>. Return 0 on success, -1 on
+ * failure.
*
- * Recognized line formats are:
+ * Recognized line formats for IPv4 are:
* INTIPLOW,INTIPHIGH,CC
* and
* "INTIPLOW","INTIPHIGH","CC","CC3","COUNTRY NAME"
* where INTIPLOW and INTIPHIGH are IPv4 addresses encoded as 4-byte unsigned
* integers, and CC is a country code.
*
+ * Recognized line format for IPv6 is:
+ * IPV6LOW,IPV6HIGH,CC
+ * where IPV6LOW and IPV6HIGH are IPv6 addresses and CC is a country code.
+ *
* It also recognizes, and skips over, blank lines and lines that start
* with '#' (comments).
*/
int
-geoip_load_file(const char *filename, const or_options_t *options)
+geoip_load_file(sa_family_t family, const char *filename)
{
FILE *f;
const char *msg = "";
+ const or_options_t *options = get_options();
int severity = options_need_geoip_info(options, &msg) ? LOG_WARN : LOG_INFO;
crypto_digest_t *geoip_digest_env = NULL;
- clear_geoip_db();
+
+ tor_assert(family == AF_INET || family == AF_INET6);
+
if (!(f = tor_fopen_cloexec(filename, "r"))) {
log_fn(severity, LD_GENERAL, "Failed to open GEOIP file %s. %s",
filename, msg);
@@ -213,33 +307,51 @@ geoip_load_file(const char *filename, const or_options_t *options)
}
if (!geoip_countries)
init_geoip_countries();
- if (geoip_entries) {
- SMARTLIST_FOREACH(geoip_entries, geoip_entry_t *, e, tor_free(e));
- smartlist_free(geoip_entries);
+
+ if (family == AF_INET) {
+ if (geoip_ipv4_entries) {
+ SMARTLIST_FOREACH(geoip_ipv4_entries, geoip_ipv4_entry_t *, e,
+ tor_free(e));
+ smartlist_free(geoip_ipv4_entries);
+ }
+ geoip_ipv4_entries = smartlist_new();
+ } else { /* AF_INET6 */
+ if (geoip_ipv6_entries) {
+ SMARTLIST_FOREACH(geoip_ipv6_entries, geoip_ipv6_entry_t *, e,
+ tor_free(e));
+ smartlist_free(geoip_ipv6_entries);
+ }
+ geoip_ipv6_entries = smartlist_new();
}
- geoip_entries = smartlist_new();
geoip_digest_env = crypto_digest_new();
- log_notice(LD_GENERAL, "Parsing GEOIP file %s.", filename);
+
+ log_notice(LD_GENERAL, "Parsing GEOIP %s file %s.",
+ (family == AF_INET) ? "IPv4" : "IPv6", filename);
while (!feof(f)) {
char buf[512];
if (fgets(buf, (int)sizeof(buf), f) == NULL)
break;
crypto_digest_add_bytes(geoip_digest_env, buf, strlen(buf));
/* FFFF track full country name. */
- geoip_parse_entry(buf);
+ geoip_parse_entry(buf, family);
}
/*XXXX abort and return -1 if no entries/illformed?*/
fclose(f);
- smartlist_sort(geoip_entries, _geoip_compare_entries);
-
- /* Okay, now we need to maybe change our mind about what is in which
- * country. */
- refresh_all_country_info();
-
- /* Remember file digest so that we can include it in our extra-info
- * descriptors. */
- crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN);
+ /* Sort list and remember file digests so that we can include it in
+ * our extra-info descriptors. */
+ if (family == AF_INET) {
+ smartlist_sort(geoip_ipv4_entries, geoip_ipv4_compare_entries_);
+ /* Okay, now we need to maybe change our mind about what is in
+ * which country. We do this for IPv4 only since that's what we
+ * store in node->country. */
+ refresh_all_country_info();
+ crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN);
+ } else {
+ /* AF_INET6 */
+ smartlist_sort(geoip_ipv6_entries, geoip_ipv6_compare_entries_);
+ crypto_digest_get_digest(geoip_digest_env, geoip6_digest, DIGEST_LEN);
+ }
crypto_digest_free(geoip_digest_env);
return 0;
@@ -252,12 +364,30 @@ geoip_load_file(const char *filename, const or_options_t *options)
* geoip_get_country_name().
*/
int
-geoip_get_country_by_ip(uint32_t ipaddr)
+geoip_get_country_by_ipv4(uint32_t ipaddr)
{
- geoip_entry_t *ent;
- if (!geoip_entries)
+ geoip_ipv4_entry_t *ent;
+ if (!geoip_ipv4_entries)
return -1;
- ent = smartlist_bsearch(geoip_entries, &ipaddr, _geoip_compare_key_to_entry);
+ ent = smartlist_bsearch(geoip_ipv4_entries, &ipaddr,
+ geoip_ipv4_compare_key_to_entry_);
+ return ent ? (int)ent->country : 0;
+}
+
+/** Given an IPv6 address, return a number representing the country to
+ * which that address belongs, -1 for "No geoip information available", or
+ * 0 for the 'unknown country'. The return value will always be less than
+ * geoip_get_n_countries(). To decode it, call geoip_get_country_name().
+ */
+int
+geoip_get_country_by_ipv6(const struct in6_addr *addr)
+{
+ geoip_ipv6_entry_t *ent;
+
+ if (!geoip_ipv6_entries)
+ return -1;
+ ent = smartlist_bsearch(geoip_ipv6_entries, addr,
+ geoip_ipv6_compare_key_to_entry_);
return ent ? (int)ent->country : 0;
}
@@ -269,14 +399,16 @@ geoip_get_country_by_ip(uint32_t ipaddr)
int
geoip_get_country_by_addr(const tor_addr_t *addr)
{
- if (tor_addr_family(addr) != AF_INET) {
- /*XXXX IP6 support ipv6 geoip.*/
+ if (tor_addr_family(addr) == AF_INET) {
+ return geoip_get_country_by_ipv4(tor_addr_to_ipv4h(addr));
+ } else if (tor_addr_family(addr) == AF_INET6) {
+ return geoip_get_country_by_ipv6(tor_addr_to_in6(addr));
+ } else {
return -1;
}
- return geoip_get_country_by_ip(tor_addr_to_ipv4h(addr));
}
-/** Return the number of countries recognized by the GeoIP database. */
+/** Return the number of countries recognized by the GeoIP country list. */
int
geoip_get_n_countries(void)
{
@@ -299,18 +431,28 @@ geoip_get_country_name(country_t num)
/** Return true iff we have loaded a GeoIP database.*/
int
-geoip_is_loaded(void)
+geoip_is_loaded(sa_family_t family)
{
- return geoip_countries != NULL && geoip_entries != NULL;
+ tor_assert(family == AF_INET || family == AF_INET6);
+ if (geoip_countries == NULL)
+ return 0;
+ if (family == AF_INET)
+ return geoip_ipv4_entries != NULL;
+ else /* AF_INET6 */
+ return geoip_ipv6_entries != NULL;
}
/** Return the hex-encoded SHA1 digest of the loaded GeoIP file. The
* result does not need to be deallocated, but will be overwritten by the
* next call of hex_str(). */
const char *
-geoip_db_digest(void)
+geoip_db_digest(sa_family_t family)
{
- return hex_str(geoip_digest, DIGEST_LEN);
+ tor_assert(family == AF_INET || family == AF_INET6);
+ if (family == AF_INET)
+ return hex_str(geoip_digest, DIGEST_LEN);
+ else /* AF_INET6 */
+ return hex_str(geoip6_digest, DIGEST_LEN);
}
/** Entry in a map from IP address to the last time we've seen an incoming
@@ -372,67 +514,6 @@ client_history_clear(void)
}
}
-/** How often do we update our estimate which share of v2 and v3 directory
- * requests is sent to us? We could as well trigger updates of shares from
- * network status updates, but that means adding a lot of calls into code
- * that is independent from geoip stats (and keeping them up-to-date). We
- * are perfectly fine with an approximation of 15-minute granularity. */
-#define REQUEST_SHARE_INTERVAL (15 * 60)
-
-/** When did we last determine which share of v2 and v3 directory requests
- * is sent to us? */
-static time_t last_time_determined_shares = 0;
-
-/** Sum of products of v2 shares times the number of seconds for which we
- * consider these shares as valid. */
-static double v2_share_times_seconds;
-
-/** Sum of products of v3 shares times the number of seconds for which we
- * consider these shares as valid. */
-static double v3_share_times_seconds;
-
-/** Number of seconds we are determining v2 and v3 shares. */
-static int share_seconds;
-
-/** Try to determine which fraction of v2 and v3 directory requests aimed at
- * caches will be sent to us at time <b>now</b> and store that value in
- * order to take a mean value later on. */
-static void
-geoip_determine_shares(time_t now)
-{
- double v2_share = 0.0, v3_share = 0.0;
- if (router_get_my_share_of_directory_requests(&v2_share, &v3_share) < 0)
- return;
- if (last_time_determined_shares) {
- v2_share_times_seconds += v2_share *
- ((double) (now - last_time_determined_shares));
- v3_share_times_seconds += v3_share *
- ((double) (now - last_time_determined_shares));
- share_seconds += (int)(now - last_time_determined_shares);
- }
- last_time_determined_shares = now;
-}
-
-/** Calculate which fraction of v2 and v3 directory requests aimed at caches
- * have been sent to us since the last call of this function up to time
- * <b>now</b>. Set *<b>v2_share_out</b> and *<b>v3_share_out</b> to the
- * fractions of v2 and v3 protocol shares we expect to have seen. Reset
- * counters afterwards. Return 0 on success, -1 on failure (e.g. when zero
- * seconds have passed since the last call).*/
-static int
-geoip_get_mean_shares(time_t now, double *v2_share_out,
- double *v3_share_out)
-{
- geoip_determine_shares(now);
- if (!share_seconds)
- return -1;
- *v2_share_out = v2_share_times_seconds / ((double) share_seconds);
- *v3_share_out = v3_share_times_seconds / ((double) share_seconds);
- v2_share_times_seconds = v3_share_times_seconds = 0.0;
- share_seconds = 0;
- return 0;
-}
-
/** Note that we've seen a client connect from the IP <b>addr</b>
* at time <b>now</b>. Ignored by all but bridges and directories if
* configured accordingly. */
@@ -467,29 +548,21 @@ geoip_note_client_seen(geoip_client_action_t action,
else
ent->last_seen_in_minutes = 0;
- if (action == GEOIP_CLIENT_NETWORKSTATUS ||
- action == GEOIP_CLIENT_NETWORKSTATUS_V2) {
+ if (action == GEOIP_CLIENT_NETWORKSTATUS) {
int country_idx = geoip_get_country_by_addr(addr);
if (country_idx < 0)
country_idx = 0; /** unresolved requests are stored at index 0. */
if (country_idx >= 0 && country_idx < smartlist_len(geoip_countries)) {
geoip_country_t *country = smartlist_get(geoip_countries, country_idx);
- if (action == GEOIP_CLIENT_NETWORKSTATUS)
- ++country->n_v3_ns_requests;
- else
- ++country->n_v2_ns_requests;
+ ++country->n_v3_ns_requests;
}
-
- /* Periodically determine share of requests that we should see */
- if (last_time_determined_shares + REQUEST_SHARE_INTERVAL < now)
- geoip_determine_shares(now);
}
}
/** HT_FOREACH helper: remove a clientmap_entry_t from the hashtable if it's
* older than a certain time. */
static int
-_remove_old_client_helper(struct clientmap_entry_t *ent, void *_cutoff)
+remove_old_client_helper_(struct clientmap_entry_t *ent, void *_cutoff)
{
time_t cutoff = *(time_t*)_cutoff / 60;
if (ent->last_seen_in_minutes < cutoff) {
@@ -505,40 +578,28 @@ void
geoip_remove_old_clients(time_t cutoff)
{
clientmap_HT_FOREACH_FN(&client_history,
- _remove_old_client_helper,
+ remove_old_client_helper_,
&cutoff);
}
-/** How many responses are we giving to clients requesting v2 network
- * statuses? */
-static uint32_t ns_v2_responses[GEOIP_NS_RESPONSE_NUM];
-
/** How many responses are we giving to clients requesting v3 network
* statuses? */
static uint32_t ns_v3_responses[GEOIP_NS_RESPONSE_NUM];
-/** Note that we've rejected a client's request for a v2 or v3 network
- * status, encoded in <b>action</b> for reason <b>reason</b> at time
- * <b>now</b>. */
+/** Note that we've rejected a client's request for a v3 network status
+ * for reason <b>reason</b> at time <b>now</b>. */
void
-geoip_note_ns_response(geoip_client_action_t action,
- geoip_ns_response_t response)
+geoip_note_ns_response(geoip_ns_response_t response)
{
static int arrays_initialized = 0;
if (!get_options()->DirReqStatistics)
return;
if (!arrays_initialized) {
- memset(ns_v2_responses, 0, sizeof(ns_v2_responses));
memset(ns_v3_responses, 0, sizeof(ns_v3_responses));
arrays_initialized = 1;
}
- tor_assert(action == GEOIP_CLIENT_NETWORKSTATUS ||
- action == GEOIP_CLIENT_NETWORKSTATUS_V2);
tor_assert(response < GEOIP_NS_RESPONSE_NUM);
- if (action == GEOIP_CLIENT_NETWORKSTATUS)
- ns_v3_responses[response]++;
- else
- ns_v2_responses[response]++;
+ ns_v3_responses[response]++;
}
/** Do not mention any country from which fewer than this number of IPs have
@@ -559,10 +620,10 @@ typedef struct c_hist_t {
} c_hist_t;
/** Sorting helper: return -1, 1, or 0 based on comparison of two
- * geoip_entry_t. Sort in descending order of total, and then by country
+ * geoip_ipv4_entry_t. Sort in descending order of total, and then by country
* code. */
static int
-_c_hist_compare(const void **_a, const void **_b)
+c_hist_compare_(const void **_a, const void **_b)
{
const c_hist_t *a = *_a, *b = *_b;
if (a->total > b->total)
@@ -578,7 +639,7 @@ _c_hist_compare(const void **_a, const void **_b)
* failed, the others as still running. */
#define DIRREQ_TIMEOUT (10*60)
-/** Entry in a map from either conn->global_identifier for direct requests
+/** Entry in a map from either chan->global_identifier for direct requests
* or a unique circuit identifier for tunneled requests to request time,
* response size, and completion time of a network status request. Used to
* measure download times of requests to derive average client
@@ -586,14 +647,13 @@ _c_hist_compare(const void **_a, const void **_b)
typedef struct dirreq_map_entry_t {
HT_ENTRY(dirreq_map_entry_t) node;
/** Unique identifier for this network status request; this is either the
- * conn->global_identifier of the dir conn (direct request) or a new
+ * chan->global_identifier of the dir channel (direct request) or a new
* locally unique identifier of a circuit (tunneled request). This ID is
* only unique among other direct or tunneled requests, respectively. */
uint64_t dirreq_id;
unsigned int state:3; /**< State of this directory request. */
unsigned int type:1; /**< Is this a direct or a tunneled request? */
unsigned int completed:1; /**< Is this request complete? */
- unsigned int action:2; /**< Is this a v2 or v3 request? */
/** When did we receive the request and started sending the response? */
struct timeval request_time;
size_t response_size; /**< What is the size of the response in bytes? */
@@ -631,7 +691,7 @@ HT_GENERATE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash,
* <b>type</b> and <b>dirreq_id</b> as key parts. If there is
* already an entry for that key, print out a BUG warning and return. */
static void
-_dirreq_map_put(dirreq_map_entry_t *entry, dirreq_type_t type,
+dirreq_map_put_(dirreq_map_entry_t *entry, dirreq_type_t type,
uint64_t dirreq_id)
{
dirreq_map_entry_t *old_ent;
@@ -653,7 +713,7 @@ _dirreq_map_put(dirreq_map_entry_t *entry, dirreq_type_t type,
* using <b>type</b> and <b>dirreq_id</b> as key parts. If there
* is no such entry, return NULL. */
static dirreq_map_entry_t *
-_dirreq_map_get(dirreq_type_t type, uint64_t dirreq_id)
+dirreq_map_get_(dirreq_type_t type, uint64_t dirreq_id)
{
dirreq_map_entry_t lookup;
lookup.type = type;
@@ -662,12 +722,11 @@ _dirreq_map_get(dirreq_type_t type, uint64_t dirreq_id)
}
/** Note that an either direct or tunneled (see <b>type</b>) directory
- * request for a network status with unique ID <b>dirreq_id</b> of size
- * <b>response_size</b> and action <b>action</b> (either v2 or v3) has
- * started. */
+ * request for a v3 network status with unique ID <b>dirreq_id</b> of size
+ * <b>response_size</b> has started. */
void
geoip_start_dirreq(uint64_t dirreq_id, size_t response_size,
- geoip_client_action_t action, dirreq_type_t type)
+ dirreq_type_t type)
{
dirreq_map_entry_t *ent;
if (!get_options()->DirReqStatistics)
@@ -676,9 +735,8 @@ geoip_start_dirreq(uint64_t dirreq_id, size_t response_size,
ent->dirreq_id = dirreq_id;
tor_gettimeofday(&ent->request_time);
ent->response_size = response_size;
- ent->action = action;
ent->type = type;
- _dirreq_map_put(ent, type, dirreq_id);
+ dirreq_map_put_(ent, type, dirreq_id);
}
/** Change the state of the either direct or tunneled (see <b>type</b>)
@@ -694,7 +752,7 @@ geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
dirreq_map_entry_t *ent;
if (!get_options()->DirReqStatistics)
return;
- ent = _dirreq_map_get(type, dirreq_id);
+ ent = dirreq_map_get_(type, dirreq_id);
if (!ent)
return;
if (new_state == DIRREQ_IS_FOR_NETWORK_STATUS)
@@ -705,7 +763,7 @@ geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
if ((type == DIRREQ_DIRECT &&
new_state == DIRREQ_FLUSHING_DIR_CONN_FINISHED) ||
(type == DIRREQ_TUNNELED &&
- new_state == DIRREQ_OR_CONN_BUFFER_FLUSHED)) {
+ new_state == DIRREQ_CHANNEL_BUFFER_FLUSHED)) {
tor_gettimeofday(&ent->completion_time);
ent->completed = 1;
}
@@ -717,8 +775,7 @@ geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
* times by deciles and quartiles. Return NULL if we have not observed
* requests for long enough. */
static char *
-geoip_get_dirreq_history(geoip_client_action_t action,
- dirreq_type_t type)
+geoip_get_dirreq_history(dirreq_type_t type)
{
char *result = NULL;
smartlist_t *dirreq_completed = NULL;
@@ -728,13 +785,10 @@ geoip_get_dirreq_history(geoip_client_action_t action,
struct timeval now;
tor_gettimeofday(&now);
- if (action != GEOIP_CLIENT_NETWORKSTATUS &&
- action != GEOIP_CLIENT_NETWORKSTATUS_V2)
- return NULL;
dirreq_completed = smartlist_new();
for (ptr = HT_START(dirreqmap, &dirreq_map); ptr; ptr = next) {
ent = *ptr;
- if (ent->action != action || ent->type != type) {
+ if (ent->type != type) {
next = HT_NEXT(dirreqmap, &dirreq_map, ptr);
continue;
} else {
@@ -813,27 +867,35 @@ geoip_get_dirreq_history(geoip_client_action_t action,
return result;
}
-/** Return a newly allocated comma-separated string containing entries for
- * all the countries from which we've seen enough clients connect as a
- * bridge, directory server, or entry guard. The entry format is cc=num
- * where num is the number of IPs we've seen connecting from that country,
- * and cc is a lowercased country code. Returns NULL if we don't want
- * to export geoip data yet. */
-char *
-geoip_get_client_history(geoip_client_action_t action)
+/** Store a newly allocated comma-separated string in
+ * *<a>country_str</a> containing entries for all the countries from
+ * which we've seen enough clients connect as a bridge, directory
+ * server, or entry guard. The entry format is cc=num where num is the
+ * number of IPs we've seen connecting from that country, and cc is a
+ * lowercased country code. *<a>country_str</a> is set to NULL if
+ * we're not ready to export per country data yet.
+ *
+ * Store a newly allocated comma-separated string in <a>ipver_str</a>
+ * containing entries for clients connecting over IPv4 and IPv6. The
+ * format is family=num where num is the nubmer of IPs we've seen
+ * connecting over that protocol family, and family is 'v4' or 'v6'.
+ *
+ * Return 0 on success and -1 if we're missing geoip data. */
+int
+geoip_get_client_history(geoip_client_action_t action,
+ char **country_str, char **ipver_str)
{
- char *result = NULL;
unsigned granularity = IP_GRANULARITY;
- smartlist_t *chunks = NULL;
smartlist_t *entries = NULL;
int n_countries = geoip_get_n_countries();
int i;
clientmap_entry_t **ent;
unsigned *counts = NULL;
unsigned total = 0;
+ unsigned ipv4_count = 0, ipv6_count = 0;
- if (!geoip_is_loaded())
- return NULL;
+ if (!geoip_is_loaded(AF_INET) && !geoip_is_loaded(AF_INET6))
+ return -1;
counts = tor_malloc_zero(sizeof(unsigned)*n_countries);
HT_FOREACH(ent, clientmap, &client_history) {
@@ -846,10 +908,34 @@ geoip_get_client_history(geoip_client_action_t action)
tor_assert(0 <= country && country < n_countries);
++counts[country];
++total;
+ switch (tor_addr_family(&(*ent)->addr)) {
+ case AF_INET:
+ ipv4_count++;
+ break;
+ case AF_INET6:
+ ipv6_count++;
+ break;
+ }
}
- /* Don't record anything if we haven't seen enough IPs. */
- if (total < MIN_IPS_TO_NOTE_ANYTHING)
- goto done;
+ if (ipver_str) {
+ smartlist_t *chunks = smartlist_new();
+ smartlist_add_asprintf(chunks, "v4=%u",
+ round_to_next_multiple_of(ipv4_count, granularity));
+ smartlist_add_asprintf(chunks, "v6=%u",
+ round_to_next_multiple_of(ipv6_count, granularity));
+ *ipver_str = smartlist_join_strings(chunks, ",", 0, NULL);
+ SMARTLIST_FOREACH(chunks, char *, c, tor_free(c));
+ smartlist_free(chunks);
+ }
+
+ /* Don't record per country data if we haven't seen enough IPs. */
+ if (total < MIN_IPS_TO_NOTE_ANYTHING) {
+ tor_free(counts);
+ if (country_str)
+ *country_str = NULL;
+ return 0;
+ }
+
/* Make a list of c_hist_t */
entries = smartlist_new();
for (i = 0; i < n_countries; ++i) {
@@ -868,40 +954,35 @@ geoip_get_client_history(geoip_client_action_t action)
}
/* Sort entries. Note that we must do this _AFTER_ rounding, or else
* the sort order could leak info. */
- smartlist_sort(entries, _c_hist_compare);
-
- /* Build the result. */
- chunks = smartlist_new();
- SMARTLIST_FOREACH(entries, c_hist_t *, ch, {
- smartlist_add_asprintf(chunks, "%s=%u", ch->country, ch->total);
- });
- result = smartlist_join_strings(chunks, ",", 0, NULL);
- done:
- tor_free(counts);
- if (chunks) {
+ smartlist_sort(entries, c_hist_compare_);
+
+ if (country_str) {
+ smartlist_t *chunks = smartlist_new();
+ SMARTLIST_FOREACH(entries, c_hist_t *, ch, {
+ smartlist_add_asprintf(chunks, "%s=%u", ch->country, ch->total);
+ });
+ *country_str = smartlist_join_strings(chunks, ",", 0, NULL);
SMARTLIST_FOREACH(chunks, char *, c, tor_free(c));
smartlist_free(chunks);
}
- if (entries) {
- SMARTLIST_FOREACH(entries, c_hist_t *, c, tor_free(c));
- smartlist_free(entries);
- }
- return result;
+
+ SMARTLIST_FOREACH(entries, c_hist_t *, c, tor_free(c));
+ smartlist_free(entries);
+ tor_free(counts);
+
+ return 0;
}
/** Return a newly allocated string holding the per-country request history
- * for <b>action</b> in a format suitable for an extra-info document, or NULL
- * on failure. */
+ * for v3 network statuses in a format suitable for an extra-info document,
+ * or NULL on failure. */
char *
-geoip_get_request_history(geoip_client_action_t action)
+geoip_get_request_history(void)
{
smartlist_t *entries, *strings;
char *result;
unsigned granularity = IP_GRANULARITY;
- if (action != GEOIP_CLIENT_NETWORKSTATUS &&
- action != GEOIP_CLIENT_NETWORKSTATUS_V2)
- return NULL;
if (!geoip_countries)
return NULL;
@@ -909,8 +990,7 @@ geoip_get_request_history(geoip_client_action_t action)
SMARTLIST_FOREACH_BEGIN(geoip_countries, geoip_country_t *, c) {
uint32_t tot = 0;
c_hist_t *ent;
- tot = (action == GEOIP_CLIENT_NETWORKSTATUS) ?
- c->n_v3_ns_requests : c->n_v2_ns_requests;
+ tot = c->n_v3_ns_requests;
if (!tot)
continue;
ent = tor_malloc_zero(sizeof(c_hist_t));
@@ -918,7 +998,7 @@ geoip_get_request_history(geoip_client_action_t action)
ent->total = round_to_next_multiple_of(tot, granularity);
smartlist_add(entries, ent);
} SMARTLIST_FOREACH_END(c);
- smartlist_sort(entries, _c_hist_compare);
+ smartlist_sort(entries, c_hist_compare_);
strings = smartlist_new();
SMARTLIST_FOREACH(entries, c_hist_t *, ent, {
@@ -948,14 +1028,13 @@ void
geoip_reset_dirreq_stats(time_t now)
{
SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
- c->n_v2_ns_requests = c->n_v3_ns_requests = 0;
+ c->n_v3_ns_requests = 0;
});
{
clientmap_entry_t **ent, **next, *this;
for (ent = HT_START(clientmap, &client_history); ent != NULL;
ent = next) {
- if ((*ent)->action == GEOIP_CLIENT_NETWORKSTATUS ||
- (*ent)->action == GEOIP_CLIENT_NETWORKSTATUS_V2) {
+ if ((*ent)->action == GEOIP_CLIENT_NETWORKSTATUS) {
this = *ent;
next = HT_NEXT_RMV(clientmap, &client_history, ent);
tor_free(this);
@@ -964,10 +1043,6 @@ geoip_reset_dirreq_stats(time_t now)
}
}
}
- v2_share_times_seconds = v3_share_times_seconds = 0.0;
- last_time_determined_shares = 0;
- share_seconds = 0;
- memset(ns_v2_responses, 0, sizeof(ns_v2_responses));
memset(ns_v3_responses, 0, sizeof(ns_v3_responses));
{
dirreq_map_entry_t **ent, **next, *this;
@@ -995,12 +1070,9 @@ char *
geoip_format_dirreq_stats(time_t now)
{
char t[ISO_TIME_LEN+1];
- double v2_share = 0.0, v3_share = 0.0;
int i;
- char *v3_ips_string, *v2_ips_string, *v3_reqs_string, *v2_reqs_string,
- *v2_share_string = NULL, *v3_share_string = NULL,
- *v3_direct_dl_string, *v2_direct_dl_string,
- *v3_tunneled_dl_string, *v2_tunneled_dl_string;
+ char *v3_ips_string, *v3_reqs_string, *v3_direct_dl_string,
+ *v3_tunneled_dl_string;
char *result;
if (!start_of_dirreq_stats_interval)
@@ -1009,89 +1081,45 @@ geoip_format_dirreq_stats(time_t now)
tor_assert(now >= start_of_dirreq_stats_interval);
format_iso_time(t, now);
- v2_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
- v3_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS);
- v2_reqs_string = geoip_get_request_history(
- GEOIP_CLIENT_NETWORKSTATUS_V2);
- v3_reqs_string = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS);
+ geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS, &v3_ips_string, NULL);
+ v3_reqs_string = geoip_get_request_history();
#define RESPONSE_GRANULARITY 8
for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) {
- ns_v2_responses[i] = round_uint32_to_next_multiple_of(
- ns_v2_responses[i], RESPONSE_GRANULARITY);
ns_v3_responses[i] = round_uint32_to_next_multiple_of(
ns_v3_responses[i], RESPONSE_GRANULARITY);
}
#undef RESPONSE_GRANULARITY
- if (!geoip_get_mean_shares(now, &v2_share, &v3_share)) {
- tor_asprintf(&v2_share_string, "dirreq-v2-share %0.2f%%\n",
- v2_share*100);
- tor_asprintf(&v3_share_string, "dirreq-v3-share %0.2f%%\n",
- v3_share*100);
- }
-
- v2_direct_dl_string = geoip_get_dirreq_history(
- GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_DIRECT);
- v3_direct_dl_string = geoip_get_dirreq_history(
- GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_DIRECT);
-
- v2_tunneled_dl_string = geoip_get_dirreq_history(
- GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_TUNNELED);
- v3_tunneled_dl_string = geoip_get_dirreq_history(
- GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_TUNNELED);
+ v3_direct_dl_string = geoip_get_dirreq_history(DIRREQ_DIRECT);
+ v3_tunneled_dl_string = geoip_get_dirreq_history(DIRREQ_TUNNELED);
/* Put everything together into a single string. */
tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n"
"dirreq-v3-ips %s\n"
- "dirreq-v2-ips %s\n"
"dirreq-v3-reqs %s\n"
- "dirreq-v2-reqs %s\n"
"dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u,"
"not-found=%u,not-modified=%u,busy=%u\n"
- "dirreq-v2-resp ok=%u,unavailable=%u,"
- "not-found=%u,not-modified=%u,busy=%u\n"
- "%s"
- "%s"
"dirreq-v3-direct-dl %s\n"
- "dirreq-v2-direct-dl %s\n"
- "dirreq-v3-tunneled-dl %s\n"
- "dirreq-v2-tunneled-dl %s\n",
+ "dirreq-v3-tunneled-dl %s\n",
t,
(unsigned) (now - start_of_dirreq_stats_interval),
v3_ips_string ? v3_ips_string : "",
- v2_ips_string ? v2_ips_string : "",
v3_reqs_string ? v3_reqs_string : "",
- v2_reqs_string ? v2_reqs_string : "",
ns_v3_responses[GEOIP_SUCCESS],
ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS],
ns_v3_responses[GEOIP_REJECT_UNAVAILABLE],
ns_v3_responses[GEOIP_REJECT_NOT_FOUND],
ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED],
ns_v3_responses[GEOIP_REJECT_BUSY],
- ns_v2_responses[GEOIP_SUCCESS],
- ns_v2_responses[GEOIP_REJECT_UNAVAILABLE],
- ns_v2_responses[GEOIP_REJECT_NOT_FOUND],
- ns_v2_responses[GEOIP_REJECT_NOT_MODIFIED],
- ns_v2_responses[GEOIP_REJECT_BUSY],
- v2_share_string ? v2_share_string : "",
- v3_share_string ? v3_share_string : "",
v3_direct_dl_string ? v3_direct_dl_string : "",
- v2_direct_dl_string ? v2_direct_dl_string : "",
- v3_tunneled_dl_string ? v3_tunneled_dl_string : "",
- v2_tunneled_dl_string ? v2_tunneled_dl_string : "");
+ v3_tunneled_dl_string ? v3_tunneled_dl_string : "");
/* Free partial strings. */
tor_free(v3_ips_string);
- tor_free(v2_ips_string);
tor_free(v3_reqs_string);
- tor_free(v2_reqs_string);
- tor_free(v2_share_string);
- tor_free(v3_share_string);
tor_free(v3_direct_dl_string);
- tor_free(v2_direct_dl_string);
tor_free(v3_tunneled_dl_string);
- tor_free(v2_tunneled_dl_string);
return result;
}
@@ -1216,7 +1244,7 @@ static char *bridge_stats_extrainfo = NULL;
char *
geoip_format_bridge_stats(time_t now)
{
- char *out = NULL, *data = NULL;
+ char *out = NULL, *country_data = NULL, *ipver_data = NULL;
long duration = now - start_of_bridge_stats_interval;
char written[ISO_TIME_LEN+1];
@@ -1226,14 +1254,17 @@ geoip_format_bridge_stats(time_t now)
return NULL; /* Not initialized. */
format_iso_time(written, now);
- data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data);
tor_asprintf(&out,
"bridge-stats-end %s (%ld s)\n"
- "bridge-ips %s\n",
+ "bridge-ips %s\n"
+ "bridge-ip-versions %s\n",
written, duration,
- data ? data : "");
- tor_free(data);
+ country_data ? country_data : "",
+ ipver_data ? ipver_data : "");
+ tor_free(country_data);
+ tor_free(ipver_data);
return out;
}
@@ -1244,17 +1275,20 @@ geoip_format_bridge_stats(time_t now)
static char *
format_bridge_stats_controller(time_t now)
{
- char *out = NULL, *data = NULL;
+ char *out = NULL, *country_data = NULL, *ipver_data = NULL;
char started[ISO_TIME_LEN+1];
(void) now;
format_iso_time(started, start_of_bridge_stats_interval);
- data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data);
tor_asprintf(&out,
- "TimeStarted=\"%s\" CountrySummary=%s",
- started, data ? data : "");
- tor_free(data);
+ "TimeStarted=\"%s\" CountrySummary=%s IPVersions=%s",
+ started,
+ country_data ? country_data : "",
+ ipver_data ? ipver_data : "");
+ tor_free(country_data);
+ tor_free(ipver_data);
return out;
}
@@ -1316,8 +1350,11 @@ load_bridge_stats(time_t now)
fname = get_datadir_fname2("stats", "bridge-stats");
contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
- if (contents && validate_bridge_stats(contents, now))
+ if (contents && validate_bridge_stats(contents, now)) {
bridge_stats_extrainfo = contents;
+ } else {
+ tor_free(contents);
+ }
tor_free(fname);
}
@@ -1381,11 +1418,13 @@ geoip_format_entry_stats(time_t now)
tor_assert(now >= start_of_entry_stats_interval);
- data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &data, NULL);
format_iso_time(t, now);
- tor_asprintf(&result, "entry-stats-end %s (%u s)\nentry-ips %s\n",
- t, (unsigned) (now - start_of_entry_stats_interval),
- data ? data : "");
+ tor_asprintf(&result,
+ "entry-stats-end %s (%u s)\n"
+ "entry-ips %s\n",
+ t, (unsigned) (now - start_of_entry_stats_interval),
+ data ? data : "");
tor_free(data);
return result;
}
@@ -1437,25 +1476,30 @@ getinfo_helper_geoip(control_connection_t *control_conn,
const char **errmsg)
{
(void)control_conn;
- if (!geoip_is_loaded()) {
- *errmsg = "GeoIP data not loaded";
- return -1;
- }
if (!strcmpstart(question, "ip-to-country/")) {
int c;
- uint32_t ip;
- struct in_addr in;
+ sa_family_t family;
+ tor_addr_t addr;
question += strlen("ip-to-country/");
- if (tor_inet_aton(question, &in) != 0) {
- ip = ntohl(in.s_addr);
- c = geoip_get_country_by_ip(ip);
- *answer = tor_strdup(geoip_get_country_name(c));
+ family = tor_addr_parse(&addr, question);
+ if (family != AF_INET && family != AF_INET6) {
+ *errmsg = "Invalid address family";
+ return -1;
+ }
+ if (!geoip_is_loaded(family)) {
+ *errmsg = "GeoIP data not loaded";
+ return -1;
}
+ if (family == AF_INET)
+ c = geoip_get_country_by_ipv4(tor_addr_to_ipv4h(&addr));
+ else /* AF_INET6 */
+ c = geoip_get_country_by_ipv6(tor_addr_to_in6(&addr));
+ *answer = tor_strdup(geoip_get_country_name(c));
}
return 0;
}
-/** Release all storage held by the GeoIP database. */
+/** Release all storage held by the GeoIP databases and country list. */
static void
clear_geoip_db(void)
{
@@ -1465,13 +1509,20 @@ clear_geoip_db(void)
}
strmap_free(country_idxplus1_by_lc_code, NULL);
- if (geoip_entries) {
- SMARTLIST_FOREACH(geoip_entries, geoip_entry_t *, ent, tor_free(ent));
- smartlist_free(geoip_entries);
+ if (geoip_ipv4_entries) {
+ SMARTLIST_FOREACH(geoip_ipv4_entries, geoip_ipv4_entry_t *, ent,
+ tor_free(ent));
+ smartlist_free(geoip_ipv4_entries);
+ }
+ if (geoip_ipv6_entries) {
+ SMARTLIST_FOREACH(geoip_ipv6_entries, geoip_ipv6_entry_t *, ent,
+ tor_free(ent));
+ smartlist_free(geoip_ipv6_entries);
}
geoip_countries = NULL;
country_idxplus1_by_lc_code = NULL;
- geoip_entries = NULL;
+ geoip_ipv4_entries = NULL;
+ geoip_ipv6_entries = NULL;
}
/** Release all storage held in this file. */
diff --git a/src/or/geoip.h b/src/or/geoip.h
index 4aed4e07b..ebefee5f4 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,37 +9,38 @@
* \brief Header file for geoip.c.
**/
-#ifndef _TOR_GEOIP_H
-#define _TOR_GEOIP_H
+#ifndef TOR_GEOIP_H
+#define TOR_GEOIP_H
#ifdef GEOIP_PRIVATE
-int geoip_parse_entry(const char *line);
+int geoip_parse_entry(const char *line, sa_family_t family);
+int geoip_get_country_by_ipv4(uint32_t ipaddr);
+int geoip_get_country_by_ipv6(const struct in6_addr *addr);
#endif
int should_record_bridge_info(const or_options_t *options);
-int geoip_load_file(const char *filename, const or_options_t *options);
-int geoip_get_country_by_ip(uint32_t ipaddr);
+int geoip_load_file(sa_family_t family, const char *filename);
int geoip_get_country_by_addr(const tor_addr_t *addr);
int geoip_get_n_countries(void);
const char *geoip_get_country_name(country_t num);
-int geoip_is_loaded(void);
-const char *geoip_db_digest(void);
+int geoip_is_loaded(sa_family_t family);
+const char *geoip_db_digest(sa_family_t family);
country_t geoip_get_country(const char *countrycode);
void geoip_note_client_seen(geoip_client_action_t action,
const tor_addr_t *addr, time_t now);
void geoip_remove_old_clients(time_t cutoff);
-void geoip_note_ns_response(geoip_client_action_t action,
- geoip_ns_response_t response);
-char *geoip_get_client_history(geoip_client_action_t action);
-char *geoip_get_request_history(geoip_client_action_t action);
+void geoip_note_ns_response(geoip_ns_response_t response);
+int geoip_get_client_history(geoip_client_action_t action,
+ char **country_str, char **ipver_str);
+char *geoip_get_request_history(void);
int getinfo_helper_geoip(control_connection_t *control_conn,
const char *question, char **answer,
const char **errmsg);
void geoip_free_all(void);
void geoip_start_dirreq(uint64_t dirreq_id, size_t response_size,
- geoip_client_action_t action, dirreq_type_t type);
+ dirreq_type_t type);
void geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
dirreq_state_t new_state);
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 3a9c1e422..a41257133 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,12 +23,15 @@ hibernating, phase 2:
#define HIBERNATE_PRIVATE
#include "or.h"
+#include "channel.h"
+#include "channeltls.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "hibernate.h"
#include "main.h"
#include "router.h"
+#include "statefile.h"
extern long stats_n_seconds_working; /* published uptime */
@@ -503,10 +506,6 @@ accounting_run_housekeeping(time_t now)
}
}
-/** When we have no idea how fast we are, how long do we assume it will take
- * us to exhaust our bandwidth? */
-#define GUESS_TIME_TO_USE_BANDWIDTH (24*60*60)
-
/** Based on our interval and our estimated bandwidth, choose a
* deterministic (but random-ish) time to wake up. */
static void
@@ -845,7 +844,13 @@ hibernate_go_dormant(time_t now)
if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */
connection_mark_unattached_ap(TO_ENTRY_CONN(conn),
END_STREAM_REASON_HIBERNATING);
- else
+ else if (conn->type == CONN_TYPE_OR) {
+ if (TO_OR_CONN(conn)->chan) {
+ channel_mark_for_close(TLS_CHAN_TO_BASE(TO_OR_CONN(conn)->chan));
+ } else {
+ connection_mark_for_close(conn);
+ }
+ } else
connection_mark_for_close(conn);
}
@@ -881,12 +886,12 @@ hibernate_end_time_elapsed(time_t now)
/* We weren't sleeping before; we should sleep now. */
log_notice(LD_ACCT,
"Accounting period ended. Commencing hibernation until "
- "%s GMT", buf);
+ "%s UTC", buf);
hibernate_go_dormant(now);
} else {
log_notice(LD_ACCT,
"Accounting period ended. This period, we will hibernate"
- " until %s GMT",buf);
+ " until %s UTC",buf);
}
}
}
diff --git a/src/or/hibernate.h b/src/or/hibernate.h
index 9aa026b7b..d2d6989e1 100644
--- a/src/or/hibernate.h
+++ b/src/or/hibernate.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for hibernate.c.
**/
-#ifndef _TOR_HIBERNATE_H
-#define _TOR_HIBERNATE_H
+#ifndef TOR_HIBERNATE_H
+#define TOR_HIBERNATE_H
int accounting_parse_options(const or_options_t *options, int validate_only);
int accounting_is_enabled(const or_options_t *options);
diff --git a/src/or/include.am b/src/or/include.am
new file mode 100644
index 000000000..65dbeff53
--- /dev/null
+++ b/src/or/include.am
@@ -0,0 +1,195 @@
+bin_PROGRAMS+= src/or/tor
+noinst_LIBRARIES+= src/or/libtor.a
+
+if BUILD_NT_SERVICES
+tor_platform_source=src/or/ntmain.c
+else
+tor_platform_source=
+endif
+
+EXTRA_DIST+= src/or/ntmain.c src/or/or_sha1.i src/or/Makefile.nmake
+
+if USE_EXTERNAL_EVDNS
+evdns_source=
+else
+evdns_source=src/ext/eventdns.c
+endif
+
+if CURVE25519_ENABLED
+onion_ntor_source=src/or/onion_ntor.c
+else
+onion_ntor_source=
+endif
+
+src_or_libtor_a_SOURCES = \
+ src/or/addressmap.c \
+ src/or/buffers.c \
+ src/or/channel.c \
+ src/or/channeltls.c \
+ src/or/circuitbuild.c \
+ src/or/circuitlist.c \
+ src/or/circuitmux.c \
+ src/or/circuitmux_ewma.c \
+ src/or/circuitstats.c \
+ src/or/circuituse.c \
+ src/or/command.c \
+ src/or/config.c \
+ src/or/confparse.c \
+ src/or/connection.c \
+ src/or/connection_edge.c \
+ src/or/connection_or.c \
+ src/or/control.c \
+ src/or/cpuworker.c \
+ src/or/directory.c \
+ src/or/dirserv.c \
+ src/or/dirvote.c \
+ src/or/dns.c \
+ src/or/dnsserv.c \
+ src/or/fp_pair.c \
+ src/or/geoip.c \
+ src/or/entrynodes.c \
+ src/or/hibernate.c \
+ src/or/main.c \
+ src/or/microdesc.c \
+ src/or/networkstatus.c \
+ src/or/nodelist.c \
+ src/or/onion.c \
+ src/or/onion_fast.c \
+ src/or/onion_tap.c \
+ src/or/transports.c \
+ src/or/policies.c \
+ src/or/reasons.c \
+ src/or/relay.c \
+ src/or/rendclient.c \
+ src/or/rendcommon.c \
+ src/or/rendmid.c \
+ src/or/rendservice.c \
+ src/or/rephist.c \
+ src/or/replaycache.c \
+ src/or/router.c \
+ src/or/routerlist.c \
+ src/or/routerparse.c \
+ src/or/routerset.c \
+ src/or/statefile.c \
+ src/or/status.c \
+ $(evdns_source) \
+ $(tor_platform_source) \
+ $(onion_ntor_source) \
+ src/or/config_codedigest.c
+
+#libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
+# ../common/libor-event.a
+
+
+src_or_tor_SOURCES = src/or/tor_main.c
+AM_CPPFLAGS += -I$(srcdir)/src/or -Isrc/or
+
+src/or/tor_main.o: micro-revision.i
+
+AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \
+ -DLOCALSTATEDIR="\"$(localstatedir)\"" \
+ -DBINDIR="\"$(bindir)\""
+
+# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
+# This seems to matter nowhere but on windows, but I assure you that it
+# matters a lot there, and is quite hard to debug if you forget to do it.
+
+
+src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
+src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-crypto.a $(LIBDONNA) \
+ src/common/libor-event.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+
+ORHEADERS = \
+ src/or/addressmap.h \
+ src/or/buffers.h \
+ src/or/channel.h \
+ src/or/channeltls.h \
+ src/or/circuitbuild.h \
+ src/or/circuitlist.h \
+ src/or/circuitmux.h \
+ src/or/circuitmux_ewma.h \
+ src/or/circuitstats.h \
+ src/or/circuituse.h \
+ src/or/command.h \
+ src/or/config.h \
+ src/or/confparse.h \
+ src/or/connection.h \
+ src/or/connection_edge.h \
+ src/or/connection_or.h \
+ src/or/control.h \
+ src/or/cpuworker.h \
+ src/or/directory.h \
+ src/or/dirserv.h \
+ src/or/dirvote.h \
+ src/or/dns.h \
+ src/or/dnsserv.h \
+ src/or/eventdns_tor.h \
+ src/or/fp_pair.h \
+ src/or/geoip.h \
+ src/or/entrynodes.h \
+ src/or/hibernate.h \
+ src/or/main.h \
+ src/or/microdesc.h \
+ src/or/networkstatus.h \
+ src/or/nodelist.h \
+ src/or/ntmain.h \
+ src/or/onion.h \
+ src/or/onion_fast.h \
+ src/or/onion_ntor.h \
+ src/or/onion_tap.h \
+ src/or/or.h \
+ src/or/transports.h \
+ src/or/policies.h \
+ src/or/reasons.h \
+ src/or/relay.h \
+ src/or/rendclient.h \
+ src/or/rendcommon.h \
+ src/or/rendmid.h \
+ src/or/rendservice.h \
+ src/or/rephist.h \
+ src/or/replaycache.h \
+ src/or/router.h \
+ src/or/routerlist.h \
+ src/or/routerset.h \
+ src/or/routerparse.h \
+ src/or/statefile.h \
+ src/or/status.h
+
+noinst_HEADERS+= $(ORHEADERS) micro-revision.i
+
+src/or/config_codedigest.o: src/or/or_sha1.i
+
+micro-revision.i: FORCE
+ @rm -f micro-revision.tmp; \
+ if test -d "$(top_srcdir)/.git" && \
+ test -x "`which git 2>&1;true`"; then \
+ HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \
+ echo \"$$HASH\" > micro-revision.tmp; \
+ fi; \
+ if test ! -f micro-revision.tmp ; then \
+ if test ! -f micro-revision.i ; then \
+ echo '""' > micro-revision.i; \
+ fi; \
+ elif test ! -f micro-revision.i || \
+ test x"`cat micro-revision.tmp`" != x"`cat micro-revision.i`"; then \
+ mv micro-revision.tmp micro-revision.i; \
+ fi; true
+
+src/or/or_sha1.i: $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS)
+ $(AM_V_GEN)if test "@SHA1SUM@" != none; then \
+ (cd "$(srcdir)" && "@SHA1SUM@" $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS) ) | \
+ "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > src/or/or_sha1.i; \
+ elif test "@OPENSSL@" != none; then \
+ (cd "$(srcdir)" && "@OPENSSL@" sha1 $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS)) | \
+ "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > src/or/or_sha1.i; \
+ else \
+ rm src/or/or_sha1.i; \
+ touch src/or/or_sha1.i; \
+ fi
+
+CLEANFILES+= micro-revision.i src/or/micro-revision.i
+
+FORCE:
diff --git a/src/or/main.c b/src/or/main.c
index 34bf3e50f..bd23141b9 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,7 +12,10 @@
#define MAIN_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
+#include "channel.h"
+#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
@@ -28,6 +31,7 @@
#include "dirvote.h"
#include "dns.h"
#include "dnsserv.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
@@ -46,6 +50,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "statefile.h"
#include "status.h"
#ifdef USE_DMALLOC
#include <dmalloc.h>
@@ -153,10 +158,6 @@ int can_complete_circuit=0;
/** How long do we let a directory connection stall before expiring it? */
#define DIR_CONN_MAX_STALL (5*60)
-/** How long do we let OR connections handshake before we decide that
- * they are obsolete? */
-#define TLS_HANDSHAKE_TIMEOUT (60)
-
/** Decides our behavior when no logs are configured/before any
* logs have been configured. For 0, we log notice to stdout as normal.
* For 1, we log warnings only. For 2, we log nothing.
@@ -397,6 +398,18 @@ connection_unlink(connection_t *conn)
if (conn->type == CONN_TYPE_OR) {
if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest))
connection_or_remove_from_identity_map(TO_OR_CONN(conn));
+ /* connection_unlink() can only get called if the connection
+ * was already on the closeable list, and it got there by
+ * connection_mark_for_close(), which was called from
+ * connection_or_close_normally() or
+ * connection_or_close_for_error(), so the channel should
+ * already be in CHANNEL_STATE_CLOSING, and then the
+ * connection_about_to_close_connection() goes to
+ * connection_or_about_to_close(), which calls channel_closed()
+ * to notify the channel_t layer, and closed the channel, so
+ * nothing more to do here to deal with the channel associated
+ * with an orconn.
+ */
}
connection_free(conn);
}
@@ -405,7 +418,7 @@ connection_unlink(connection_t *conn)
void
add_connection_to_closeable_list(connection_t *conn)
{
- tor_assert(!smartlist_isin(closeable_connection_lst, conn));
+ tor_assert(!smartlist_contains(closeable_connection_lst, conn));
tor_assert(conn->marked_for_close);
assert_connection_ok(conn, time(NULL));
smartlist_add(closeable_connection_lst, conn);
@@ -415,14 +428,14 @@ add_connection_to_closeable_list(connection_t *conn)
int
connection_is_on_closeable_list(connection_t *conn)
{
- return smartlist_isin(closeable_connection_lst, conn);
+ return smartlist_contains(closeable_connection_lst, conn);
}
/** Return true iff conn is in the current poll array. */
int
connection_in_array(connection_t *conn)
{
- return smartlist_isin(connection_array, conn);
+ return smartlist_contains(connection_array, conn);
}
/** Set <b>*array</b> to an array of all connections, and <b>*n</b>
@@ -649,7 +662,7 @@ connection_start_reading_from_linked_conn(connection_t *conn)
tor_event_base_loopexit(tor_libevent_get_base(), &tv);
}
} else {
- tor_assert(smartlist_isin(active_linked_connection_lst, conn));
+ tor_assert(smartlist_contains(active_linked_connection_lst, conn));
}
}
@@ -669,7 +682,7 @@ connection_stop_reading_from_linked_conn(connection_t *conn)
* so let's leave it alone for now. */
smartlist_remove(active_linked_connection_lst, conn);
} else {
- tor_assert(!smartlist_isin(active_linked_connection_lst, conn));
+ tor_assert(!smartlist_contains(active_linked_connection_lst, conn));
}
}
@@ -796,7 +809,8 @@ conn_close_if_marked(int i)
}
#endif
- log_debug(LD_NET,"Cleaning up connection (fd %d).",conn->s);
+ log_debug(LD_NET,"Cleaning up connection (fd "TOR_SOCKET_T_FORMAT").",
+ conn->s);
/* If the connection we are about to close was trying to connect to
a proxy server and failed, the client won't be able to use that
@@ -953,8 +967,9 @@ directory_info_has_arrived(time_t now, int from_cache)
const or_options_t *options = get_options();
if (!router_have_minimum_dir_info()) {
- int quiet = directory_too_idle_to_fetch_descriptors(options, now);
- log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
+ int quiet = from_cache ||
+ directory_too_idle_to_fetch_descriptors(options, now);
+ tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
"I learned some more directory information, but not enough to "
"build a circuit: %s", get_dir_info_status_string());
update_all_descriptor_downloads(now);
@@ -1044,7 +1059,8 @@ run_connection_housekeeping(int i, time_t now)
tor_assert(conn->outbuf);
#endif
- if (or_conn->is_bad_for_new_circs && !or_conn->n_circuits) {
+ if (channel_is_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan)) &&
+ !connection_or_get_num_circuits(or_conn)) {
/* It's bad for new circuits, and has no unmarked circuits on it:
* mark it now. */
log_info(LD_OR,
@@ -1054,28 +1070,29 @@ run_connection_housekeeping(int i, time_t now)
connection_or_connect_failed(TO_OR_CONN(conn),
END_OR_CONN_REASON_TIMEOUT,
"Tor gave up on the connection");
- connection_mark_and_flush(conn);
+ connection_or_close_normally(TO_OR_CONN(conn), 1);
} else if (!connection_state_is_open(conn)) {
if (past_keepalive) {
/* We never managed to actually get this connection open and happy. */
log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).",
(int)conn->s,conn->address, conn->port);
- connection_mark_for_close(conn);
+ connection_or_close_normally(TO_OR_CONN(conn), 0);
}
- } else if (we_are_hibernating() && !or_conn->n_circuits &&
+ } else if (we_are_hibernating() &&
+ !connection_or_get_num_circuits(or_conn) &&
!connection_get_outbuf_len(conn)) {
/* We're hibernating, there's no circuits, and nothing to flush.*/
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
"[Hibernating or exiting].",
(int)conn->s,conn->address, conn->port);
- connection_mark_and_flush(conn);
- } else if (!or_conn->n_circuits &&
+ connection_or_close_normally(TO_OR_CONN(conn), 1);
+ } else if (!connection_or_get_num_circuits(or_conn) &&
now >= or_conn->timestamp_last_added_nonpadding +
IDLE_OR_CONN_TIMEOUT) {
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
"[idle %d].", (int)conn->s,conn->address, conn->port,
(int)(now - or_conn->timestamp_last_added_nonpadding));
- connection_mark_for_close(conn);
+ connection_or_close_normally(TO_OR_CONN(conn), 0);
} else if (
now >= or_conn->timestamp_lastempty + options->KeepalivePeriod*10 &&
now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) {
@@ -1085,7 +1102,7 @@ run_connection_housekeeping(int i, time_t now)
(int)conn->s, conn->address, conn->port,
(int)connection_get_outbuf_len(conn),
(int)(now-conn->timestamp_lastwritten));
- connection_mark_for_close(conn);
+ connection_or_close_normally(TO_OR_CONN(conn), 0);
} else if (past_keepalive && !connection_get_outbuf_len(conn)) {
/* send a padding cell */
log_fn(LOG_DEBUG,LD_OR,"Sending keepalive to (%s:%d)",
@@ -1108,7 +1125,7 @@ signewnym_impl(time_t now)
return;
}
- circuit_expire_all_dirty_circs();
+ circuit_mark_all_dirty_circs_as_unusable();
addressmap_clear_transient();
rend_client_purge_state();
time_of_last_signewnym = now;
@@ -1136,7 +1153,6 @@ run_scheduled_events(time_t now)
static time_t time_to_check_v3_certificate = 0;
static time_t time_to_check_listeners = 0;
static time_t time_to_check_descriptor = 0;
- static time_t time_to_check_ipaddress = 0;
static time_t time_to_shrink_memory = 0;
static time_t time_to_try_getting_descriptors = 0;
static time_t time_to_reset_descriptor_failures = 0;
@@ -1180,7 +1196,7 @@ run_scheduled_events(time_t now)
* eventually. */
if (signewnym_is_pending &&
time_of_last_signewnym + MAX_SIGNEWNYM_RATE <= now) {
- log(LOG_INFO, LD_CONTROL, "Honoring delayed NEWNYM request");
+ log_info(LD_CONTROL, "Honoring delayed NEWNYM request");
signewnym_impl(now);
}
@@ -1382,11 +1398,10 @@ run_scheduled_events(time_t now)
/** 2. Periodically, we consider force-uploading our descriptor
* (if we've passed our internal checks). */
-/** How often do we check whether part of our router info has changed in a way
- * that would require an upload? */
+/** How often do we check whether part of our router info has changed in a
+ * way that would require an upload? That includes checking whether our IP
+ * address has changed. */
#define CHECK_DESCRIPTOR_INTERVAL (60)
-/** How often do we (as a router) check whether our IP address has changed? */
-#define CHECK_IPADDRESS_INTERVAL (15*60)
/* 2b. Once per minute, regenerate and upload the descriptor if the old
* one is inaccurate. */
@@ -1394,10 +1409,7 @@ run_scheduled_events(time_t now)
static int dirport_reachability_count = 0;
time_to_check_descriptor = now + CHECK_DESCRIPTOR_INTERVAL;
check_descriptor_bandwidth_changed(now);
- if (time_to_check_ipaddress < now) {
- time_to_check_ipaddress = now + CHECK_IPADDRESS_INTERVAL;
- check_descriptor_ipaddress_changed(now);
- }
+ check_descriptor_ipaddress_changed(now);
mark_my_descriptor_dirty_if_too_old(now);
consider_publishable_server(0);
/* also, check religiously for reachability, if it's within the first
@@ -1519,6 +1531,10 @@ run_scheduled_events(time_t now)
* flush it. */
or_state_save(now);
+ /** 8c. Do channel cleanup just like for connections */
+ channel_run_cleanup();
+ channel_listener_run_cleanup();
+
/** 9. and if we're a server, check whether our DNS is telling stories to
* us. */
if (!net_is_disabled() &&
@@ -1546,11 +1562,15 @@ run_scheduled_events(time_t now)
options->PortForwarding &&
is_server) {
#define PORT_FORWARDING_CHECK_INTERVAL 5
- /* XXXXX this should take a list of ports, not just two! */
- tor_check_port_forwarding(options->PortForwardingHelper,
- get_primary_dir_port(),
- get_primary_or_port(),
- now);
+ smartlist_t *ports_to_forward = get_list_of_ports_to_forward();
+ if (ports_to_forward) {
+ tor_check_port_forwarding(options->PortForwardingHelper,
+ ports_to_forward,
+ now);
+
+ SMARTLIST_FOREACH(ports_to_forward, char *, cp, tor_free(cp));
+ smartlist_free(ports_to_forward);
+ }
time_to_check_port_forwarding = now+PORT_FORWARDING_CHECK_INTERVAL;
}
@@ -1561,7 +1581,8 @@ run_scheduled_events(time_t now)
/** 12. write the heartbeat message */
if (options->HeartbeatPeriod &&
time_to_next_heartbeat <= now) {
- log_heartbeat(now);
+ if (time_to_next_heartbeat) /* don't log the first heartbeat */
+ log_heartbeat(now);
time_to_next_heartbeat = now+options->HeartbeatPeriod;
}
}
@@ -1823,7 +1844,7 @@ do_hup(void)
/* Rotate away from the old dirty circuits. This has to be done
* after we've read the new options, but before we start using
* circuits for directory fetches. */
- circuit_expire_all_dirty_circs();
+ circuit_mark_all_dirty_circs_as_unusable();
/* retry appropriate downloads */
router_reset_status_download_failures();
@@ -1861,6 +1882,13 @@ do_main_loop(void)
}
}
+#ifdef USE_BUFFEREVENTS
+ log_warn(LD_GENERAL, "Tor was compiled with the --enable-bufferevents "
+ "option. This is still experimental, and might cause strange "
+ "bugs. If you want a more stable Tor, be sure to build without "
+ "--enable-bufferevents.");
+#endif
+
handle_signals(1);
/* load the private keys, if we're supposed to have them, and set up the
@@ -2053,7 +2081,7 @@ process_signal(uintptr_t sig)
time_t now = time(NULL);
if (time_of_last_signewnym + MAX_SIGNEWNYM_RATE > now) {
signewnym_is_pending = 1;
- log(LOG_NOTICE, LD_CONTROL,
+ log_notice(LD_CONTROL,
"Rate limiting NEWNYM request: delaying by %d second(s)",
(int)(MAX_SIGNEWNYM_RATE+time_of_last_signewnym-now));
} else {
@@ -2085,7 +2113,7 @@ static void
dumpmemusage(int severity)
{
connection_dump_buffer_mem_stats(severity);
- log(severity, LD_GENERAL, "In rephist: "U64_FORMAT" used by %d Tors.",
+ tor_log(severity, LD_GENERAL, "In rephist: "U64_FORMAT" used by %d Tors.",
U64_PRINTF_ARG(rephist_total_alloc), rephist_total_num);
dump_routerlist_mem_usage(severity);
dump_cell_pool_usage(severity);
@@ -2103,27 +2131,27 @@ dumpstats(int severity)
time_t elapsed;
size_t rbuf_cap, wbuf_cap, rbuf_len, wbuf_len;
- log(severity, LD_GENERAL, "Dumping stats:");
+ tor_log(severity, LD_GENERAL, "Dumping stats:");
SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
int i = conn_sl_idx;
- log(severity, LD_GENERAL,
+ tor_log(severity, LD_GENERAL,
"Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago",
i, (int)conn->s, conn->type, conn_type_to_string(conn->type),
conn->state, conn_state_to_string(conn->type, conn->state),
(int)(now - conn->timestamp_created));
if (!connection_is_listener(conn)) {
- log(severity,LD_GENERAL,
+ tor_log(severity,LD_GENERAL,
"Conn %d is to %s:%d.", i,
safe_str_client(conn->address),
conn->port);
- log(severity,LD_GENERAL,
+ tor_log(severity,LD_GENERAL,
"Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)",
i,
(int)connection_get_inbuf_len(conn),
(int)buf_allocation(conn->inbuf),
(int)(now - conn->timestamp_lastread));
- log(severity,LD_GENERAL,
+ tor_log(severity,LD_GENERAL,
"Conn %d: %d bytes waiting on outbuf "
"(len %d, last written %d secs ago)",i,
(int)connection_get_outbuf_len(conn),
@@ -2134,7 +2162,7 @@ dumpstats(int severity)
if (or_conn->tls) {
tor_tls_get_buffer_sizes(or_conn->tls, &rbuf_cap, &rbuf_len,
&wbuf_cap, &wbuf_len);
- log(severity, LD_GENERAL,
+ tor_log(severity, LD_GENERAL,
"Conn %d: %d/%d bytes used on OpenSSL read buffer; "
"%d/%d bytes used on write buffer.",
i, (int)rbuf_len, (int)rbuf_cap, (int)wbuf_len, (int)wbuf_cap);
@@ -2144,7 +2172,11 @@ dumpstats(int severity)
circuit_dump_by_conn(conn, severity); /* dump info about all the circuits
* using this conn */
} SMARTLIST_FOREACH_END(conn);
- log(severity, LD_NET,
+
+ channel_dumpstats(severity);
+ channel_listener_dumpstats(severity);
+
+ tor_log(severity, LD_NET,
"Cells processed: "U64_FORMAT" padding\n"
" "U64_FORMAT" create\n"
" "U64_FORMAT" created\n"
@@ -2160,33 +2192,36 @@ dumpstats(int severity)
U64_PRINTF_ARG(stats_n_relay_cells_delivered),
U64_PRINTF_ARG(stats_n_destroy_cells_processed));
if (stats_n_data_cells_packaged)
- log(severity,LD_NET,"Average packaged cell fullness: %2.3f%%",
+ tor_log(severity,LD_NET,"Average packaged cell fullness: %2.3f%%",
100*(U64_TO_DBL(stats_n_data_bytes_packaged) /
U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) );
if (stats_n_data_cells_received)
- log(severity,LD_NET,"Average delivered cell fullness: %2.3f%%",
+ tor_log(severity,LD_NET,"Average delivered cell fullness: %2.3f%%",
100*(U64_TO_DBL(stats_n_data_bytes_received) /
U64_TO_DBL(stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) );
+ cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_TAP, "TAP");
+ cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_NTOR,"ntor");
+
if (now - time_of_process_start >= 0)
elapsed = now - time_of_process_start;
else
elapsed = 0;
if (elapsed) {
- log(severity, LD_NET,
+ tor_log(severity, LD_NET,
"Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec reading",
U64_PRINTF_ARG(stats_n_bytes_read),
(int)elapsed,
(int) (stats_n_bytes_read/elapsed));
- log(severity, LD_NET,
+ tor_log(severity, LD_NET,
"Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec writing",
U64_PRINTF_ARG(stats_n_bytes_written),
(int)elapsed,
(int) (stats_n_bytes_written/elapsed));
}
- log(severity, LD_NET, "--------------- Dumping memory information:");
+ tor_log(severity, LD_NET, "--------------- Dumping memory information:");
dumpmemusage(severity);
rep_hist_dump_stats(now,severity);
@@ -2286,6 +2321,9 @@ tor_init(int argc, char *argv[])
quiet = 1;
if (!strcmp(argv[i], "--quiet"))
quiet = 2;
+ /* --version implies --quiet */
+ if (!strcmp(argv[i], "--version"))
+ quiet = 2;
}
/* give it somewhere to log to initially */
switch (quiet) {
@@ -2302,12 +2340,17 @@ tor_init(int argc, char *argv[])
{
const char *version = get_version();
+ const char *bev_str =
#ifdef USE_BUFFEREVENTS
- log_notice(LD_GENERAL, "Tor v%s (with bufferevents) running on %s.",
- version, get_uname());
+ "(with bufferevents) ";
#else
- log_notice(LD_GENERAL, "Tor v%s running on %s.", version, get_uname());
+ "";
#endif
+ log_notice(LD_GENERAL, "Tor v%s %srunning on %s with Libevent %s "
+ "and OpenSSL %s.", version, bev_str,
+ get_uname(),
+ tor_libevent_get_version_str(),
+ crypto_openssl_get_version_str());
log_notice(LD_GENERAL, "Tor can't help you if you use it wrong! "
"Learn how to be safe at "
@@ -2319,7 +2362,7 @@ tor_init(int argc, char *argv[])
}
#ifdef NON_ANONYMOUS_MODE_ENABLED
- log(LOG_WARN, LD_GENERAL, "This copy of Tor was compiled to run in a "
+ log_warn(LD_GENERAL, "This copy of Tor was compiled to run in a "
"non-anonymous mode. It will provide NO ANONYMITY.");
#endif
@@ -2346,6 +2389,7 @@ tor_init(int argc, char *argv[])
log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting.");
return -1;
}
+ stream_choice_seed_weak_rng();
return 0;
}
@@ -2441,6 +2485,8 @@ tor_free_all(int postfork)
circuit_free_all();
entry_guards_free_all();
pt_free_all();
+ channel_tls_free_all();
+ channel_free_all();
connection_free_all();
buf_shrink_freelists(1);
memarea_clear_freelist();
@@ -2448,6 +2494,7 @@ tor_free_all(int postfork)
microdesc_free_all();
if (!postfork) {
config_free_all();
+ or_state_free_all();
router_free_all();
policies_free_all();
}
@@ -2461,6 +2508,10 @@ tor_free_all(int postfork)
smartlist_free(closeable_connection_lst);
smartlist_free(active_linked_connection_lst);
periodic_timer_free(second_timer);
+#ifndef USE_BUFFEREVENTS
+ periodic_timer_free(refill_timer);
+#endif
+
if (!postfork) {
release_lockfile();
}
@@ -2631,7 +2682,7 @@ tor_main(int argc, char *argv[])
{
/* Instruct OpenSSL to use our internal wrappers for malloc,
realloc and free. */
- int r = CRYPTO_set_mem_ex_functions(_tor_malloc, _tor_realloc, _tor_free);
+ int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
tor_assert(r);
}
#endif
diff --git a/src/or/main.h b/src/or/main.h
index f843b6f9f..338449b6a 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for main.c.
**/
-#ifndef _TOR_MAIN_H
-#define _TOR_MAIN_H
+#ifndef TOR_MAIN_H
+#define TOR_MAIN_H
extern int can_complete_circuit;
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index b4d22c1c6..90ac0ac64 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Tor Project, Inc. */
+/* Copyright (c) 2009-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -6,6 +6,7 @@
#include "config.h"
#include "directory.h"
#include "dirserv.h"
+#include "entrynodes.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
@@ -42,7 +43,7 @@ struct microdesc_cache_t {
/** Helper: computes a hash of <b>md</b> to place it in a hash table. */
static INLINE unsigned int
-_microdesc_hash(microdesc_t *md)
+microdesc_hash_(microdesc_t *md)
{
unsigned *d = (unsigned*)md->digest;
#if SIZEOF_INT == 4
@@ -54,15 +55,15 @@ _microdesc_hash(microdesc_t *md)
/** Helper: compares <b>a</b> and </b> for equality for hash-table purposes. */
static INLINE int
-_microdesc_eq(microdesc_t *a, microdesc_t *b)
+microdesc_eq_(microdesc_t *a, microdesc_t *b)
{
return tor_memeq(a->digest, b->digest, DIGEST256_LEN);
}
HT_PROTOTYPE(microdesc_map, microdesc_t, node,
- _microdesc_hash, _microdesc_eq);
+ microdesc_hash_, microdesc_eq_);
HT_GENERATE(microdesc_map, microdesc_t, node,
- _microdesc_hash, _microdesc_eq, 0.6,
+ microdesc_hash_, microdesc_eq_, 0.6,
malloc, realloc, free);
/** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations.
@@ -70,20 +71,24 @@ HT_GENERATE(microdesc_map, microdesc_t, node,
* *<b>annotation_len_out</b> to the number of bytes written as
* annotations. */
static ssize_t
-dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
+dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out)
{
ssize_t r = 0;
- size_t written;
- /* XXXX drops unkown annotations. */
+ ssize_t written;
+ if (md->body == NULL) {
+ *annotation_len_out = 0;
+ return 0;
+ }
+ /* XXXX drops unknown annotations. */
if (md->last_listed) {
char buf[ISO_TIME_LEN+1];
char annotation[ISO_TIME_LEN+32];
format_iso_time(buf, md->last_listed);
tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf);
- if (fputs(annotation, f) < 0) {
+ if (write_all(fd, annotation, strlen(annotation), 0) < 0) {
log_warn(LD_DIR,
"Couldn't write microdescriptor annotation: %s",
- strerror(ferror(f)));
+ strerror(errno));
return -1;
}
r += strlen(annotation);
@@ -92,13 +97,13 @@ dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
*annotation_len_out = 0;
}
- md->off = (off_t) ftell(f);
- written = fwrite(md->body, 1, md->bodylen, f);
- if (written != md->bodylen) {
+ md->off = tor_fd_getpos(fd);
+ written = write_all(fd, md->body, md->bodylen, 0);
+ if (written != (ssize_t)md->bodylen) {
log_warn(LD_DIR,
- "Couldn't dump microdescriptor (wrote %lu out of %lu): %s",
- (unsigned long)written, (unsigned long)md->bodylen,
- strerror(ferror(f)));
+ "Couldn't dump microdescriptor (wrote %ld out of %lu): %s",
+ (long)written, (unsigned long)md->bodylen,
+ strerror(errno));
return -1;
}
r += md->bodylen;
@@ -131,7 +136,7 @@ get_microdesc_cache(void)
*/
/** Decode the microdescriptors from the string starting at <b>s</b> and
- * ending at <b>eos</b>, and store them in <b>cache</b>. If <b>no-save</b>,
+ * ending at <b>eos</b>, and store them in <b>cache</b>. If <b>no_save</b>,
* mark them as non-writable to disk. If <b>where</b> is SAVED_IN_CACHE,
* leave their bodies as pointers to the mmap'd cache. If where is
* <b>SAVED_NOWHERE</b>, do not allow annotations. If listed_at is positive,
@@ -149,17 +154,16 @@ microdescs_add_to_cache(microdesc_cache_t *cache,
{
smartlist_t *descriptors, *added;
const int allow_annotations = (where != SAVED_NOWHERE);
- const int copy_body = (where != SAVED_IN_CACHE);
descriptors = microdescs_parse_from_string(s, eos,
allow_annotations,
- copy_body);
+ where);
if (listed_at > 0) {
SMARTLIST_FOREACH(descriptors, microdesc_t *, md,
md->last_listed = listed_at);
}
if (requested_digests256) {
- digestmap_t *requested; /* XXXX actuqlly we should just use a
+ digestmap_t *requested; /* XXXX actually we should just use a
digest256map */
requested = digestmap_new();
SMARTLIST_FOREACH(requested_digests256, const char *, cp,
@@ -168,7 +172,7 @@ microdescs_add_to_cache(microdesc_cache_t *cache,
if (digestmap_get(requested, md->digest)) {
digestmap_set(requested, md->digest, (void*)2);
} else {
- log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Received non-requested microcdesc");
+ log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Received non-requested microdesc");
microdesc_free(md);
SMARTLIST_DEL_CURRENT(descriptors, md);
}
@@ -187,7 +191,7 @@ microdescs_add_to_cache(microdesc_cache_t *cache,
return added;
}
-/** As microdescs_add_to_cache, but takes a list of micrdescriptors instead of
+/** As microdescs_add_to_cache, but takes a list of microdescriptors instead of
* a string to decode. Frees any members of <b>descriptors</b> that it does
* not add. */
smartlist_t *
@@ -197,18 +201,17 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
{
smartlist_t *added;
open_file_t *open_file = NULL;
- FILE *f = NULL;
+ int fd = -1;
// int n_added = 0;
ssize_t size = 0;
if (where == SAVED_NOWHERE && !no_save) {
- f = start_writing_to_stdio_file(cache->journal_fname,
- OPEN_FLAGS_APPEND|O_BINARY,
- 0600, &open_file);
- if (!f) {
+ fd = start_writing_to_file(cache->journal_fname,
+ OPEN_FLAGS_APPEND|O_BINARY,
+ 0600, &open_file);
+ if (fd < 0) {
log_warn(LD_DIR, "Couldn't append to journal in %s: %s",
cache->journal_fname, strerror(errno));
- return NULL;
}
}
@@ -227,17 +230,17 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
}
/* Okay, it's a new one. */
- if (f) {
+ if (fd >= 0) {
size_t annotation_len;
- size = dump_microdescriptor(f, md, &annotation_len);
+ size = dump_microdescriptor(fd, md, &annotation_len);
if (size < 0) {
- /* we already warned in dump_microdescriptor; */
+ /* we already warned in dump_microdescriptor */
abort_writing_to_file(open_file);
- smartlist_clear(added);
- return added;
+ fd = -1;
+ } else {
+ md->saved_location = SAVED_IN_JOURNAL;
+ cache->journal_len += size;
}
- md->saved_location = SAVED_IN_JOURNAL;
- cache->journal_len += size;
} else {
md->saved_location = where;
}
@@ -251,8 +254,14 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
cache->total_len_seen += md->bodylen;
} SMARTLIST_FOREACH_END(md);
- if (f)
- finish_writing_to_file(open_file); /*XXX Check me.*/
+ if (fd >= 0) {
+ if (finish_writing_to_file(open_file) < 0) {
+ log_warn(LD_DIR, "Error appending to microdescriptor file: %s",
+ strerror(errno));
+ smartlist_clear(added);
+ return added;
+ }
+ }
{
networkstatus_t *ns = networkstatus_get_latest_consensus();
@@ -323,8 +332,8 @@ microdesc_cache_reload(microdesc_cache_t *cache)
}
tor_free(journal_content);
}
- log_notice(LD_DIR, "Reloaded microdescriptor cache. Found %d descriptors.",
- total);
+ log_info(LD_DIR, "Reloaded microdescriptor cache. Found %d descriptors.",
+ total);
microdesc_cache_rebuild(cache, 0 /* don't force */);
@@ -397,6 +406,26 @@ should_rebuild_md_cache(microdesc_cache_t *cache)
return 0;
}
+/**
+ * Mark <b>md</b> as having no body, and release any storage previously held
+ * by its body.
+ */
+static void
+microdesc_wipe_body(microdesc_t *md)
+{
+ if (!md)
+ return;
+
+ if (md->saved_location != SAVED_IN_CACHE)
+ tor_free(md->body);
+
+ md->off = 0;
+ md->saved_location = SAVED_NOWHERE;
+ md->body = NULL;
+ md->bodylen = 0;
+ md->no_save = 1;
+}
+
/** Regenerate the main cache file for <b>cache</b>, clear the journal file,
* and update every microdesc_t in the cache with pointers to its new
* location. If <b>force</b> is true, do this unconditionally. If
@@ -405,11 +434,11 @@ int
microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
{
open_file_t *open_file;
- FILE *f;
+ int fd = -1;
microdesc_t **mdp;
smartlist_t *wrote;
ssize_t size;
- off_t off = 0;
+ off_t off = 0, off_real;
int orig_size, new_size;
if (cache == NULL) {
@@ -429,10 +458,10 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
orig_size = (int)(cache->cache_content ? cache->cache_content->size : 0);
orig_size += (int)cache->journal_len;
- f = start_writing_to_stdio_file(cache->cache_fname,
- OPEN_FLAGS_REPLACE|O_BINARY,
- 0600, &open_file);
- if (!f)
+ fd = start_writing_to_file(cache->cache_fname,
+ OPEN_FLAGS_REPLACE|O_BINARY,
+ 0600, &open_file);
+ if (fd < 0)
return -1;
wrote = smartlist_new();
@@ -440,18 +469,28 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
HT_FOREACH(mdp, microdesc_map, &cache->map) {
microdesc_t *md = *mdp;
size_t annotation_len;
- if (md->no_save)
+ if (md->no_save || !md->body)
continue;
- size = dump_microdescriptor(f, md, &annotation_len);
+ size = dump_microdescriptor(fd, md, &annotation_len);
if (size < 0) {
- /* XXX handle errors from dump_microdescriptor() */
- /* log? return -1? die? coredump the universe? */
+ microdesc_wipe_body(md);
+
+ /* rewind, in case it was a partial write. */
+ tor_fd_setpos(fd, off);
continue;
}
tor_assert(((size_t)size) == annotation_len + md->bodylen);
md->off = off + annotation_len;
off += size;
+ off_real = tor_fd_getpos(fd);
+ if (off_real != off) {
+ log_warn(LD_BUG, "Discontinuity in position in microdescriptor cache."
+ "By my count, I'm at "I64_FORMAT
+ ", but I should be at "I64_FORMAT,
+ I64_PRINTF_ARG(off), I64_PRINTF_ARG(off_real));
+ off = off_real;
+ }
if (md->saved_location != SAVED_IN_CACHE) {
tor_free(md->body);
md->saved_location = SAVED_IN_CACHE;
@@ -459,10 +498,24 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
smartlist_add(wrote, md);
}
+ /* We must do this unmap _before_ we call finish_writing_to_file(), or
+ * windows will not actually replace the file. */
if (cache->cache_content)
tor_munmap_file(cache->cache_content);
- finish_writing_to_file(open_file); /*XXX Check me.*/
+ if (finish_writing_to_file(open_file) < 0) {
+ log_warn(LD_DIR, "Error rebuilding microdescriptor cache: %s",
+ strerror(errno));
+ /* Okay. Let's prevent from making things worse elsewhere. */
+ cache->cache_content = NULL;
+ HT_FOREACH(mdp, microdesc_map, &cache->map) {
+ microdesc_t *md = *mdp;
+ if (md->saved_location == SAVED_IN_CACHE) {
+ microdesc_wipe_body(md);
+ }
+ }
+ return -1;
+ }
cache->cache_content = tor_mmap_file(cache->cache_fname);
@@ -478,7 +531,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
if (PREDICT_UNLIKELY(
md->bodylen < 9 || fast_memneq(md->body, "onion-key", 9) != 0)) {
/* XXXX once bug 2022 is solved, we can kill this block and turn it
- * into just the tor_assert(!memcmp) */
+ * into just the tor_assert(fast_memeq) */
off_t avail = cache->cache_content->size - md->off;
char *bad_str;
tor_assert(avail >= 0);
@@ -531,7 +584,7 @@ microdesc_check_counts(void)
/** Deallocate a single microdescriptor. Note: the microdescriptor MUST have
* previously been removed from the cache if it had ever been inserted. */
void
-microdesc_free(microdesc_t *md)
+microdesc_free_(microdesc_t *md, const char *fname, int lineno)
{
if (!md)
return;
@@ -542,12 +595,12 @@ microdesc_free(microdesc_t *md)
microdesc_cache_t *cache = get_microdesc_cache();
microdesc_t *md2 = HT_FIND(microdesc_map, &cache->map, md);
if (md2 == md) {
- log_warn(LD_BUG, "microdesc_free() called, but md was still in "
- "microdesc_map");
+ log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still "
+ "in microdesc_map", fname, lineno);
HT_REMOVE(microdesc_map, &cache->map, md);
} else {
- log_warn(LD_BUG, "microdesc_free() called with held_in_map set, but "
- "microdesc was not in the map.");
+ log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_in_map "
+ "set, but microdesc was not in the map.", fname, lineno);
}
tor_fragile_assert();
}
@@ -561,11 +614,13 @@ microdesc_free(microdesc_t *md)
}
});
if (found) {
- log_warn(LD_BUG, "microdesc_free() called, but md was still referenced "
- "%d node(s); held_by_nodes == %u", found, md->held_by_nodes);
+ log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still "
+ "referenced %d node(s); held_by_nodes == %u",
+ fname, lineno, found, md->held_by_nodes);
} else {
- log_warn(LD_BUG, "microdesc_free() called with held_by_nodes set to %u, "
- "but md was not referenced by any nodes", md->held_by_nodes);
+ log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_by_nodes "
+ "set to %u, but md was not referenced by any nodes",
+ fname, lineno, md->held_by_nodes);
}
tor_fragile_assert();
}
@@ -574,6 +629,7 @@ microdesc_free(microdesc_t *md)
if (md->onion_pkey)
crypto_pk_free(md->onion_pkey);
+ tor_free(md->onion_curve25519_pkey);
if (md->body && md->saved_location != SAVED_IN_CACHE)
tor_free(md->body);
@@ -582,6 +638,7 @@ microdesc_free(microdesc_t *md)
smartlist_free(md->family);
}
short_policy_free(md->exit_policy);
+ short_policy_free(md->ipv6_exit_policy);
tor_free(md);
}
@@ -727,9 +784,9 @@ we_use_microdescriptors_for_circuits(const or_options_t *options)
int ret = options->UseMicrodescriptors;
if (ret == -1) {
/* UseMicrodescriptors is "auto"; we need to decide: */
- /* If we are configured to use bridges and one of our bridges doesn't
+ /* If we are configured to use bridges and none of our bridges
* know what a microdescriptor is, the answer is no. */
- if (options->UseBridges && any_bridges_dont_support_microdescriptors())
+ if (options->UseBridges && !any_bridge_supports_microdescriptors())
return 0;
/* Otherwise, we decide that we'll use microdescriptors iff we are
* not a server, and we're not autofetching everything. */
diff --git a/src/or/microdesc.h b/src/or/microdesc.h
index 5646fc7a8..7adb8c68a 100644
--- a/src/or/microdesc.h
+++ b/src/or/microdesc.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for microdesc.c.
**/
-#ifndef _TOR_MICRODESC_H
-#define _TOR_MICRODESC_H
+#ifndef TOR_MICRODESC_H
+#define TOR_MICRODESC_H
microdesc_cache_t *get_microdesc_cache(void);
@@ -39,7 +39,9 @@ smartlist_t *microdesc_list_missing_digest256(networkstatus_t *ns,
int downloadable_only,
digestmap_t *skip);
-void microdesc_free(microdesc_t *md);
+void microdesc_free_(microdesc_t *md, const char *fname, int line);
+#define microdesc_free(md) \
+ microdesc_free_((md), __FILE__, __LINE__)
void microdesc_free_all(void);
void update_microdesc_downloads(time_t now);
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index e780eadac..1b5c6dbb3 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,7 +11,10 @@
*/
#include "or.h"
-#include "circuitbuild.h"
+#include "channel.h"
+#include "circuitmux.h"
+#include "circuitmux_ewma.h"
+#include "circuitstats.h"
#include "config.h"
#include "connection.h"
#include "connection_or.h"
@@ -19,6 +22,7 @@
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
+#include "entrynodes.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@@ -215,8 +219,6 @@ router_reload_consensus_networkstatus(void)
{
char *filename;
char *s;
- struct stat st;
- const or_options_t *options = get_options();
const unsigned int flags = NSSET_FROM_CACHE | NSSET_DONT_DOWNLOAD_CERTS;
int flav;
@@ -259,25 +261,6 @@ router_reload_consensus_networkstatus(void)
tor_free(filename);
}
- if (!current_consensus ||
- (stat(options->FallbackNetworkstatusFile, &st)==0 &&
- st.st_mtime > current_consensus->valid_after)) {
- s = read_file_to_str(options->FallbackNetworkstatusFile,
- RFTS_IGNORE_MISSING, NULL);
- if (s) {
- if (networkstatus_set_current_consensus(s, "ns",
- flags|NSSET_ACCEPT_OBSOLETE)) {
- log_info(LD_FS, "Couldn't load consensus networkstatus from \"%s\"",
- options->FallbackNetworkstatusFile);
- } else {
- log_notice(LD_FS,
- "Loaded fallback consensus networkstatus from \"%s\"",
- options->FallbackNetworkstatusFile);
- }
- tor_free(s);
- }
- }
-
if (!current_consensus) {
if (!named_server_map)
named_server_map = strmap_new();
@@ -561,7 +544,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
/* Now see whether we're missing any voters entirely. */
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- trusted_dir_server_t *, ds,
+ dir_server_t *, ds,
{
if ((ds->type & V3_DIRINFO) &&
!networkstatus_get_voter_by_id(consensus, ds->v3_identity_digest))
@@ -578,7 +561,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
if (warn >= 0) {
SMARTLIST_FOREACH(unrecognized, networkstatus_voter_info_t *, voter,
{
- log(severity, LD_DIR, "Consensus includes unrecognized authority "
+ tor_log(severity, LD_DIR, "Consensus includes unrecognized authority "
"'%s' at %s:%d (contact %s; identity %s)",
voter->nickname, voter->address, (int)voter->dir_port,
voter->contact?voter->contact:"n/a",
@@ -586,16 +569,16 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
});
SMARTLIST_FOREACH(need_certs_from, networkstatus_voter_info_t *, voter,
{
- log(severity, LD_DIR, "Looks like we need to download a new "
+ tor_log(severity, LD_DIR, "Looks like we need to download a new "
"certificate from authority '%s' at %s:%d (contact %s; "
"identity %s)",
voter->nickname, voter->address, (int)voter->dir_port,
voter->contact?voter->contact:"n/a",
hex_str(voter->identity_digest, DIGEST_LEN));
});
- SMARTLIST_FOREACH(missing_authorities, trusted_dir_server_t *, ds,
+ SMARTLIST_FOREACH(missing_authorities, dir_server_t *, ds,
{
- log(severity, LD_DIR, "Consensus does not include configured "
+ tor_log(severity, LD_DIR, "Consensus does not include configured "
"authority '%s' at %s:%d (identity %s)",
ds->nickname, ds->address, (int)ds->dir_port,
hex_str(ds->v3_identity_digest, DIGEST_LEN));
@@ -631,7 +614,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
"because we were missing the keys.", n_missing_key);
}
joined = smartlist_join_strings(sl, " ", 0, NULL);
- log(severity, LD_DIR, "%s", joined);
+ tor_log(severity, LD_DIR, "%s", joined);
tor_free(joined);
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
@@ -667,7 +650,7 @@ networkstatus_get_cache_filename(const char *identity_digest)
/** Helper for smartlist_sort: Compare two networkstatus objects by
* publication date. */
static int
-_compare_networkstatus_v2_published_on(const void **_a, const void **_b)
+compare_networkstatus_v2_published_on_(const void **_a, const void **_b)
{
const networkstatus_v2_t *a = *_a, *b = *_b;
if (a->published_on < b->published_on)
@@ -735,7 +718,7 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at,
int i, found;
time_t now;
int skewed = 0;
- trusted_dir_server_t *trusted_dir = NULL;
+ dir_server_t *trusted_dir = NULL;
const char *source_desc = NULL;
char fp[HEX_DIGEST_LEN+1];
char published[ISO_TIME_LEN+1];
@@ -771,7 +754,7 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at,
long delta = now - ns->published_on;
format_time_interval(dbuf, sizeof(dbuf), delta);
log_warn(LD_GENERAL, "Network status from %s was published %s in the "
- "future (%s GMT). Check your time and date settings! "
+ "future (%s UTC). Check your time and date settings! "
"Not caching.",
source_desc, dbuf, published);
control_event_general_status(LOG_WARN,
@@ -791,7 +774,7 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at,
}
if (requested_fingerprints) {
- if (smartlist_string_isin(requested_fingerprints, fp)) {
+ if (smartlist_contains_string(requested_fingerprints, fp)) {
smartlist_string_remove(requested_fingerprints, fp);
} else {
if (source != NS_FROM_DIR_ALL) {
@@ -901,7 +884,7 @@ router_set_networkstatus_v2(const char *s, time_t arrived_at,
networkstatus_v2_list_has_changed = 1;
smartlist_sort(networkstatus_v2_list,
- _compare_networkstatus_v2_published_on);
+ compare_networkstatus_v2_published_on_);
if (!skewed)
add_networkstatus_to_cache(s, source, ns);
@@ -954,6 +937,17 @@ compare_digest_to_routerstatus_entry(const void *_key, const void **_member)
return tor_memcmp(key, rs->identity_digest, DIGEST_LEN);
}
+/** Helper for bsearching a list of routerstatus_t pointers: compare a
+ * digest in the key to the identity digest of a routerstatus_t. */
+int
+compare_digest_to_vote_routerstatus_entry(const void *_key,
+ const void **_member)
+{
+ const char *key = _key;
+ const vote_routerstatus_t *vrs = *_member;
+ return tor_memcmp(key, vrs->status.identity_digest, DIGEST_LEN);
+}
+
/** As networkstatus_v2_find_entry, but do not return a const pointer */
routerstatus_t *
networkstatus_v2_find_mutable_entry(networkstatus_v2_t *ns, const char *digest)
@@ -1140,7 +1134,7 @@ update_v2_networkstatus_cache_downloads(time_t now)
if (authority) {
/* An authority launches a separate connection for everybody. */
- SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, ds)
+ SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ds)
{
char resource[HEX_DIGEST_LEN+6]; /* fp/hexdigit.z\0 */
tor_addr_t addr;
@@ -1168,7 +1162,7 @@ update_v2_networkstatus_cache_downloads(time_t now)
directory_initiate_command_routerstatus(
&ds->fake_status, DIR_PURPOSE_FETCH_V2_NETWORKSTATUS,
ROUTER_PURPOSE_GENERAL,
- 0, /* Not private */
+ DIRIND_ONEHOP,
resource,
NULL, 0 /* No payload. */,
0 /* No I-M-S. */);
@@ -1438,18 +1432,6 @@ consensus_is_waiting_for_certs(void)
? 1 : 0;
}
-/** Return the network status with a given identity digest. */
-networkstatus_v2_t *
-networkstatus_v2_get_by_digest(const char *digest)
-{
- SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
- {
- if (tor_memeq(ns->identity_digest, digest, DIGEST_LEN))
- return ns;
- });
- return NULL;
-}
-
/** Return the most recent consensus that we have downloaded, or NULL if we
* don't have one. */
networkstatus_t *
@@ -1530,13 +1512,7 @@ routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b)
a->is_bad_exit != b->is_bad_exit ||
a->is_bad_directory != b->is_bad_directory ||
a->is_hs_dir != b->is_hs_dir ||
- a->version_known != b->version_known ||
- a->version_supports_begindir != b->version_supports_begindir ||
- a->version_supports_extrainfo_upload !=
- b->version_supports_extrainfo_upload ||
- a->version_supports_conditional_consensus !=
- b->version_supports_conditional_consensus ||
- a->version_supports_v3_dir != b->version_supports_v3_dir;
+ a->version_known != b->version_known;
}
/** Notify controllers of any router status entries that changed between
@@ -1640,6 +1616,7 @@ networkstatus_set_current_consensus(const char *consensus,
consensus_waiting_for_certs_t *waiting = NULL;
time_t current_valid_after = 0;
int free_consensus = 1; /* Free 'c' at the end of the function */
+ int old_ewma_enabled;
if (flav < 0) {
/* XXXX we don't handle unrecognized flavors yet. */
@@ -1675,9 +1652,6 @@ networkstatus_set_current_consensus(const char *consensus,
if (from_cache && !accept_obsolete &&
c->valid_until < now-OLD_ROUTER_DESC_MAX_AGE) {
- /* XXXX If we try to make fallbackconsensus work again, we should
- * consider taking this out. Until then, believing obsolete consensuses
- * is causing more harm than good. See also bug 887. */
log_info(LD_DIR, "Loaded an expired consensus. Discarding.");
goto done;
}
@@ -1833,7 +1807,18 @@ networkstatus_set_current_consensus(const char *consensus,
dirvote_recalculate_timing(options, now);
routerstatus_list_update_named_server_map();
- cell_ewma_set_scale_factor(options, current_consensus);
+
+ /* Update ewma and adjust policy if needed; first cache the old value */
+ old_ewma_enabled = cell_ewma_enabled();
+ /* Change the cell EWMA settings */
+ cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus());
+ /* If we just enabled ewma, set the cmux policy on all active channels */
+ if (cell_ewma_enabled() && !old_ewma_enabled) {
+ channel_set_cmux_policy_everywhere(&ewma_policy);
+ } else if (!cell_ewma_enabled() && old_ewma_enabled) {
+ /* Turn it off everywhere */
+ channel_set_cmux_policy_everywhere(NULL);
+ }
/* XXXX024 this call might be unnecessary here: can changing the
* current consensus really alter our view of any OR's rate limits? */
@@ -1864,7 +1849,7 @@ networkstatus_set_current_consensus(const char *consensus,
format_iso_time(tbuf, c->valid_after);
format_time_interval(dbuf, sizeof(dbuf), delta);
log_warn(LD_GENERAL, "Our clock is %s behind the time published in the "
- "consensus network status document (%s GMT). Tor needs an "
+ "consensus network status document (%s UTC). Tor needs an "
"accurate clock to work correctly. Please check your time and "
"date settings!", dbuf, tbuf);
control_event_general_status(LOG_WARN,
@@ -1893,11 +1878,12 @@ networkstatus_note_certs_arrived(void)
if (!waiting->consensus)
continue;
if (networkstatus_check_consensus_signature(waiting->consensus, 0)>=0) {
+ char *waiting_body = waiting->body;
if (!networkstatus_set_current_consensus(
- waiting->body,
+ waiting_body,
networkstatus_get_flavor_name(i),
NSSET_WAS_WAITING_FOR_CERTS)) {
- tor_free(waiting->body);
+ tor_free(waiting_body);
}
}
}
@@ -1996,7 +1982,7 @@ download_status_map_update_from_v2_networkstatus(void)
digestmap_set(dl_status, d, s);
} SMARTLIST_FOREACH_END(rs);
} SMARTLIST_FOREACH_END(ns);
- digestmap_free(v2_download_status_map, _tor_free);
+ digestmap_free(v2_download_status_map, tor_free_);
v2_download_status_map = dl_status;
networkstatus_v2_list_has_changed = 0;
}
@@ -2009,7 +1995,7 @@ routerstatus_list_update_named_server_map(void)
if (!current_consensus)
return;
- strmap_free(named_server_map, _tor_free);
+ strmap_free(named_server_map, tor_free_);
named_server_map = strmap_new();
strmap_free(unnamed_server_map, NULL);
unnamed_server_map = strmap_new();
@@ -2032,7 +2018,7 @@ void
routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
int reset_failures)
{
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
const or_options_t *options = get_options();
int authdir = authdir_mode_v2(options) || authdir_mode_v3(options);
networkstatus_t *ns = current_consensus;
@@ -2052,7 +2038,7 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
/* We have a routerstatus for this router. */
const char *digest = router->cache_info.identity_digest;
- ds = router_get_trusteddirserver_by_digest(digest);
+ ds = router_get_fallback_dirserver_by_digest(digest);
/* Is it the same descriptor, or only the same identity? */
if (tor_memeq(router->cache_info.signed_descriptor_digest,
@@ -2130,9 +2116,7 @@ signed_descs_update_status_from_consensus_networkstatus(smartlist_t *descs)
char *
networkstatus_getinfo_helper_single(const routerstatus_t *rs)
{
- char buf[RS_ENTRY_LEN+1];
- routerstatus_format_entry(buf, sizeof(buf), rs, NULL, NS_CONTROL_PORT);
- return tor_strdup(buf);
+ return routerstatus_format_entry(rs, NULL, NS_CONTROL_PORT, NULL);
}
/** Alloc and return a string describing routerstatuses for the most
@@ -2253,6 +2237,21 @@ networkstatus_get_param(const networkstatus_t *ns, const char *param_name,
default_val, min_val, max_val);
}
+/**
+ * Retrieve the consensus parameter that governs the
+ * fixed-point precision of our network balancing 'bandwidth-weights'
+ * (which are themselves integer consensus values). We divide them
+ * by this value and ensure they never exceed this value.
+ */
+int
+networkstatus_get_weight_scale_param(networkstatus_t *ns)
+{
+ return networkstatus_get_param(ns, "bwweightscale",
+ BW_WEIGHT_SCALE,
+ BW_MIN_WEIGHT_SCALE,
+ BW_MAX_WEIGHT_SCALE);
+}
+
/** Return the value of a integer bw weight parameter from the networkstatus
* <b>ns</b> whose name is <b>weight_name</b>. If <b>ns</b> is NULL, try
* loading the latest consensus ourselves. Return <b>default_val</b> if no
@@ -2269,7 +2268,7 @@ networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight_name,
if (!ns || !ns->weight_params)
return default_val;
- max = circuit_build_times_get_bw_scale(ns);
+ max = networkstatus_get_weight_scale_param(ns);
param = get_net_param_from_list(ns->weight_params, weight_name,
default_val, -1,
BW_MAX_WEIGHT_SCALE);
@@ -2310,6 +2309,30 @@ networkstatus_parse_flavor_name(const char *flavname)
return -1;
}
+/** Return 0 if this routerstatus is obsolete, too new, isn't
+ * running, or otherwise not a descriptor that we would make any
+ * use of even if we had it. Else return 1. */
+int
+client_would_use_router(const routerstatus_t *rs, time_t now,
+ const or_options_t *options)
+{
+ if (!rs->is_flagged_running && !options->FetchUselessDescriptors) {
+ /* If we had this router descriptor, we wouldn't even bother using it.
+ * But, if we want to have a complete list, fetch it anyway. */
+ return 0;
+ }
+ if (rs->published_on + options->TestingEstimatedDescriptorPropagationTime
+ > now) {
+ /* Most caches probably don't have this descriptor yet. */
+ return 0;
+ }
+ if (rs->published_on + OLD_ROUTER_DESC_MAX_AGE < now) {
+ /* We'd drop it immediately for being too old. */
+ return 0;
+ }
+ return 1;
+}
+
/** If <b>question</b> is a string beginning with "ns/" in a format the
* control interface expects for a GETINFO question, set *<b>answer</b> to a
* newly-allocated string containing networkstatus lines for the appropriate
@@ -2340,8 +2363,11 @@ getinfo_helper_networkstatus(control_connection_t *conn,
return 0;
} else if (!strcmpstart(question, "ns/id/")) {
char d[DIGEST_LEN];
+ const char *q = question + 6;
+ if (*q == '$')
+ ++q;
- if (base16_decode(d, DIGEST_LEN, question+6, strlen(question+6))) {
+ if (base16_decode(d, DIGEST_LEN, q, strlen(q))) {
*errmsg = "Data not decodeable as hex";
return -1;
}
@@ -2372,7 +2398,7 @@ networkstatus_free_all(void)
networkstatus_v2_list = NULL;
}
- digestmap_free(v2_download_status_map, _tor_free);
+ digestmap_free(v2_download_status_map, tor_free_);
v2_download_status_map = NULL;
networkstatus_vote_free(current_ns_consensus);
networkstatus_vote_free(current_md_consensus);
@@ -2387,7 +2413,7 @@ networkstatus_free_all(void)
tor_free(waiting->body);
}
- strmap_free(named_server_map, _tor_free);
+ strmap_free(named_server_map, tor_free_);
strmap_free(unnamed_server_map, NULL);
}
diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h
index 0af17512d..761f8e7f0 100644
--- a/src/or/networkstatus.h
+++ b/src/or/networkstatus.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for networkstatus.c.
**/
-#ifndef _TOR_NETWORKSTATUS_H
-#define _TOR_NETWORKSTATUS_H
+#ifndef TOR_NETWORKSTATUS_H
+#define TOR_NETWORKSTATUS_H
/** How old do we allow a v2 network-status to get before removing it
* completely? */
@@ -38,6 +38,8 @@ int router_set_networkstatus_v2(const char *s, time_t arrived_at,
void networkstatus_v2_list_clean(time_t now);
int compare_digest_to_routerstatus_entry(const void *_key,
const void **_member);
+int compare_digest_to_vote_routerstatus_entry(const void *_key,
+ const void **_member);
const routerstatus_t *networkstatus_v2_find_entry(networkstatus_v2_t *ns,
const char *digest);
const routerstatus_t *networkstatus_vote_find_entry(networkstatus_t *ns,
@@ -71,7 +73,8 @@ int should_delay_dir_fetches(const or_options_t *options);
void update_networkstatus_downloads(time_t now);
void update_certificate_downloads(time_t now);
int consensus_is_waiting_for_certs(void);
-networkstatus_v2_t *networkstatus_v2_get_by_digest(const char *digest);
+int client_would_use_router(const routerstatus_t *rs, time_t now,
+ const or_options_t *options);
networkstatus_t *networkstatus_get_latest_consensus(void);
networkstatus_t *networkstatus_get_latest_consensus_by_flavor(
consensus_flavor_t f);
@@ -110,6 +113,7 @@ int networkstatus_parse_flavor_name(const char *flavname);
void document_signature_free(document_signature_t *sig);
document_signature_t *document_signature_dup(const document_signature_t *sig);
void networkstatus_free_all(void);
+int networkstatus_get_weight_scale_param(networkstatus_t *ns);
#endif
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index d17850888..178f084b6 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -1,23 +1,30 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
+#include "address.h"
#include "config.h"
+#include "control.h"
#include "dirserv.h"
+#include "geoip.h"
+#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "policies.h"
+#include "rendservice.h"
#include "router.h"
#include "routerlist.h"
+#include "routerset.h"
#include <string.h>
static void nodelist_drop_node(node_t *node, int remove_from_ht);
static void node_free(node_t *node);
+static void update_router_have_minimum_dir_info(void);
/** A nodelist_t holds a node_t object for every router we're "willing to use
* for something". Specifically, it should hold a node_t for every node that
@@ -115,19 +122,47 @@ node_get_or_create(const char *identity_digest)
return node;
}
-/** Add <b>ri</b> to the nodelist. */
+/** Called when a node's address changes. */
+static void
+node_addrs_changed(node_t *node)
+{
+ node->last_reachable = node->last_reachable6 = 0;
+ node->country = -1;
+}
+
+/** Add <b>ri</b> to an appropriate node in the nodelist. If we replace an
+ * old routerinfo, and <b>ri_old_out</b> is not NULL, set *<b>ri_old_out</b>
+ * to the previous routerinfo.
+ */
node_t *
-nodelist_add_routerinfo(routerinfo_t *ri)
+nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out)
{
node_t *node;
+ const char *id_digest;
+ int had_router = 0;
+ tor_assert(ri);
+
init_nodelist();
- node = node_get_or_create(ri->cache_info.identity_digest);
+ id_digest = ri->cache_info.identity_digest;
+ node = node_get_or_create(id_digest);
+
+ if (node->ri) {
+ if (!routers_have_same_or_addrs(node->ri, ri)) {
+ node_addrs_changed(node);
+ }
+ had_router = 1;
+ if (ri_old_out)
+ *ri_old_out = node->ri;
+ } else {
+ if (ri_old_out)
+ *ri_old_out = NULL;
+ }
node->ri = ri;
if (node->country == -1)
node_set_country(node);
- if (authdir_mode(get_options())) {
+ if (authdir_mode(get_options()) && !had_router) {
const char *discard=NULL;
uint32_t status = dirserv_router_get_status(ri, &discard);
dirserv_set_node_flags_from_authoritative_status(node, status);
@@ -167,7 +202,7 @@ nodelist_add_microdesc(microdesc_t *md)
return node;
}
-/** Tell the nodelist that the current usable consensus to <b>ns</b>.
+/** Tell the nodelist that the current usable consensus is <b>ns</b>.
* This makes the nodelist change all of the routerstatus entries for
* the nodes, drop nodes that no longer have enough info to get used,
* and grab microdescriptors into nodes as appropriate.
@@ -177,6 +212,7 @@ nodelist_set_consensus(networkstatus_t *ns)
{
const or_options_t *options = get_options();
int authdir = authdir_mode_v2(options) || authdir_mode_v3(options);
+ int client = !server_mode(options);
init_nodelist();
if (ns->flavor == FLAV_MICRODESC)
@@ -213,6 +249,11 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_bad_directory = rs->is_bad_directory;
node->is_bad_exit = rs->is_bad_exit;
node->is_hs_dir = rs->is_hs_dir;
+ node->ipv6_preferred = 0;
+ if (client && options->ClientPreferIPv6ORPort == 1 &&
+ (tor_addr_is_null(&rs->ipv6_addr) == 0 ||
+ (node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0)))
+ node->ipv6_preferred = 1;
}
} SMARTLIST_FOREACH_END(rs);
@@ -231,7 +272,8 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_valid = node->is_running = node->is_hs_dir =
node->is_fast = node->is_stable =
node->is_possible_guard = node->is_exit =
- node->is_bad_exit = node->is_bad_directory = 0;
+ node->is_bad_exit = node->is_bad_directory =
+ node->ipv6_preferred = 0;
}
}
} SMARTLIST_FOREACH_END(node);
@@ -582,7 +624,7 @@ node_is_dir(const node_t *node)
}
/** Return true iff <b>node</b> has either kind of usable descriptor -- that
- * is, a routerdecriptor or a microdescriptor. */
+ * is, a routerdescriptor or a microdescriptor. */
int
node_has_descriptor(const node_t *node)
{
@@ -646,6 +688,24 @@ node_exit_policy_rejects_all(const node_t *node)
return 1;
}
+/** Return true iff the exit policy for <b>node</b> is such that we can treat
+ * rejecting an address of type <b>family</b> unexpectedly as a sign of that
+ * node's failure. */
+int
+node_exit_policy_is_exact(const node_t *node, sa_family_t family)
+{
+ if (family == AF_UNSPEC) {
+ return 1; /* Rejecting an address but not telling us what address
+ * is a bad sign. */
+ } else if (family == AF_INET) {
+ return node->ri != NULL;
+ } else if (family == AF_INET6) {
+ return 0;
+ }
+ tor_fragile_assert();
+ return 1;
+}
+
/** Return list of tor_addr_port_t with all OR ports (in the sense IP
* addr + TCP port) for <b>node</b>. Caller must free all elements
* using tor_free() and free the list using smartlist_free().
@@ -682,19 +742,6 @@ node_get_all_orports(const node_t *node)
return sl;
}
-/** Copy the primary (IPv4) OR port (IP address and TCP port) for
- * <b>node</b> into *<b>ap_out</b>. */
-void
-node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
-{
- if (node->ri) {
- router_get_prim_orport(node->ri, ap_out);
- } else if (node->rs) {
- tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
- ap_out->port = node->rs->or_port;
- }
-}
-
/** Wrapper around node_get_prim_orport for backward
compatibility. */
void
@@ -718,36 +765,6 @@ node_get_prim_addr_ipv4h(const node_t *node)
return 0;
}
-/** Copy the preferred OR port (IP address and TCP port) for
- * <b>node</b> into <b>ap_out</b>. */
-void
-node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out)
-{
- if (node->ri) {
- router_get_pref_orport(node->ri, ap_out);
- } else if (node->rs) {
- /* No IPv6 in routerstatus_t yet. XXXprop186 ok for private
- bridges but needs fixing */
- tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
- ap_out->port = node->rs->or_port;
- }
-}
-
-/** Copy the preferred IPv6 OR port (address and TCP port) for
- * <b>node</b> into *<b>ap_out</b>. */
-void
-node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
-{
- if (node->ri) {
- router_get_pref_ipv6_orport(node->ri, ap_out);
- } else if (node->rs) {
- /* No IPv6 in routerstatus_t yet. XXXprop186 ok for private
- bridges but needs fixing */
- tor_addr_make_unspec(&ap_out->addr);
- ap_out->port = 0;
- }
-}
-
/** Copy a string representation of an IP address for <b>node</b> into
* the <b>len</b>-byte buffer at <b>buf</b>. */
void
@@ -818,3 +835,678 @@ node_get_declared_family(const node_t *node)
return NULL;
}
+/** Return 1 if we prefer the IPv6 address and OR TCP port of
+ * <b>node</b>, else 0.
+ *
+ * We prefer the IPv6 address if the router has an IPv6 address and
+ * i) the node_t says that it prefers IPv6
+ * or
+ * ii) the router has no IPv4 address. */
+int
+node_ipv6_preferred(const node_t *node)
+{
+ tor_addr_port_t ipv4_addr;
+ node_assert_ok(node);
+
+ if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) {
+ if (node->ri)
+ return !tor_addr_is_null(&node->ri->ipv6_addr);
+ if (node->md)
+ return !tor_addr_is_null(&node->md->ipv6_addr);
+ if (node->rs)
+ return !tor_addr_is_null(&node->rs->ipv6_addr);
+ }
+ return 0;
+}
+
+/** Copy the primary (IPv4) OR port (IP address and TCP port) for
+ * <b>node</b> into *<b>ap_out</b>. Return 0 if a valid address and
+ * port was copied, else return non-zero.*/
+int
+node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
+{
+ node_assert_ok(node);
+ tor_assert(ap_out);
+
+ if (node->ri) {
+ if (node->ri->addr == 0 || node->ri->or_port == 0)
+ return -1;
+ tor_addr_from_ipv4h(&ap_out->addr, node->ri->addr);
+ ap_out->port = node->ri->or_port;
+ return 0;
+ }
+ if (node->rs) {
+ if (node->rs->addr == 0 || node->rs->or_port == 0)
+ return -1;
+ tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
+ ap_out->port = node->rs->or_port;
+ return 0;
+ }
+ return -1;
+}
+
+/** Copy the preferred OR port (IP address and TCP port) for
+ * <b>node</b> into *<b>ap_out</b>. */
+void
+node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out)
+{
+ const or_options_t *options = get_options();
+ tor_assert(ap_out);
+
+ /* Cheap implementation of config option ClientUseIPv6 -- simply
+ don't prefer IPv6 when ClientUseIPv6 is not set and we're not a
+ client running with bridges. See #4455 for more on this subject.
+
+ Note that this filter is too strict since we're hindering not
+ only clients! Erring on the safe side shouldn't be a problem
+ though. XXX move this check to where outgoing connections are
+ made? -LN */
+ if ((options->ClientUseIPv6 || options->UseBridges) &&
+ node_ipv6_preferred(node)) {
+ node_get_pref_ipv6_orport(node, ap_out);
+ } else {
+ node_get_prim_orport(node, ap_out);
+ }
+}
+
+/** Copy the preferred IPv6 OR port (IP address and TCP port) for
+ * <b>node</b> into *<b>ap_out</b>. */
+void
+node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
+{
+ node_assert_ok(node);
+ tor_assert(ap_out);
+
+ /* We prefer the microdesc over a potential routerstatus here. They
+ are not being synchronised atm so there might be a chance that
+ they differ at some point, f.ex. when flipping
+ UseMicrodescriptors? -LN */
+
+ if (node->ri) {
+ tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
+ ap_out->port = node->ri->ipv6_orport;
+ } else if (node->md) {
+ tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr);
+ ap_out->port = node->md->ipv6_orport;
+ } else if (node->rs) {
+ tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
+ ap_out->port = node->rs->ipv6_orport;
+ }
+}
+
+/** Return true iff <b>node</b> has a curve25519 onion key. */
+int
+node_has_curve25519_onion_key(const node_t *node)
+{
+ if (node->ri)
+ return node->ri->onion_curve25519_pkey != NULL;
+ else if (node->md)
+ return node->md->onion_curve25519_pkey != NULL;
+ else
+ return 0;
+}
+
+/** Refresh the country code of <b>ri</b>. This function MUST be called on
+ * each router when the GeoIP database is reloaded, and on all new routers. */
+void
+node_set_country(node_t *node)
+{
+ tor_addr_t addr = TOR_ADDR_NULL;
+
+ /* XXXXipv6 */
+ if (node->rs)
+ tor_addr_from_ipv4h(&addr, node->rs->addr);
+ else if (node->ri)
+ tor_addr_from_ipv4h(&addr, node->ri->addr);
+
+ node->country = geoip_get_country_by_addr(&addr);
+}
+
+/** Set the country code of all routers in the routerlist. */
+void
+nodelist_refresh_countries(void)
+{
+ smartlist_t *nodes = nodelist_get_list();
+ SMARTLIST_FOREACH(nodes, node_t *, node,
+ node_set_country(node));
+}
+
+/** Return true iff router1 and router2 have similar enough network addresses
+ * that we should treat them as being in the same family */
+static INLINE int
+addrs_in_same_network_family(const tor_addr_t *a1,
+ const tor_addr_t *a2)
+{
+ return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC);
+}
+
+/** Return true if <b>node</b>'s nickname matches <b>nickname</b>
+ * (case-insensitive), or if <b>node's</b> identity key digest
+ * matches a hexadecimal value stored in <b>nickname</b>. Return
+ * false otherwise. */
+static int
+node_nickname_matches(const node_t *node, const char *nickname)
+{
+ const char *n = node_get_nickname(node);
+ if (n && nickname[0]!='$' && !strcasecmp(n, nickname))
+ return 1;
+ return hex_digest_nickname_matches(nickname,
+ node->identity,
+ n,
+ node_is_named(node));
+}
+
+/** Return true iff <b>node</b> is named by some nickname in <b>lst</b>. */
+static INLINE int
+node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node)
+{
+ if (!lst) return 0;
+ SMARTLIST_FOREACH(lst, const char *, name, {
+ if (node_nickname_matches(node, name))
+ return 1;
+ });
+ return 0;
+}
+
+/** Return true iff r1 and r2 are in the same family, but not the same
+ * router. */
+int
+nodes_in_same_family(const node_t *node1, const node_t *node2)
+{
+ const or_options_t *options = get_options();
+
+ /* Are they in the same family because of their addresses? */
+ if (options->EnforceDistinctSubnets) {
+ tor_addr_t a1, a2;
+ node_get_addr(node1, &a1);
+ node_get_addr(node2, &a2);
+ if (addrs_in_same_network_family(&a1, &a2))
+ return 1;
+ }
+
+ /* Are they in the same family because the agree they are? */
+ {
+ const smartlist_t *f1, *f2;
+ f1 = node_get_declared_family(node1);
+ f2 = node_get_declared_family(node2);
+ if (f1 && f2 &&
+ node_in_nickname_smartlist(f1, node2) &&
+ node_in_nickname_smartlist(f2, node1))
+ return 1;
+ }
+
+ /* Are they in the same option because the user says they are? */
+ if (options->NodeFamilySets) {
+ SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
+ if (routerset_contains_node(rs, node1) &&
+ routerset_contains_node(rs, node2))
+ return 1;
+ });
+ }
+
+ return 0;
+}
+
+/**
+ * Add all the family of <b>node</b>, including <b>node</b> itself, to
+ * the smartlist <b>sl</b>.
+ *
+ * This is used to make sure we don't pick siblings in a single path, or
+ * pick more than one relay from a family for our entry guard list.
+ * Note that a node may be added to <b>sl</b> more than once if it is
+ * part of <b>node</b>'s family for more than one reason.
+ */
+void
+nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
+{
+ const smartlist_t *all_nodes = nodelist_get_list();
+ const smartlist_t *declared_family;
+ const or_options_t *options = get_options();
+
+ tor_assert(node);
+
+ declared_family = node_get_declared_family(node);
+
+ /* Let's make sure that we have the node itself, if it's a real node. */
+ {
+ const node_t *real_node = node_get_by_id(node->identity);
+ if (real_node)
+ smartlist_add(sl, (node_t*)real_node);
+ }
+
+ /* First, add any nodes with similar network addresses. */
+ if (options->EnforceDistinctSubnets) {
+ tor_addr_t node_addr;
+ node_get_addr(node, &node_addr);
+
+ SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) {
+ tor_addr_t a;
+ node_get_addr(node2, &a);
+ if (addrs_in_same_network_family(&a, &node_addr))
+ smartlist_add(sl, (void*)node2);
+ } SMARTLIST_FOREACH_END(node2);
+ }
+
+ /* Now, add all nodes in the declared_family of this node, if they
+ * also declare this node to be in their family. */
+ if (declared_family) {
+ /* Add every r such that router declares familyness with node, and node
+ * declares familyhood with router. */
+ SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) {
+ const node_t *node2;
+ const smartlist_t *family2;
+ if (!(node2 = node_get_by_nickname(name, 0)))
+ continue;
+ if (!(family2 = node_get_declared_family(node2)))
+ continue;
+ SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) {
+ if (node_nickname_matches(node, name2)) {
+ smartlist_add(sl, (void*)node2);
+ break;
+ }
+ } SMARTLIST_FOREACH_END(name2);
+ } SMARTLIST_FOREACH_END(name);
+ }
+
+ /* If the user declared any families locally, honor those too. */
+ if (options->NodeFamilySets) {
+ SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
+ if (routerset_contains_node(rs, node)) {
+ routerset_get_all_nodes(sl, rs, NULL, 0);
+ }
+ });
+ }
+}
+
+/** Find a router that's up, that has this IP address, and
+ * that allows exit to this address:port, or return NULL if there
+ * isn't a good one.
+ * Don't exit enclave to excluded relays -- it wouldn't actually
+ * hurt anything, but this way there are fewer confused users.
+ */
+const node_t *
+router_find_exact_exit_enclave(const char *address, uint16_t port)
+{/*XXXX MOVE*/
+ uint32_t addr;
+ struct in_addr in;
+ tor_addr_t a;
+ const or_options_t *options = get_options();
+
+ if (!tor_inet_aton(address, &in))
+ return NULL; /* it's not an IP already */
+ addr = ntohl(in.s_addr);
+
+ tor_addr_from_ipv4h(&a, addr);
+
+ SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
+ if (node_get_addr_ipv4h(node) == addr &&
+ node->is_running &&
+ compare_tor_addr_to_node_policy(&a, port, node) ==
+ ADDR_POLICY_ACCEPTED &&
+ !routerset_contains_node(options->ExcludeExitNodesUnion_, node))
+ return node;
+ });
+ return NULL;
+}
+
+/** Return 1 if <b>router</b> is not suitable for these parameters, else 0.
+ * If <b>need_uptime</b> is non-zero, we require a minimum uptime.
+ * If <b>need_capacity</b> is non-zero, we require a minimum advertised
+ * bandwidth.
+ * If <b>need_guard</b>, we require that the router is a possible entry guard.
+ */
+int
+node_is_unreliable(const node_t *node, int need_uptime,
+ int need_capacity, int need_guard)
+{
+ if (need_uptime && !node->is_stable)
+ return 1;
+ if (need_capacity && !node->is_fast)
+ return 1;
+ if (need_guard && !node->is_possible_guard)
+ return 1;
+ return 0;
+}
+
+/** Return 1 if all running sufficiently-stable routers we can use will reject
+ * addr:port. Return 0 if any might accept it. */
+int
+router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
+ int need_uptime)
+{
+ addr_policy_result_t r;
+
+ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
+ if (node->is_running &&
+ !node_is_unreliable(node, need_uptime, 0, 0)) {
+
+ r = compare_tor_addr_to_node_policy(addr, port, node);
+
+ if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
+ return 0; /* this one could be ok. good enough. */
+ }
+ } SMARTLIST_FOREACH_END(node);
+ return 1; /* all will reject. */
+}
+
+/** Mark the router with ID <b>digest</b> as running or non-running
+ * in our routerlist. */
+void
+router_set_status(const char *digest, int up)
+{
+ node_t *node;
+ tor_assert(digest);
+
+ SMARTLIST_FOREACH(router_get_fallback_dir_servers(),
+ dir_server_t *, d,
+ if (tor_memeq(d->digest, digest, DIGEST_LEN))
+ d->is_running = up);
+
+ SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
+ dir_server_t *, d,
+ if (tor_memeq(d->digest, digest, DIGEST_LEN))
+ d->is_running = up);
+
+ node = node_get_mutable_by_id(digest);
+ if (node) {
+#if 0
+ log_debug(LD_DIR,"Marking router %s as %s.",
+ node_describe(node), up ? "up" : "down");
+#endif
+ if (!up && node_is_me(node) && !net_is_disabled())
+ log_warn(LD_NET, "We just marked ourself as down. Are your external "
+ "addresses reachable?");
+ node->is_running = up;
+ }
+
+ router_dir_info_changed();
+}
+
+/** True iff, the last time we checked whether we had enough directory info
+ * to build circuits, the answer was "yes". */
+static int have_min_dir_info = 0;
+/** True iff enough has changed since the last time we checked whether we had
+ * enough directory info to build circuits that our old answer can no longer
+ * be trusted. */
+static int need_to_update_have_min_dir_info = 1;
+/** String describing what we're missing before we have enough directory
+ * info. */
+static char dir_info_status[256] = "";
+
+/** Return true iff we have enough networkstatus and router information to
+ * start building circuits. Right now, this means "more than half the
+ * networkstatus documents, and at least 1/4 of expected routers." */
+//XXX should consider whether we have enough exiting nodes here.
+int
+router_have_minimum_dir_info(void)
+{
+ if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) {
+ update_router_have_minimum_dir_info();
+ need_to_update_have_min_dir_info = 0;
+ }
+ return have_min_dir_info;
+}
+
+/** Called when our internal view of the directory has changed. This can be
+ * when the authorities change, networkstatuses change, the list of routerdescs
+ * changes, or number of running routers changes.
+ */
+void
+router_dir_info_changed(void)
+{
+ need_to_update_have_min_dir_info = 1;
+ rend_hsdir_routers_changed();
+}
+
+/** Return a string describing what we're missing before we have enough
+ * directory info. */
+const char *
+get_dir_info_status_string(void)
+{
+ return dir_info_status;
+}
+
+/** Iterate over the servers listed in <b>consensus</b>, and count how many of
+ * them seem like ones we'd use, and how many of <em>those</em> we have
+ * descriptors for. Store the former in *<b>num_usable</b> and the latter in
+ * *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those
+ * routers in <b>in_set</b>. If <b>exit_only</b> is true, only consider nodes
+ * with the Exit flag. If *descs_out is present, add a node_t for each
+ * usable descriptor to it.
+ */
+static void
+count_usable_descriptors(int *num_present, int *num_usable,
+ smartlist_t *descs_out,
+ const networkstatus_t *consensus,
+ const or_options_t *options, time_t now,
+ routerset_t *in_set, int exit_only)
+{
+ const int md = (consensus->flavor == FLAV_MICRODESC);
+ *num_present = 0, *num_usable=0;
+
+ SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs)
+ {
+ const node_t *node = node_get_by_id(rs->identity_digest);
+ if (!node)
+ continue; /* This would be a bug: every entry in the consensus is
+ * supposed to have a node. */
+ if (exit_only && ! rs->is_exit)
+ continue;
+ if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
+ continue;
+ if (client_would_use_router(rs, now, options)) {
+ const char * const digest = rs->descriptor_digest;
+ int present;
+ ++*num_usable; /* the consensus says we want it. */
+ if (md)
+ present = NULL != microdesc_cache_lookup_by_digest256(NULL, digest);
+ else
+ present = NULL != router_get_by_descriptor_digest(digest);
+ if (present) {
+ /* we have the descriptor listed in the consensus. */
+ ++*num_present;
+ }
+ if (descs_out)
+ smartlist_add(descs_out, (node_t*)node);
+ }
+ }
+ SMARTLIST_FOREACH_END(rs);
+
+ log_debug(LD_DIR, "%d usable, %d present (%s%s).",
+ *num_usable, *num_present,
+ md ? "microdesc" : "desc", exit_only ? " exits" : "s");
+}
+
+/** Return an extimate of which fraction of usable paths through the Tor
+ * network we have available for use. */
+static double
+compute_frac_paths_available(const networkstatus_t *consensus,
+ const or_options_t *options, time_t now,
+ int *num_present_out, int *num_usable_out,
+ char **status_out)
+{
+ smartlist_t *guards = smartlist_new();
+ smartlist_t *mid = smartlist_new();
+ smartlist_t *exits = smartlist_new();
+ smartlist_t *myexits= smartlist_new();
+ double f_guard, f_mid, f_exit, f_myexit;
+ int np, nu; /* Ignored */
+ const int authdir = authdir_mode_v2(options) || authdir_mode_v3(options);
+
+ count_usable_descriptors(num_present_out, num_usable_out,
+ mid, consensus, options, now, NULL, 0);
+ if (options->EntryNodes) {
+ count_usable_descriptors(&np, &nu, guards, consensus, options, now,
+ options->EntryNodes, 0);
+ } else {
+ SMARTLIST_FOREACH(mid, const node_t *, node, {
+ if (authdir) {
+ if (node->rs && node->rs->is_possible_guard)
+ smartlist_add(guards, (node_t*)node);
+ } else {
+ if (node->is_possible_guard)
+ smartlist_add(guards, (node_t*)node);
+ }
+ });
+ }
+
+ count_usable_descriptors(&np, &nu, exits, consensus, options, now,
+ NULL, 1);
+ count_usable_descriptors(&np, &nu, myexits, consensus, options, now,
+ options->ExitNodes, 1);
+
+ f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD);
+ f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID);
+ f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT);
+ f_myexit= frac_nodes_with_descriptors(myexits,WEIGHT_FOR_EXIT);
+
+ smartlist_free(guards);
+ smartlist_free(mid);
+ smartlist_free(exits);
+ smartlist_free(myexits);
+
+ /* This is a tricky point here: we don't want to make it easy for a
+ * directory to trickle exits to us until it learns which exits we have
+ * configured, so require that we have a threshold both of total exits
+ * and usable exits. */
+ if (f_myexit < f_exit)
+ f_exit = f_myexit;
+
+ tor_asprintf(status_out,
+ "%d%% of guards bw, "
+ "%d%% of midpoint bw, and "
+ "%d%% of exit bw",
+ (int)(f_guard*100),
+ (int)(f_mid*100),
+ (int)(f_exit*100));
+
+ return f_guard * f_mid * f_exit;
+}
+
+/** We just fetched a new set of descriptors. Compute how far through
+ * the "loading descriptors" bootstrapping phase we are, so we can inform
+ * the controller of our progress. */
+int
+count_loading_descriptors_progress(void)
+{
+ int num_present = 0, num_usable=0;
+ time_t now = time(NULL);
+ const networkstatus_t *consensus =
+ networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
+ double fraction;
+
+ if (!consensus)
+ return 0; /* can't count descriptors if we have no list of them */
+
+ count_usable_descriptors(&num_present, &num_usable, NULL,
+ consensus, get_options(), now, NULL, 0);
+
+ if (num_usable == 0)
+ return 0; /* don't div by 0 */
+ fraction = num_present / (num_usable/4.);
+ if (fraction > 1.0)
+ return 0; /* it's not the number of descriptors holding us back */
+ return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int)
+ (fraction*(BOOTSTRAP_STATUS_CONN_OR-1 -
+ BOOTSTRAP_STATUS_LOADING_DESCRIPTORS));
+}
+
+/** Return the fraction of paths needed before we're willing to build
+ * circuits, as configured in <b>options</b>, or in the consensus <b>ns</b>. */
+static double
+get_frac_paths_needed_for_circs(const or_options_t *options,
+ const networkstatus_t *ns)
+{
+#define DFLT_PCT_USABLE_NEEDED 60
+ if (options->PathsNeededToBuildCircuits >= 0.0) {
+ return options->PathsNeededToBuildCircuits;
+ } else {
+ return networkstatus_get_param(ns, "min_paths_for_circs_pct",
+ DFLT_PCT_USABLE_NEEDED,
+ 25, 95)/100.0;
+ }
+}
+
+/** Change the value of have_min_dir_info, setting it true iff we have enough
+ * network and router information to build circuits. Clear the value of
+ * need_to_update_have_min_dir_info. */
+static void
+update_router_have_minimum_dir_info(void)
+{
+ time_t now = time(NULL);
+ int res;
+ const or_options_t *options = get_options();
+ const networkstatus_t *consensus =
+ networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
+ int using_md;
+
+ if (!consensus) {
+ if (!networkstatus_get_latest_consensus())
+ strlcpy(dir_info_status, "We have no usable consensus.",
+ sizeof(dir_info_status));
+ else
+ strlcpy(dir_info_status, "We have no recent usable consensus.",
+ sizeof(dir_info_status));
+ res = 0;
+ goto done;
+ }
+
+ if (should_delay_dir_fetches(get_options())) {
+ log_notice(LD_DIR, "no known bridge descriptors running yet; stalling");
+ strlcpy(dir_info_status, "No live bridge descriptors.",
+ sizeof(dir_info_status));
+ res = 0;
+ goto done;
+ }
+
+ using_md = consensus->flavor == FLAV_MICRODESC;
+
+ {
+ char *status = NULL;
+ int num_present=0, num_usable=0;
+ double paths = compute_frac_paths_available(consensus, options, now,
+ &num_present, &num_usable,
+ &status);
+
+ if (paths < get_frac_paths_needed_for_circs(options,consensus)) {
+ tor_snprintf(dir_info_status, sizeof(dir_info_status),
+ "We need more %sdescriptors: we have %d/%d, and "
+ "can only build %d%% of likely paths. (We have %s.)",
+ using_md?"micro":"", num_present, num_usable,
+ (int)(paths*100), status);
+ /* log_notice(LD_NET, "%s", dir_info_status); */
+ tor_free(status);
+ res = 0;
+ control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
+ goto done;
+ }
+
+ tor_free(status);
+ res = 1;
+ }
+
+ done:
+ if (res && !have_min_dir_info) {
+ log_notice(LD_DIR,
+ "We now have enough directory information to build circuits.");
+ control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
+ control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0);
+ }
+ if (!res && have_min_dir_info) {
+ int quiet = directory_too_idle_to_fetch_descriptors(options, now);
+ tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
+ "Our directory information is no longer up-to-date "
+ "enough to build circuits: %s", dir_info_status);
+
+ /* a) make us log when we next complete a circuit, so we know when Tor
+ * is back up and usable, and b) disable some activities that Tor
+ * should only do while circuits are working, like reachability tests
+ * and fetching bridge descriptors only over circuits. */
+ can_complete_circuit = 0;
+
+ control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO");
+ }
+ have_min_dir_info = res;
+ need_to_update_have_min_dir_info = 0;
+}
+
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 1e9da88d4..8a4665a8b 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -1,21 +1,25 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file microdesc.h
- * \brief Header file for microdesc.c.
+ * \file nodelist.h
+ * \brief Header file for nodelist.c.
**/
-#ifndef _TOR_NODELIST_H
-#define _TOR_NODELIST_H
+#ifndef TOR_NODELIST_H
+#define TOR_NODELIST_H
+
+#define node_assert_ok(n) STMT_BEGIN { \
+ tor_assert((n)->ri || (n)->rs); \
+ } STMT_END
node_t *node_get_mutable_by_id(const char *identity_digest);
const node_t *node_get_by_id(const char *identity_digest);
const node_t *node_get_by_hex_id(const char *identity_digest);
-node_t *nodelist_add_routerinfo(routerinfo_t *ri);
+node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
node_t *nodelist_add_microdesc(microdesc_t *md);
void nodelist_set_consensus(networkstatus_t *ns);
@@ -37,19 +41,21 @@ int node_get_purpose(const node_t *node);
(node_get_purpose((node)) == ROUTER_PURPOSE_BRIDGE)
int node_is_me(const node_t *node);
int node_exit_policy_rejects_all(const node_t *node);
+int node_exit_policy_is_exact(const node_t *node, sa_family_t family);
smartlist_t *node_get_all_orports(const node_t *node);
-void node_get_prim_orport(const node_t *node, tor_addr_port_t *addr_port_out);
-void node_get_pref_orport(const node_t *node, tor_addr_port_t *addr_port_out);
-void node_get_pref_ipv6_orport(const node_t *node,
- tor_addr_port_t *addr_port_out);
-uint32_t node_get_prim_addr_ipv4h(const node_t *node);
int node_allows_single_hop_exits(const node_t *node);
const char *node_get_nickname(const node_t *node);
const char *node_get_platform(const node_t *node);
+uint32_t node_get_prim_addr_ipv4h(const node_t *node);
void node_get_address_string(const node_t *node, char *cp, size_t len);
long node_get_declared_uptime(const node_t *node);
time_t node_get_published_on(const node_t *node);
const smartlist_t *node_get_declared_family(const node_t *node);
+int node_ipv6_preferred(const node_t *node);
+int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out);
+void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out);
+void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out);
+int node_has_curve25519_onion_key(const node_t *node);
smartlist_t *nodelist_get_list(void);
@@ -57,11 +63,22 @@ smartlist_t *nodelist_get_list(void);
void node_get_addr(const node_t *node, tor_addr_t *addr_out);
#define node_get_addr_ipv4h(n) node_get_prim_addr_ipv4h((n))
-/* XXXX These need to move out of routerlist.c */
void nodelist_refresh_countries(void);
void node_set_country(node_t *node);
void nodelist_add_node_and_family(smartlist_t *nodes, const node_t *node);
int nodes_in_same_family(const node_t *node1, const node_t *node2);
+const node_t *router_find_exact_exit_enclave(const char *address,
+ uint16_t port);
+int node_is_unreliable(const node_t *router, int need_uptime,
+ int need_capacity, int need_guard);
+int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
+ int need_uptime);
+void router_set_status(const char *digest, int up);
+int router_have_minimum_dir_info(void);
+void router_dir_info_changed(void);
+const char *get_dir_info_status_string(void);
+int count_loading_descriptors_progress(void);
+
#endif
diff --git a/src/or/ntmain.c b/src/or/ntmain.c
index d001f7be1..8b67b8682 100644
--- a/src/or/ntmain.c
+++ b/src/or/ntmain.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define MAIN_PRIVATE
diff --git a/src/or/ntmain.h b/src/or/ntmain.h
index 07fdcf466..d3027936c 100644
--- a/src/or/ntmain.h
+++ b/src/or/ntmain.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for ntmain.c.
**/
-#ifndef _TOR_NTMAIN_H
-#define _TOR_NTMAIN_H
+#ifndef TOR_NTMAIN_H
+#define TOR_NTMAIN_H
#ifdef _WIN32
#if !defined (WINCE)
diff --git a/src/or/onion.c b/src/or/onion.c
index f8c4d72b5..1a0bcf106 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -1,74 +1,158 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file onion.c
- * \brief Functions to queue create cells, and handle onionskin
- * parsing and creation.
+ * \brief Functions to queue create cells, wrap the various onionskin types,
+ * and parse and create the CREATE cell and its allies.
**/
#include "or.h"
#include "circuitlist.h"
#include "config.h"
+#include "cpuworker.h"
+#include "networkstatus.h"
#include "onion.h"
+#include "onion_fast.h"
+#include "onion_ntor.h"
+#include "onion_tap.h"
+#include "relay.h"
#include "rephist.h"
+#include "router.h"
+#include "tor_queue.h"
/** Type for a linked list of circuits that are waiting for a free CPU worker
* to process a waiting onion handshake. */
typedef struct onion_queue_t {
+ TOR_TAILQ_ENTRY(onion_queue_t) next;
or_circuit_t *circ;
- char *onionskin;
+ uint16_t handshake_type;
+ create_cell_t *onionskin;
time_t when_added;
- struct onion_queue_t *next;
} onion_queue_t;
/** 5 seconds on the onion queue til we just send back a destroy */
#define ONIONQUEUE_WAIT_CUTOFF 5
-/** First and last elements in the linked list of circuits waiting for CPU
- * workers, or NULL if the list is empty.
- * @{ */
-static onion_queue_t *ol_list=NULL;
-static onion_queue_t *ol_tail=NULL;
-/**@}*/
-/** Length of ol_list */
-static int ol_length=0;
+/** Array of queues of circuits waiting for CPU workers. An element is NULL
+ * if that queue is empty.*/
+TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t)
+ ol_list[MAX_ONION_HANDSHAKE_TYPE+1] = {
+ TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */
+ TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */
+ TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */
+};
+
+/** Number of entries of each type currently in each element of ol_list[]. */
+static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1];
+
+static int num_ntors_per_tap(void);
+static void onion_queue_entry_remove(onion_queue_t *victim);
+
+/* XXXX024 Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN.
+ *
+ * (By which I think I meant, "make sure that no
+ * X_ONIONSKIN_CHALLENGE/REPLY_LEN is greater than
+ * MAX_ONIONSKIN_CHALLENGE/REPLY_LEN." Also, make sure that we can pass
+ * over-large values via EXTEND2/EXTENDED2, for future-compatibility.*/
+
+/** Return true iff we have room to queue another oninoskin of type
+ * <b>type</b>. */
+static int
+have_room_for_onionskin(uint16_t type)
+{
+ const or_options_t *options = get_options();
+ int num_cpus;
+ uint64_t tap_usec, ntor_usec;
+ uint64_t ntor_during_tap_usec, tap_during_ntor_usec;
+
+ /* If we've got fewer than 50 entries, we always have room for one more. */
+ if (ol_entries[type] < 50)
+ return 1;
+ num_cpus = get_num_cpus(options);
+ /* Compute how many microseconds we'd expect to need to clear all
+ * onionskins in various combinations of the queues. */
+
+ /* How long would it take to process all the TAP cells in the queue? */
+ tap_usec = estimated_usec_for_onionskins(
+ ol_entries[ONION_HANDSHAKE_TYPE_TAP],
+ ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
+
+ /* How long would it take to process all the NTor cells in the queue? */
+ ntor_usec = estimated_usec_for_onionskins(
+ ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
+ ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
+
+ /* How long would it take to process the tap cells that we expect to
+ * process while draining the ntor queue? */
+ tap_during_ntor_usec = estimated_usec_for_onionskins(
+ MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP],
+ ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / num_ntors_per_tap()),
+ ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
+
+ /* How long would it take to process the ntor cells that we expect to
+ * process while draining the tap queue? */
+ ntor_during_tap_usec = estimated_usec_for_onionskins(
+ MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
+ ol_entries[ONION_HANDSHAKE_TYPE_TAP] * num_ntors_per_tap()),
+ ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
+
+ /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
+ * this. */
+ if (type == ONION_HANDSHAKE_TYPE_NTOR &&
+ (ntor_usec + tap_during_ntor_usec) / 1000 >
+ (uint64_t)options->MaxOnionQueueDelay)
+ return 0;
+
+ if (type == ONION_HANDSHAKE_TYPE_TAP &&
+ (tap_usec + ntor_during_tap_usec) / 1000 >
+ (uint64_t)options->MaxOnionQueueDelay)
+ return 0;
+
+#ifdef CURVE25519_ENABLED
+ /* If we support the ntor handshake, then don't let TAP handshakes use
+ * more than 2/3 of the space on the queue. */
+ if (type == ONION_HANDSHAKE_TYPE_TAP &&
+ tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3)
+ return 0;
+#else
+ (void) type;
+#endif
+
+ return 1;
+}
/** Add <b>circ</b> to the end of ol_list and return 0, except
* if ol_list is too long, in which case do nothing and return -1.
*/
int
-onion_pending_add(or_circuit_t *circ, char *onionskin)
+onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
{
onion_queue_t *tmp;
time_t now = time(NULL);
+ if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
+ log_warn(LD_BUG, "Handshake %d out of range! Dropping.",
+ onionskin->handshake_type);
+ return -1;
+ }
+
tmp = tor_malloc_zero(sizeof(onion_queue_t));
tmp->circ = circ;
+ tmp->handshake_type = onionskin->handshake_type;
tmp->onionskin = onionskin;
tmp->when_added = now;
- if (!ol_tail) {
- tor_assert(!ol_list);
- tor_assert(!ol_length);
- ol_list = tmp;
- ol_tail = tmp;
- ol_length++;
- return 0;
- }
-
- tor_assert(ol_list);
- tor_assert(!ol_tail->next);
-
- if (ol_length >= get_options()->MaxOnionsPending) {
+ if (!have_room_for_onionskin(onionskin->handshake_type)) {
#define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60)
static ratelim_t last_warned =
RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
char *m;
- if ((m = rate_limit_log(&last_warned, approx_time()))) {
+ if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR &&
+ (m = rate_limit_log(&last_warned, approx_time()))) {
log_warn(LD_GENERAL,
"Your computer is too slow to handle this many circuit "
"creation requests! Please consider using the "
@@ -80,13 +164,24 @@ onion_pending_add(or_circuit_t *circ, char *onionskin)
return -1;
}
- ol_length++;
- ol_tail->next = tmp;
- ol_tail = tmp;
- while ((int)(now - ol_list->when_added) >= ONIONQUEUE_WAIT_CUTOFF) {
- /* cull elderly requests. */
- circ = ol_list->circ;
- onion_pending_remove(ol_list->circ);
+ ++ol_entries[onionskin->handshake_type];
+ log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.",
+ onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
+ ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
+ ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
+
+ circ->onionqueue_entry = tmp;
+ TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next);
+
+ /* cull elderly requests. */
+ while (1) {
+ onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]);
+ if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF)
+ break;
+
+ circ = head->circ;
+ circ->onionqueue_entry = NULL;
+ onion_queue_entry_remove(head);
log_info(LD_CIRC,
"Circuit create request is too old; canceling due to overload.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
@@ -94,355 +189,993 @@ onion_pending_add(or_circuit_t *circ, char *onionskin)
return 0;
}
-/** Remove the first item from ol_list and return it, or return
- * NULL if the list is empty.
+/** Return a fairness parameter, to prefer processing NTOR style
+ * handshakes but still slowly drain the TAP queue so we don't starve
+ * it entirely. */
+static int
+num_ntors_per_tap(void)
+{
+#define DEFAULT_NUM_NTORS_PER_TAP 10
+#define MIN_NUM_NTORS_PER_TAP 1
+#define MAX_NUM_NTORS_PER_TAP 100000
+
+ return networkstatus_get_param(NULL, "NumNTorsPerTAP",
+ DEFAULT_NUM_NTORS_PER_TAP,
+ MIN_NUM_NTORS_PER_TAP,
+ MAX_NUM_NTORS_PER_TAP);
+}
+
+/** Choose which onion queue we'll pull from next. If one is empty choose
+ * the other; if they both have elements, load balance across them but
+ * favoring NTOR. */
+static uint16_t
+decide_next_handshake_type(void)
+{
+ /* The number of times we've chosen ntor lately when both were available. */
+ static int recently_chosen_ntors = 0;
+
+ if (!ol_entries[ONION_HANDSHAKE_TYPE_NTOR])
+ return ONION_HANDSHAKE_TYPE_TAP; /* no ntors? try tap */
+
+ if (!ol_entries[ONION_HANDSHAKE_TYPE_TAP]) {
+
+ /* Nick wants us to prioritize new tap requests when there aren't
+ * any in the queue and we've processed k ntor cells since the last
+ * tap cell. This strategy is maybe a good idea, since it starves tap
+ * less in the case where tap is rare, or maybe a poor idea, since it
+ * makes the new tap cell unfairly jump in front of ntor cells that
+ * got here first. In any case this edge case will only become relevant
+ * once tap is rare. We should reevaluate whether we like this decision
+ * once tap gets more rare. */
+ if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] &&
+ recently_chosen_ntors <= num_ntors_per_tap())
+ ++recently_chosen_ntors;
+
+ return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */
+ }
+
+ /* They both have something queued. Pick ntor if we haven't done that
+ * too much lately. */
+ if (++recently_chosen_ntors <= num_ntors_per_tap()) {
+ return ONION_HANDSHAKE_TYPE_NTOR;
+ }
+
+ /* Else, it's time to let tap have its turn. */
+ recently_chosen_ntors = 0;
+ return ONION_HANDSHAKE_TYPE_TAP;
+}
+
+/** Remove the highest priority item from ol_list[] and return it, or
+ * return NULL if the lists are empty.
*/
or_circuit_t *
-onion_next_task(char **onionskin_out)
+onion_next_task(create_cell_t **onionskin_out)
{
or_circuit_t *circ;
+ uint16_t handshake_to_choose = decide_next_handshake_type();
+ onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[handshake_to_choose]);
- if (!ol_list)
+ if (!head)
return NULL; /* no onions pending, we're done */
- tor_assert(ol_list->circ);
- tor_assert(ol_list->circ->p_conn); /* make sure it's still valid */
- tor_assert(ol_length > 0);
- circ = ol_list->circ;
- *onionskin_out = ol_list->onionskin;
- ol_list->onionskin = NULL; /* prevent free. */
- onion_pending_remove(ol_list->circ);
+ tor_assert(head->circ);
+ tor_assert(head->handshake_type <= MAX_ONION_HANDSHAKE_TYPE);
+// tor_assert(head->circ->p_chan); /* make sure it's still valid */
+/* XXX I only commented out the above line to make the unit tests
+ * more manageable. That's probably not good long-term. -RD */
+ circ = head->circ;
+ if (head->onionskin)
+ --ol_entries[head->handshake_type];
+ log_info(LD_OR, "Processing create (%s). Queues now ntor=%d and tap=%d.",
+ head->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
+ ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
+ ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
+
+ *onionskin_out = head->onionskin;
+ head->onionskin = NULL; /* prevent free. */
+ circ->onionqueue_entry = NULL;
+ onion_queue_entry_remove(head);
return circ;
}
+/** Return the number of <b>handshake_type</b>-style create requests pending.
+ */
+int
+onion_num_pending(uint16_t handshake_type)
+{
+ return ol_entries[handshake_type];
+}
+
/** Go through ol_list, find the onion_queue_t element which points to
* circ, remove and free that element. Leave circ itself alone.
*/
void
onion_pending_remove(or_circuit_t *circ)
{
- onion_queue_t *tmpo, *victim;
-
- if (!ol_list)
- return; /* nothing here. */
-
- /* first check to see if it's the first entry */
- tmpo = ol_list;
- if (tmpo->circ == circ) {
- /* it's the first one. remove it from the list. */
- ol_list = tmpo->next;
- if (!ol_list)
- ol_tail = NULL;
- ol_length--;
- victim = tmpo;
- } else { /* we need to hunt through the rest of the list */
- for ( ;tmpo->next && tmpo->next->circ != circ; tmpo=tmpo->next) ;
- if (!tmpo->next) {
- log_debug(LD_GENERAL,
- "circ (p_circ_id %d) not in list, probably at cpuworker.",
- circ->p_circ_id);
- return;
- }
- /* now we know tmpo->next->circ == circ */
- victim = tmpo->next;
- tmpo->next = victim->next;
- if (ol_tail == victim)
- ol_tail = tmpo;
- ol_length--;
+ onion_queue_t *victim;
+
+ if (!circ)
+ return;
+
+ victim = circ->onionqueue_entry;
+ if (victim)
+ onion_queue_entry_remove(victim);
+}
+
+/** Remove a queue entry <b>victim</b> from the queue, unlinking it from
+ * its circuit and freeing it and any structures it owns.*/
+static void
+onion_queue_entry_remove(onion_queue_t *victim)
+{
+ if (victim->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
+ log_warn(LD_BUG, "Handshake %d out of range! Dropping.",
+ victim->handshake_type);
+ /* XXX leaks */
+ return;
}
- /* now victim points to the element that needs to be removed */
+ TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next);
+
+ if (victim->circ)
+ victim->circ->onionqueue_entry = NULL;
+
+ if (victim->onionskin)
+ --ol_entries[victim->handshake_type];
tor_free(victim->onionskin);
tor_free(victim);
}
-/*----------------------------------------------------------------------*/
+/** Remove all circuits from the pending list. Called from tor_free_all. */
+void
+clear_pending_onions(void)
+{
+ onion_queue_t *victim;
+ int i;
+ for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) {
+ while ((victim = TOR_TAILQ_FIRST(&ol_list[i]))) {
+ onion_queue_entry_remove(victim);
+ }
+ }
+ memset(ol_entries, 0, sizeof(ol_entries));
+}
-/** Given a router's 128 byte public key,
- * stores the following in onion_skin_out:
- * - [42 bytes] OAEP padding
- * - [16 bytes] Symmetric key for encrypting blob past RSA
- * - [70 bytes] g^x part 1 (inside the RSA)
- * - [58 bytes] g^x part 2 (symmetrically encrypted)
- *
- * Stores the DH private key into handshake_state_out for later completion
- * of the handshake.
- *
- * The meeting point/cookies and auth are zeroed out for now.
+/* ============================================================ */
+
+/** Fill in a server_onion_keys_t object at <b>keys</b> with all of the keys
+ * and other info we might need to do onion handshakes. (We make a copy of
+ * our keys for each cpuworker to avoid race conditions with the main thread,
+ * and to avoid locking) */
+void
+setup_server_onion_keys(server_onion_keys_t *keys)
+{
+ memset(keys, 0, sizeof(server_onion_keys_t));
+ memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN);
+ dup_onion_keys(&keys->onion_key, &keys->last_onion_key);
+#ifdef CURVE25519_ENABLED
+ keys->curve25519_key_map = construct_ntor_key_map();
+ keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t));
+ curve25519_keypair_generate(keys->junk_keypair, 0);
+#endif
+}
+
+/** Release all storage held in <b>keys</b>, but do not free <b>keys</b>
+ * itself (as it's likely to be stack-allocated.) */
+void
+release_server_onion_keys(server_onion_keys_t *keys)
+{
+ if (! keys)
+ return;
+
+ crypto_pk_free(keys->onion_key);
+ crypto_pk_free(keys->last_onion_key);
+#ifdef CURVE25519_ENABLED
+ ntor_key_map_free(keys->curve25519_key_map);
+ tor_free(keys->junk_keypair);
+#endif
+ memset(keys, 0, sizeof(server_onion_keys_t));
+}
+
+/** Release whatever storage is held in <b>state</b>, depending on its
+ * type, and clear its pointer. */
+void
+onion_handshake_state_release(onion_handshake_state_t *state)
+{
+ switch (state->tag) {
+ case ONION_HANDSHAKE_TYPE_TAP:
+ crypto_dh_free(state->u.tap);
+ state->u.tap = NULL;
+ break;
+ case ONION_HANDSHAKE_TYPE_FAST:
+ fast_handshake_state_free(state->u.fast);
+ state->u.fast = NULL;
+ break;
+#ifdef CURVE25519_ENABLED
+ case ONION_HANDSHAKE_TYPE_NTOR:
+ ntor_handshake_state_free(state->u.ntor);
+ state->u.ntor = NULL;
+ break;
+#endif
+ default:
+ log_warn(LD_BUG, "called with unknown handshake state type %d",
+ (int)state->tag);
+ tor_fragile_assert();
+ }
+}
+
+/** Perform the first step of a circuit-creation handshake of type <b>type</b>
+ * (one of ONION_HANDSHAKE_TYPE_*): generate the initial "onion skin" in
+ * <b>onion_skin_out</b>, and store any state information in <b>state_out</b>.
+ * Return -1 on failure, and the length of the onionskin on acceptance.
*/
int
-onion_skin_create(crypto_pk_t *dest_router_key,
- crypto_dh_t **handshake_state_out,
- char *onion_skin_out) /* ONIONSKIN_CHALLENGE_LEN bytes */
+onion_skin_create(int type,
+ const extend_info_t *node,
+ onion_handshake_state_t *state_out,
+ uint8_t *onion_skin_out)
{
- char challenge[DH_KEY_LEN];
- crypto_dh_t *dh = NULL;
- int dhbytes, pkbytes;
-
- tor_assert(dest_router_key);
- tor_assert(handshake_state_out);
- tor_assert(onion_skin_out);
- *handshake_state_out = NULL;
- memset(onion_skin_out, 0, ONIONSKIN_CHALLENGE_LEN);
+ int r = -1;
- if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
- goto err;
+ switch (type) {
+ case ONION_HANDSHAKE_TYPE_TAP:
+ if (!node->onion_key)
+ return -1;
- dhbytes = crypto_dh_get_bytes(dh);
- pkbytes = (int) crypto_pk_keysize(dest_router_key);
- tor_assert(dhbytes == 128);
- tor_assert(pkbytes == 128);
+ if (onion_skin_TAP_create(node->onion_key,
+ &state_out->u.tap,
+ (char*)onion_skin_out) < 0)
+ return -1;
- if (crypto_dh_get_public(dh, challenge, dhbytes))
- goto err;
+ r = TAP_ONIONSKIN_CHALLENGE_LEN;
+ break;
+ case ONION_HANDSHAKE_TYPE_FAST:
+ if (fast_onionskin_create(&state_out->u.fast, onion_skin_out) < 0)
+ return -1;
- note_crypto_pk_op(ENC_ONIONSKIN);
+ r = CREATE_FAST_LEN;
+ break;
+ case ONION_HANDSHAKE_TYPE_NTOR:
+#ifdef CURVE25519_ENABLED
+ if (tor_mem_is_zero((const char*)node->curve25519_onion_key.public_key,
+ CURVE25519_PUBKEY_LEN))
+ return -1;
+ if (onion_skin_ntor_create((const uint8_t*)node->identity_digest,
+ &node->curve25519_onion_key,
+ &state_out->u.ntor,
+ onion_skin_out) < 0)
+ return -1;
- /* set meeting point, meeting cookie, etc here. Leave zero for now. */
- if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out,
- ONIONSKIN_CHALLENGE_LEN,
- challenge, DH_KEY_LEN,
- PK_PKCS1_OAEP_PADDING, 1)<0)
- goto err;
+ r = NTOR_ONIONSKIN_LEN;
+#else
+ return -1;
+#endif
+ break;
+ default:
+ log_warn(LD_BUG, "called with unknown handshake state type %d", type);
+ tor_fragile_assert();
+ r = -1;
+ }
- memwipe(challenge, 0, sizeof(challenge));
- *handshake_state_out = dh;
+ if (r > 0)
+ state_out->tag = (uint16_t) type;
- return 0;
- err:
- memwipe(challenge, 0, sizeof(challenge));
- if (dh) crypto_dh_free(dh);
- return -1;
+ return r;
}
-/** Given an encrypted DH public key as generated by onion_skin_create,
- * and the private key for this onion router, generate the reply (128-byte
- * DH plus the first 20 bytes of shared key material), and store the
- * next key_out_len bytes of key material in key_out.
+/** Perform the second (server-side) step of a circuit-creation handshake of
+ * type <b>type</b>, responding to the client request in <b>onion_skin</b>
+ * using the keys in <b>keys</b>. On success, write our response into
+ * <b>reply_out</b>, generate <b>keys_out_len</b> bytes worth of key material
+ * in <b>keys_out_len</b>, a hidden service nonce to <b>rend_nonce_out</b>,
+ * and return the length of the reply. On failure, return -1.
*/
int
-onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/
- crypto_pk_t *private_key,
- crypto_pk_t *prev_private_key,
- char *handshake_reply_out, /*ONIONSKIN_REPLY_LEN*/
- char *key_out,
- size_t key_out_len)
+onion_skin_server_handshake(int type,
+ const uint8_t *onion_skin, size_t onionskin_len,
+ const server_onion_keys_t *keys,
+ uint8_t *reply_out,
+ uint8_t *keys_out, size_t keys_out_len,
+ uint8_t *rend_nonce_out)
{
- char challenge[ONIONSKIN_CHALLENGE_LEN];
- crypto_dh_t *dh = NULL;
- ssize_t len;
- char *key_material=NULL;
- size_t key_material_len=0;
- int i;
- crypto_pk_t *k;
+ int r = -1;
- len = -1;
- for (i=0;i<2;++i) {
- k = i==0?private_key:prev_private_key;
- if (!k)
- break;
- note_crypto_pk_op(DEC_ONIONSKIN);
- len = crypto_pk_private_hybrid_decrypt(k, challenge,
- ONIONSKIN_CHALLENGE_LEN,
- onion_skin, ONIONSKIN_CHALLENGE_LEN,
- PK_PKCS1_OAEP_PADDING,0);
- if (len>0)
- break;
+ switch (type) {
+ case ONION_HANDSHAKE_TYPE_TAP:
+ if (onionskin_len != TAP_ONIONSKIN_CHALLENGE_LEN)
+ return -1;
+ if (onion_skin_TAP_server_handshake((const char*)onion_skin,
+ keys->onion_key, keys->last_onion_key,
+ (char*)reply_out,
+ (char*)keys_out, keys_out_len)<0)
+ return -1;
+ r = TAP_ONIONSKIN_REPLY_LEN;
+ memcpy(rend_nonce_out, reply_out+DH_KEY_LEN, DIGEST_LEN);
+ break;
+ case ONION_HANDSHAKE_TYPE_FAST:
+ if (onionskin_len != CREATE_FAST_LEN)
+ return -1;
+ if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0)
+ return -1;
+ r = CREATED_FAST_LEN;
+ memcpy(rend_nonce_out, reply_out+DIGEST_LEN, DIGEST_LEN);
+ break;
+ case ONION_HANDSHAKE_TYPE_NTOR:
+#ifdef CURVE25519_ENABLED
+ if (onionskin_len < NTOR_ONIONSKIN_LEN)
+ return -1;
+ {
+ size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+ uint8_t *keys_tmp = tor_malloc(keys_out_len + DIGEST_LEN);
+
+ if (onion_skin_ntor_server_handshake(
+ onion_skin, keys->curve25519_key_map,
+ keys->junk_keypair,
+ keys->my_identity,
+ reply_out, keys_tmp, keys_tmp_len)<0) {
+ tor_free(keys_tmp);
+ return -1;
+ }
+ memcpy(keys_out, keys_tmp, keys_out_len);
+ memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN);
+ memwipe(keys_tmp, 0, keys_tmp_len);
+ tor_free(keys_tmp);
+ r = NTOR_REPLY_LEN;
+ }
+#else
+ return -1;
+#endif
+ break;
+ default:
+ log_warn(LD_BUG, "called with unknown handshake state type %d", type);
+ tor_fragile_assert();
+ return -1;
}
- if (len<0) {
- log_info(LD_PROTOCOL,
- "Couldn't decrypt onionskin: client may be using old onion key");
- goto err;
- } else if (len != DH_KEY_LEN) {
- log_warn(LD_PROTOCOL, "Unexpected onionskin length after decryption: %ld",
- (long)len);
- goto err;
+
+ return r;
+}
+
+/** Perform the final (client-side) step of a circuit-creation handshake of
+ * type <b>type</b>, using our state in <b>handshake_state</b> and the
+ * server's response in <b>reply</b>. On success, generate <b>keys_out_len</b>
+ * bytes worth of key material in <b>keys_out_len</b>, set
+ * <b>rend_authenticator_out</b> to the "KH" field that can be used to
+ * establish introduction points at this hop, and return 0. On failure,
+ * return -1. */
+int
+onion_skin_client_handshake(int type,
+ const onion_handshake_state_t *handshake_state,
+ const uint8_t *reply, size_t reply_len,
+ uint8_t *keys_out, size_t keys_out_len,
+ uint8_t *rend_authenticator_out)
+{
+ if (handshake_state->tag != type)
+ return -1;
+
+ switch (type) {
+ case ONION_HANDSHAKE_TYPE_TAP:
+ if (reply_len != TAP_ONIONSKIN_REPLY_LEN)
+ return -1;
+ if (onion_skin_TAP_client_handshake(handshake_state->u.tap,
+ (const char*)reply,
+ (char *)keys_out, keys_out_len) < 0)
+ return -1;
+
+ memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN);
+
+ return 0;
+ case ONION_HANDSHAKE_TYPE_FAST:
+ if (reply_len != CREATED_FAST_LEN)
+ return -1;
+ if (fast_client_handshake(handshake_state->u.fast, reply,
+ keys_out, keys_out_len) < 0)
+ return -1;
+
+ memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN);
+ return 0;
+#ifdef CURVE25519_ENABLED
+ case ONION_HANDSHAKE_TYPE_NTOR:
+ if (reply_len < NTOR_REPLY_LEN)
+ return -1;
+ {
+ size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+ uint8_t *keys_tmp = tor_malloc(keys_tmp_len);
+ if (onion_skin_ntor_client_handshake(handshake_state->u.ntor,
+ reply,
+ keys_tmp, keys_tmp_len) < 0) {
+ tor_free(keys_tmp);
+ return -1;
+ }
+ memcpy(keys_out, keys_tmp, keys_out_len);
+ memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN);
+ memwipe(keys_tmp, 0, keys_tmp_len);
+ tor_free(keys_tmp);
+ }
+ return 0;
+#endif
+ default:
+ log_warn(LD_BUG, "called with unknown handshake state type %d", type);
+ tor_fragile_assert();
+ return -1;
}
+}
- dh = crypto_dh_new(DH_TYPE_CIRCUIT);
- if (!dh) {
- log_warn(LD_BUG, "Couldn't allocate DH key");
- goto err;
+/** Helper: return 0 if <b>cell</b> appears valid, -1 otherwise. If
+ * <b>unknown_ok</b> is true, allow cells with handshake types we don't
+ * recognize. */
+static int
+check_create_cell(const create_cell_t *cell, int unknown_ok)
+{
+ switch (cell->cell_type) {
+ case CELL_CREATE:
+ if (cell->handshake_type != ONION_HANDSHAKE_TYPE_TAP &&
+ cell->handshake_type != ONION_HANDSHAKE_TYPE_NTOR)
+ return -1;
+ break;
+ case CELL_CREATE_FAST:
+ if (cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST)
+ return -1;
+ break;
+ case CELL_CREATE2:
+ break;
+ default:
+ return -1;
}
- if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN)) {
- log_info(LD_GENERAL, "crypto_dh_get_public failed.");
- goto err;
+
+ switch (cell->handshake_type) {
+ case ONION_HANDSHAKE_TYPE_TAP:
+ if (cell->handshake_len != TAP_ONIONSKIN_CHALLENGE_LEN)
+ return -1;
+ break;
+ case ONION_HANDSHAKE_TYPE_FAST:
+ if (cell->handshake_len != CREATE_FAST_LEN)
+ return -1;
+ break;
+#ifdef CURVE25519_ENABLED
+ case ONION_HANDSHAKE_TYPE_NTOR:
+ if (cell->handshake_len != NTOR_ONIONSKIN_LEN)
+ return -1;
+ break;
+#endif
+ default:
+ if (! unknown_ok)
+ return -1;
}
- key_material_len = DIGEST_LEN+key_out_len;
- key_material = tor_malloc(key_material_len);
- len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge,
- DH_KEY_LEN, key_material,
- key_material_len);
- if (len < 0) {
- log_info(LD_GENERAL, "crypto_dh_compute_secret failed.");
- goto err;
+ return 0;
+}
+
+/** Write the various parameters into the create cell. Separate from
+ * create_cell_parse() to make unit testing easier.
+ */
+void
+create_cell_init(create_cell_t *cell_out, uint8_t cell_type,
+ uint16_t handshake_type, uint16_t handshake_len,
+ const uint8_t *onionskin)
+{
+ memset(cell_out, 0, sizeof(*cell_out));
+
+ cell_out->cell_type = cell_type;
+ cell_out->handshake_type = handshake_type;
+ cell_out->handshake_len = handshake_len;
+ memcpy(cell_out->onionskin, onionskin, handshake_len);
+}
+
+/** Helper: parse the CREATE2 payload at <b>p</b>, which could be up to
+ * <b>p_len</b> bytes long, and use it to fill the fields of
+ * <b>cell_out</b>. Return 0 on success and -1 on failure.
+ *
+ * Note that part of the body of an EXTEND2 cell is a CREATE2 payload, so
+ * this function is also used for parsing those.
+ */
+static int
+parse_create2_payload(create_cell_t *cell_out, const uint8_t *p, size_t p_len)
+{
+ uint16_t handshake_type, handshake_len;
+
+ if (p_len < 4)
+ return -1;
+
+ handshake_type = ntohs(get_uint16(p));
+ handshake_len = ntohs(get_uint16(p+2));
+
+ if (handshake_len > CELL_PAYLOAD_SIZE - 4 || handshake_len > p_len - 4)
+ return -1;
+ if (handshake_type == ONION_HANDSHAKE_TYPE_FAST)
+ return -1;
+
+ create_cell_init(cell_out, CELL_CREATE2, handshake_type, handshake_len,
+ p+4);
+ return 0;
+}
+
+/** Magic string which, in a CREATE or EXTEND cell, indicates that a seeming
+ * TAP payload is really an ntor payload. We'd do away with this if every
+ * relay supported EXTEND2, but we want to be able to extend from A to B with
+ * ntor even when A doesn't understand EXTEND2 and so can't generate a
+ * CREATE2 cell.
+ **/
+#define NTOR_CREATE_MAGIC "ntorNTORntorNTOR"
+
+/** Parse a CREATE, CREATE_FAST, or CREATE2 cell from <b>cell_in</b> into
+ * <b>cell_out</b>. Return 0 on success, -1 on failure. (We reject some
+ * syntactically valid CREATE2 cells that we can't generate or react to.) */
+int
+create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in)
+{
+ switch (cell_in->command) {
+ case CELL_CREATE:
+ if (tor_memeq(cell_in->payload, NTOR_CREATE_MAGIC, 16)) {
+ create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
+ NTOR_ONIONSKIN_LEN, cell_in->payload+16);
+ } else {
+ create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
+ TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->payload);
+ }
+ break;
+ case CELL_CREATE_FAST:
+ create_cell_init(cell_out, CELL_CREATE_FAST, ONION_HANDSHAKE_TYPE_FAST,
+ CREATE_FAST_LEN, cell_in->payload);
+ break;
+ case CELL_CREATE2:
+ if (parse_create2_payload(cell_out, cell_in->payload,
+ CELL_PAYLOAD_SIZE) < 0)
+ return -1;
+ break;
+ default:
+ return -1;
}
- /* send back H(K|0) as proof that we learned K. */
- memcpy(handshake_reply_out+DH_KEY_LEN, key_material, DIGEST_LEN);
+ return check_create_cell(cell_out, 0);
+}
- /* use the rest of the key material for our shared keys, digests, etc */
- memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
+/** Helper: return 0 if <b>cell</b> appears valid, -1 otherwise. */
+static int
+check_created_cell(const created_cell_t *cell)
+{
+ switch (cell->cell_type) {
+ case CELL_CREATED:
+ if (cell->handshake_len != TAP_ONIONSKIN_REPLY_LEN &&
+ cell->handshake_len != NTOR_REPLY_LEN)
+ return -1;
+ break;
+ case CELL_CREATED_FAST:
+ if (cell->handshake_len != CREATED_FAST_LEN)
+ return -1;
+ break;
+ case CELL_CREATED2:
+ if (cell->handshake_len > RELAY_PAYLOAD_SIZE-2)
+ return -1;
+ break;
+ }
- memwipe(challenge, 0, sizeof(challenge));
- memwipe(key_material, 0, key_material_len);
- tor_free(key_material);
- crypto_dh_free(dh);
return 0;
- err:
- memwipe(challenge, 0, sizeof(challenge));
- if (key_material) {
- memwipe(key_material, 0, key_material_len);
- tor_free(key_material);
+}
+
+/** Parse a CREATED, CREATED_FAST, or CREATED2 cell from <b>cell_in</b> into
+ * <b>cell_out</b>. Return 0 on success, -1 on failure. */
+int
+created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in)
+{
+ memset(cell_out, 0, sizeof(*cell_out));
+
+ switch (cell_in->command) {
+ case CELL_CREATED:
+ cell_out->cell_type = CELL_CREATED;
+ cell_out->handshake_len = TAP_ONIONSKIN_REPLY_LEN;
+ memcpy(cell_out->reply, cell_in->payload, TAP_ONIONSKIN_REPLY_LEN);
+ break;
+ case CELL_CREATED_FAST:
+ cell_out->cell_type = CELL_CREATED_FAST;
+ cell_out->handshake_len = CREATED_FAST_LEN;
+ memcpy(cell_out->reply, cell_in->payload, CREATED_FAST_LEN);
+ break;
+ case CELL_CREATED2:
+ {
+ const uint8_t *p = cell_in->payload;
+ cell_out->cell_type = CELL_CREATED2;
+ cell_out->handshake_len = ntohs(get_uint16(p));
+ if (cell_out->handshake_len > CELL_PAYLOAD_SIZE - 2)
+ return -1;
+ memcpy(cell_out->reply, p+2, cell_out->handshake_len);
+ break;
+ }
}
- if (dh) crypto_dh_free(dh);
- return -1;
+ return check_created_cell(cell_out);
}
-/** Finish the client side of the DH handshake.
- * Given the 128 byte DH reply + 20 byte hash as generated by
- * onion_skin_server_handshake and the handshake state generated by
- * onion_skin_create, verify H(K) with the first 20 bytes of shared
- * key material, then generate key_out_len more bytes of shared key
- * material and store them in key_out.
- *
- * After the invocation, call crypto_dh_free on handshake_state.
+/** Helper: return 0 if <b>cell</b> appears valid, -1 otherwise. */
+static int
+check_extend_cell(const extend_cell_t *cell)
+{
+ if (tor_digest_is_zero((const char*)cell->node_id))
+ return -1;
+ /* We don't currently allow EXTEND2 cells without an IPv4 address */
+ if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC)
+ return -1;
+ if (cell->create_cell.cell_type == CELL_CREATE) {
+ if (cell->cell_type != RELAY_COMMAND_EXTEND)
+ return -1;
+ } else if (cell->create_cell.cell_type == CELL_CREATE2) {
+ if (cell->cell_type != RELAY_COMMAND_EXTEND2 &&
+ cell->cell_type != RELAY_COMMAND_EXTEND)
+ return -1;
+ } else {
+ /* In particular, no CREATE_FAST cells are allowed */
+ return -1;
+ }
+ if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST)
+ return -1;
+
+ return check_create_cell(&cell->create_cell, 1);
+}
+
+/** Protocol constants for specifier types in EXTEND2
+ * @{
*/
+#define SPECTYPE_IPV4 0
+#define SPECTYPE_IPV6 1
+#define SPECTYPE_LEGACY_ID 2
+/** @} */
+
+/** Parse an EXTEND or EXTEND2 cell (according to <b>command</b>) from the
+ * <b>payload_length</b> bytes of <b>payload</b> into <b>cell_out</b>. Return
+ * 0 on success, -1 on failure. */
int
-onion_skin_client_handshake(crypto_dh_t *handshake_state,
- const char *handshake_reply, /* ONIONSKIN_REPLY_LEN bytes */
- char *key_out,
- size_t key_out_len)
+extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
+ const uint8_t *payload, size_t payload_length)
{
- ssize_t len;
- char *key_material=NULL;
- size_t key_material_len;
- tor_assert(crypto_dh_get_bytes(handshake_state) == DH_KEY_LEN);
-
- key_material_len = DIGEST_LEN + key_out_len;
- key_material = tor_malloc(key_material_len);
- len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state,
- handshake_reply, DH_KEY_LEN, key_material,
- key_material_len);
- if (len < 0)
- goto err;
-
- if (tor_memneq(key_material, handshake_reply+DH_KEY_LEN, DIGEST_LEN)) {
- /* H(K) does *not* match. Something fishy. */
- log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on onion handshake. "
- "Bug or attack.");
- goto err;
+ const uint8_t *eop;
+
+ memset(cell_out, 0, sizeof(*cell_out));
+ if (payload_length > RELAY_PAYLOAD_SIZE)
+ return -1;
+ eop = payload + payload_length;
+
+ switch (command) {
+ case RELAY_COMMAND_EXTEND:
+ {
+ if (payload_length != 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN)
+ return -1;
+
+ cell_out->cell_type = RELAY_COMMAND_EXTEND;
+ tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr, get_uint32(payload));
+ cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4));
+ tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
+ if (tor_memeq(payload + 6, NTOR_CREATE_MAGIC, 16)) {
+ cell_out->create_cell.cell_type = CELL_CREATE2;
+ cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_NTOR;
+ cell_out->create_cell.handshake_len = NTOR_ONIONSKIN_LEN;
+ memcpy(cell_out->create_cell.onionskin, payload + 22,
+ NTOR_ONIONSKIN_LEN);
+ } else {
+ cell_out->create_cell.cell_type = CELL_CREATE;
+ cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
+ cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
+ memcpy(cell_out->create_cell.onionskin, payload + 6,
+ TAP_ONIONSKIN_CHALLENGE_LEN);
+ }
+ memcpy(cell_out->node_id, payload + 6 + TAP_ONIONSKIN_CHALLENGE_LEN,
+ DIGEST_LEN);
+ break;
+ }
+ case RELAY_COMMAND_EXTEND2:
+ {
+ uint8_t n_specs = *payload, spectype, speclen;
+ int i;
+ int found_ipv4 = 0, found_ipv6 = 0, found_id = 0;
+ tor_addr_make_unspec(&cell_out->orport_ipv4.addr);
+ tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
+
+ cell_out->cell_type = RELAY_COMMAND_EXTEND2;
+ ++payload;
+ /* Parse the specifiers. We'll only take the first IPv4 and first IPv6
+ * addres, and the node ID, and ignore everything else */
+ for (i = 0; i < n_specs; ++i) {
+ if (eop - payload < 2)
+ return -1;
+ spectype = payload[0];
+ speclen = payload[1];
+ payload += 2;
+ if (eop - payload < speclen)
+ return -1;
+ switch (spectype) {
+ case SPECTYPE_IPV4:
+ if (speclen != 6)
+ return -1;
+ if (!found_ipv4) {
+ tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr,
+ get_uint32(payload));
+ cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4));
+ found_ipv4 = 1;
+ }
+ break;
+ case SPECTYPE_IPV6:
+ if (speclen != 18)
+ return -1;
+ if (!found_ipv6) {
+ tor_addr_from_ipv6_bytes(&cell_out->orport_ipv6.addr,
+ (const char*)payload);
+ cell_out->orport_ipv6.port = ntohs(get_uint16(payload+16));
+ found_ipv6 = 1;
+ }
+ break;
+ case SPECTYPE_LEGACY_ID:
+ if (speclen != 20)
+ return -1;
+ if (found_id)
+ return -1;
+ memcpy(cell_out->node_id, payload, 20);
+ found_id = 1;
+ break;
+ }
+ payload += speclen;
+ }
+ if (!found_id || !found_ipv4)
+ return -1;
+ if (parse_create2_payload(&cell_out->create_cell,payload,eop-payload)<0)
+ return -1;
+ break;
+ }
+ default:
+ return -1;
}
- /* use the rest of the key material for our shared keys, digests, etc */
- memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
+ return check_extend_cell(cell_out);
+}
- memwipe(key_material, 0, key_material_len);
- tor_free(key_material);
- return 0;
- err:
- memwipe(key_material, 0, key_material_len);
- tor_free(key_material);
- return -1;
+/** Helper: return 0 if <b>cell</b> appears valid, -1 otherwise. */
+static int
+check_extended_cell(const extended_cell_t *cell)
+{
+ if (cell->created_cell.cell_type == CELL_CREATED) {
+ if (cell->cell_type != RELAY_COMMAND_EXTENDED)
+ return -1;
+ } else if (cell->created_cell.cell_type == CELL_CREATED2) {
+ if (cell->cell_type != RELAY_COMMAND_EXTENDED2)
+ return -1;
+ } else {
+ return -1;
+ }
+
+ return check_created_cell(&cell->created_cell);
}
-/** Implement the server side of the CREATE_FAST abbreviated handshake. The
- * client has provided DIGEST_LEN key bytes in <b>key_in</b> ("x"). We
- * generate a reply of DIGEST_LEN*2 bytes in <b>key_out</b>, consisting of a
- * new random "y", followed by H(x|y) to check for correctness. We set
- * <b>key_out_len</b> bytes of key material in <b>key_out</b>.
- * Return 0 on success, &lt;0 on failure.
- **/
+/** Parse an EXTENDED or EXTENDED2 cell (according to <b>command</b>) from the
+ * <b>payload_length</b> bytes of <b>payload</b> into <b>cell_out</b>. Return
+ * 0 on success, -1 on failure. */
int
-fast_server_handshake(const uint8_t *key_in, /* DIGEST_LEN bytes */
- uint8_t *handshake_reply_out, /* DIGEST_LEN*2 bytes */
- uint8_t *key_out,
- size_t key_out_len)
+extended_cell_parse(extended_cell_t *cell_out,
+ const uint8_t command, const uint8_t *payload,
+ size_t payload_len)
{
- char tmp[DIGEST_LEN+DIGEST_LEN];
- char *out = NULL;
- size_t out_len;
- int r = -1;
+ memset(cell_out, 0, sizeof(*cell_out));
+ if (payload_len > RELAY_PAYLOAD_SIZE)
+ return -1;
+
+ switch (command) {
+ case RELAY_COMMAND_EXTENDED:
+ if (payload_len != TAP_ONIONSKIN_REPLY_LEN)
+ return -1;
+ cell_out->cell_type = RELAY_COMMAND_EXTENDED;
+ cell_out->created_cell.cell_type = CELL_CREATED;
+ cell_out->created_cell.handshake_len = TAP_ONIONSKIN_REPLY_LEN;
+ memcpy(cell_out->created_cell.reply, payload, TAP_ONIONSKIN_REPLY_LEN);
+ break;
+ case RELAY_COMMAND_EXTENDED2:
+ {
+ cell_out->cell_type = RELAY_COMMAND_EXTENDED2;
+ cell_out->created_cell.cell_type = CELL_CREATED2;
+ cell_out->created_cell.handshake_len = ntohs(get_uint16(payload));
+ if (cell_out->created_cell.handshake_len > RELAY_PAYLOAD_SIZE - 2 ||
+ cell_out->created_cell.handshake_len > payload_len - 2)
+ return -1;
+ memcpy(cell_out->created_cell.reply, payload+2,
+ cell_out->created_cell.handshake_len);
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return check_extended_cell(cell_out);
+}
- if (crypto_rand((char*)handshake_reply_out, DIGEST_LEN)<0)
+/** Fill <b>cell_out</b> with a correctly formatted version of the
+ * CREATE{,_FAST,2} cell in <b>cell_in</b>. Return 0 on success, -1 on
+ * failure. This is a cell we didn't originate if <b>relayed</b> is true. */
+static int
+create_cell_format_impl(cell_t *cell_out, const create_cell_t *cell_in,
+ int relayed)
+{
+ uint8_t *p;
+ size_t space;
+ if (check_create_cell(cell_in, relayed) < 0)
return -1;
- memcpy(tmp, key_in, DIGEST_LEN);
- memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN);
- out_len = key_out_len+DIGEST_LEN;
- out = tor_malloc(out_len);
- if (crypto_expand_key_material(tmp, sizeof(tmp), out, out_len)) {
- goto done;
+ memset(cell_out->payload, 0, sizeof(cell_out->payload));
+ cell_out->command = cell_in->cell_type;
+
+ p = cell_out->payload;
+ space = sizeof(cell_out->payload);
+
+ switch (cell_in->cell_type) {
+ case CELL_CREATE:
+ if (cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
+ memcpy(p, NTOR_CREATE_MAGIC, 16);
+ p += 16;
+ space -= 16;
+ }
+ /* Fall through */
+ case CELL_CREATE_FAST:
+ tor_assert(cell_in->handshake_len <= space);
+ memcpy(p, cell_in->onionskin, cell_in->handshake_len);
+ break;
+ case CELL_CREATE2:
+ tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)-4);
+ set_uint16(cell_out->payload, htons(cell_in->handshake_type));
+ set_uint16(cell_out->payload+2, htons(cell_in->handshake_len));
+ memcpy(cell_out->payload + 4, cell_in->onionskin, cell_in->handshake_len);
+ break;
+ default:
+ return -1;
}
- memcpy(handshake_reply_out+DIGEST_LEN, out, DIGEST_LEN);
- memcpy(key_out, out+DIGEST_LEN, key_out_len);
- r = 0;
- done:
- memwipe(tmp, 0, sizeof(tmp));
- memwipe(out, 0, out_len);
- tor_free(out);
- return r;
+
+ return 0;
}
-/** Implement the second half of the client side of the CREATE_FAST handshake.
- * We sent the server <b>handshake_state</b> ("x") already, and the server
- * told us <b>handshake_reply_out</b> (y|H(x|y)). Make sure that the hash is
- * correct, and generate key material in <b>key_out</b>. Return 0 on success,
- * true on failure.
- *
- * NOTE: The "CREATE_FAST" handshake path is distinguishable from regular
- * "onionskin" handshakes, and is not secure if an adversary can see or modify
- * the messages. Therefore, it should only be used by clients, and only as
- * the first hop of a circuit (since the first hop is already authenticated
- * and protected by TLS).
- */
int
-fast_client_handshake(const uint8_t *handshake_state,/*DIGEST_LEN bytes*/
- const uint8_t *handshake_reply_out,/*DIGEST_LEN*2 bytes*/
- uint8_t *key_out,
- size_t key_out_len)
+create_cell_format(cell_t *cell_out, const create_cell_t *cell_in)
{
- char tmp[DIGEST_LEN+DIGEST_LEN];
- char *out;
- size_t out_len;
- int r = -1;
+ return create_cell_format_impl(cell_out, cell_in, 0);
+}
+
+int
+create_cell_format_relayed(cell_t *cell_out, const create_cell_t *cell_in)
+{
+ return create_cell_format_impl(cell_out, cell_in, 1);
+}
- memcpy(tmp, handshake_state, DIGEST_LEN);
- memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN);
- out_len = key_out_len+DIGEST_LEN;
- out = tor_malloc(out_len);
- if (crypto_expand_key_material(tmp, sizeof(tmp), out, out_len)) {
- goto done;
+/** Fill <b>cell_out</b> with a correctly formatted version of the
+ * CREATED{,_FAST,2} cell in <b>cell_in</b>. Return 0 on success, -1 on
+ * failure. */
+int
+created_cell_format(cell_t *cell_out, const created_cell_t *cell_in)
+{
+ if (check_created_cell(cell_in) < 0)
+ return -1;
+
+ memset(cell_out->payload, 0, sizeof(cell_out->payload));
+ cell_out->command = cell_in->cell_type;
+
+ switch (cell_in->cell_type) {
+ case CELL_CREATED:
+ case CELL_CREATED_FAST:
+ tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload));
+ memcpy(cell_out->payload, cell_in->reply, cell_in->handshake_len);
+ break;
+ case CELL_CREATED2:
+ tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)-2);
+ set_uint16(cell_out->payload, htons(cell_in->handshake_len));
+ memcpy(cell_out->payload + 2, cell_in->reply, cell_in->handshake_len);
+ break;
+ default:
+ return -1;
}
- if (tor_memneq(out, handshake_reply_out+DIGEST_LEN, DIGEST_LEN)) {
- /* H(K) does *not* match. Something fishy. */
- log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on fast handshake. "
- "Bug or attack.");
- goto done;
+ return 0;
+}
+
+/** Format the EXTEND{,2} cell in <b>cell_in</b>, storing its relay payload in
+ * <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the
+ * relay command in *<b>command_out</b>. The <b>payload_out</b> must have
+ * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */
+int
+extend_cell_format(uint8_t *command_out, uint16_t *len_out,
+ uint8_t *payload_out, const extend_cell_t *cell_in)
+{
+ uint8_t *p, *eop;
+ if (check_extend_cell(cell_in) < 0)
+ return -1;
+
+ p = payload_out;
+ eop = payload_out + RELAY_PAYLOAD_SIZE;
+
+ memset(p, 0, RELAY_PAYLOAD_SIZE);
+
+ switch (cell_in->cell_type) {
+ case RELAY_COMMAND_EXTEND:
+ {
+ *command_out = RELAY_COMMAND_EXTEND;
+ *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN;
+ set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr));
+ set_uint16(p+4, ntohs(cell_in->orport_ipv4.port));
+ if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
+ memcpy(p+6, NTOR_CREATE_MAGIC, 16);
+ memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN);
+ } else {
+ memcpy(p+6, cell_in->create_cell.onionskin,
+ TAP_ONIONSKIN_CHALLENGE_LEN);
+ }
+ memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN);
+ }
+ break;
+ case RELAY_COMMAND_EXTEND2:
+ {
+ uint8_t n = 2;
+ *command_out = RELAY_COMMAND_EXTEND2;
+
+ *p++ = n; /* 2 identifiers */
+ *p++ = SPECTYPE_IPV4; /* First is IPV4. */
+ *p++ = 6; /* It's 6 bytes long. */
+ set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr));
+ set_uint16(p+4, htons(cell_in->orport_ipv4.port));
+ p += 6;
+ *p++ = SPECTYPE_LEGACY_ID; /* Next is an identity digest. */
+ *p++ = 20; /* It's 20 bytes long */
+ memcpy(p, cell_in->node_id, DIGEST_LEN);
+ p += 20;
+
+ /* Now we can send the handshake */
+ set_uint16(p, htons(cell_in->create_cell.handshake_type));
+ set_uint16(p+2, htons(cell_in->create_cell.handshake_len));
+ p += 4;
+
+ if (cell_in->create_cell.handshake_len > eop - p)
+ return -1;
+
+ memcpy(p, cell_in->create_cell.onionskin,
+ cell_in->create_cell.handshake_len);
+
+ p += cell_in->create_cell.handshake_len;
+ *len_out = p - payload_out;
+ }
+ break;
+ default:
+ return -1;
}
- memcpy(key_out, out+DIGEST_LEN, key_out_len);
- r = 0;
- done:
- memwipe(tmp, 0, sizeof(tmp));
- memwipe(out, 0, out_len);
- tor_free(out);
- return r;
+
+ return 0;
}
-/** Remove all circuits from the pending list. Called from tor_free_all. */
-void
-clear_pending_onions(void)
+/** Format the EXTENDED{,2} cell in <b>cell_in</b>, storing its relay payload
+ * in <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the
+ * relay command in *<b>command_out</b>. The <b>payload_out</b> must have
+ * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */
+int
+extended_cell_format(uint8_t *command_out, uint16_t *len_out,
+ uint8_t *payload_out, const extended_cell_t *cell_in)
{
- while (ol_list) {
- onion_queue_t *victim = ol_list;
- ol_list = victim->next;
- tor_free(victim->onionskin);
- tor_free(victim);
+ uint8_t *p;
+ if (check_extended_cell(cell_in) < 0)
+ return -1;
+
+ p = payload_out;
+ memset(p, 0, RELAY_PAYLOAD_SIZE);
+
+ switch (cell_in->cell_type) {
+ case RELAY_COMMAND_EXTENDED:
+ {
+ *command_out = RELAY_COMMAND_EXTENDED;
+ *len_out = TAP_ONIONSKIN_REPLY_LEN;
+ memcpy(payload_out, cell_in->created_cell.reply,
+ TAP_ONIONSKIN_REPLY_LEN);
+ }
+ break;
+ case RELAY_COMMAND_EXTENDED2:
+ {
+ *command_out = RELAY_COMMAND_EXTENDED2;
+ *len_out = 2 + cell_in->created_cell.handshake_len;
+ set_uint16(payload_out, htons(cell_in->created_cell.handshake_len));
+ if (2+cell_in->created_cell.handshake_len > RELAY_PAYLOAD_SIZE)
+ return -1;
+ memcpy(payload_out+2, cell_in->created_cell.reply,
+ cell_in->created_cell.handshake_len);
+ }
+ break;
+ default:
+ return -1;
}
- ol_list = ol_tail = NULL;
- ol_length = 0;
+
+ return 0;
}
diff --git a/src/or/onion.h b/src/or/onion.h
index 7e0f873c7..d62f032b8 100644
--- a/src/or/onion.h
+++ b/src/or/onion.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,40 +9,114 @@
* \brief Header file for onion.c.
**/
-#ifndef _TOR_ONION_H
-#define _TOR_ONION_H
+#ifndef TOR_ONION_H
+#define TOR_ONION_H
-int onion_pending_add(or_circuit_t *circ, char *onionskin);
-or_circuit_t *onion_next_task(char **onionskin_out);
+struct create_cell_t;
+int onion_pending_add(or_circuit_t *circ, struct create_cell_t *onionskin);
+or_circuit_t *onion_next_task(struct create_cell_t **onionskin_out);
+int onion_num_pending(uint16_t handshake_type);
void onion_pending_remove(or_circuit_t *circ);
+void clear_pending_onions(void);
+
+typedef struct server_onion_keys_t {
+ uint8_t my_identity[DIGEST_LEN];
+ crypto_pk_t *onion_key;
+ crypto_pk_t *last_onion_key;
+#ifdef CURVE25519_ENABLED
+ di_digest256_map_t *curve25519_key_map;
+ curve25519_keypair_t *junk_keypair;
+#endif
+} server_onion_keys_t;
-int onion_skin_create(crypto_pk_t *router_key,
- crypto_dh_t **handshake_state_out,
- char *onion_skin_out);
+#define MAX_ONIONSKIN_CHALLENGE_LEN 255
+#define MAX_ONIONSKIN_REPLY_LEN 255
-int onion_skin_server_handshake(const char *onion_skin,
- crypto_pk_t *private_key,
- crypto_pk_t *prev_private_key,
- char *handshake_reply_out,
- char *key_out,
- size_t key_out_len);
+void setup_server_onion_keys(server_onion_keys_t *keys);
+void release_server_onion_keys(server_onion_keys_t *keys);
-int onion_skin_client_handshake(crypto_dh_t *handshake_state,
- const char *handshake_reply,
- char *key_out,
- size_t key_out_len);
+void onion_handshake_state_release(onion_handshake_state_t *state);
-int fast_server_handshake(const uint8_t *key_in,
- uint8_t *handshake_reply_out,
- uint8_t *key_out,
- size_t key_out_len);
+int onion_skin_create(int type,
+ const extend_info_t *node,
+ onion_handshake_state_t *state_out,
+ uint8_t *onion_skin_out);
+int onion_skin_server_handshake(int type,
+ const uint8_t *onion_skin, size_t onionskin_len,
+ const server_onion_keys_t *keys,
+ uint8_t *reply_out,
+ uint8_t *keys_out, size_t key_out_len,
+ uint8_t *rend_nonce_out);
+int onion_skin_client_handshake(int type,
+ const onion_handshake_state_t *handshake_state,
+ const uint8_t *reply, size_t reply_len,
+ uint8_t *keys_out, size_t key_out_len,
+ uint8_t *rend_authenticator_out);
-int fast_client_handshake(const uint8_t *handshake_state,
- const uint8_t *handshake_reply_out,
- uint8_t *key_out,
- size_t key_out_len);
+/** A parsed CREATE, CREATE_FAST, or CREATE2 cell. */
+typedef struct create_cell_t {
+ /** The cell command. One of CREATE{,_FAST,2} */
+ uint8_t cell_type;
+ /** One of the ONION_HANDSHAKE_TYPE_* values */
+ uint16_t handshake_type;
+ /** The number of bytes used in <b>onionskin</b>. */
+ uint16_t handshake_len;
+ /** The client-side message for the circuit creation handshake. */
+ uint8_t onionskin[CELL_PAYLOAD_SIZE - 4];
+} create_cell_t;
-void clear_pending_onions(void);
+/** A parsed CREATED, CREATED_FAST, or CREATED2 cell. */
+typedef struct created_cell_t {
+ /** The cell command. One of CREATED{,_FAST,2} */
+ uint8_t cell_type;
+ /** The number of bytes used in <b>reply</b>. */
+ uint16_t handshake_len;
+ /** The server-side message for the circuit creation handshake. */
+ uint8_t reply[CELL_PAYLOAD_SIZE - 2];
+} created_cell_t;
+
+/** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */
+typedef struct extend_cell_t {
+ /** One of RELAY_EXTEND or RELAY_EXTEND2 */
+ uint8_t cell_type;
+ /** An IPv4 address and port for the node we're connecting to. */
+ tor_addr_port_t orport_ipv4;
+ /** An IPv6 address and port for the node we're connecting to. Not currently
+ * used. */
+ tor_addr_port_t orport_ipv6;
+ /** Identity fingerprint of the node we're conecting to.*/
+ uint8_t node_id[DIGEST_LEN];
+ /** The "create cell" embedded in this extend cell. Note that unlike the
+ * create cells we generate ourself, this once can have a handshake type we
+ * don't recognize. */
+ create_cell_t create_cell;
+} extend_cell_t;
+
+/** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */
+typedef struct extended_cell_t {
+ /** One of RELAY_EXTENDED or RELAY_EXTENDED2. */
+ uint8_t cell_type;
+ /** The "created cell" embedded in this extended cell. */
+ created_cell_t created_cell;
+} extended_cell_t;
+
+void create_cell_init(create_cell_t *cell_out, uint8_t cell_type,
+ uint16_t handshake_type, uint16_t handshake_len,
+ const uint8_t *onionskin);
+int create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in);
+int created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in);
+int extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
+ const uint8_t *payload_in, size_t payload_len);
+int extended_cell_parse(extended_cell_t *cell_out, const uint8_t command,
+ const uint8_t *payload_in, size_t payload_len);
+
+int create_cell_format(cell_t *cell_out, const create_cell_t *cell_in);
+int create_cell_format_relayed(cell_t *cell_out, const create_cell_t *cell_in);
+int created_cell_format(cell_t *cell_out, const created_cell_t *cell_in);
+int extend_cell_format(uint8_t *command_out, uint16_t *len_out,
+ uint8_t *payload_out, const extend_cell_t *cell_in);
+int extended_cell_format(uint8_t *command_out, uint16_t *len_out,
+ uint8_t *payload_out, const extended_cell_t *cell_in);
#endif
diff --git a/src/or/onion_fast.c b/src/or/onion_fast.c
new file mode 100644
index 000000000..aa034a8bd
--- /dev/null
+++ b/src/or/onion_fast.c
@@ -0,0 +1,123 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file onion_fast.c
+ * \brief Functions implement the CREATE_FAST circuit handshake.
+ **/
+
+#include "or.h"
+#include "onion_fast.h"
+
+/** Release all state held in <b>victim</b>. */
+void
+fast_handshake_state_free(fast_handshake_state_t *victim)
+{
+ if (! victim)
+ return;
+ memwipe(victim, 0, sizeof(fast_handshake_state_t));
+ tor_free(victim);
+}
+
+/** Create the state needed to perform a CREATE_FAST hasnshake. Return 0
+ * on success, -1 on failure. */
+int
+fast_onionskin_create(fast_handshake_state_t **handshake_state_out,
+ uint8_t *handshake_out)
+{
+ fast_handshake_state_t *s;
+ *handshake_state_out = s = tor_malloc(sizeof(fast_handshake_state_t));
+ if (crypto_rand((char*)s->state, sizeof(s->state)) < 0) {
+ tor_free(s);
+ return -1;
+ }
+ memcpy(handshake_out, s->state, DIGEST_LEN);
+ return 0;
+}
+
+/** Implement the server side of the CREATE_FAST abbreviated handshake. The
+ * client has provided DIGEST_LEN key bytes in <b>key_in</b> ("x"). We
+ * generate a reply of DIGEST_LEN*2 bytes in <b>key_out</b>, consisting of a
+ * new random "y", followed by H(x|y) to check for correctness. We set
+ * <b>key_out_len</b> bytes of key material in <b>key_out</b>.
+ * Return 0 on success, &lt;0 on failure.
+ **/
+int
+fast_server_handshake(const uint8_t *key_in, /* DIGEST_LEN bytes */
+ uint8_t *handshake_reply_out, /* DIGEST_LEN*2 bytes */
+ uint8_t *key_out,
+ size_t key_out_len)
+{
+ uint8_t tmp[DIGEST_LEN+DIGEST_LEN];
+ uint8_t *out = NULL;
+ size_t out_len;
+ int r = -1;
+
+ if (crypto_rand((char*)handshake_reply_out, DIGEST_LEN)<0)
+ return -1;
+
+ memcpy(tmp, key_in, DIGEST_LEN);
+ memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN);
+ out_len = key_out_len+DIGEST_LEN;
+ out = tor_malloc(out_len);
+ if (crypto_expand_key_material_TAP(tmp, sizeof(tmp), out, out_len)) {
+ goto done;
+ }
+ memcpy(handshake_reply_out+DIGEST_LEN, out, DIGEST_LEN);
+ memcpy(key_out, out+DIGEST_LEN, key_out_len);
+ r = 0;
+ done:
+ memwipe(tmp, 0, sizeof(tmp));
+ memwipe(out, 0, out_len);
+ tor_free(out);
+ return r;
+}
+
+/** Implement the second half of the client side of the CREATE_FAST handshake.
+ * We sent the server <b>handshake_state</b> ("x") already, and the server
+ * told us <b>handshake_reply_out</b> (y|H(x|y)). Make sure that the hash is
+ * correct, and generate key material in <b>key_out</b>. Return 0 on success,
+ * true on failure.
+ *
+ * NOTE: The "CREATE_FAST" handshake path is distinguishable from regular
+ * "onionskin" handshakes, and is not secure if an adversary can see or modify
+ * the messages. Therefore, it should only be used by clients, and only as
+ * the first hop of a circuit (since the first hop is already authenticated
+ * and protected by TLS).
+ */
+int
+fast_client_handshake(const fast_handshake_state_t *handshake_state,
+ const uint8_t *handshake_reply_out,/*DIGEST_LEN*2 bytes*/
+ uint8_t *key_out,
+ size_t key_out_len)
+{
+ uint8_t tmp[DIGEST_LEN+DIGEST_LEN];
+ uint8_t *out;
+ size_t out_len;
+ int r = -1;
+
+ memcpy(tmp, handshake_state->state, DIGEST_LEN);
+ memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN);
+ out_len = key_out_len+DIGEST_LEN;
+ out = tor_malloc(out_len);
+ if (crypto_expand_key_material_TAP(tmp, sizeof(tmp), out, out_len)) {
+ goto done;
+ }
+ if (tor_memneq(out, handshake_reply_out+DIGEST_LEN, DIGEST_LEN)) {
+ /* H(K) does *not* match. Something fishy. */
+ log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on fast handshake. "
+ "Bug or attack.");
+ goto done;
+ }
+ memcpy(key_out, out+DIGEST_LEN, key_out_len);
+ r = 0;
+ done:
+ memwipe(tmp, 0, sizeof(tmp));
+ memwipe(out, 0, out_len);
+ tor_free(out);
+ return r;
+}
+
diff --git a/src/or/onion_fast.h b/src/or/onion_fast.h
new file mode 100644
index 000000000..8c078378d
--- /dev/null
+++ b/src/or/onion_fast.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file onion_fast.h
+ * \brief Header file for onion_fast.c.
+ **/
+
+#ifndef TOR_ONION_FAST_H
+#define TOR_ONION_FAST_H
+
+#define CREATE_FAST_LEN DIGEST_LEN
+#define CREATED_FAST_LEN (DIGEST_LEN*2)
+
+typedef struct fast_handshake_state_t {
+ uint8_t state[DIGEST_LEN];
+} fast_handshake_state_t;
+
+void fast_handshake_state_free(fast_handshake_state_t *victim);
+
+int fast_onionskin_create(fast_handshake_state_t **handshake_state_out,
+ uint8_t *handshake_out);
+
+int fast_server_handshake(const uint8_t *message_in,
+ uint8_t *handshake_reply_out,
+ uint8_t *key_out,
+ size_t key_out_len);
+
+int fast_client_handshake(const fast_handshake_state_t *handshake_state,
+ const uint8_t *handshake_reply_out,
+ uint8_t *key_out,
+ size_t key_out_len);
+
+#endif
+
diff --git a/src/or/onion_ntor.c b/src/or/onion_ntor.c
new file mode 100644
index 000000000..9cf7d5dd6
--- /dev/null
+++ b/src/or/onion_ntor.c
@@ -0,0 +1,295 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#include "crypto.h"
+#define ONION_NTOR_PRIVATE
+#include "onion_ntor.h"
+#include "torlog.h"
+#include "util.h"
+
+/** Free storage held in an ntor handshake state. */
+void
+ntor_handshake_state_free(ntor_handshake_state_t *state)
+{
+ if (!state)
+ return;
+ memwipe(state, 0, sizeof(*state));
+ tor_free(state);
+}
+
+/** Convenience function to represent HMAC_SHA256 as our instantiation of
+ * ntor's "tweaked hash'. Hash the <b>inp_len</b> bytes at <b>inp</b> into
+ * a DIGEST256_LEN-byte digest at <b>out</b>, with the hash changing
+ * depending on the value of <b>tweak</b>. */
+static void
+h_tweak(uint8_t *out,
+ const uint8_t *inp, size_t inp_len,
+ const char *tweak)
+{
+ size_t tweak_len = strlen(tweak);
+ crypto_hmac_sha256((char*)out, tweak, tweak_len, (const char*)inp, inp_len);
+}
+
+/** Wrapper around a set of tweak-values for use with the ntor handshake. */
+typedef struct tweakset_t {
+ const char *t_mac;
+ const char *t_key;
+ const char *t_verify;
+ const char *m_expand;
+} tweakset_t;
+
+/** The tweaks to be used with our handshake. */
+const tweakset_t proto1_tweaks = {
+#define PROTOID "ntor-curve25519-sha256-1"
+#define PROTOID_LEN 24
+ PROTOID ":mac",
+ PROTOID ":key_extract",
+ PROTOID ":verify",
+ PROTOID ":key_expand"
+};
+
+/** Convenience macro: copy <b>len</b> bytes from <b>inp</b> to <b>ptr</b>,
+ * and advance <b>ptr</b> by the number of bytes copied. */
+#define APPEND(ptr, inp, len) \
+ STMT_BEGIN { \
+ memcpy(ptr, (inp), (len)); \
+ ptr += len; \
+ } STMT_END
+
+/**
+ * Compute the first client-side step of the ntor handshake for communicating
+ * with a server whose DIGEST_LEN-byte server identity is <b>router_id</b>,
+ * and whose onion key is <b>router_key</b>. Store the NTOR_ONIONSKIN_LEN-byte
+ * message in <b>onion_skin_out</b>, and store the handshake state in
+ * *<b>handshake_state_out</b>. Return 0 on success, -1 on failure.
+ */
+int
+onion_skin_ntor_create(const uint8_t *router_id,
+ const curve25519_public_key_t *router_key,
+ ntor_handshake_state_t **handshake_state_out,
+ uint8_t *onion_skin_out)
+{
+ ntor_handshake_state_t *state;
+ uint8_t *op;
+
+ state = tor_malloc_zero(sizeof(ntor_handshake_state_t));
+
+ memcpy(state->router_id, router_id, DIGEST_LEN);
+ memcpy(&state->pubkey_B, router_key, sizeof(curve25519_public_key_t));
+ if (curve25519_secret_key_generate(&state->seckey_x, 0) < 0) {
+ tor_free(state);
+ return -1;
+ }
+ curve25519_public_key_generate(&state->pubkey_X, &state->seckey_x);
+
+ op = onion_skin_out;
+ APPEND(op, router_id, DIGEST_LEN);
+ APPEND(op, router_key->public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(op, state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
+ tor_assert(op == onion_skin_out + NTOR_ONIONSKIN_LEN);
+
+ *handshake_state_out = state;
+
+ return 0;
+}
+
+#define SERVER_STR "Server"
+#define SERVER_STR_LEN 6
+
+#define SECRET_INPUT_LEN (CURVE25519_PUBKEY_LEN * 3 + \
+ CURVE25519_OUTPUT_LEN * 2 + \
+ DIGEST_LEN + PROTOID_LEN)
+#define AUTH_INPUT_LEN (DIGEST256_LEN + DIGEST_LEN + \
+ CURVE25519_PUBKEY_LEN*3 + \
+ PROTOID_LEN + SERVER_STR_LEN)
+
+/**
+ * Perform the server side of an ntor handshake. Given an
+ * NTOR_ONIONSKIN_LEN-byte message in <b>onion_skin</b>, our own identity
+ * fingerprint as <b>my_node_id</b>, and an associative array mapping public
+ * onion keys to curve25519_keypair_t in <b>private_keys</b>, attempt to
+ * perform the handshake. Use <b>junk_keys</b> if present if the handshake
+ * indicates an unrecognized public key. Write an NTOR_REPLY_LEN-byte
+ * message to send back to the client into <b>handshake_reply_out</b>, and
+ * generate <b>key_out_len</b> bytes of key material in <b>key_out</b>. Return
+ * 0 on success, -1 on failure.
+ */
+int
+onion_skin_ntor_server_handshake(const uint8_t *onion_skin,
+ const di_digest256_map_t *private_keys,
+ const curve25519_keypair_t *junk_keys,
+ const uint8_t *my_node_id,
+ uint8_t *handshake_reply_out,
+ uint8_t *key_out,
+ size_t key_out_len)
+{
+ const tweakset_t *T = &proto1_tweaks;
+ /* Sensitive stack-allocated material. Kept in an anonymous struct to make
+ * it easy to wipe. */
+ struct {
+ uint8_t secret_input[SECRET_INPUT_LEN];
+ uint8_t auth_input[AUTH_INPUT_LEN];
+ curve25519_public_key_t pubkey_X;
+ curve25519_secret_key_t seckey_y;
+ curve25519_public_key_t pubkey_Y;
+ uint8_t verify[DIGEST256_LEN];
+ } s;
+ uint8_t *si = s.secret_input, *ai = s.auth_input;
+ const curve25519_keypair_t *keypair_bB;
+ int bad;
+
+ /* Decode the onion skin */
+ /* XXXX Does this possible early-return business threaten our security? */
+ if (tor_memneq(onion_skin, my_node_id, DIGEST_LEN))
+ return -1;
+ /* Note that on key-not-found, we go through with this operation anyway,
+ * using "junk_keys". This will result in failed authentication, but won't
+ * leak whether we recognized the key. */
+ keypair_bB = dimap_search(private_keys, onion_skin + DIGEST_LEN,
+ (void*)junk_keys);
+ if (!keypair_bB)
+ return -1;
+
+ memcpy(s.pubkey_X.public_key, onion_skin+DIGEST_LEN+DIGEST256_LEN,
+ CURVE25519_PUBKEY_LEN);
+
+ /* Make y, Y */
+ curve25519_secret_key_generate(&s.seckey_y, 0);
+ curve25519_public_key_generate(&s.pubkey_Y, &s.seckey_y);
+
+ /* NOTE: If we ever use a group other than curve25519, or a different
+ * representation for its points, we may need to perform different or
+ * additional checks on X here and on Y in the client handshake, or lose our
+ * security properties. What checks we need would depend on the properties
+ * of the group and its representation.
+ *
+ * In short: if you use anything other than curve25519, this aspect of the
+ * code will need to be reconsidered carefully. */
+
+ /* build secret_input */
+ curve25519_handshake(si, &s.seckey_y, &s.pubkey_X);
+ bad = safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
+ si += CURVE25519_OUTPUT_LEN;
+ curve25519_handshake(si, &keypair_bB->seckey, &s.pubkey_X);
+ bad |= safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
+ si += CURVE25519_OUTPUT_LEN;
+
+ APPEND(si, my_node_id, DIGEST_LEN);
+ APPEND(si, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(si, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(si, PROTOID, PROTOID_LEN);
+ tor_assert(si == s.secret_input + sizeof(s.secret_input));
+
+ /* Compute hashes of secret_input */
+ h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify);
+
+ /* Compute auth_input */
+ APPEND(ai, s.verify, DIGEST256_LEN);
+ APPEND(ai, my_node_id, DIGEST_LEN);
+ APPEND(ai, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(ai, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(ai, PROTOID, PROTOID_LEN);
+ APPEND(ai, SERVER_STR, SERVER_STR_LEN);
+ tor_assert(ai == s.auth_input + sizeof(s.auth_input));
+
+ /* Build the reply */
+ memcpy(handshake_reply_out, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
+ h_tweak(handshake_reply_out+CURVE25519_PUBKEY_LEN,
+ s.auth_input, sizeof(s.auth_input),
+ T->t_mac);
+
+ /* Generate the key material */
+ crypto_expand_key_material_rfc5869_sha256(
+ s.secret_input, sizeof(s.secret_input),
+ (const uint8_t*)T->t_key, strlen(T->t_key),
+ (const uint8_t*)T->m_expand, strlen(T->m_expand),
+ key_out, key_out_len);
+
+ /* Wipe all of our local state */
+ memwipe(&s, 0, sizeof(s));
+
+ return bad ? -1 : 0;
+}
+
+/**
+ * Perform the final client side of the ntor handshake, using the state in
+ * <b>handshake_state</b> and the server's NTOR_REPLY_LEN-byte reply in
+ * <b>handshake_reply</b>. Generate <b>key_out_len</b> bytes of key material
+ * in <b>key_out</b>. Return 0 on success, -1 on failure.
+ */
+int
+onion_skin_ntor_client_handshake(
+ const ntor_handshake_state_t *handshake_state,
+ const uint8_t *handshake_reply,
+ uint8_t *key_out,
+ size_t key_out_len)
+{
+ const tweakset_t *T = &proto1_tweaks;
+ /* Sensitive stack-allocated material. Kept in an anonymous struct to make
+ * it easy to wipe. */
+ struct {
+ curve25519_public_key_t pubkey_Y;
+ uint8_t secret_input[SECRET_INPUT_LEN];
+ uint8_t verify[DIGEST256_LEN];
+ uint8_t auth_input[AUTH_INPUT_LEN];
+ uint8_t auth[DIGEST256_LEN];
+ } s;
+ uint8_t *ai = s.auth_input, *si = s.secret_input;
+ const uint8_t *auth_candidate;
+ int bad;
+
+ /* Decode input */
+ memcpy(s.pubkey_Y.public_key, handshake_reply, CURVE25519_PUBKEY_LEN);
+ auth_candidate = handshake_reply + CURVE25519_PUBKEY_LEN;
+
+ /* See note in server_handshake above about checking points. The
+ * circumstances under which we'd need to check Y for membership are
+ * different than those under which we'd be checking X. */
+
+ /* Compute secret_input */
+ curve25519_handshake(si, &handshake_state->seckey_x, &s.pubkey_Y);
+ bad = safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
+ si += CURVE25519_OUTPUT_LEN;
+ curve25519_handshake(si, &handshake_state->seckey_x,
+ &handshake_state->pubkey_B);
+ bad |= safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
+ si += CURVE25519_OUTPUT_LEN;
+ APPEND(si, handshake_state->router_id, DIGEST_LEN);
+ APPEND(si, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(si, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(si, PROTOID, PROTOID_LEN);
+ tor_assert(si == s.secret_input + sizeof(s.secret_input));
+
+ /* Compute verify from secret_input */
+ h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify);
+
+ /* Compute auth_input */
+ APPEND(ai, s.verify, DIGEST256_LEN);
+ APPEND(ai, handshake_state->router_id, DIGEST_LEN);
+ APPEND(ai, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(ai, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
+ APPEND(ai, PROTOID, PROTOID_LEN);
+ APPEND(ai, SERVER_STR, SERVER_STR_LEN);
+ tor_assert(ai == s.auth_input + sizeof(s.auth_input));
+
+ /* Compute auth */
+ h_tweak(s.auth, s.auth_input, sizeof(s.auth_input), T->t_mac);
+
+ bad |= tor_memneq(s.auth, auth_candidate, DIGEST256_LEN);
+
+ crypto_expand_key_material_rfc5869_sha256(
+ s.secret_input, sizeof(s.secret_input),
+ (const uint8_t*)T->t_key, strlen(T->t_key),
+ (const uint8_t*)T->m_expand, strlen(T->m_expand),
+ key_out, key_out_len);
+
+ memwipe(&s, 0, sizeof(s));
+ return bad ? -1 : 0;
+}
+
diff --git a/src/or/onion_ntor.h b/src/or/onion_ntor.h
new file mode 100644
index 000000000..c942e6e0f
--- /dev/null
+++ b/src/or/onion_ntor.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_ONION_NTOR_H
+#define TOR_ONION_NTOR_H
+
+#include "torint.h"
+#include "crypto_curve25519.h"
+#include "di_ops.h"
+
+/** State to be maintained by a client between sending an ntor onionskin
+ * and receiving a reply. */
+typedef struct ntor_handshake_state_t ntor_handshake_state_t;
+
+/** Length of an ntor onionskin, as sent from the client to server. */
+#define NTOR_ONIONSKIN_LEN 84
+/** Length of an ntor reply, as sent from server to client. */
+#define NTOR_REPLY_LEN 64
+
+#ifdef CURVE25519_ENABLED
+void ntor_handshake_state_free(ntor_handshake_state_t *state);
+
+int onion_skin_ntor_create(const uint8_t *router_id,
+ const curve25519_public_key_t *router_key,
+ ntor_handshake_state_t **handshake_state_out,
+ uint8_t *onion_skin_out);
+
+int onion_skin_ntor_server_handshake(const uint8_t *onion_skin,
+ const di_digest256_map_t *private_keys,
+ const curve25519_keypair_t *junk_keypair,
+ const uint8_t *my_node_id,
+ uint8_t *handshake_reply_out,
+ uint8_t *key_out,
+ size_t key_out_len);
+
+int onion_skin_ntor_client_handshake(
+ const ntor_handshake_state_t *handshake_state,
+ const uint8_t *handshake_reply,
+ uint8_t *key_out,
+ size_t key_out_len);
+
+#ifdef ONION_NTOR_PRIVATE
+
+/** Storage held by a client while waiting for an ntor reply from a server. */
+struct ntor_handshake_state_t {
+ /** Identity digest of the router we're talking to. */
+ uint8_t router_id[DIGEST_LEN];
+ /** Onion key of the router we're talking to. */
+ curve25519_public_key_t pubkey_B;
+
+ /**
+ * Short-lived keypair for use with this handshake.
+ * @{ */
+ curve25519_secret_key_t seckey_x;
+ curve25519_public_key_t pubkey_X;
+ /** @} */
+};
+#endif
+
+#endif
+
+#endif
+
diff --git a/src/or/onion_tap.c b/src/or/onion_tap.c
new file mode 100644
index 000000000..3782e75ab
--- /dev/null
+++ b/src/or/onion_tap.c
@@ -0,0 +1,218 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file onion_tap.c
+ * \brief Functions to implement the original Tor circuit extension handshake
+ * (a.k.a TAP).
+ *
+ * We didn't call it "TAP" ourselves -- Ian Goldberg named it in "On the
+ * Security of the Tor Authentication Protocol". (Spoiler: it's secure, but
+ * its security is kind of fragile and implementation dependent. Never modify
+ * this implementation without reading and understanding that paper at least.)
+ **/
+
+#include "or.h"
+#include "config.h"
+#include "onion_tap.h"
+#include "rephist.h"
+
+/*----------------------------------------------------------------------*/
+
+/** Given a router's 128 byte public key,
+ * stores the following in onion_skin_out:
+ * - [42 bytes] OAEP padding
+ * - [16 bytes] Symmetric key for encrypting blob past RSA
+ * - [70 bytes] g^x part 1 (inside the RSA)
+ * - [58 bytes] g^x part 2 (symmetrically encrypted)
+ *
+ * Stores the DH private key into handshake_state_out for later completion
+ * of the handshake.
+ *
+ * The meeting point/cookies and auth are zeroed out for now.
+ */
+int
+onion_skin_TAP_create(crypto_pk_t *dest_router_key,
+ crypto_dh_t **handshake_state_out,
+ char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
+{
+ char challenge[DH_KEY_LEN];
+ crypto_dh_t *dh = NULL;
+ int dhbytes, pkbytes;
+
+ tor_assert(dest_router_key);
+ tor_assert(handshake_state_out);
+ tor_assert(onion_skin_out);
+ *handshake_state_out = NULL;
+ memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
+
+ if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
+ goto err;
+
+ dhbytes = crypto_dh_get_bytes(dh);
+ pkbytes = (int) crypto_pk_keysize(dest_router_key);
+ tor_assert(dhbytes == 128);
+ tor_assert(pkbytes == 128);
+
+ if (crypto_dh_get_public(dh, challenge, dhbytes))
+ goto err;
+
+ note_crypto_pk_op(ENC_ONIONSKIN);
+
+ /* set meeting point, meeting cookie, etc here. Leave zero for now. */
+ if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out,
+ TAP_ONIONSKIN_CHALLENGE_LEN,
+ challenge, DH_KEY_LEN,
+ PK_PKCS1_OAEP_PADDING, 1)<0)
+ goto err;
+
+ memwipe(challenge, 0, sizeof(challenge));
+ *handshake_state_out = dh;
+
+ return 0;
+ err:
+ memwipe(challenge, 0, sizeof(challenge));
+ if (dh) crypto_dh_free(dh);
+ return -1;
+}
+
+/** Given an encrypted DH public key as generated by onion_skin_create,
+ * and the private key for this onion router, generate the reply (128-byte
+ * DH plus the first 20 bytes of shared key material), and store the
+ * next key_out_len bytes of key material in key_out.
+ */
+int
+onion_skin_TAP_server_handshake(
+ /*TAP_ONIONSKIN_CHALLENGE_LEN*/
+ const char *onion_skin,
+ crypto_pk_t *private_key,
+ crypto_pk_t *prev_private_key,
+ /*TAP_ONIONSKIN_REPLY_LEN*/
+ char *handshake_reply_out,
+ char *key_out,
+ size_t key_out_len)
+{
+ char challenge[TAP_ONIONSKIN_CHALLENGE_LEN];
+ crypto_dh_t *dh = NULL;
+ ssize_t len;
+ char *key_material=NULL;
+ size_t key_material_len=0;
+ int i;
+ crypto_pk_t *k;
+
+ len = -1;
+ for (i=0;i<2;++i) {
+ k = i==0?private_key:prev_private_key;
+ if (!k)
+ break;
+ note_crypto_pk_op(DEC_ONIONSKIN);
+ len = crypto_pk_private_hybrid_decrypt(k, challenge,
+ TAP_ONIONSKIN_CHALLENGE_LEN,
+ onion_skin,
+ TAP_ONIONSKIN_CHALLENGE_LEN,
+ PK_PKCS1_OAEP_PADDING,0);
+ if (len>0)
+ break;
+ }
+ if (len<0) {
+ log_info(LD_PROTOCOL,
+ "Couldn't decrypt onionskin: client may be using old onion key");
+ goto err;
+ } else if (len != DH_KEY_LEN) {
+ log_warn(LD_PROTOCOL, "Unexpected onionskin length after decryption: %ld",
+ (long)len);
+ goto err;
+ }
+
+ dh = crypto_dh_new(DH_TYPE_CIRCUIT);
+ if (!dh) {
+ log_warn(LD_BUG, "Couldn't allocate DH key");
+ goto err;
+ }
+ if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN)) {
+ log_info(LD_GENERAL, "crypto_dh_get_public failed.");
+ goto err;
+ }
+
+ key_material_len = DIGEST_LEN+key_out_len;
+ key_material = tor_malloc(key_material_len);
+ len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge,
+ DH_KEY_LEN, key_material,
+ key_material_len);
+ if (len < 0) {
+ log_info(LD_GENERAL, "crypto_dh_compute_secret failed.");
+ goto err;
+ }
+
+ /* send back H(K|0) as proof that we learned K. */
+ memcpy(handshake_reply_out+DH_KEY_LEN, key_material, DIGEST_LEN);
+
+ /* use the rest of the key material for our shared keys, digests, etc */
+ memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
+
+ memwipe(challenge, 0, sizeof(challenge));
+ memwipe(key_material, 0, key_material_len);
+ tor_free(key_material);
+ crypto_dh_free(dh);
+ return 0;
+ err:
+ memwipe(challenge, 0, sizeof(challenge));
+ if (key_material) {
+ memwipe(key_material, 0, key_material_len);
+ tor_free(key_material);
+ }
+ if (dh) crypto_dh_free(dh);
+
+ return -1;
+}
+
+/** Finish the client side of the DH handshake.
+ * Given the 128 byte DH reply + 20 byte hash as generated by
+ * onion_skin_server_handshake and the handshake state generated by
+ * onion_skin_create, verify H(K) with the first 20 bytes of shared
+ * key material, then generate key_out_len more bytes of shared key
+ * material and store them in key_out.
+ *
+ * After the invocation, call crypto_dh_free on handshake_state.
+ */
+int
+onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
+ const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */
+ char *key_out,
+ size_t key_out_len)
+{
+ ssize_t len;
+ char *key_material=NULL;
+ size_t key_material_len;
+ tor_assert(crypto_dh_get_bytes(handshake_state) == DH_KEY_LEN);
+
+ key_material_len = DIGEST_LEN + key_out_len;
+ key_material = tor_malloc(key_material_len);
+ len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state,
+ handshake_reply, DH_KEY_LEN, key_material,
+ key_material_len);
+ if (len < 0)
+ goto err;
+
+ if (tor_memneq(key_material, handshake_reply+DH_KEY_LEN, DIGEST_LEN)) {
+ /* H(K) does *not* match. Something fishy. */
+ log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on onion handshake. "
+ "Bug or attack.");
+ goto err;
+ }
+
+ /* use the rest of the key material for our shared keys, digests, etc */
+ memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
+
+ memwipe(key_material, 0, key_material_len);
+ tor_free(key_material);
+ return 0;
+ err:
+ memwipe(key_material, 0, key_material_len);
+ tor_free(key_material);
+ return -1;
+}
+
diff --git a/src/or/onion_tap.h b/src/or/onion_tap.h
new file mode 100644
index 000000000..b978b6673
--- /dev/null
+++ b/src/or/onion_tap.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file onion_tap.h
+ * \brief Header file for onion_tap.c.
+ **/
+
+#ifndef TOR_ONION_TAP_H
+#define TOR_ONION_TAP_H
+
+#define TAP_ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\
+ CIPHER_KEY_LEN+\
+ DH_KEY_LEN)
+#define TAP_ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN)
+
+int onion_skin_TAP_create(crypto_pk_t *router_key,
+ crypto_dh_t **handshake_state_out,
+ char *onion_skin_out);
+
+int onion_skin_TAP_server_handshake(const char *onion_skin,
+ crypto_pk_t *private_key,
+ crypto_pk_t *prev_private_key,
+ char *handshake_reply_out,
+ char *key_out,
+ size_t key_out_len);
+
+int onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
+ const char *handshake_reply,
+ char *key_out,
+ size_t key_out_len);
+
+#endif
+
diff --git a/src/or/or.h b/src/or/or.h
index 462239190..5318b0fe5 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Master header file for Tor-specific functionality.
**/
-#ifndef _TOR_OR_H
-#define _TOR_OR_H
+#ifndef TOR_OR_H
+#define TOR_OR_H
#include "orconfig.h"
@@ -81,7 +81,6 @@
#include <process.h>
#include <direct.h>
#include <windows.h>
-#define snprintf _snprintf
#endif
#ifdef USE_BUFFEREVENTS
@@ -98,6 +97,8 @@
#include "address.h"
#include "compat_libevent.h"
#include "ht.h"
+#include "replaycache.h"
+#include "crypto_curve25519.h"
/* These signals are defined to help handle_control_signal work.
*/
@@ -176,8 +177,6 @@
#define MIN_ONION_KEY_LIFETIME (7*24*60*60)
/** How often do we rotate TLS contexts? */
#define MAX_SSL_KEY_LIFETIME_INTERNAL (2*60*60)
-/** What expiry time shall we place on our SSL certs? */
-#define MAX_SSL_KEY_LIFETIME_ADVERTISED (365*24*60*60)
/** How old do we allow a router to get before removing it
* from the router list? In seconds. */
@@ -197,7 +196,7 @@ typedef enum {
CIRC_ID_TYPE_NEITHER=2
} circ_id_type_t;
-#define _CONN_TYPE_MIN 3
+#define CONN_TYPE_MIN_ 3
/** Type for sockets listening for OR connections. */
#define CONN_TYPE_OR_LISTENER 3
/** A bidirectional TLS connection transmitting a sequence of cells.
@@ -228,8 +227,8 @@ typedef enum {
#define CONN_TYPE_AP_NATD_LISTENER 14
/** Type for sockets listening for DNS requests. */
#define CONN_TYPE_AP_DNS_LISTENER 15
-#define _CONN_TYPE_MAX 15
-/* !!!! If _CONN_TYPE_MAX is ever over 15, we must grow the type field in
+#define CONN_TYPE_MAX_ 15
+/* !!!! If CONN_TYPE_MAX_ is ever over 15, we must grow the type field in
* connection_t. */
/* Proxy client types */
@@ -269,17 +268,18 @@ typedef enum {
/** State for any listener connection. */
#define LISTENER_STATE_READY 0
-#define _CPUWORKER_STATE_MIN 1
+#define CPUWORKER_STATE_MIN_ 1
/** State for a connection to a cpuworker process that's idle. */
#define CPUWORKER_STATE_IDLE 1
/** State for a connection to a cpuworker process that's processing a
* handshake. */
#define CPUWORKER_STATE_BUSY_ONION 2
-#define _CPUWORKER_STATE_MAX 2
+#define CPUWORKER_STATE_MAX_ 2
#define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION
+#define CPUWORKER_TASK_SHUTDOWN 255
-#define _OR_CONN_STATE_MIN 1
+#define OR_CONN_STATE_MIN_ 1
/** State for a connection to an OR: waiting for connect() to finish. */
#define OR_CONN_STATE_CONNECTING 1
/** State for a connection to an OR: waiting for proxy handshake to complete */
@@ -304,9 +304,9 @@ typedef enum {
#define OR_CONN_STATE_OR_HANDSHAKING_V3 7
/** State for an OR connection: Ready to send/receive cells. */
#define OR_CONN_STATE_OPEN 8
-#define _OR_CONN_STATE_MAX 8
+#define OR_CONN_STATE_MAX_ 8
-#define _EXIT_CONN_STATE_MIN 1
+#define EXIT_CONN_STATE_MIN_ 1
/** State for an exit connection: waiting for response from DNS farm. */
#define EXIT_CONN_STATE_RESOLVING 1
/** State for an exit connection: waiting for connect() to finish. */
@@ -315,10 +315,10 @@ typedef enum {
#define EXIT_CONN_STATE_OPEN 3
/** State for an exit connection: waiting to be removed. */
#define EXIT_CONN_STATE_RESOLVEFAILED 4
-#define _EXIT_CONN_STATE_MAX 4
+#define EXIT_CONN_STATE_MAX_ 4
/* The AP state values must be disjoint from the EXIT state values. */
-#define _AP_CONN_STATE_MIN 5
+#define AP_CONN_STATE_MIN_ 5
/** State for a SOCKS connection: waiting for SOCKS request. */
#define AP_CONN_STATE_SOCKS_WAIT 5
/** State for a SOCKS connection: got a y.onion URL; waiting to receive
@@ -338,14 +338,14 @@ typedef enum {
/** State for a transparent natd connection: waiting for original
* destination. */
#define AP_CONN_STATE_NATD_WAIT 12
-#define _AP_CONN_STATE_MAX 12
+#define AP_CONN_STATE_MAX_ 12
/** True iff the AP_CONN_STATE_* value <b>s</b> means that the corresponding
* edge connection is not attached to any circuit. */
#define AP_CONN_STATE_IS_UNATTACHED(s) \
((s) <= AP_CONN_STATE_CIRCUIT_WAIT || (s) == AP_CONN_STATE_NATD_WAIT)
-#define _DIR_CONN_STATE_MIN 1
+#define DIR_CONN_STATE_MIN_ 1
/** State for connection to directory server: waiting for connect(). */
#define DIR_CONN_STATE_CONNECTING 1
/** State for connection to directory server: sending HTTP request. */
@@ -358,21 +358,21 @@ typedef enum {
#define DIR_CONN_STATE_SERVER_COMMAND_WAIT 5
/** State for connection at directory server: sending HTTP response. */
#define DIR_CONN_STATE_SERVER_WRITING 6
-#define _DIR_CONN_STATE_MAX 6
+#define DIR_CONN_STATE_MAX_ 6
/** True iff the purpose of <b>conn</b> means that it's a server-side
* directory connection. */
#define DIR_CONN_IS_SERVER(conn) ((conn)->purpose == DIR_PURPOSE_SERVER)
-#define _CONTROL_CONN_STATE_MIN 1
+#define CONTROL_CONN_STATE_MIN_ 1
/** State for a control connection: Authenticated and accepting v1 commands. */
#define CONTROL_CONN_STATE_OPEN 1
/** State for a control connection: Waiting for authentication; speaking
* protocol v1. */
#define CONTROL_CONN_STATE_NEEDAUTH 2
-#define _CONTROL_CONN_STATE_MAX 2
+#define CONTROL_CONN_STATE_MAX_ 2
-#define _DIR_PURPOSE_MIN 3
+#define DIR_PURPOSE_MIN_ 3
/** A connection to a directory server: download a rendezvous
* descriptor. */
#define DIR_PURPOSE_FETCH_RENDDESC 3
@@ -420,7 +420,7 @@ typedef enum {
#define DIR_PURPOSE_FETCH_RENDDESC_V2 18
/** A connection to a directory server: download a microdescriptor. */
#define DIR_PURPOSE_FETCH_MICRODESC 19
-#define _DIR_PURPOSE_MAX 19
+#define DIR_PURPOSE_MAX_ 19
/** True iff <b>p</b> is a purpose corresponding to uploading data to a
* directory server. */
@@ -430,12 +430,12 @@ typedef enum {
(p)==DIR_PURPOSE_UPLOAD_VOTE || \
(p)==DIR_PURPOSE_UPLOAD_SIGNATURES)
-#define _EXIT_PURPOSE_MIN 1
+#define EXIT_PURPOSE_MIN_ 1
/** This exit stream wants to do an ordinary connect. */
#define EXIT_PURPOSE_CONNECT 1
/** This exit stream wants to do a resolve (either normal or reverse). */
#define EXIT_PURPOSE_RESOLVE 2
-#define _EXIT_PURPOSE_MAX 2
+#define EXIT_PURPOSE_MAX_ 2
/* !!!! If any connection purpose is ever over 31, we must grow the type
* field in connection_t. */
@@ -444,16 +444,16 @@ typedef enum {
#define CIRCUIT_STATE_BUILDING 0
/** Circuit state: Waiting to process the onionskin. */
#define CIRCUIT_STATE_ONIONSKIN_PENDING 1
-/** Circuit state: I'd like to deliver a create, but my n_conn is still
+/** Circuit state: I'd like to deliver a create, but my n_chan is still
* connecting. */
-#define CIRCUIT_STATE_OR_WAIT 2
+#define CIRCUIT_STATE_CHAN_WAIT 2
/** Circuit state: onionskin(s) processed, ready to send/receive cells. */
#define CIRCUIT_STATE_OPEN 3
-#define _CIRCUIT_PURPOSE_MIN 1
+#define CIRCUIT_PURPOSE_MIN_ 1
/* these circuits were initiated elsewhere */
-#define _CIRCUIT_PURPOSE_OR_MIN 1
+#define CIRCUIT_PURPOSE_OR_MIN_ 1
/** OR-side circuit purpose: normal circuit, at OR. */
#define CIRCUIT_PURPOSE_OR 1
/** OR-side circuit purpose: At OR, from Bob, waiting for intro from Alices. */
@@ -462,7 +462,7 @@ typedef enum {
#define CIRCUIT_PURPOSE_REND_POINT_WAITING 3
/** OR-side circuit purpose: At OR, both circuits have this purpose. */
#define CIRCUIT_PURPOSE_REND_ESTABLISHED 4
-#define _CIRCUIT_PURPOSE_OR_MAX 4
+#define CIRCUIT_PURPOSE_OR_MAX_ 4
/* these circuits originate at this node */
@@ -505,7 +505,7 @@ typedef enum {
#define CIRCUIT_PURPOSE_C_REND_JOINED 12
/** This circuit is used for build time measurement only */
#define CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT 13
-#define _CIRCUIT_PURPOSE_C_MAX 13
+#define CIRCUIT_PURPOSE_C_MAX_ 13
/** Hidden-service-side circuit purpose: at Bob, waiting for introductions. */
#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 14
/** Hidden-service-side circuit purpose: at Bob, successfully established
@@ -519,19 +519,21 @@ typedef enum {
#define CIRCUIT_PURPOSE_TESTING 18
/** A controller made this circuit and Tor should not use it. */
#define CIRCUIT_PURPOSE_CONTROLLER 19
-#define _CIRCUIT_PURPOSE_MAX 19
+/** This circuit is used for path bias probing only */
+#define CIRCUIT_PURPOSE_PATH_BIAS_TESTING 20
+#define CIRCUIT_PURPOSE_MAX_ 20
/** A catch-all for unrecognized purposes. Currently we don't expect
* to make or see any circuits with this purpose. */
#define CIRCUIT_PURPOSE_UNKNOWN 255
/** True iff the circuit purpose <b>p</b> is for a circuit that
* originated at this node. */
-#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>_CIRCUIT_PURPOSE_OR_MAX)
+#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>CIRCUIT_PURPOSE_OR_MAX_)
/** True iff the circuit purpose <b>p</b> is for a circuit that originated
* here to serve as a client. (Hidden services don't count here.) */
#define CIRCUIT_PURPOSE_IS_CLIENT(p) \
- ((p)> _CIRCUIT_PURPOSE_OR_MAX && \
- (p)<=_CIRCUIT_PURPOSE_C_MAX)
+ ((p)> CIRCUIT_PURPOSE_OR_MAX_ && \
+ (p)<=CIRCUIT_PURPOSE_C_MAX_)
/** True iff the circuit_t <b>c</b> is actually an origin_circuit_t. */
#define CIRCUIT_IS_ORIGIN(c) (CIRCUIT_PURPOSE_IS_ORIGIN((c)->purpose))
/** True iff the circuit purpose <b>p</b> is for an established rendezvous
@@ -561,6 +563,8 @@ typedef enum {
#define RELAY_COMMAND_RESOLVE 11
#define RELAY_COMMAND_RESOLVED 12
#define RELAY_COMMAND_BEGIN_DIR 13
+#define RELAY_COMMAND_EXTEND2 14
+#define RELAY_COMMAND_EXTENDED2 15
#define RELAY_COMMAND_ESTABLISH_INTRO 32
#define RELAY_COMMAND_ESTABLISH_RENDEZVOUS 33
@@ -666,7 +670,7 @@ typedef enum {
/* Reasons why we (or a remote OR) might close a circuit. See tor-spec.txt for
* documentation of these. */
-#define _END_CIRC_REASON_MIN 0
+#define END_CIRC_REASON_MIN_ 0
#define END_CIRC_REASON_NONE 0
#define END_CIRC_REASON_TORPROTOCOL 1
#define END_CIRC_REASON_INTERNAL 2
@@ -675,12 +679,12 @@ typedef enum {
#define END_CIRC_REASON_RESOURCELIMIT 5
#define END_CIRC_REASON_CONNECTFAILED 6
#define END_CIRC_REASON_OR_IDENTITY 7
-#define END_CIRC_REASON_OR_CONN_CLOSED 8
+#define END_CIRC_REASON_CHANNEL_CLOSED 8
#define END_CIRC_REASON_FINISHED 9
#define END_CIRC_REASON_TIMEOUT 10
#define END_CIRC_REASON_DESTROYED 11
#define END_CIRC_REASON_NOSUCHSERVICE 12
-#define _END_CIRC_REASON_MAX 12
+#define END_CIRC_REASON_MAX_ 12
/** Bitwise-OR this with the argument to circuit_mark_for_close() or
* control_event_circuit_status() to indicate that the reason was
@@ -834,6 +838,8 @@ typedef enum {
#define CELL_VERSIONS 7
#define CELL_NETINFO 8
#define CELL_RELAY_EARLY 9
+#define CELL_CREATE2 10
+#define CELL_CREATED2 11
#define CELL_VPADDING 128
#define CELL_CERTS 129
@@ -870,11 +876,29 @@ typedef enum {
/** Number of bytes in a cell, minus cell header. */
#define CELL_PAYLOAD_SIZE 509
-/** Number of bytes in a cell transmitted over the network. */
-#define CELL_NETWORK_SIZE 512
+/** Number of bytes in a cell transmitted over the network, in the longest
+ * form */
+#define CELL_MAX_NETWORK_SIZE 514
-/** Length of a header on a variable-length cell. */
-#define VAR_CELL_HEADER_SIZE 5
+/** Maximum length of a header on a variable-length cell. */
+#define VAR_CELL_MAX_HEADER_SIZE 7
+
+static int get_cell_network_size(int wide_circ_ids);
+static INLINE int get_cell_network_size(int wide_circ_ids)
+{
+ return wide_circ_ids ? CELL_MAX_NETWORK_SIZE : CELL_MAX_NETWORK_SIZE - 2;
+}
+static int get_var_cell_header_size(int wide_circ_ids);
+static INLINE int get_var_cell_header_size(int wide_circ_ids)
+{
+ return wide_circ_ids ? VAR_CELL_MAX_HEADER_SIZE :
+ VAR_CELL_MAX_HEADER_SIZE - 2;
+}
+static int get_circ_id_size(int wide_circ_ids);
+static INLINE int get_circ_id_size(int wide_circ_ids)
+{
+ return wide_circ_ids ? 4 : 2;
+}
/** Number of bytes in a relay cell's header (not including general cell
* header). */
@@ -883,10 +907,151 @@ typedef enum {
#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE)
/** Identifies a circuit on an or_connection */
-typedef uint16_t circid_t;
+typedef uint32_t circid_t;
/** Identifies a stream on a circuit */
typedef uint16_t streamid_t;
+/* channel_t typedef; struct channel_s is in channel.h */
+
+typedef struct channel_s channel_t;
+
+/* channel_listener_t typedef; struct channel_listener_s is in channel.h */
+
+typedef struct channel_listener_s channel_listener_t;
+
+/* channel states for channel_t */
+
+typedef enum {
+ /*
+ * Closed state - channel is inactive
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_CLOSING
+ * Permitted transitions to:
+ * - CHANNEL_STATE_OPENING
+ */
+ CHANNEL_STATE_CLOSED = 0,
+ /*
+ * Opening state - channel is trying to connect
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_CLOSED
+ * Permitted transitions to:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_ERROR
+ * - CHANNEL_STATE_OPEN
+ */
+ CHANNEL_STATE_OPENING,
+ /*
+ * Open state - channel is active and ready for use
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_MAINT
+ * - CHANNEL_STATE_OPENING
+ * Permitted transitions to:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_ERROR
+ * - CHANNEL_STATE_MAINT
+ */
+ CHANNEL_STATE_OPEN,
+ /*
+ * Maintenance state - channel is temporarily offline for subclass specific
+ * maintenance activities such as TLS renegotiation.
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_OPEN
+ * Permitted transitions to:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_ERROR
+ * - CHANNEL_STATE_OPEN
+ */
+ CHANNEL_STATE_MAINT,
+ /*
+ * Closing state - channel is shutting down
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_MAINT
+ * - CHANNEL_STATE_OPEN
+ * Permitted transitions to:
+ * - CHANNEL_STATE_CLOSED,
+ * - CHANNEL_STATE_ERROR
+ */
+ CHANNEL_STATE_CLOSING,
+ /*
+ * Error state - channel has experienced a permanent error
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_MAINT
+ * - CHANNEL_STATE_OPENING
+ * - CHANNEL_STATE_OPEN
+ * Permitted transitions to:
+ * - None
+ */
+ CHANNEL_STATE_ERROR,
+ /*
+ * Placeholder for maximum state value
+ */
+ CHANNEL_STATE_LAST
+} channel_state_t;
+
+/* channel listener states for channel_listener_t */
+
+typedef enum {
+ /*
+ * Closed state - channel listener is inactive
+ *
+ * Permitted transitions from:
+ * - CHANNEL_LISTENER_STATE_CLOSING
+ * Permitted transitions to:
+ * - CHANNEL_LISTENER_STATE_LISTENING
+ */
+ CHANNEL_LISTENER_STATE_CLOSED = 0,
+ /*
+ * Listening state - channel listener is listening for incoming
+ * connections
+ *
+ * Permitted transitions from:
+ * - CHANNEL_LISTENER_STATE_CLOSED
+ * Permitted transitions to:
+ * - CHANNEL_LISTENER_STATE_CLOSING
+ * - CHANNEL_LISTENER_STATE_ERROR
+ */
+ CHANNEL_LISTENER_STATE_LISTENING,
+ /*
+ * Closing state - channel listener is shutting down
+ *
+ * Permitted transitions from:
+ * - CHANNEL_LISTENER_STATE_LISTENING
+ * Permitted transitions to:
+ * - CHANNEL_LISTENER_STATE_CLOSED,
+ * - CHANNEL_LISTENER_STATE_ERROR
+ */
+ CHANNEL_LISTENER_STATE_CLOSING,
+ /*
+ * Error state - channel listener has experienced a permanent error
+ *
+ * Permitted transitions from:
+ * - CHANNEL_STATE_CLOSING
+ * - CHANNEL_STATE_LISTENING
+ * Permitted transitions to:
+ * - None
+ */
+ CHANNEL_LISTENER_STATE_ERROR,
+ /*
+ * Placeholder for maximum state value
+ */
+ CHANNEL_LISTENER_STATE_LAST
+} channel_listener_state_t;
+
+/* TLS channel stuff */
+
+typedef struct channel_tls_s channel_tls_t;
+
+/* circuitmux_t typedef; struct circuitmux_s is in circuitmux.h */
+
+typedef struct circuitmux_s circuitmux_t;
+
/** Parsed onion routing cell. All communication between nodes
* is via cells. */
typedef struct cell_t {
@@ -911,7 +1076,7 @@ typedef struct var_cell_t {
/** A cell as packed for writing to the network. */
typedef struct packed_cell_t {
struct packed_cell_t *next; /**< Next cell queued on this circuit. */
- char body[CELL_NETWORK_SIZE]; /**< Cell as packed for network. */
+ char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */
uint32_t inserted_time; /**< Time (in milliseconds since epoch, with high
* bits truncated) when this cell was inserted. */
} packed_cell_t;
@@ -1077,14 +1242,11 @@ typedef struct connection_t {
/** Unique identifier for this connection on this Tor instance. */
uint64_t global_identifier;
-
- /** Unique ID for measuring tunneled network status requests. */
- uint64_t dirreq_id;
} connection_t;
/** Subtype of connection_t; used for a listener socket. */
typedef struct listener_connection_t {
- connection_t _base;
+ connection_t base_;
/** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points
* to the evdns_server_port it uses to listen to and answer connections. */
@@ -1102,6 +1264,40 @@ typedef struct listener_connection_t {
/** One or more ISO_ flags to describe how to isolate streams. */
uint8_t isolation_flags;
/**@}*/
+ /** For SOCKS connections only: If this is set, we will choose "no
+ * authentication" instead of "username/password" authentication if both
+ * are offered. Used as input to parse_socks. */
+ unsigned int socks_prefer_no_auth : 1;
+
+ /** For a SOCKS listeners, these fields describe whether we should
+ * allow IPv4 and IPv6 addresses from our exit nodes, respectively.
+ *
+ * @{
+ */
+ unsigned int socks_ipv4_traffic : 1;
+ unsigned int socks_ipv6_traffic : 1;
+ /** @} */
+ /** For a socks listener: should we tell the exit that we prefer IPv6
+ * addresses? */
+ unsigned int socks_prefer_ipv6 : 1;
+
+ /** For a socks listener: should we cache IPv4/IPv6 DNS information that
+ * exit nodes tell us?
+ *
+ * @{ */
+ unsigned int cache_ipv4_answers : 1;
+ unsigned int cache_ipv6_answers : 1;
+ /** @} */
+ /** For a socks listeners: if we find an answer in our client-side DNS cache,
+ * should we use it?
+ *
+ * @{ */
+ unsigned int use_cached_ipv4_answers : 1;
+ unsigned int use_cached_ipv6_answers : 1;
+ /** @} */
+ /** For socks listeners: When we can automap an address to IPv4 or IPv6,
+ * do we prefer IPv6? */
+ unsigned int prefer_ipv6_virtaddr : 1;
} listener_connection_t;
@@ -1210,7 +1406,7 @@ typedef struct or_handshake_state_t {
/** Subtype of connection_t for an "OR connection" -- that is, one that speaks
* cells over TLS. */
typedef struct or_connection_t {
- connection_t _base;
+ connection_t base_;
/** Hash of the public RSA key for the other side's identity key, or zeroes
* if the other side hasn't shown us a valid identity key. */
@@ -1221,29 +1417,22 @@ typedef struct or_connection_t {
int tls_error; /**< Last tor_tls error code. */
/** When we last used this conn for any client traffic. If not
* recent, we can rate limit it further. */
- time_t client_used;
+
+ /* Channel using this connection */
+ channel_tls_t *chan;
tor_addr_t real_addr; /**< The actual address that this connection came from
* or went to. The <b>addr</b> field is prone to
* getting overridden by the address from the router
* descriptor matching <b>identity_digest</b>. */
- circ_id_type_t circ_id_type:2; /**< When we send CREATE cells along this
- * connection, which half of the space should
- * we use? */
/** Should this connection be used for extending circuits to the server
* matching the <b>identity_digest</b> field? Set to true if we're pretty
* sure we aren't getting MITMed, either because we're connected to an
* address listed in a server descriptor, or because an authenticated
* NETINFO cell listed the address we're connected to as recognized. */
unsigned int is_canonical:1;
- /** True iff this connection shouldn't get any new circs attached to it,
- * because the connection is too old, or because there's a better one.
- * More generally, this flag is used to note an unhealthy connection;
- * for example, if a bad connection fails we shouldn't assume that the
- * router itself has a problem.
- */
- unsigned int is_bad_for_new_circs:1;
+
/** True iff we have decided that the other end of this connection
* is a client. Connections with this flag set should never be used
* to satisfy an EXTEND request. */
@@ -1251,14 +1440,13 @@ typedef struct or_connection_t {
/** True iff this is an outgoing connection. */
unsigned int is_outgoing:1;
unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */
- uint8_t link_proto; /**< What protocol version are we using? 0 for
- * "none negotiated yet." */
- circid_t next_circ_id; /**< Which circ_id do we try to use next on
- * this connection? This is always in the
- * range 0..1<<15-1. */
+ unsigned int wide_circ_ids:1;
+ uint16_t link_proto; /**< What protocol version are we using? 0 for
+ * "none negotiated yet." */
or_handshake_state_t *handshake_state; /**< If we are setting this connection
* up, state information to do so. */
+
time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/
time_t timestamp_last_added_nonpadding; /** When did we last add a
* non-padding cell to the outbuf? */
@@ -1277,24 +1465,7 @@ typedef struct or_connection_t {
/* XXXX we could share this among all connections. */
struct ev_token_bucket_cfg *bucket_cfg;
#endif
- int n_circuits; /**< How many circuits use this connection as p_conn or
- * n_conn ? */
-
- /** Double-linked ring of circuits with queued cells waiting for room to
- * free up on this connection's outbuf. Every time we pull cells from a
- * circuit, we advance this pointer to the next circuit in the ring. */
- struct circuit_t *active_circuits;
- /** Priority queue of cell_ewma_t for circuits with queued cells waiting for
- * room to free up on this connection's outbuf. Kept in heap order
- * according to EWMA.
- *
- * This is redundant with active_circuits; if we ever decide only to use the
- * cell_ewma algorithm for choosing circuits, we can remove active_circuits.
- */
- smartlist_t *active_circuit_pqueue;
- /** The tick on which the cell_ewma_ts in active_circuit_pqueue last had
- * their ewma values rescaled. */
- unsigned active_circuit_pqueue_last_recalibrated;
+
struct or_connection_t *next_with_same_id; /**< Next connection with same
* identity digest as this one. */
} or_connection_t;
@@ -1302,7 +1473,7 @@ typedef struct or_connection_t {
/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap)
* connection, or an exit. */
typedef struct edge_connection_t {
- connection_t _base;
+ connection_t base_;
struct edge_connection_t *next_stream; /**< Points to the next stream at this
* edge, if any */
@@ -1322,6 +1493,8 @@ typedef struct edge_connection_t {
uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit
* connection. Exit connections only. */
+ uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell
+ * for this connection */
streamid_t stream_id; /**< The stream ID used for this edge connection on its
* circuit */
@@ -1337,6 +1510,8 @@ typedef struct edge_connection_t {
/** True iff this connection is for a DNS request only. */
unsigned int is_dns_request:1;
+ /** True iff this connection is for a PTR DNS request. (exit only) */
+ unsigned int is_reverse_dns_lookup:1;
unsigned int edge_has_sent_end:1; /**< For debugging; only used on edge
* connections. Set once we've set the stream end,
@@ -1346,12 +1521,16 @@ typedef struct edge_connection_t {
* cells. */
unsigned int edge_blocked_on_circ:1;
+ /** Unique ID for directory requests; this used to be in connection_t, but
+ * that's going away and being used on channels instead. We still tag
+ * edge connections with dirreq_id from circuits, so it's copied here. */
+ uint64_t dirreq_id;
} edge_connection_t;
/** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS
* connection, a DNS request, a TransPort connection or a NATD connection */
typedef struct entry_connection_t {
- edge_connection_t _edge;
+ edge_connection_t edge_;
/** Nickname of planned exit node -- used with .exit support. */
char *chosen_exit_name;
@@ -1424,12 +1603,46 @@ typedef struct entry_connection_t {
*/
unsigned int may_use_optimistic_data : 1;
+ /** Should we permit IPv4 and IPv6 traffic to use this connection?
+ *
+ * @{ */
+ unsigned int ipv4_traffic_ok : 1;
+ unsigned int ipv6_traffic_ok : 1;
+ /** @} */
+ /** Should we say we prefer IPv6 traffic? */
+ unsigned int prefer_ipv6_traffic : 1;
+
+ /** For a socks listener: should we cache IPv4/IPv6 DNS information that
+ * exit nodes tell us?
+ *
+ * @{ */
+ unsigned int cache_ipv4_answers : 1;
+ unsigned int cache_ipv6_answers : 1;
+ /** @} */
+ /** For a socks listeners: if we find an answer in our client-side DNS cache,
+ * should we use it?
+ *
+ * @{ */
+ unsigned int use_cached_ipv4_answers : 1;
+ unsigned int use_cached_ipv6_answers : 1;
+ /** @} */
+ /** For socks listeners: When we can automap an address to IPv4 or IPv6,
+ * do we prefer IPv6? */
+ unsigned int prefer_ipv6_virtaddr : 1;
+
} entry_connection_t;
+typedef enum {
+ DIR_SPOOL_NONE=0, DIR_SPOOL_SERVER_BY_DIGEST, DIR_SPOOL_SERVER_BY_FP,
+ DIR_SPOOL_EXTRA_BY_DIGEST, DIR_SPOOL_EXTRA_BY_FP,
+ DIR_SPOOL_CACHED_DIR, DIR_SPOOL_NETWORKSTATUS,
+ DIR_SPOOL_MICRODESC, /* NOTE: if we add another entry, add another bit. */
+} dir_spool_source_t;
+
/** Subtype of connection_t for an "directory connection" -- that is, an HTTP
* connection to retrieve or serve directory material. */
typedef struct dir_connection_t {
- connection_t _base;
+ connection_t base_;
/** Which 'resource' did we ask the directory for? This is typically the part
* of the URL string that defines, relative to the directory conn purpose,
@@ -1444,12 +1657,8 @@ typedef struct dir_connection_t {
* "spooling" of directory material to the outbuf. Otherwise, we'd have
* to append everything to the outbuf in one enormous chunk. */
/** What exactly are we spooling right now? */
- enum {
- DIR_SPOOL_NONE=0, DIR_SPOOL_SERVER_BY_DIGEST, DIR_SPOOL_SERVER_BY_FP,
- DIR_SPOOL_EXTRA_BY_DIGEST, DIR_SPOOL_EXTRA_BY_FP,
- DIR_SPOOL_CACHED_DIR, DIR_SPOOL_NETWORKSTATUS,
- DIR_SPOOL_MICRODESC, /* NOTE: if we add another entry, add another bit. */
- } dir_spool_src : 3;
+ ENUM_BF(dir_spool_source_t) dir_spool_src : 3;
+
/** If we're fetching descriptors, what router purpose shall we assign
* to them? */
uint8_t router_purpose;
@@ -1468,11 +1677,15 @@ typedef struct dir_connection_t {
char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for
* the directory server's signing key. */
+ /** Unique ID for directory requests; this used to be in connection_t, but
+ * that's going away and being used on channels instead. The dirserver still
+ * needs this for the incoming side, so it's moved here. */
+ uint64_t dirreq_id;
} dir_connection_t;
/** Subtype of connection_t for an connection to a controller. */
typedef struct control_connection_t {
- connection_t _base;
+ connection_t base_;
uint32_t event_mask; /**< Bitfield: which events does this controller
* care about? */
@@ -1499,12 +1712,12 @@ typedef struct control_connection_t {
} control_connection_t;
/** Cast a connection_t subtype pointer to a connection_t **/
-#define TO_CONN(c) (&(((c)->_base)))
-/** Helper macro: Given a pointer to to._base, of type from*, return &to. */
-#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, _base))
+#define TO_CONN(c) (&(((c)->base_)))
+/** Helper macro: Given a pointer to to.base_, of type from*, return &to. */
+#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_))
/** Cast a entry_connection_t subtype pointer to a edge_connection_t **/
-#define ENTRY_TO_EDGE_CONN(c) (&(((c))->_edge))
+#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_))
/** Cast a entry_connection_t subtype pointer to a connection_t **/
#define ENTRY_TO_CONN(c) (TO_CONN(ENTRY_TO_EDGE_CONN(c)))
@@ -1549,12 +1762,12 @@ static INLINE edge_connection_t *TO_EDGE_CONN(connection_t *c)
static INLINE entry_connection_t *TO_ENTRY_CONN(connection_t *c)
{
tor_assert(c->magic == ENTRY_CONNECTION_MAGIC);
- return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, _edge._base);
+ return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_);
}
static INLINE entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *c)
{
- tor_assert(c->_base.magic == ENTRY_CONNECTION_MAGIC);
- return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, _edge);
+ tor_assert(c->base_.magic == ENTRY_CONNECTION_MAGIC);
+ return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_);
}
static INLINE control_connection_t *TO_CONTROL_CONN(connection_t *c)
{
@@ -1621,7 +1834,8 @@ typedef enum {
/** A reference-counted address policy rule. */
typedef struct addr_policy_t {
int refcnt; /**< Reference count */
- addr_policy_action_t policy_type:2;/**< What to do when the policy matches.*/
+ /** What to do when the policy matches.*/
+ ENUM_BF(addr_policy_action_t) policy_type:2;
unsigned int is_private:1; /**< True iff this is the pseudo-address,
* "private". */
unsigned int is_canonical:1; /**< True iff this policy is the canonical
@@ -1630,7 +1844,15 @@ typedef struct addr_policy_t {
maskbits_t maskbits; /**< Accept/reject all addresses <b>a</b> such that the
* first <b>maskbits</b> bits of <b>a</b> match
* <b>addr</b>. */
- tor_addr_t addr; /**< Base address to accept or reject. */
+ /** Base address to accept or reject.
+ *
+ * Note that wildcards are treated
+ * differntly depending on address family. An AF_UNSPEC address means
+ * "All addresses, IPv4 or IPv6." An AF_INET address with maskbits==0 means
+ * "All IPv4 addresses" and an AF_INET6 address with maskbits == 0 means
+ * "All IPv6 addresses".
+ **/
+ tor_addr_t addr;
uint16_t prt_min; /**< Lowest port number to accept/reject. */
uint16_t prt_max; /**< Highest port number to accept/reject. */
} addr_policy_t;
@@ -1681,7 +1903,7 @@ typedef struct download_status_t {
* again? */
uint8_t n_download_failures; /**< Number of failures trying to download the
* most recent descriptor. */
- download_schedule_t schedule : 8;
+ ENUM_BF(download_schedule_t) schedule : 8;
} download_status_t;
/** If n_download_failures is this high, the download can never happen. */
@@ -1760,6 +1982,8 @@ typedef struct {
crypto_pk_t *onion_pkey; /**< Public RSA key for onions. */
crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */
+ /** Public curve25519 key for onions */
+ curve25519_public_key_t *onion_curve25519_pkey;
char *platform; /**< What software/operating system is this OR using? */
@@ -1770,7 +1994,10 @@ typedef struct {
/** How many bytes/s is this router known to handle? */
uint32_t bandwidthcapacity;
smartlist_t *exit_policy; /**< What streams will this OR permit
- * to exit? NULL for 'reject *:*'. */
+ * to exit on IPv4? NULL for 'reject *:*'. */
+ /** What streams will this OR permit to exit on IPv6?
+ * NULL for 'reject *:*' */
+ struct short_policy_t *ipv6_exit_policy;
long uptime; /**< How many seconds the router claims to have been up */
smartlist_t *declared_family; /**< Nicknames of router which this router
* claims are its family. */
@@ -1789,8 +2016,6 @@ typedef struct {
/** True if, after we have added this router, we should re-launch
* tests for it. */
unsigned int needs_retest_if_added:1;
- /** True if ipv6_addr:ipv6_orport is preferred. */
- unsigned int ipv6_preferred:1;
/** Tor can use this router for general positions in circuits; we got it
* from a directory server as usual, or we're an authority and a server
@@ -1813,15 +2038,6 @@ typedef struct {
* things; see notes on ROUTER_PURPOSE_* macros above.
*/
uint8_t purpose;
-
- /* The below items are used only by authdirservers for
- * reachability testing. */
-
- /** When was the last time we could reach this OR? */
- time_t last_reachable;
- /** When did we start testing reachability for this OR? */
- time_t testing_since;
-
} routerinfo_t;
/** Information needed to keep and cache a signed extra-info document. */
@@ -1853,6 +2069,8 @@ typedef struct routerstatus_t {
uint32_t addr; /**< IPv4 address for this router. */
uint16_t or_port; /**< OR port for this router. */
uint16_t dir_port; /**< Directory port for this router. */
+ tor_addr_t ipv6_addr; /**< IPv6 address for this router. */
+ uint16_t ipv6_orport; /**<IPV6 OR port for this router. */
unsigned int is_authority:1; /**< True iff this router is an authority. */
unsigned int is_exit:1; /**< True iff this router is a good exit. */
unsigned int is_stable:1; /**< True iff this router stays up a long time. */
@@ -1882,30 +2100,23 @@ typedef struct routerstatus_t {
* included.) We'll replace all these with a big tor_version_t or a char[]
* if the number of traits we care about ever becomes incredibly big. */
unsigned int version_known:1;
- /** True iff this router is a version that supports BEGIN_DIR cells. */
- unsigned int version_supports_begindir:1;
- /** True iff this router is a version that supports conditional consensus
- * downloads (signed by list of authorities). */
- unsigned int version_supports_conditional_consensus:1;
- /** True iff this router is a version that we can post extrainfo docs to. */
- unsigned int version_supports_extrainfo_upload:1;
- /** True iff this router is a version that, if it caches directory info,
- * we can get v3 downloads from. */
- unsigned int version_supports_v3_dir:1;
+
/** True iff this router is a version that, if it caches directory info,
* we can get microdescriptors from. */
unsigned int version_supports_microdesc_cache:1;
/** True iff this router is a version that allows DATA cells to arrive on
* a stream before it has sent a CONNECTED cell. */
unsigned int version_supports_optimistic_data:1;
+ /** True iff this router has a version that allows it to accept EXTEND2
+ * cells */
+ unsigned int version_supports_extend2_cells:1;
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
- unsigned int has_measured_bw:1; /**< The vote/consensus had a measured bw */
-
- uint32_t measured_bw; /**< Measured bandwidth (capacity) of the router */
+ unsigned int bw_is_unmeasured:1; /**< This is a consensus entry, with
+ * the Unmeasured flag set. */
- uint32_t bandwidth; /**< Bandwidth (capacity) of the router as reported in
+ uint32_t bandwidth_kb; /**< Bandwidth (capacity) of the router as reported in
* the vote/consensus, in kilobytes/sec. */
char *exitsummary; /**< exit policy summary -
* XXX weasel: this probably should not stay a string. */
@@ -1960,7 +2171,7 @@ typedef struct microdesc_t {
*/
time_t last_listed;
/** Where is this microdescriptor currently stored? */
- saved_location_t saved_location : 3;
+ ENUM_BF(saved_location_t) saved_location : 3;
/** If true, do not attempt to cache this microdescriptor on disk. */
unsigned int no_save : 1;
/** If true, this microdesc has an entry in the microdesc_map */
@@ -1988,10 +2199,19 @@ typedef struct microdesc_t {
/** As routerinfo_t.onion_pkey */
crypto_pk_t *onion_pkey;
+ /** As routerinfo_t.onion_curve25519_pkey */
+ curve25519_public_key_t *onion_curve25519_pkey;
+ /** As routerinfo_t.ipv6_add */
+ tor_addr_t ipv6_addr;
+ /** As routerinfo_t.ipv6_orport */
+ uint16_t ipv6_orport;
/** As routerinfo_t.family */
smartlist_t *family;
- /** Exit policy summary */
+ /** IPv4 exit policy summary */
short_policy_t *exit_policy;
+ /** IPv6 exit policy summary */
+ short_policy_t *ipv6_exit_policy;
+
} microdesc_t;
/** A node_t represents a Tor router.
@@ -2026,13 +2246,13 @@ typedef struct node_t {
routerstatus_t *rs;
/* local info: copied from routerstatus, then possibly frobbed based
- * on experience. Authorities set this stuff directly. */
+ * on experience. Authorities set this stuff directly. Note that
+ * these reflect knowledge of the primary (IPv4) OR port only. */
unsigned int is_running:1; /**< As far as we know, is this OR currently
* running? */
unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR?
- * (For Authdir: Have we validated this OR?)
- */
+ * (For Authdir: Have we validated this OR?) */
unsigned int is_fast:1; /** Do we think this is a fast OR? */
unsigned int is_stable:1; /** Do we think this is a stable OR? */
unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */
@@ -2053,10 +2273,25 @@ typedef struct node_t {
/** Local info: we treat this node as if it rejects everything */
unsigned int rejects_all:1;
+ /** Local info: this node is in our list of guards */
+ unsigned int using_as_guard:1;
+
/* Local info: derived. */
+ /** True if the IPv6 OR port is preferred over the IPv4 OR port. */
+ unsigned int ipv6_preferred:1;
+
/** According to the geoip db what country is this router in? */
+ /* XXXprop186 what is this suppose to mean with multiple OR ports? */
country_t country;
+
+ /* The below items are used only by authdirservers for
+ * reachability testing. */
+
+ /** When was the last time we could reach this OR? */
+ time_t last_reachable; /* IPv4. */
+ time_t last_reachable6; /* IPv6. */
+
} node_t;
/** How many times will we try to download a router's descriptor before giving
@@ -2111,7 +2346,8 @@ typedef struct networkstatus_v2_t {
typedef struct vote_microdesc_hash_t {
/** Next element in the list, or NULL. */
struct vote_microdesc_hash_t *next;
- /** The raw contents of the microdesc hash line, excluding the "m". */
+ /** The raw contents of the microdesc hash line, from the "m" through the
+ * newline. */
char *microdesc_hash_line;
} vote_microdesc_hash_t;
@@ -2119,10 +2355,15 @@ typedef struct vote_microdesc_hash_t {
typedef struct vote_routerstatus_t {
routerstatus_t status; /**< Underlying 'status' object for this router.
* Flags are redundant. */
+ /** How many known-flags are allowed in a vote? This is the width of
+ * the flags field of vote_routerstatus_t */
+#define MAX_KNOWN_FLAGS_IN_VOTE 64
uint64_t flags; /**< Bit-field for all recognized flags; index into
* networkstatus_t.known_flags. */
char *version; /**< The version that the authority says this router is
* running. */
+ unsigned int has_measured_bw:1; /**< The vote had a measured bw */
+ uint32_t measured_bw_kb; /**< Measured bandwidth (capacity) of the router */
/** The hash or hashes that the authority claims this microdesc has. */
vote_microdesc_hash_t *microdesc;
} vote_routerstatus_t;
@@ -2186,8 +2427,11 @@ typedef enum {
/** A common structure to hold a v3 network status vote, or a v3 network
* status consensus. */
typedef struct networkstatus_t {
- networkstatus_type_t type : 8; /**< Vote, consensus, or opinion? */
- consensus_flavor_t flavor : 8; /**< If a consensus, what kind? */
+ ENUM_BF(networkstatus_type_t) type : 8; /**< Vote, consensus, or opinion? */
+ ENUM_BF(consensus_flavor_t) flavor : 8; /**< If a consensus, what kind? */
+ unsigned int has_measured_bws : 1;/**< True iff this networkstatus contains
+ * measured= bandwidth values. */
+
time_t published; /**< Vote only: Time when vote was written. */
time_t valid_after; /**< Time after which this vote or consensus applies. */
time_t fresh_until; /**< Time before which this is the most recent vote or
@@ -2325,6 +2569,9 @@ typedef struct extend_info_t {
uint16_t port; /**< OR port. */
tor_addr_t addr; /**< IP address. */
crypto_pk_t *onion_key; /**< Current onionskin key. */
+#ifdef CURVE25519_ENABLED
+ curve25519_public_key_t curve25519_onion_key;
+#endif
} extend_info_t;
/** Certificate for v3 directory protocol: binds long-term authority identity
@@ -2377,8 +2624,25 @@ typedef enum {
MICRODESC_DIRINFO=1 << 6,
} dirinfo_type_t;
+#define ALL_DIRINFO ((dirinfo_type_t)((1<<7)-1))
+
#define CRYPT_PATH_MAGIC 0x70127012u
+struct fast_handshake_state_t;
+struct ntor_handshake_state_t;
+#define ONION_HANDSHAKE_TYPE_TAP 0x0000
+#define ONION_HANDSHAKE_TYPE_FAST 0x0001
+#define ONION_HANDSHAKE_TYPE_NTOR 0x0002
+#define MAX_ONION_HANDSHAKE_TYPE 0x0002
+typedef struct {
+ uint16_t tag;
+ union {
+ struct fast_handshake_state_t *fast;
+ crypto_dh_t *tap;
+ struct ntor_handshake_state_t *ntor;
+ } u;
+} onion_handshake_state_t;
+
/** Holds accounting information for a single step in the layered encryption
* performed by a circuit. Used only at the client edge of a circuit. */
typedef struct crypt_path_t {
@@ -2397,17 +2661,15 @@ typedef struct crypt_path_t {
/** Digest state for cells heading away from the OR at this step. */
crypto_digest_t *b_digest;
- /** Current state of Diffie-Hellman key negotiation with the OR at this
+ /** Current state of the handshake as performed with the OR at this
* step. */
- crypto_dh_t *dh_handshake_state;
- /** Current state of 'fast' (non-PK) key negotiation with the OR at this
- * step. Used to save CPU when TLS is already providing all the
- * authentication, secrecy, and integrity we need, and we're already
- * distinguishable from an OR.
- */
- uint8_t fast_handshake_state[DIGEST_LEN];
+ onion_handshake_state_t handshake_state;
+ /** Diffie-hellman handshake state for performing an introduction
+ * operations */
+ crypto_dh_t *rend_dh_handshake_state;
+
/** Negotiated key material shared with the OR at this step. */
- char handshake_digest[DIGEST_LEN];/* KH in tor-spec.txt */
+ char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */
/** Information to extend to the OR at this step. */
extend_info_t *extend_info;
@@ -2448,10 +2710,6 @@ typedef struct {
#define CPATH_KEY_MATERIAL_LEN (20*2+16*2)
#define DH_KEY_LEN DH_BYTES
-#define ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\
- CIPHER_KEY_LEN+\
- DH_KEY_LEN)
-#define ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN)
/** Information used to build a circuit. */
typedef struct {
@@ -2480,32 +2738,11 @@ typedef struct {
time_t expiry_time;
} cpath_build_state_t;
-/**
- * The cell_ewma_t structure keeps track of how many cells a circuit has
- * transferred recently. It keeps an EWMA (exponentially weighted moving
- * average) of the number of cells flushed from the circuit queue onto a
- * connection in connection_or_flush_from_first_active_circuit().
- */
-typedef struct {
- /** The last 'tick' at which we recalibrated cell_count.
- *
- * A cell sent at exactly the start of this tick has weight 1.0. Cells sent
- * since the start of this tick have weight greater than 1.0; ones sent
- * earlier have less weight. */
- unsigned last_adjusted_tick;
- /** The EWMA of the cell count. */
- double cell_count;
- /** True iff this is the cell count for a circuit's previous
- * connection. */
- unsigned int is_for_p_conn : 1;
- /** The position of the circuit within the OR connection's priority
- * queue. */
- int heap_index;
-} cell_ewma_t;
-
#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
#define OR_CIRCUIT_MAGIC 0x98ABC04Fu
+struct create_cell_t;
+
/**
* A circuit is a path over the onion routing
* network. Applications can connect to one end of the circuit, and can
@@ -2533,23 +2770,39 @@ typedef struct circuit_t {
uint32_t magic; /**< For memory and type debugging: must equal
* ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */
- /** Queue of cells waiting to be transmitted on n_conn. */
- cell_queue_t n_conn_cells;
- /** The OR connection that is next in this circuit. */
- or_connection_t *n_conn;
- /** The circuit_id used in the next (forward) hop of this circuit. */
+ /** The channel that is next in this circuit. */
+ channel_t *n_chan;
+
+ /**
+ * The circuit_id used in the next (forward) hop of this circuit;
+ * this is unique to n_chan, but this ordered pair is globally
+ * unique:
+ *
+ * (n_chan->global_identifier, n_circ_id)
+ */
circid_t n_circ_id;
- /** The hop to which we want to extend this circuit. Should be NULL if
- * the circuit has attached to a connection. */
+ /**
+ * Circuit mux associated with n_chan to which this circuit is attached;
+ * NULL if we have no n_chan.
+ */
+ circuitmux_t *n_mux;
+
+ /** Queue of cells waiting to be transmitted on n_chan */
+ cell_queue_t n_chan_cells;
+
+ /**
+ * The hop to which we want to extend this circuit. Should be NULL if
+ * the circuit has attached to a channel.
+ */
extend_info_t *n_hop;
- /** True iff we are waiting for n_conn_cells to become less full before
+ /** True iff we are waiting for n_chan_cells to become less full before
* allowing p_streams to add any more cells. (Origin circuit only.) */
- unsigned int streams_blocked_on_n_conn : 1;
- /** True iff we are waiting for p_conn_cells to become less full before
+ unsigned int streams_blocked_on_n_chan : 1;
+ /** True iff we are waiting for p_chan_cells to become less full before
* allowing n_streams to add any more cells. (OR circuit only.) */
- unsigned int streams_blocked_on_p_conn : 1;
+ unsigned int streams_blocked_on_p_chan : 1;
uint8_t state; /**< Current status of this circuit. */
uint8_t purpose; /**< Why are we creating this circuit? */
@@ -2564,15 +2817,24 @@ typedef struct circuit_t {
* more. */
int deliver_window;
- /** For storage while n_conn is pending
- * (state CIRCUIT_STATE_OR_WAIT). When defined, it is always
- * length ONIONSKIN_CHALLENGE_LEN. */
- char *n_conn_onionskin;
+ /** For storage while n_chan is pending (state CIRCUIT_STATE_CHAN_WAIT). */
+ struct create_cell_t *n_chan_create_cell;
- /** When was this circuit created? We keep this timestamp with a higher
- * resolution than most so that the circuit-build-time tracking code can
- * get millisecond resolution. */
+ /** When did circuit construction actually begin (ie send the
+ * CREATE cell or begin cannibalization).
+ *
+ * Note: This timer will get reset if we decide to cannibalize
+ * a circuit. It may also get reset during certain phases of hidden
+ * service circuit use.
+ *
+ * We keep this timestamp with a higher resolution than most so that the
+ * circuit-build-time tracking code can get millisecond resolution.
+ */
+ struct timeval timestamp_began;
+
+ /** This timestamp marks when the init_circuit_base constructor ran. */
struct timeval timestamp_created;
+
/** When the circuit was first used, or 0 if the circuit is clean.
*
* XXXX023 Note that some code will artifically adjust this value backward
@@ -2593,23 +2855,19 @@ typedef struct circuit_t {
const char *marked_for_close_file; /**< For debugging: in which file was this
* circuit marked for close? */
+ /** Unique ID for measuring tunneled network status requests. */
+ uint64_t dirreq_id;
+
+ struct circuit_t *next; /**< Next circuit in linked list of all circuits. */
+
/** Next circuit in the doubly-linked ring of circuits waiting to add
* cells to n_conn. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
- struct circuit_t *next_active_on_n_conn;
+ struct circuit_t *next_active_on_n_chan;
/** Previous circuit in the doubly-linked ring of circuits waiting to add
* cells to n_conn. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
- struct circuit_t *prev_active_on_n_conn;
- struct circuit_t *next; /**< Next circuit in linked list of all circuits. */
-
- /** Unique ID for measuring tunneled network status requests. */
- uint64_t dirreq_id;
-
- /** The EWMA count for the number of cells flushed from the
- * n_conn_cells queue. Used to determine which circuit to flush from next.
- */
- cell_ewma_t n_cell_ewma;
+ struct circuit_t *prev_active_on_n_chan;
} circuit_t;
/** Largest number of relay_early cells that we can send on a given
@@ -2618,25 +2876,64 @@ typedef struct circuit_t {
/**
* Describes the circuit building process in simplified terms based
- * on the path bias accounting state for a circuit. Created to prevent
- * overcounting due to unknown cases of circuit reuse. See Bug #6475.
+ * on the path bias accounting state for a circuit.
+ *
+ * NOTE: These state values are enumerated in the order for which we
+ * expect circuits to transition through them. If you add states,
+ * you need to preserve this overall ordering. The various pathbias
+ * state transition and accounting functions (pathbias_mark_* and
+ * pathbias_count_*) contain ordinal comparisons to enforce proper
+ * state transitions for corrections.
+ *
+ * This state machine and the associated logic was created to prevent
+ * miscounting due to unknown cases of circuit reuse. See also tickets
+ * #6475 and #7802.
*/
typedef enum {
/** This circuit is "new". It has not yet completed a first hop
* or been counted by the path bias code. */
PATH_STATE_NEW_CIRC = 0,
- /** This circuit has completed a first hop, and has been counted by
+ /** This circuit has completed one/two hops, and has been counted by
* the path bias logic. */
- PATH_STATE_DID_FIRST_HOP = 1,
- /** This circuit has been completely built, and has been counted as
- * successful by the path bias logic. */
- PATH_STATE_SUCCEEDED = 2,
+ PATH_STATE_BUILD_ATTEMPTED = 1,
+ /** This circuit has been completely built */
+ PATH_STATE_BUILD_SUCCEEDED = 2,
+ /** Did we try to attach any SOCKS streams or hidserv introductions to
+ * this circuit?
+ *
+ * Note: If we ever implement end-to-end stream timing through test
+ * stream probes (#5707), we must *not* set this for those probes
+ * (or any other automatic streams) because the adversary could
+ * just tag at a later point.
+ */
+ PATH_STATE_USE_ATTEMPTED = 3,
+ /** Did any SOCKS streams or hidserv introductions actually succeed on
+ * this circuit?
+ *
+ * If any streams detatch/fail from this circuit, the code transitions
+ * the circuit back to PATH_STATE_USE_ATTEMPTED to ensure we probe. See
+ * pathbias_mark_use_rollback() for that.
+ */
+ PATH_STATE_USE_SUCCEEDED = 4,
+
+ /**
+ * This is a special state to indicate that we got a corrupted
+ * relay cell on a circuit and we don't intend to probe it.
+ */
+ PATH_STATE_USE_FAILED = 5,
+
+ /**
+ * This is a special state to indicate that we already counted
+ * the circuit. Used to guard against potential state machine
+ * violations.
+ */
+ PATH_STATE_ALREADY_COUNTED = 6,
} path_state_t;
/** An origin_circuit_t holds data necessary to build and use a circuit.
*/
typedef struct origin_circuit_t {
- circuit_t _base;
+ circuit_t base_;
/** Linked list of AP streams (or EXIT streams if hidden service)
* associated with this circuit. */
@@ -2666,9 +2963,36 @@ typedef struct origin_circuit_t {
* cannibalized circuits. */
unsigned int has_opened : 1;
- /** Kludge to help us prevent the warn in bug #6475 and eventually
- * debug why we are not seeing first hops in some cases. */
- path_state_t path_state : 2;
+ /**
+ * Path bias state machine. Used to ensure integrity of our
+ * circuit building and usage accounting. See path_state_t
+ * for more details.
+ */
+ ENUM_BF(path_state_t) path_state : 3;
+
+ /* If this flag is set, we should not consider attaching any more
+ * connections to this circuit. */
+ unsigned int unusable_for_new_conns : 1;
+
+ /**
+ * Tristate variable to guard against pathbias miscounting
+ * due to circuit purpose transitions changing the decision
+ * of pathbias_should_count(). This variable is informational
+ * only. The current results of pathbias_should_count() are
+ * the official decision for pathbias accounting.
+ */
+ uint8_t pathbias_shouldcount;
+#define PATHBIAS_SHOULDCOUNT_UNDECIDED 0
+#define PATHBIAS_SHOULDCOUNT_IGNORED 1
+#define PATHBIAS_SHOULDCOUNT_COUNTED 2
+
+ /** For path probing. Store the temporary probe stream ID
+ * for response comparison */
+ streamid_t pathbias_probe_id;
+
+ /** For path probing. Store the temporary probe address nonce
+ * (in host byte order) for response comparison. */
+ uint32_t pathbias_probe_nonce;
/** Set iff this is a hidden-service circuit which has timed out
* according to our current circuit-build timeout, but which has
@@ -2686,6 +3010,10 @@ typedef struct origin_circuit_t {
* service-side introduction circuits never have this flag set.) */
unsigned int hs_circ_has_timed_out : 1;
+ /** Set iff this circuit has been given a relaxed timeout because
+ * no circuits have opened. Used to prevent spamming logs. */
+ unsigned int relaxed_timeout : 1;
+
/** Set iff this is a service-side rendezvous circuit for which a
* new connection attempt has been launched. We consider launching
* a new service-side rend circ to a client when the previous one
@@ -2763,29 +3091,42 @@ typedef struct origin_circuit_t {
* ISO_STREAM. */
uint64_t associated_isolated_stream_global_id;
/**@}*/
-
+ /** A list of addr_policy_t for this circuit in particular. Used by
+ * adjust_exit_policy_from_exitpolicy_failure.
+ */
+ smartlist_t *prepend_policy;
} origin_circuit_t;
+struct onion_queue_t;
+
/** An or_circuit_t holds information needed to implement a circuit at an
* OR. */
typedef struct or_circuit_t {
- circuit_t _base;
+ circuit_t base_;
/** Next circuit in the doubly-linked ring of circuits waiting to add
- * cells to p_conn. NULL if we have no cells pending, or if we're not
+ * cells to p_chan. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
- struct circuit_t *next_active_on_p_conn;
+ struct circuit_t *next_active_on_p_chan;
/** Previous circuit in the doubly-linked ring of circuits waiting to add
- * cells to p_conn. NULL if we have no cells pending, or if we're not
+ * cells to p_chan. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
- struct circuit_t *prev_active_on_p_conn;
+ struct circuit_t *prev_active_on_p_chan;
+ /** Pointer to an entry on the onion queue, if this circuit is waiting for a
+ * chance to give an onionskin to a cpuworker. Used only in onion.c */
+ struct onion_queue_t *onionqueue_entry;
/** The circuit_id used in the previous (backward) hop of this circuit. */
circid_t p_circ_id;
/** Queue of cells waiting to be transmitted on p_conn. */
- cell_queue_t p_conn_cells;
- /** The OR connection that is previous in this circuit. */
- or_connection_t *p_conn;
+ cell_queue_t p_chan_cells;
+ /** The channel that is previous in this circuit. */
+ channel_t *p_chan;
+ /**
+ * Circuit mux associated with p_chan to which this circuit is attached;
+ * NULL if we have no p_chan.
+ */
+ circuitmux_t *p_mux;
/** Linked list of Exit streams associated with this circuit. */
edge_connection_t *n_streams;
/** Linked list of Exit streams associated with this circuit that are
@@ -2825,7 +3166,8 @@ typedef struct or_circuit_t {
char rend_token[REND_TOKEN_LEN];
/* ???? move to a subtype or adjunct structure? Wastes 20 bytes -NM */
- char handshake_digest[DIGEST_LEN]; /**< Stores KH for the handshake. */
+ /** Stores KH for the handshake. */
+ char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */
/** How many more relay_early cells can we send on this circuit, according
* to the specification? */
@@ -2842,14 +3184,10 @@ typedef 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;
-
- /** The EWMA count for the number of cells flushed from the
- * p_conn_cells queue. */
- cell_ewma_t p_cell_ewma;
} or_circuit_t;
/** Convert a circuit subtype to a circuit_t. */
-#define TO_CIRCUIT(x) (&((x)->_base))
+#define TO_CIRCUIT(x) (&((x)->base_))
/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert
* if the cast is impossible. */
@@ -2930,13 +3268,40 @@ typedef struct port_cfg_t {
uint8_t isolation_flags; /**< Zero or more isolation flags */
int session_group; /**< A session group, or -1 if this port is not in a
* session group. */
+ /* Socks only: */
+ /** When both no-auth and user/pass are advertised by a SOCKS client, select
+ * no-auth. */
+ unsigned int socks_prefer_no_auth : 1;
/* Server port types (or, dir) only: */
unsigned int no_advertise : 1;
unsigned int no_listen : 1;
unsigned int all_addrs : 1;
- unsigned int ipv4_only : 1;
- unsigned int ipv6_only : 1;
+ unsigned int bind_ipv4_only : 1;
+ unsigned int bind_ipv6_only : 1;
+
+ /* Client port types only: */
+ unsigned int ipv4_traffic : 1;
+ unsigned int ipv6_traffic : 1;
+ unsigned int prefer_ipv6 : 1;
+
+ /** For a socks listener: should we cache IPv4/IPv6 DNS information that
+ * exit nodes tell us?
+ *
+ * @{ */
+ unsigned int cache_ipv4_answers : 1;
+ unsigned int cache_ipv6_answers : 1;
+ /** @} */
+ /** For a socks listeners: if we find an answer in our client-side DNS cache,
+ * should we use it?
+ *
+ * @{ */
+ unsigned int use_cached_ipv4_answers : 1;
+ unsigned int use_cached_ipv6_answers : 1;
+ /** @} */
+ /** For socks listeners: When we can automap an address to IPv4 or IPv6,
+ * do we prefer IPv6? */
+ unsigned int prefer_ipv6_virtaddr : 1;
/* Unix sockets only: */
/** Path for an AF_UNIX address */
@@ -2972,7 +3337,7 @@ typedef struct routerset_t routerset_t;
/** Configuration options for a Tor process. */
typedef struct {
- uint32_t _magic;
+ uint32_t magic_;
/** What should the tor process actually do? */
enum {
@@ -3014,7 +3379,7 @@ typedef struct {
* ORs not to consider as exits. */
/** Union of ExcludeNodes and ExcludeExitNodes */
- routerset_t *_ExcludeExitNodesUnion;
+ routerset_t *ExcludeExitNodesUnion_;
int DisableAllSwap; /**< Boolean: Attempt to call mlockall() on our
* process for all current and future memory. */
@@ -3022,7 +3387,7 @@ typedef struct {
/** List of "entry", "middle", "exit", "introduction", "rendezvous". */
smartlist_t *AllowInvalidNodes;
/** Bitmask; derived from AllowInvalidNodes. */
- invalid_router_usage_t _AllowInvalid;
+ invalid_router_usage_t AllowInvalid_;
config_line_t *ExitPolicy; /**< Lists of exit policy components. */
int ExitPolicyRejectPrivate; /**< Should we not exit to local addresses? */
config_line_t *SocksPolicy; /**< Lists of socks policy components */
@@ -3043,7 +3408,11 @@ typedef struct {
/** Addresses to bind for listening for control connections. */
config_line_t *ControlListenAddress;
/** Local address to bind outbound sockets */
- char *OutboundBindAddress;
+ config_line_t *OutboundBindAddress;
+ /** IPv4 address derived from OutboundBindAddress. */
+ tor_addr_t OutboundBindAddressIPv4_;
+ /** IPv6 address derived from OutboundBindAddress. */
+ tor_addr_t OutboundBindAddressIPv6_;
/** Directory server only: which versions of
* Tor should we tell users to run? */
config_line_t *RecommendedVersions;
@@ -3116,7 +3485,7 @@ typedef struct {
char *BridgePassword;
/** If BridgePassword is set, this is a SHA256 digest of the basic http
* authenticator for it. Used so we can do a time-independent comparison. */
- char *_BridgePassword_AuthDigest;
+ char *BridgePassword_AuthDigest_;
int UseBridges; /**< Boolean: should we start all circuits with a bridge? */
config_line_t *Bridges; /**< List of bootstrap bridge addresses. */
@@ -3127,6 +3496,9 @@ typedef struct {
config_line_t *ServerTransportPlugin; /**< List of client
transport plugins. */
+ /** List of TCP/IP addresses that transports should listen at. */
+ config_line_t *ServerTransportListenAddr;
+
int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make
* this explicit so we can change how we behave in the
* future. */
@@ -3142,7 +3514,7 @@ typedef struct {
* "v1", "v2", "v3", "bridge", or "". */
smartlist_t *PublishServerDescriptor;
/** A bitfield of authority types, derived from PublishServerDescriptor. */
- dirinfo_type_t _PublishServerDescriptor;
+ dirinfo_type_t PublishServerDescriptor_;
/** Boolean: do we publish hidden service descriptors to the HS auths? */
int PublishHidServDescriptors;
int FetchServerDescriptors; /**< Do we fetch server descriptors as normal? */
@@ -3175,7 +3547,7 @@ typedef struct {
int CloseHSServiceRendCircuitsImmediatelyOnTimeout;
int ConnLimit; /**< Demanded minimum number of simultaneous connections. */
- int _ConnLimit; /**< Maximum allowed number of simultaneous connections. */
+ int ConnLimit_; /**< Maximum allowed number of simultaneous connections. */
int RunAsDaemon; /**< If true, run in the background. (Unix only) */
int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */
smartlist_t *FirewallPorts; /**< Which ports our firewall allows
@@ -3234,9 +3606,7 @@ typedef struct {
* and try a new circuit if the stream has been
* waiting for this many seconds. If zero, use
* our default internal timeout schedule. */
- int MaxOnionsPending; /**< How many circuit CREATE requests do we allow
- * to wait simultaneously before we start dropping
- * them? */
+ int MaxOnionQueueDelay; /**<DOCDOC*/
int NewCircuitPeriod; /**< How long do we use a circuit before building
* a new one? */
int MaxCircuitDirtiness; /**< Never use circs that were first used more than
@@ -3288,7 +3658,14 @@ typedef struct {
/** List of configuration lines for replacement directory authorities.
* If you just want to replace one class of authority at a time,
* use the "Alternate*Authority" options below instead. */
- config_line_t *DirServers;
+ config_line_t *DirAuthorities;
+
+ /** List of fallback directory servers */
+ config_line_t *FallbackDir;
+
+ /** Weight to apply to all directory authority rates if considering them
+ * along with fallbackdirs */
+ double DirAuthorityFallbackRate;
/** If set, use these main (currently v3) directory authorities and
* not the default ones. */
@@ -3336,6 +3713,7 @@ typedef struct {
int AuthDirMaxServersPerAuthAddr; /**< Do not permit more than this
* number of servers per IP address shared
* with an authority. */
+ int AuthDirHasIPv6Connectivity; /**< Boolean: are we on IPv6? */
/** If non-zero, always vote the Fast flag for any relay advertising
* this amount of capacity or more. */
@@ -3378,7 +3756,7 @@ typedef struct {
/* Derived from SafeLogging */
enum {
SAFELOG_SCRUB_ALL, SAFELOG_SCRUB_RELAY, SAFELOG_SCRUB_NONE
- } _SafeLogging;
+ } SafeLogging_;
int SafeSocks; /**< Boolean: should we outright refuse application
* connections that use socks4 or socks5-with-local-dns? */
@@ -3397,6 +3775,10 @@ typedef struct {
int UseEntryGuards; /**< Boolean: Do we try to enter from a smallish number
* of fixed nodes? */
int NumEntryGuards; /**< How many entry guards do we try to establish? */
+ int UseEntryGuardsAsDirGuards; /** Boolean: Do we try to get directory info
+ * from a smallish number of fixed nodes? */
+ int NumDirectoryGuards; /**< How many dir guards do we try to establish?
+ * If 0, use value from NumEntryGuards. */
int RephistTrackTime; /**< How many seconds do we keep rephist info? */
int FastFirstHopPK; /**< If Tor believes it is safe, should we save a third
* of our PK time by sending CREATE_FAST cells? */
@@ -3407,8 +3789,10 @@ typedef struct {
/** Should we fetch our dir info at the start of the consensus period? */
int FetchDirInfoExtraEarly;
- char *VirtualAddrNetwork; /**< Address and mask to hand out for virtual
- * MAPADDRESS requests. */
+ char *VirtualAddrNetworkIPv4; /**< Address and mask to hand out for virtual
+ * MAPADDRESS requests for IPv4 addresses */
+ char *VirtualAddrNetworkIPv6; /**< Address and mask to hand out for virtual
+ * MAPADDRESS requests for IPv6 addresses */
int ServerDNSSearchDomains; /**< Boolean: If set, we don't force exit
* addresses to be FQDNs, but rather search for them in
* the local domains. */
@@ -3502,6 +3886,13 @@ typedef struct {
* over randomly chosen exits. */
int ClientRejectInternalAddresses;
+ /** If true, clients may connect over IPv6. XXX we don't really
+ enforce this -- clients _may_ set up outgoing IPv6 connections
+ even when this option is not set. */
+ int ClientUseIPv6;
+ /** If true, prefer an IPv6 OR port over an IPv4 one. */
+ int ClientPreferIPv6ORPort;
+
/** The length of time that we think a consensus should be fresh. */
int V3AuthVotingInterval;
/** The length of time we think it will take to distribute votes. */
@@ -3522,6 +3913,10 @@ typedef struct {
* consensus vote on the 'params' line. */
char *ConsensusParams;
+ /** Authority only: minimum number of measured bandwidths we must see
+ * before we only beliee measured bandwidths to assign flags. */
+ int MinMeasuredBWsForAuthToIgnoreAdvertised;
+
/** The length of time that we think an initial consensus should be fresh.
* Only altered on testing networks. */
int TestingV3AuthInitialVotingInterval;
@@ -3549,17 +3944,25 @@ typedef struct {
* of certain configuration options. */
int TestingTorNetwork;
- /** File to check for a consensus networkstatus, if we don't have one
- * cached. */
- char *FallbackNetworkstatusFile;
+ /** Minimum value for the Exit flag threshold on testing networks. */
+ uint64_t TestingMinExitFlagThreshold;
+
+ /** Minimum value for the Fast flag threshold on testing networks. */
+ uint64_t TestingMinFastFlagThreshold;
/** If true, and we have GeoIP data, and we're a bridge, keep a per-country
* count of how many client addresses have contacted us so that we can help
* the bridge authority guess which countries have blocked access to us. */
int BridgeRecordUsageByCountry;
- /** Optionally, a file with GeoIP data. */
+ /** Optionally, IPv4 and IPv6 GeoIP data. */
char *GeoIPFile;
+ char *GeoIPv6File;
+
+ /** Autobool: if auto, then any attempt to Exclude{Exit,}Nodes a particular
+ * country code will exclude all nodes in ?? and A1. If true, all nodes in
+ * ?? and A1 are excluded. Has no effect if we don't know any GeoIP data. */
+ int GeoIPExcludeUnknown;
/** If true, SIGHUP should reload the torrc. Sometimes controllers want
* to make this false. */
@@ -3583,13 +3986,13 @@ typedef struct {
/** If true, do not enable IOCP on windows with bufferevents, even if
* we think we could. */
int DisableIOCP;
- /** For testing only: will go away in 0.2.3.x. */
- int _UseFilteringSSLBufferevents;
+ /** For testing only: will go away eventually. */
+ int UseFilteringSSLBufferevents;
/** Set to true if the TestingTorNetwork configuration option is set.
* This is used so that options_validate() has a chance to realize that
* the defaults have changed. */
- int _UsingTestNetworkDefaults;
+ int UsingTestNetworkDefaults_;
/** If 1, we try to use microdescriptors to build circuits. If 0, we don't.
* If -1, Tor decides. */
@@ -3621,19 +4024,94 @@ typedef struct {
/**
* Parameters for path-bias detection.
* @{
+ * These options override the default behavior of Tor's (**currently
+ * experimental**) path bias detection algorithm. To try to find broken or
+ * misbehaving guard nodes, Tor looks for nodes where more than a certain
+ * fraction of circuits through that guard fail to get built.
+ *
+ * The PathBiasCircThreshold option controls how many circuits we need to
+ * build through a guard before we make these checks. The
+ * PathBiasNoticeRate, PathBiasWarnRate and PathBiasExtremeRate options
+ * control what fraction of circuits must succeed through a guard so we
+ * won't write log messages. If less than PathBiasExtremeRate circuits
+ * succeed *and* PathBiasDropGuards is set to 1, we disable use of that
+ * guard.
+ *
+ * When we have seen more than PathBiasScaleThreshold circuits through a
+ * guard, we scale our observations by 0.5 (governed by the consensus) so
+ * that new observations don't get swamped by old ones.
+ *
+ * By default, or if a negative value is provided for one of these options,
+ * Tor uses reasonable defaults from the networkstatus consensus document.
+ * If no defaults are available there, these options default to 150, .70,
+ * .50, .30, 0, and 300 respectively.
*/
int PathBiasCircThreshold;
double PathBiasNoticeRate;
- double PathBiasDisableRate;
+ double PathBiasWarnRate;
+ double PathBiasExtremeRate;
+ int PathBiasDropGuards;
int PathBiasScaleThreshold;
- int PathBiasScaleFactor;
/** @} */
+ /**
+ * Parameters for path-bias use detection
+ * @{
+ * Similar to the above options, these options override the default behavior
+ * of Tor's (**currently experimental**) path use bias detection algorithm.
+ *
+ * Where as the path bias parameters govern thresholds for successfully
+ * building circuits, these four path use bias parameters govern thresholds
+ * only for circuit usage. Circuits which receive no stream usage are not
+ * counted by this detection algorithm. A used circuit is considered
+ * successful if it is capable of carrying streams or otherwise receiving
+ * well-formed responses to RELAY cells.
+ *
+ * By default, or if a negative value is provided for one of these options,
+ * Tor uses reasonable defaults from the networkstatus consensus document.
+ * If no defaults are available there, these options default to 20, .80,
+ * .60, and 100, respectively.
+ */
+ int PathBiasUseThreshold;
+ double PathBiasNoticeUseRate;
+ double PathBiasExtremeUseRate;
+ int PathBiasScaleUseThreshold;
+ /** @} */
+
+ int IPv6Exit; /**< Do we support exiting to IPv6 addresses? */
+
+ char *TLSECGroup; /**< One of "P256", "P224", or nil for auto */
+
+ /** Autobool: should we use the ntor handshake if we can? */
+ int UseNTorHandshake;
+
+ /** Fraction: */
+ double PathsNeededToBuildCircuits;
+
+ /** Do we serve v2 directory info at all? This is a temporary option, since
+ * we'd like to disable v2 directory serving entirely, but we need a way to
+ * make it temporarily disableable, in order to do fast testing and be
+ * able to turn it back on if it turns out to be non-workable.
+ *
+ * XXXX025 Make this always-on, or always-off. Right now, it's only
+ * enableable for authorities.
+ */
+ int DisableV2DirectoryInfo_;
+
+ /** What expiry time shall we place on our SSL certs? "0" means we
+ * should guess a suitable value. */
+ int SSLKeyLifetime;
+
+ /** How long (seconds) do we keep a guard before picking a new one? */
+ int GuardLifetime;
+
+ /** Should we send the timestamps that pre-023 hidden services want? */
+ int Support022HiddenServices;
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */
typedef struct {
- uint32_t _magic;
+ uint32_t magic_;
/** The time at which we next plan to write the state to the disk. Equal to
* TIME_MAX if there are no savable changes, 0 if there are changes that
* should be saved right away. */
@@ -3753,6 +4231,10 @@ struct socks_request_t {
* make sure we send back a socks reply for
* every connection. */
unsigned int got_auth : 1; /**< Have we received any authentication data? */
+ /** If this is set, we will choose "no authentication" instead of
+ * "username/password" authentication if both are offered. Used as input to
+ * parse_socks. */
+ unsigned int socks_prefer_no_auth : 1;
/** Number of bytes in username; 0 if username is NULL */
size_t usernamelen;
@@ -4060,7 +4542,7 @@ typedef enum {
typedef struct measured_bw_line_t {
char node_id[DIGEST_LEN];
char node_hex[MAX_HEX_NICKNAME_LEN+1];
- long int bw;
+ long int bw_kb;
} measured_bw_line_t;
#endif
@@ -4082,15 +4564,6 @@ typedef struct vote_timing_t {
/********************************* geoip.c **************************/
-/** Round all GeoIP results to the next multiple of this value, to avoid
- * leaking information. */
-#define DIR_RECORD_USAGE_GRANULARITY 8
-/** Time interval: Flush geoip data to disk this often. */
-#define DIR_ENTRY_RECORD_USAGE_RETAIN_IPS (24*60*60)
-/** How long do we have to have observed per-country request history before
- * we are willing to talk about it? */
-#define DIR_RECORD_USAGE_MIN_OBSERVATION_TIME (12*60*60)
-
/** Indicates an action that we might be noting geoip statistics on.
* Note that if we're noticing CONNECT, we're a bridge, and if we're noticing
* the others, we're not.
@@ -4145,10 +4618,10 @@ typedef enum {
/** Flushed last cell from queue of the circuit that initiated a
* tunneled request to the outbuf of the OR connection. */
DIRREQ_CIRC_QUEUE_FLUSHED = 3,
- /** Flushed last byte from buffer of the OR connection belonging to the
+ /** Flushed last byte from buffer of the channel belonging to the
* circuit that initiated a tunneled request; completes a tunneled
* request. */
- DIRREQ_OR_CONN_BUFFER_FLUSHED = 4
+ DIRREQ_CHANNEL_BUFFER_FLUSHED = 4
} dirreq_state_t;
#define WRITE_STATS_INTERVAL (24*60*60)
@@ -4239,12 +4712,12 @@ typedef struct rend_encoded_v2_service_descriptor_t {
* sooner.)
*
* XXX023 Should this be configurable? */
-#define INTRO_POINT_LIFETIME_MIN_SECONDS 18*60*60
+#define INTRO_POINT_LIFETIME_MIN_SECONDS (18*60*60)
/** The maximum number of seconds that an introduction point will last
* before expiring due to old age.
*
* XXX023 Should this be configurable? */
-#define INTRO_POINT_LIFETIME_MAX_SECONDS 24*60*60
+#define INTRO_POINT_LIFETIME_MAX_SECONDS (24*60*60)
/** Introduction point information. Used both in rend_service_t (on
* the service side) and in rend_service_descriptor_t (on both the
@@ -4275,12 +4748,15 @@ typedef struct rend_intro_point_t {
* intro point. */
unsigned int rend_service_note_removing_intro_point_called : 1;
- /** (Service side only) A digestmap recording the INTRODUCE2 cells
- * this intro point's circuit has received. Each key is the digest
- * of the RSA-encrypted part of a received INTRODUCE2 cell; each
- * value is a pointer to the time_t at which the cell was received.
- * This digestmap is used to prevent replay attacks. */
- digestmap_t *accepted_intro_rsa_parts;
+ /** (Service side only) A replay cache recording the RSA-encrypted parts
+ * of INTRODUCE2 cells this intro point's circuit has received. This is
+ * used to prevent replay attacks. */
+ replaycache_t *accepted_intro_rsa_parts;
+
+ /** (Service side only) Count of INTRODUCE2 cells accepted from this
+ * intro point.
+ */
+ int accepted_introduce2_count;
/** (Service side only) The time at which this intro point was first
* published, or -1 if this intro point has not yet been
@@ -4336,19 +4812,23 @@ typedef struct rend_cache_entry_t {
/********************************* routerlist.c ***************************/
-/** Represents information about a single trusted directory server. */
-typedef struct trusted_dir_server_t {
+/** Represents information about a single trusted or fallback directory
+ * server. */
+typedef struct dir_server_t {
char *description;
char *nickname;
char *address; /**< Hostname. */
uint32_t addr; /**< IPv4 address. */
uint16_t dir_port; /**< Directory port. */
uint16_t or_port; /**< OR port: Used for tunneling connections. */
+ double weight; /** Weight used when selecting this node at random */
char digest[DIGEST_LEN]; /**< Digest of identity key. */
char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only,
* high-security) identity key. */
unsigned int is_running:1; /**< True iff we think this server is running. */
+ unsigned int is_authority:1; /**< True iff this is a directory authority
+ * of some kind. */
/** True iff this server has accepted the most recent server descriptor
* we tried to upload to it. */
@@ -4367,7 +4847,7 @@ typedef struct trusted_dir_server_t {
* as a routerstatus_t. Not updated by the
* router-status management code!
**/
-} trusted_dir_server_t;
+} dir_server_t;
#define ROUTER_REQUIRED_MIN_BANDWIDTH (20*1024)
@@ -4403,7 +4883,11 @@ typedef struct trusted_dir_server_t {
#define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3)
#define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4)
-#define _PDS_PREFER_TUNNELED_DIR_CONNS (1<<16)
+/** This node is to be chosen as a directory guard, so don't choose any
+ * node that's currently a guard. */
+#define PDS_FOR_GUARD (1<<5)
+
+#define PDS_PREFER_TUNNELED_DIR_CONNS_ (1<<16)
/** Possible ways to weight routers when choosing one randomly. See
* routerlist_sl_choose_by_bandwidth() for more information.*/
diff --git a/src/or/policies.c b/src/or/policies.c
index 81e480968..be4da5506 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -59,8 +59,10 @@ typedef struct policy_summary_item_t {
static const char *private_nets[] = {
"0.0.0.0/8", "169.254.0.0/16",
"127.0.0.0/8", "192.168.0.0/16", "10.0.0.0/8", "172.16.0.0/12",
- // "fc00::/7", "fe80::/10", "fec0::/10", "::/127",
- NULL };
+ "[::]/8",
+ "[fc00::]/7", "[fe80::]/10", "[fec0::]/10", "[ff00::]/8", "[::]/127",
+ NULL
+};
/** Replace all "private" entries in *<b>policy</b> with their expanded
* equivalents. */
@@ -87,7 +89,8 @@ policy_expand_private(smartlist_t **policy)
memcpy(&newpolicy, p, sizeof(addr_policy_t));
newpolicy.is_private = 0;
newpolicy.is_canonical = 0;
- if (tor_addr_parse_mask_ports(private_nets[i], &newpolicy.addr,
+ if (tor_addr_parse_mask_ports(private_nets[i], 0,
+ &newpolicy.addr,
&newpolicy.maskbits, &port_min, &port_max)<0) {
tor_assert(0);
}
@@ -100,6 +103,49 @@ policy_expand_private(smartlist_t **policy)
*policy = tmp;
}
+/** Expand each of the AF_UNSPEC elements in *<b>policy</b> (which indicate
+ * protocol-neutral wildcards) into a pair of wildcard elements: one IPv4-
+ * specific and one IPv6-specific. */
+void
+policy_expand_unspec(smartlist_t **policy)
+{
+ smartlist_t *tmp;
+ if (!*policy)
+ return;
+
+ tmp = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(*policy, addr_policy_t *, p) {
+ sa_family_t family = tor_addr_family(&p->addr);
+ if (family == AF_INET6 || family == AF_INET || p->is_private) {
+ smartlist_add(tmp, p);
+ } else if (family == AF_UNSPEC) {
+ addr_policy_t newpolicy_ipv4;
+ addr_policy_t newpolicy_ipv6;
+ memcpy(&newpolicy_ipv4, p, sizeof(addr_policy_t));
+ memcpy(&newpolicy_ipv6, p, sizeof(addr_policy_t));
+ newpolicy_ipv4.is_canonical = 0;
+ newpolicy_ipv6.is_canonical = 0;
+ if (p->maskbits != 0) {
+ log_warn(LD_BUG, "AF_UNSPEC policy with maskbits==%d", p->maskbits);
+ newpolicy_ipv4.maskbits = 0;
+ newpolicy_ipv6.maskbits = 0;
+ }
+ tor_addr_from_ipv4h(&newpolicy_ipv4.addr, 0);
+ tor_addr_from_ipv6_bytes(&newpolicy_ipv6.addr,
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
+ smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv4));
+ smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv6));
+ addr_policy_free(p);
+ } else {
+ log_warn(LD_BUG, "Funny-looking address policy with family %d", family);
+ smartlist_add(tmp, p);
+ }
+ } SMARTLIST_FOREACH_END(p);
+
+ smartlist_free(*policy);
+ *policy = tmp;
+}
+
/**
* Given a linked list of config lines containing "allow" and "deny"
* tokens, parse them and append the result to <b>dest</b>. Return -1
@@ -144,6 +190,7 @@ parse_addr_policy(config_line_t *cfg, smartlist_t **dest,
addr_policy_list_free(result);
} else {
policy_expand_private(&result);
+ policy_expand_unspec(&result);
if (*dest) {
smartlist_add_all(*dest, result);
@@ -319,11 +366,15 @@ addr_is_in_cc_list(uint32_t addr, const smartlist_t *cc_list)
{
country_t country;
const char *name;
+ tor_addr_t tar;
+
if (!cc_list)
return 0;
- country = geoip_get_country_by_ip(addr);
+ /* XXXXipv6 */
+ tor_addr_from_ipv4h(&tar, addr);
+ country = geoip_get_country_by_addr(&tar);
name = geoip_get_country_name(country);
- return smartlist_string_isin_case(cc_list, name);
+ return smartlist_contains_string_case(cc_list, name);
}
/** Return 1 if <b>addr</b>:<b>port</b> is permitted to publish to our
@@ -386,6 +437,7 @@ validate_addr_policies(const or_options_t *options, char **msg)
*msg = NULL;
if (policies_parse_exit_policy(options->ExitPolicy, &addr_policy,
+ options->IPv6Exit,
options->ExitPolicyRejectPrivate, NULL,
!options->BridgeRelay))
REJECT("Error in ExitPolicy entry.");
@@ -730,6 +782,10 @@ compare_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port,
static int
addr_policy_covers(addr_policy_t *a, addr_policy_t *b)
{
+ if (tor_addr_family(&a->addr) != tor_addr_family(&b->addr)) {
+ /* You can't cover a different family. */
+ return 0;
+ }
/* We can ignore accept/reject, since "accept *:80, reject *:80" reduces
* to "accept *:80". */
if (a->maskbits > b->maskbits) {
@@ -781,24 +837,54 @@ append_exit_policy_string(smartlist_t **policy, const char *more)
}
}
+/** Add "reject <b>addr</b>:*" to <b>dest</b>, creating the list as needed. */
+void
+addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr)
+{
+ addr_policy_t p, *add;
+ memset(&p, 0, sizeof(p));
+ p.policy_type = ADDR_POLICY_REJECT;
+ p.maskbits = tor_addr_family(addr) == AF_INET6 ? 128 : 32;
+ tor_addr_copy(&p.addr, addr);
+ p.prt_min = 1;
+ p.prt_max = 65535;
+
+ add = addr_policy_get_canonical_entry(&p);
+ if (!*dest)
+ *dest = smartlist_new();
+ smartlist_add(*dest, add);
+}
+
/** Detect and excise "dead code" from the policy *<b>dest</b>. */
static void
exit_policy_remove_redundancies(smartlist_t *dest)
{
- addr_policy_t *ap, *tmp, *victim;
+ addr_policy_t *ap, *tmp;
int i, j;
- /* Step one: find a *:* entry and cut off everything after it. */
- for (i = 0; i < smartlist_len(dest); ++i) {
- ap = smartlist_get(dest, i);
- if (ap->maskbits == 0 && ap->prt_min <= 1 && ap->prt_max >= 65535) {
- /* This is a catch-all line -- later lines are unreachable. */
- while (i+1 < smartlist_len(dest)) {
- victim = smartlist_get(dest, i+1);
- smartlist_del(dest, i+1);
- addr_policy_free(victim);
+ /* Step one: kill every ipv4 thing after *4:*, every IPv6 thing after *6:*
+ */
+ {
+ int kill_v4=0, kill_v6=0;
+ for (i = 0; i < smartlist_len(dest); ++i) {
+ sa_family_t family;
+ ap = smartlist_get(dest, i);
+ family = tor_addr_family(&ap->addr);
+ if ((family == AF_INET && kill_v4) ||
+ (family == AF_INET6 && kill_v6)) {
+ smartlist_del_keeporder(dest, i--);
+ addr_policy_free(ap);
+ continue;
+ }
+
+ if (ap->maskbits == 0 && ap->prt_min <= 1 && ap->prt_max >= 65535) {
+ /* This is a catch-all line -- later lines are unreachable. */
+ if (family == AF_INET) {
+ kill_v4 = 1;
+ } else if (family == AF_INET6) {
+ kill_v6 = 1;
+ }
}
- break;
}
}
@@ -813,7 +899,7 @@ exit_policy_remove_redundancies(smartlist_t *dest)
char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN];
policy_write_item(p1, sizeof(p1), tmp, 0);
policy_write_item(p2, sizeof(p2), ap, 0);
- log(LOG_DEBUG, LD_CONFIG, "Removing exit policy %s (%d). It is made "
+ log_debug(LD_CONFIG, "Removing exit policy %s (%d). It is made "
"redundant by %s (%d).", p1, j, p2, i);
smartlist_del_keeporder(dest, j--);
addr_policy_free(tmp);
@@ -842,7 +928,7 @@ exit_policy_remove_redundancies(smartlist_t *dest)
char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN];
policy_write_item(p1, sizeof(p1), ap, 0);
policy_write_item(p2, sizeof(p2), tmp, 0);
- log(LOG_DEBUG, LD_CONFIG, "Removing exit policy %s. It is already "
+ log_debug(LD_CONFIG, "Removing exit policy %s. It is already "
"covered by %s.", p1, p2);
smartlist_del_keeporder(dest, i--);
addr_policy_free(ap);
@@ -864,12 +950,20 @@ exit_policy_remove_redundancies(smartlist_t *dest)
* policy afterwards. If <b>rejectprivate</b> is true, prepend
* "reject private:*" to the policy. Return -1 if we can't parse cfg,
* else return 0.
+ *
+ * This function is used to parse the exit policy from our torrc. For
+ * the functions used to parse the exit policy from a router descriptor,
+ * see router_add_exit_policy.
*/
int
policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
+ int ipv6_exit,
int rejectprivate, const char *local_address,
int add_default_policy)
{
+ if (!ipv6_exit) {
+ append_exit_policy_string(dest, "reject *6:*");
+ }
if (rejectprivate) {
append_exit_policy_string(dest, "reject private:*");
if (local_address) {
@@ -880,10 +974,12 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
}
if (parse_addr_policy(cfg, dest, -1))
return -1;
- if (add_default_policy)
+ if (add_default_policy) {
append_exit_policy_string(dest, DEFAULT_EXIT_POLICY);
- else
- append_exit_policy_string(dest, "reject *:*");
+ } else {
+ append_exit_policy_string(dest, "reject *4:*");
+ append_exit_policy_string(dest, "reject *6:*");
+ }
exit_policy_remove_redundancies(*dest);
return 0;
@@ -894,7 +990,8 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
void
policies_exit_policy_append_reject_star(smartlist_t **dest)
{
- append_exit_policy_string(dest, "reject *:*");
+ append_exit_policy_string(dest, "reject *4:*");
+ append_exit_policy_string(dest, "reject *6:*");
}
/** Replace the exit policy of <b>node</b> with reject *:* */
@@ -970,18 +1067,23 @@ exit_policy_is_general_exit(smartlist_t *policy)
/** Return false if <b>policy</b> might permit access to some addr:port;
* otherwise if we are certain it rejects everything, return true. */
int
-policy_is_reject_star(const smartlist_t *policy)
+policy_is_reject_star(const smartlist_t *policy, sa_family_t family)
{
if (!policy) /*XXXX disallow NULL policies? */
return 1;
- SMARTLIST_FOREACH(policy, addr_policy_t *, p, {
- if (p->policy_type == ADDR_POLICY_ACCEPT)
+ SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) {
+ if (p->policy_type == ADDR_POLICY_ACCEPT &&
+ (tor_addr_family(&p->addr) == family ||
+ tor_addr_family(&p->addr) == AF_UNSPEC)) {
return 0;
- else if (p->policy_type == ADDR_POLICY_REJECT &&
- p->prt_min <= 1 && p->prt_max == 65535 &&
- p->maskbits == 0)
+ } else if (p->policy_type == ADDR_POLICY_REJECT &&
+ p->prt_min <= 1 && p->prt_max == 65535 &&
+ p->maskbits == 0 &&
+ (tor_addr_family(&p->addr) == family ||
+ tor_addr_family(&p->addr) == AF_UNSPEC)) {
return 1;
- });
+ }
+ } SMARTLIST_FOREACH_END(p);
return 1;
}
@@ -996,20 +1098,28 @@ policy_write_item(char *buf, size_t buflen, addr_policy_t *policy,
const char *addrpart;
int result;
const int is_accept = policy->policy_type == ADDR_POLICY_ACCEPT;
- const int is_ip6 = tor_addr_family(&policy->addr) == AF_INET6;
+ const sa_family_t family = tor_addr_family(&policy->addr);
+ const int is_ip6 = (family == AF_INET6);
tor_addr_to_str(addrbuf, &policy->addr, sizeof(addrbuf), 1);
/* write accept/reject 1.2.3.4 */
- if (policy->is_private)
+ if (policy->is_private) {
addrpart = "private";
- else if (policy->maskbits == 0)
- addrpart = "*";
- else
+ } else if (policy->maskbits == 0) {
+ if (format_for_desc)
+ addrpart = "*";
+ else if (family == AF_INET6)
+ addrpart = "*6";
+ else if (family == AF_INET)
+ addrpart = "*4";
+ else
+ addrpart = "*";
+ } else {
addrpart = addrbuf;
+ }
- result = tor_snprintf(buf, buflen, "%s%s%s %s",
- (is_ip6&&format_for_desc)?"opt ":"",
+ result = tor_snprintf(buf, buflen, "%s%s %s",
is_accept ? "accept" : "reject",
(is_ip6&&format_for_desc)?"6":"",
addrpart);
@@ -1189,8 +1299,8 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p)
for (i = 0; private_nets[i]; ++i) {
tor_addr_t addr;
maskbits_t maskbits;
- if (tor_addr_parse_mask_ports(private_nets[i], &addr,
- &maskbits, NULL, NULL)<0) {
+ if (tor_addr_parse_mask_ports(private_nets[i], 0, &addr,
+ &maskbits, NULL, NULL)<0) {
tor_assert(0);
}
if (tor_addr_compare(&p->addr, &addr, CMP_EXACT) == 0 &&
@@ -1216,7 +1326,7 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p)
* is an exception to the shorter-representation-wins rule).
*/
char *
-policy_summarize(smartlist_t *policy)
+policy_summarize(smartlist_t *policy, sa_family_t family)
{
smartlist_t *summary = policy_summary_create();
smartlist_t *accepts, *rejects;
@@ -1228,9 +1338,16 @@ policy_summarize(smartlist_t *policy)
tor_assert(policy);
/* Create the summary list */
- SMARTLIST_FOREACH(policy, addr_policy_t *, p, {
+ SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) {
+ sa_family_t f = tor_addr_family(&p->addr);
+ if (f != AF_INET && f != AF_INET6) {
+ log_warn(LD_BUG, "Weird family when summarizing address policy");
+ }
+ if (f != family)
+ continue;
+ /* XXXX-ipv6 More family work is needed */
policy_summary_add_item(summary, p);
- });
+ } SMARTLIST_FOREACH_END(p);
/* Now create two lists of strings, one for accepted and one
* for rejected ports. We take care to merge ranges so that
@@ -1517,7 +1634,7 @@ short_policy_is_reject_star(const short_policy_t *policy)
policy->entries[0].max_port == 65535);
}
-/** Decides whether addr:port is probably or definitely accepted or rejcted by
+/** Decide whether addr:port is probably or definitely accepted or rejected by
* <b>node</b>. See compare_tor_addr_to_addr_policy for details on addr/port
* interpretation. */
addr_policy_result_t
@@ -1527,16 +1644,29 @@ compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port,
if (node->rejects_all)
return ADDR_POLICY_REJECTED;
- if (node->ri)
+ if (addr && tor_addr_family(addr) == AF_INET6) {
+ const short_policy_t *p = NULL;
+ if (node->ri)
+ p = node->ri->ipv6_exit_policy;
+ else if (node->md)
+ p = node->md->ipv6_exit_policy;
+ if (p)
+ return compare_tor_addr_to_short_policy(addr, port, p);
+ else
+ return ADDR_POLICY_REJECTED;
+ }
+
+ if (node->ri) {
return compare_tor_addr_to_addr_policy(addr, port, node->ri->exit_policy);
- else if (node->md) {
+ } else if (node->md) {
if (node->md->exit_policy == NULL)
return ADDR_POLICY_REJECTED;
else
return compare_tor_addr_to_short_policy(addr, port,
node->md->exit_policy);
- } else
+ } else {
return ADDR_POLICY_PROBABLY_REJECTED;
+ }
}
/** Implementation for GETINFO control command: knows the answer for questions
diff --git a/src/or/policies.h b/src/or/policies.h
index f00d8299b..facbbb6b5 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,13 +9,14 @@
* \brief Header file for policies.c.
**/
-#ifndef _TOR_POLICIES_H
-#define _TOR_POLICIES_H
+#ifndef TOR_POLICIES_H
+#define TOR_POLICIES_H
-/* (length of "accept 255.255.255.255/255.255.255.255:65535-65535\n" plus a
- * NUL.)
+/* (length of
+ * "accept6 [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]/128:65535-65535\n"
+ * plus a terminating NUL, rounded up to a nice number.)
*/
-#define POLICY_BUF_LEN 52
+#define POLICY_BUF_LEN 72
int firewall_is_fascist_or(void);
int fascist_firewall_allows_address_or(const tor_addr_t *addr, uint16_t port);
@@ -31,6 +32,7 @@ int authdir_policy_badexit_address(uint32_t addr, uint16_t port);
int validate_addr_policies(const or_options_t *options, char **msg);
void policy_expand_private(smartlist_t **policy);
+void policy_expand_unspec(smartlist_t **policy);
int policies_parse_from_options(const or_options_t *options);
addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent);
@@ -42,12 +44,15 @@ addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr,
uint16_t port, const node_t *node);
int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
+ int ipv6exit,
int rejectprivate, const char *local_address,
int add_default_policy);
void policies_exit_policy_append_reject_star(smartlist_t **dest);
+void addr_policy_append_reject_addr(smartlist_t **dest,
+ const tor_addr_t *addr);
void policies_set_node_exitpolicy_to_reject_all(node_t *exitrouter);
int exit_policy_is_general_exit(smartlist_t *policy);
-int policy_is_reject_star(const smartlist_t *policy);
+int policy_is_reject_star(const smartlist_t *policy, sa_family_t family);
int getinfo_helper_policies(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);
@@ -58,7 +63,7 @@ void addr_policy_list_free(smartlist_t *p);
void addr_policy_free(addr_policy_t *p);
void policies_free_all(void);
-char *policy_summarize(smartlist_t *policy);
+char *policy_summarize(smartlist_t *policy, sa_family_t family);
short_policy_t *parse_short_policy(const char *summary);
char *write_short_policy(const short_policy_t *policy);
diff --git a/src/or/reasons.c b/src/or/reasons.c
index c51d8ee6f..0674474e7 100644
--- a/src/or/reasons.c
+++ b/src/or/reasons.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -105,7 +105,12 @@ stream_end_reason_to_socks5_response(int reason)
case END_STREAM_REASON_DESTROY:
return SOCKS5_GENERAL_ERROR;
case END_STREAM_REASON_DONE:
- return SOCKS5_SUCCEEDED;
+ /* Note that 'DONE' usually indicates a successful close from the other
+ * side of the stream... but if we receive it before a connected cell --
+ * that is, before we have sent a SOCKS reply -- that means that the
+ * other side of the circuit closed the connection before telling us it
+ * was complete. */
+ return SOCKS5_CONNECTION_REFUSED;
case END_STREAM_REASON_TIMEOUT:
return SOCKS5_TTL_EXPIRED;
case END_STREAM_REASON_NOROUTE:
@@ -169,11 +174,12 @@ errno_to_stream_end_reason(int e)
S_CASE(ENOTSOCK):
S_CASE(EPROTONOSUPPORT):
S_CASE(EAFNOSUPPORT):
- E_CASE(EACCES):
S_CASE(ENOTCONN):
- S_CASE(ENETUNREACH):
return END_STREAM_REASON_INTERNAL;
+ S_CASE(ENETUNREACH):
S_CASE(EHOSTUNREACH):
+ E_CASE(EACCES):
+ case EPERM:
return END_STREAM_REASON_NOROUTE;
S_CASE(ECONNREFUSED):
return END_STREAM_REASON_CONNECTREFUSED;
@@ -300,8 +306,13 @@ errno_to_orconn_end_reason(int e)
const char *
circuit_end_reason_to_control_string(int reason)
{
- if (reason >= 0 && reason & END_CIRC_REASON_FLAG_REMOTE)
+ int is_remote = 0;
+
+ if (reason >= 0 && reason & END_CIRC_REASON_FLAG_REMOTE) {
reason &= ~END_CIRC_REASON_FLAG_REMOTE;
+ is_remote = 1;
+ }
+
switch (reason) {
case END_CIRC_AT_ORIGIN:
/* This shouldn't get passed here; it's a catch-all reason. */
@@ -323,8 +334,8 @@ circuit_end_reason_to_control_string(int reason)
return "CONNECTFAILED";
case END_CIRC_REASON_OR_IDENTITY:
return "OR_IDENTITY";
- case END_CIRC_REASON_OR_CONN_CLOSED:
- return "OR_CONN_CLOSED";
+ case END_CIRC_REASON_CHANNEL_CLOSED:
+ return "CHANNEL_CLOSED";
case END_CIRC_REASON_FINISHED:
return "FINISHED";
case END_CIRC_REASON_TIMEOUT:
@@ -338,7 +349,18 @@ circuit_end_reason_to_control_string(int reason)
case END_CIRC_REASON_MEASUREMENT_EXPIRED:
return "MEASUREMENT_EXPIRED";
default:
- log_warn(LD_BUG, "Unrecognized reason code %d", (int)reason);
+ if (is_remote) {
+ /*
+ * If it's remote, it's not a bug *here*, so don't use LD_BUG, but
+ * do note that the someone we're talking to is speaking the Tor
+ * protocol with a weird accent.
+ */
+ log_warn(LD_PROTOCOL,
+ "Remote server sent bogus reason code %d", reason);
+ } else {
+ log_warn(LD_BUG,
+ "Unrecognized reason code %d", reason);
+ }
return NULL;
}
}
diff --git a/src/or/reasons.h b/src/or/reasons.h
index 377b61b11..fe7e67722 100644
--- a/src/or/reasons.h
+++ b/src/or/reasons.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for reasons.c.
**/
-#ifndef _TOR_REASONS_H
-#define _TOR_REASONS_H
+#ifndef TOR_REASONS_H
+#define TOR_REASONS_H
const char *stream_end_reason_to_control_string(int reason);
const char *stream_end_reason_to_string(int reason);
diff --git a/src/or/relay.c b/src/or/relay.c
index a193ad843..57633f86a 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,12 +10,14 @@
* receiving from circuits, plus queuing on circuits.
**/
-#include <math.h>
#define RELAY_PRIVATE
#include "or.h"
+#include "addressmap.h"
#include "buffers.h"
+#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "circuituse.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
@@ -26,6 +28,7 @@
#include "mempool.h"
#include "networkstatus.h"
#include "nodelist.h"
+#include "onion.h"
#include "policies.h"
#include "reasons.h"
#include "relay.h"
@@ -51,6 +54,10 @@ static int circuit_resume_edge_reading_helper(edge_connection_t *conn,
static int circuit_consider_stop_edge_reading(circuit_t *circ,
crypt_path_t *layer_hint);
static int circuit_queue_streams_are_blocked(circuit_t *circ);
+static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ,
+ entry_connection_t *conn,
+ node_t *node,
+ const tor_addr_t *addr);
/** Stop reading on edge connections when we have this many cells
* waiting on the appropriate queue. */
@@ -68,6 +75,9 @@ uint64_t stats_n_relay_cells_relayed = 0;
*/
uint64_t stats_n_relay_cells_delivered = 0;
+/** Used to tell which stream to read from first on a circuit. */
+static tor_weak_rng_t stream_choice_rng = TOR_WEAK_RNG_INIT;
+
/** Update digest from the payload of cell. Assign integrity part to
* cell.
*/
@@ -166,7 +176,7 @@ int
circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction)
{
- or_connection_t *or_conn=NULL;
+ channel_t *chan = NULL;
crypt_path_t *layer_hint=NULL;
char recognized=0;
int reason;
@@ -184,7 +194,17 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
}
if (recognized) {
- edge_connection_t *conn = relay_lookup_conn(circ, cell, cell_direction,
+ edge_connection_t *conn = NULL;
+
+ if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) {
+ pathbias_check_probe_response(circ, cell);
+
+ /* We need to drop this cell no matter what to avoid code that expects
+ * a certain purpose (such as the hidserv code). */
+ return 0;
+ }
+
+ conn = relay_lookup_conn(circ, cell, cell_direction,
layer_hint);
if (cell_direction == CELL_DIRECTION_OUT) {
++stats_n_relay_cells_delivered;
@@ -213,24 +233,32 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
/* not recognized. pass it on. */
if (cell_direction == CELL_DIRECTION_OUT) {
cell->circ_id = circ->n_circ_id; /* switch it */
- or_conn = circ->n_conn;
+ chan = circ->n_chan;
} else if (! CIRCUIT_IS_ORIGIN(circ)) {
cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */
- or_conn = TO_OR_CIRCUIT(circ)->p_conn;
+ chan = TO_OR_CIRCUIT(circ)->p_chan;
} else {
log_fn(LOG_PROTOCOL_WARN, LD_OR,
"Dropping unrecognized inbound cell on origin circuit.");
- return 0;
+ /* If we see unrecognized cells on path bias testing circs,
+ * it's bad mojo. Those circuits need to die.
+ * XXX: Shouldn't they always die? */
+ if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) {
+ TO_ORIGIN_CIRCUIT(circ)->path_state = PATH_STATE_USE_FAILED;
+ return -END_CIRC_REASON_TORPROTOCOL;
+ } else {
+ return 0;
+ }
}
- if (!or_conn) {
+ if (!chan) {
// XXXX Can this splice stuff be done more cleanly?
if (! CIRCUIT_IS_ORIGIN(circ) &&
TO_OR_CIRCUIT(circ)->rend_splice &&
cell_direction == CELL_DIRECTION_OUT) {
or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice;
tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
- tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
+ tor_assert(splice->base_.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
cell->circ_id = splice->p_circ_id;
cell->command = CELL_RELAY; /* can't be relay_early anyway */
if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice),
@@ -254,7 +282,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
* we might kill the circ before we relay
* the cells. */
- append_cell_to_circuit_queue(circ, or_conn, cell, cell_direction, 0);
+ append_cell_to_circuit_queue(circ, chan, cell, cell_direction, 0);
return 0;
}
@@ -351,15 +379,22 @@ relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
static int
circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction,
- crypt_path_t *layer_hint, streamid_t on_stream)
+ crypt_path_t *layer_hint, streamid_t on_stream,
+ const char *filename, int lineno)
{
- or_connection_t *conn; /* where to send the cell */
+ channel_t *chan; /* where to send the cell */
if (cell_direction == CELL_DIRECTION_OUT) {
crypt_path_t *thishop; /* counter for repeated crypts */
- conn = circ->n_conn;
- if (!CIRCUIT_IS_ORIGIN(circ) || !conn) {
- log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping.");
+ chan = circ->n_chan;
+ if (!chan) {
+ log_warn(LD_BUG,"outgoing relay cell sent from %s:%d has n_chan==NULL."
+ " Dropping.", filename, lineno);
+ return 0; /* just drop it */
+ }
+ if (!CIRCUIT_IS_ORIGIN(circ)) {
+ log_warn(LD_BUG,"outgoing relay cell sent from %s:%d on non-origin "
+ "circ. Dropping.", filename, lineno);
return 0; /* just drop it */
}
@@ -388,14 +423,14 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
return 0; /* just drop it */
}
or_circ = TO_OR_CIRCUIT(circ);
- conn = or_circ->p_conn;
+ chan = or_circ->p_chan;
relay_set_digest(or_circ->p_digest, cell);
if (relay_crypt_one_payload(or_circ->p_crypto, cell->payload, 1) < 0)
return -1;
}
++stats_n_relay_cells_relayed;
- append_cell_to_circuit_queue(circ, conn, cell, cell_direction, on_stream);
+ append_cell_to_circuit_queue(circ, chan, cell, cell_direction, on_stream);
return 0;
}
@@ -422,7 +457,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell,
for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (rh.stream_id == tmpconn->stream_id &&
- !tmpconn->_base.marked_for_close &&
+ !tmpconn->base_.marked_for_close &&
tmpconn->cpath_layer == layer_hint) {
log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
return tmpconn;
@@ -432,7 +467,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell,
for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (rh.stream_id == tmpconn->stream_id &&
- !tmpconn->_base.marked_for_close) {
+ !tmpconn->base_.marked_for_close) {
log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
if (cell_direction == CELL_DIRECTION_OUT ||
connection_edge_is_rendezvous_stream(tmpconn))
@@ -442,7 +477,7 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell,
for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
if (rh.stream_id == tmpconn->stream_id &&
- !tmpconn->_base.marked_for_close) {
+ !tmpconn->base_.marked_for_close) {
log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
return tmpconn;
}
@@ -520,9 +555,10 @@ relay_command_to_string(uint8_t command)
* return 0.
*/
int
-relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
- uint8_t relay_command, const char *payload,
- size_t payload_len, crypt_path_t *cpath_layer)
+relay_send_command_from_edge_(streamid_t stream_id, circuit_t *circ,
+ uint8_t relay_command, const char *payload,
+ size_t payload_len, crypt_path_t *cpath_layer,
+ const char *filename, int lineno)
{
cell_t cell;
relay_header_t rh;
@@ -561,15 +597,16 @@ relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
geoip_change_dirreq_state(circ->dirreq_id, DIRREQ_TUNNELED,
DIRREQ_END_CELL_SENT);
- if (cell_direction == CELL_DIRECTION_OUT && circ->n_conn) {
+ if (cell_direction == CELL_DIRECTION_OUT && circ->n_chan) {
/* if we're using relaybandwidthrate, this conn wants priority */
- circ->n_conn->client_used = approx_time();
+ channel_timestamp_client(circ->n_chan);
}
if (cell_direction == CELL_DIRECTION_OUT) {
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
if (origin_circ->remaining_relay_early_cells > 0 &&
(relay_command == RELAY_COMMAND_EXTEND ||
+ relay_command == RELAY_COMMAND_EXTEND2 ||
cpath_layer != origin_circ->cpath)) {
/* If we've got any relay_early cells left and (we're sending
* an extend cell or we're not talking to the first hop), use
@@ -583,7 +620,8 @@ relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
* task 878. */
origin_circ->relay_early_commands[
origin_circ->relay_early_cells_sent++] = relay_command;
- } else if (relay_command == RELAY_COMMAND_EXTEND) {
+ } else if (relay_command == RELAY_COMMAND_EXTEND ||
+ relay_command == RELAY_COMMAND_EXTEND2) {
/* If no RELAY_EARLY cells can be sent over this circuit, log which
* commands have been sent as RELAY_EARLY cells before; helps debug
* task 878. */
@@ -603,7 +641,7 @@ relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
}
if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer,
- stream_id) < 0) {
+ stream_id, filename, lineno) < 0) {
log_warn(LD_BUG,"circuit_package_relay_cell failed. Closing.");
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
return -1;
@@ -631,16 +669,16 @@ connection_edge_send_command(edge_connection_t *fromconn,
tor_assert(fromconn);
circ = fromconn->on_circuit;
- if (fromconn->_base.marked_for_close) {
+ if (fromconn->base_.marked_for_close) {
log_warn(LD_BUG,
"called on conn that's already marked for close at %s:%d.",
- fromconn->_base.marked_for_close_file,
- fromconn->_base.marked_for_close);
+ fromconn->base_.marked_for_close_file,
+ fromconn->base_.marked_for_close);
return 0;
}
if (!circ) {
- if (fromconn->_base.type == CONN_TYPE_AP) {
+ if (fromconn->base_.type == CONN_TYPE_AP) {
log_info(LD_APP,"no circ. Closing conn.");
connection_mark_unattached_ap(EDGE_TO_ENTRY_CONN(fromconn),
END_STREAM_REASON_INTERNAL);
@@ -685,14 +723,41 @@ connection_ap_process_end_not_open(
relay_header_t *rh, cell_t *cell, origin_circuit_t *circ,
entry_connection_t *conn, crypt_path_t *layer_hint)
{
- struct in_addr in;
node_t *exitrouter;
int reason = *(cell->payload+RELAY_HEADER_SIZE);
- int control_reason = reason | END_STREAM_REASON_FLAG_REMOTE;
+ int control_reason;
edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn);
(void) layer_hint; /* unused */
- if (rh->length > 0 && edge_reason_is_retriable(reason) &&
+ if (rh->length > 0) {
+ if (reason == END_STREAM_REASON_TORPROTOCOL ||
+ reason == END_STREAM_REASON_DESTROY) {
+ /* Both of these reasons could mean a failed tag
+ * hit the exit and it complained. Do not probe.
+ * Fail the circuit. */
+ circ->path_state = PATH_STATE_USE_FAILED;
+ return -END_CIRC_REASON_TORPROTOCOL;
+ } else if (reason == END_STREAM_REASON_INTERNAL) {
+ /* We can't infer success or failure, since older Tors report
+ * ENETUNREACH as END_STREAM_REASON_INTERNAL. */
+ } else {
+ /* Path bias: If we get a valid reason code from the exit,
+ * it wasn't due to tagging.
+ *
+ * We rely on recognized+digest being strong enough to make
+ * tags unlikely to allow us to get tagged, yet 'recognized'
+ * reason codes here. */
+ pathbias_mark_use_success(circ);
+ }
+ }
+
+ if (rh->length == 0) {
+ reason = END_STREAM_REASON_MISC;
+ }
+
+ control_reason = reason | END_STREAM_REASON_FLAG_REMOTE;
+
+ if (edge_reason_is_retriable(reason) &&
/* avoid retry if rend */
!connection_edge_is_rendezvous_stream(edge_conn)) {
const char *chosen_exit_digest =
@@ -702,48 +767,67 @@ connection_ap_process_end_not_open(
stream_end_reason_to_string(reason));
exitrouter = node_get_mutable_by_id(chosen_exit_digest);
switch (reason) {
- case END_STREAM_REASON_EXITPOLICY:
+ case END_STREAM_REASON_EXITPOLICY: {
+ tor_addr_t addr;
+ tor_addr_make_unspec(&addr);
if (rh->length >= 5) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
- int ttl;
- if (!addr) {
+ int ttl = -1;
+ tor_addr_make_unspec(&addr);
+ if (rh->length == 5 || rh->length == 9) {
+ tor_addr_from_ipv4n(&addr,
+ get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
+ if (rh->length == 9)
+ ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
+ } else if (rh->length == 17 || rh->length == 21) {
+ tor_addr_from_ipv6_bytes(&addr,
+ (char*)(cell->payload+RELAY_HEADER_SIZE+1));
+ if (rh->length == 21)
+ ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+17));
+ }
+ if (tor_addr_is_null(&addr)) {
log_info(LD_APP,"Address '%s' resolved to 0.0.0.0. Closing,",
safe_str(conn->socks_request->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return 0;
}
- if (rh->length >= 9)
- ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
- else
- ttl = -1;
+ if ((tor_addr_family(&addr) == AF_INET && !conn->ipv4_traffic_ok) ||
+ (tor_addr_family(&addr) == AF_INET6 && !conn->ipv6_traffic_ok)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_APP,
+ "Got an EXITPOLICY failure on a connection with a "
+ "mismatched family. Closing.");
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
+ return 0;
+ }
if (get_options()->ClientDNSRejectInternalAddresses &&
- is_internal_IP(addr, 0)) {
+ tor_addr_is_internal(&addr, 0)) {
log_info(LD_APP,"Address '%s' resolved to internal. Closing,",
safe_str(conn->socks_request->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return 0;
}
- client_dns_set_addressmap(conn->socks_request->address, addr,
+
+ client_dns_set_addressmap(conn,
+ conn->socks_request->address, &addr,
conn->chosen_exit_name, ttl);
+
+ {
+ char new_addr[TOR_ADDR_BUF_LEN];
+ tor_addr_to_str(new_addr, &addr, sizeof(new_addr), 1);
+ if (strcmp(conn->socks_request->address, new_addr)) {
+ strlcpy(conn->socks_request->address, new_addr,
+ sizeof(conn->socks_request->address));
+ control_event_stream_status(conn, STREAM_EVENT_REMAP, 0);
+ }
+ }
}
/* check if he *ought* to have allowed it */
- if (exitrouter &&
- (rh->length < 5 ||
- (tor_inet_aton(conn->socks_request->address, &in) &&
- !conn->chosen_exit_name))) {
- log_info(LD_APP,
- "Exitrouter %s seems to be more restrictive than its exit "
- "policy. Not using this router as exit for now.",
- node_describe(exitrouter));
- policies_set_node_exitpolicy_to_reject_all(exitrouter);
- }
- /* rewrite it to an IP if we learned one. */
- if (addressmap_rewrite(conn->socks_request->address,
- sizeof(conn->socks_request->address),
- NULL, NULL)) {
- control_event_stream_status(conn, STREAM_EVENT_REMAP, 0);
- }
+
+ adjust_exit_policy_from_exitpolicy_failure(circ,
+ conn,
+ exitrouter,
+ &addr);
+
if (conn->chosen_exit_optional ||
conn->chosen_exit_retries) {
/* stop wanting a specific exit */
@@ -762,6 +846,7 @@ connection_ap_process_end_not_open(
return 0;
/* else, conn will get closed below */
break;
+ }
case END_STREAM_REASON_CONNECTREFUSED:
if (!conn->chosen_exit_optional)
break; /* break means it'll close, below */
@@ -776,9 +861,7 @@ connection_ap_process_end_not_open(
/* We haven't retried too many times; reattach the connection. */
circuit_log_path(LOG_INFO,LD_APP,circ);
/* Mark this circuit "unusable for new streams". */
- /* XXXX024 this is a kludgy way to do this. */
- tor_assert(circ->_base.timestamp_dirty);
- circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+ mark_circuit_unusable_for_new_conns(circ);
if (conn->chosen_exit_optional) {
/* stop wanting a specific exit */
@@ -826,21 +909,102 @@ connection_ap_process_end_not_open(
return 0;
}
+/** Called when we have gotten an END_REASON_EXITPOLICY failure on <b>circ</b>
+ * for <b>conn</b>, while attempting to connect via <b>node</b>. If the node
+ * told us which address it rejected, then <b>addr</b> is that address;
+ * otherwise it is AF_UNSPEC.
+ *
+ * If we are sure the node should have allowed this address, mark the node as
+ * having a reject *:* exit policy. Otherwise, mark the circuit as unusable
+ * for this particular address.
+ **/
+static void
+adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ,
+ entry_connection_t *conn,
+ node_t *node,
+ const tor_addr_t *addr)
+{
+ int make_reject_all = 0;
+ const sa_family_t family = tor_addr_family(addr);
+
+ if (node) {
+ tor_addr_t tmp;
+ int asked_for_family = tor_addr_parse(&tmp, conn->socks_request->address);
+ if (family == AF_UNSPEC) {
+ make_reject_all = 1;
+ } else if (node_exit_policy_is_exact(node, family) &&
+ asked_for_family != -1 && !conn->chosen_exit_name) {
+ make_reject_all = 1;
+ }
+
+ if (make_reject_all) {
+ log_info(LD_APP,
+ "Exitrouter %s seems to be more restrictive than its exit "
+ "policy. Not using this router as exit for now.",
+ node_describe(node));
+ policies_set_node_exitpolicy_to_reject_all(node);
+ }
+ }
+
+ if (family != AF_UNSPEC)
+ addr_policy_append_reject_addr(&circ->prepend_policy, addr);
+}
+
/** Helper: change the socks_request-&gt;address field on conn to the
- * dotted-quad representation of <b>new_addr</b> (given in host order),
+ * dotted-quad representation of <b>new_addr</b>,
* and send an appropriate REMAP event. */
static void
-remap_event_helper(entry_connection_t *conn, uint32_t new_addr)
+remap_event_helper(entry_connection_t *conn, const tor_addr_t *new_addr)
{
- struct in_addr in;
-
- in.s_addr = htonl(new_addr);
- tor_inet_ntoa(&in, conn->socks_request->address,
- sizeof(conn->socks_request->address));
+ tor_addr_to_str(conn->socks_request->address, new_addr,
+ sizeof(conn->socks_request->address),
+ 1);
control_event_stream_status(conn, STREAM_EVENT_REMAP,
REMAP_STREAM_SOURCE_EXIT);
}
+/** Extract the contents of a connected cell in <b>cell</b>, whose relay
+ * header has already been parsed into <b>rh</b>. On success, set
+ * <b>addr_out</b> to the address we're connected to, and <b>ttl_out</b> to
+ * the ttl of that address, in seconds, and return 0. On failure, return
+ * -1. */
+int
+connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
+ tor_addr_t *addr_out, int *ttl_out)
+{
+ uint32_t bytes;
+ const uint8_t *payload = cell->payload + RELAY_HEADER_SIZE;
+
+ tor_addr_make_unspec(addr_out);
+ *ttl_out = -1;
+ if (rh->length == 0)
+ return 0;
+ if (rh->length < 4)
+ return -1;
+ bytes = ntohl(get_uint32(payload));
+
+ /* If bytes is 0, this is maybe a v6 address. Otherwise it's a v4 address */
+ if (bytes != 0) {
+ /* v4 address */
+ tor_addr_from_ipv4h(addr_out, bytes);
+ if (rh->length >= 8) {
+ bytes = ntohl(get_uint32(payload + 4));
+ if (bytes <= INT32_MAX)
+ *ttl_out = bytes;
+ }
+ } else {
+ if (rh->length < 25) /* 4 bytes of 0s, 1 addr, 16 ipv4, 4 ttl. */
+ return -1;
+ if (get_uint8(payload + 4) != 6)
+ return -1;
+ tor_addr_from_ipv6_bytes(addr_out, (char*)(payload + 5));
+ bytes = ntohl(get_uint32(payload + 21));
+ if (bytes <= INT32_MAX)
+ *ttl_out = (int) bytes;
+ }
+ return 0;
+}
+
/** An incoming relay cell has arrived from circuit <b>circ</b> to
* stream <b>conn</b>.
*
@@ -854,7 +1018,7 @@ connection_edge_process_relay_cell_not_open(
edge_connection_t *conn, crypt_path_t *layer_hint)
{
if (rh->command == RELAY_COMMAND_END) {
- if (CIRCUIT_IS_ORIGIN(circ) && conn->_base.type == CONN_TYPE_AP) {
+ if (CIRCUIT_IS_ORIGIN(circ) && conn->base_.type == CONN_TYPE_AP) {
return connection_ap_process_end_not_open(rh, cell,
TO_ORIGIN_CIRCUIT(circ),
EDGE_TO_ENTRY_CONN(conn),
@@ -869,38 +1033,55 @@ connection_edge_process_relay_cell_not_open(
}
}
- if (conn->_base.type == CONN_TYPE_AP &&
+ if (conn->base_.type == CONN_TYPE_AP &&
rh->command == RELAY_COMMAND_CONNECTED) {
+ tor_addr_t addr;
+ int ttl;
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
- if (conn->_base.state != AP_CONN_STATE_CONNECT_WAIT) {
+ if (conn->base_.state != AP_CONN_STATE_CONNECT_WAIT) {
log_fn(LOG_PROTOCOL_WARN, LD_APP,
"Got 'connected' while not in state connect_wait. Dropping.");
return 0;
}
- conn->_base.state = AP_CONN_STATE_OPEN;
+ conn->base_.state = AP_CONN_STATE_OPEN;
log_info(LD_APP,"'connected' received after %d seconds.",
- (int)(time(NULL) - conn->_base.timestamp_lastread));
- if (rh->length >= 4) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
- int ttl;
- if (!addr || (get_options()->ClientDNSRejectInternalAddresses &&
- is_internal_IP(addr, 0))) {
+ (int)(time(NULL) - conn->base_.timestamp_lastread));
+ if (connected_cell_parse(rh, cell, &addr, &ttl) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_APP,
+ "Got a badly formatted connected cell. Closing.");
+ connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
+ connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL);
+ }
+ if (tor_addr_family(&addr) != AF_UNSPEC) {
+ const sa_family_t family = tor_addr_family(&addr);
+ if (tor_addr_is_null(&addr) ||
+ (get_options()->ClientDNSRejectInternalAddresses &&
+ tor_addr_is_internal(&addr, 0))) {
log_info(LD_APP, "...but it claims the IP address was %s. Closing.",
- fmt_addr32(addr));
+ fmt_addr(&addr));
+ connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
+ connection_mark_unattached_ap(entry_conn,
+ END_STREAM_REASON_TORPROTOCOL);
+ return 0;
+ }
+
+ if ((family == AF_INET && ! entry_conn->ipv4_traffic_ok) ||
+ (family == AF_INET6 && ! entry_conn->ipv6_traffic_ok)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_APP,
+ "Got a connected cell to %s with unsupported address family."
+ " Closing.", fmt_addr(&addr));
connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
connection_mark_unattached_ap(entry_conn,
END_STREAM_REASON_TORPROTOCOL);
return 0;
}
- if (rh->length >= 8)
- ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+4));
- else
- ttl = -1;
- client_dns_set_addressmap(entry_conn->socks_request->address, addr,
+
+ client_dns_set_addressmap(entry_conn,
+ entry_conn->socks_request->address, &addr,
entry_conn->chosen_exit_name, ttl);
- remap_event_helper(entry_conn, addr);
+ remap_event_helper(entry_conn, &addr);
}
circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ));
/* don't send a socks reply to transparent conns */
@@ -924,6 +1105,7 @@ connection_edge_process_relay_cell_not_open(
control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_STATUS, 0);
break;
case DIR_PURPOSE_FETCH_SERVERDESC:
+ case DIR_PURPOSE_FETCH_MICRODESC:
control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS,
count_loading_descriptors_progress());
break;
@@ -944,13 +1126,13 @@ connection_edge_process_relay_cell_not_open(
}
return 0;
}
- if (conn->_base.type == CONN_TYPE_AP &&
+ if (conn->base_.type == CONN_TYPE_AP &&
rh->command == RELAY_COMMAND_RESOLVED) {
int ttl;
int answer_len;
uint8_t answer_type;
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
- if (conn->_base.state != AP_CONN_STATE_RESOLVE_WAIT) {
+ if (conn->base_.state != AP_CONN_STATE_RESOLVE_WAIT) {
log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a 'resolved' cell while "
"not in state resolve_wait. Dropping.");
return 0;
@@ -969,12 +1151,15 @@ connection_edge_process_relay_cell_not_open(
2+answer_len));
else
ttl = -1;
- if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+2));
- if (get_options()->ClientDNSRejectInternalAddresses &&
- is_internal_IP(addr, 0)) {
+ if (answer_type == RESOLVED_TYPE_IPV4 ||
+ answer_type == RESOLVED_TYPE_IPV6) {
+ tor_addr_t addr;
+ if (decode_address_from_payload(&addr, cell->payload+RELAY_HEADER_SIZE,
+ rh->length) &&
+ tor_addr_is_internal(&addr, 0) &&
+ get_options()->ClientDNSRejectInternalAddresses) {
log_info(LD_APP,"Got a resolve with answer %s. Rejecting.",
- fmt_addr32(addr));
+ fmt_addr(&addr));
connection_ap_handshake_socks_resolved(entry_conn,
RESOLVED_TYPE_ERROR_TRANSIENT,
0, NULL, 0, TIME_MAX);
@@ -990,8 +1175,15 @@ connection_edge_process_relay_cell_not_open(
ttl,
-1);
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+2));
- remap_event_helper(entry_conn, addr);
+ tor_addr_t addr;
+ tor_addr_from_ipv4n(&addr,
+ get_uint32(cell->payload+RELAY_HEADER_SIZE+2));
+ remap_event_helper(entry_conn, &addr);
+ } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
+ tor_addr_t addr;
+ tor_addr_from_ipv6_bytes(&addr,
+ (char*)(cell->payload+RELAY_HEADER_SIZE+2));
+ remap_event_helper(entry_conn, &addr);
}
connection_mark_unattached_ap(entry_conn,
END_STREAM_REASON_DONE |
@@ -1001,8 +1193,8 @@ connection_edge_process_relay_cell_not_open(
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Got an unexpected relay command %d, in state %d (%s). Dropping.",
- rh->command, conn->_base.state,
- conn_state_to_string(conn->_base.type, conn->_base.state));
+ rh->command, conn->base_.state,
+ conn_state_to_string(conn->base_.type, conn->base_.state));
return 0; /* for forward compatibility, don't kill the circuit */
// connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
// connection_mark_for_close(conn);
@@ -1067,9 +1259,9 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
* 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) &&
+ 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.
@@ -1112,7 +1304,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
* and linked. */
static uint64_t next_id = 0;
circ->dirreq_id = ++next_id;
- TO_CONN(TO_OR_CIRCUIT(circ)->p_conn)->dirreq_id = circ->dirreq_id;
+ TO_OR_CIRCUIT(circ)->p_chan->dirreq_id = circ->dirreq_id;
}
return connection_exit_begin_conn(cell, circ);
@@ -1168,11 +1360,12 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
return 0;
}
/* XXX add to this log_fn the exit node's nickname? */
- log_info(domain,"%d: end cell (%s) for stream %d. Removing stream.",
- conn->_base.s,
+ log_info(domain,TOR_SOCKET_T_FORMAT": end cell (%s) for stream %d. "
+ "Removing stream.",
+ conn->base_.s,
stream_end_reason_to_string(reason),
conn->stream_id);
- if (conn->_base.type == CONN_TYPE_AP) {
+ if (conn->base_.type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
if (entry_conn->socks_request &&
!entry_conn->socks_request->has_finished)
@@ -1183,16 +1376,17 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
conn->edge_has_sent_end = 1;
if (!conn->end_reason)
conn->end_reason = reason | END_STREAM_REASON_FLAG_REMOTE;
- if (!conn->_base.marked_for_close) {
+ if (!conn->base_.marked_for_close) {
/* only mark it if not already marked. it's possible to
* get the 'end' right around when the client hangs up on us. */
connection_mark_and_flush(TO_CONN(conn));
}
return 0;
- case RELAY_COMMAND_EXTEND: {
+ case RELAY_COMMAND_EXTEND:
+ case RELAY_COMMAND_EXTEND2: {
static uint64_t total_n_extend=0, total_nonearly=0;
total_n_extend++;
- if (conn) {
+ if (rh.stream_id) {
log_fn(LOG_PROTOCOL_WARN, domain,
"'extend' cell received for non-zero stream. Dropping.");
return 0;
@@ -1224,17 +1418,27 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
return circuit_extend(cell, circ);
}
case RELAY_COMMAND_EXTENDED:
+ case RELAY_COMMAND_EXTENDED2:
if (!layer_hint) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"'extended' unsupported at non-origin. Dropping.");
return 0;
}
log_debug(domain,"Got an extended cell! Yay.");
- if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ),
- CELL_CREATED,
- cell->payload+RELAY_HEADER_SIZE)) < 0) {
- log_warn(domain,"circuit_finish_handshake failed.");
- return reason;
+ {
+ extended_cell_t extended_cell;
+ if (extended_cell_parse(&extended_cell, rh.command,
+ (const uint8_t*)cell->payload+RELAY_HEADER_SIZE,
+ rh.length)<0) {
+ log_warn(LD_PROTOCOL,
+ "Can't parse EXTENDED cell; killing circuit.");
+ return -END_CIRC_REASON_TORPROTOCOL;
+ }
+ if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ),
+ &extended_cell.created_cell)) < 0) {
+ log_warn(domain,"circuit_finish_handshake failed.");
+ return reason;
+ }
}
if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) {
log_info(domain,"circuit_send_next_onion_skin() failed.");
@@ -1247,12 +1451,20 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
"'truncate' unsupported at origin. Dropping.");
return 0;
}
- if (circ->n_conn) {
- uint8_t trunc_reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE);
- circuit_clear_cell_queue(circ, circ->n_conn);
- connection_or_send_destroy(circ->n_circ_id, circ->n_conn,
- trunc_reason);
- circuit_set_n_circid_orconn(circ, 0, NULL);
+ if (circ->n_hop) {
+ if (circ->n_chan)
+ log_warn(LD_BUG, "n_chan and n_hop set on the same circuit!");
+ extend_info_free(circ->n_hop);
+ circ->n_hop = NULL;
+ tor_free(circ->n_chan_create_cell);
+ circuit_set_state(circ, CIRCUIT_STATE_OPEN);
+ }
+ if (circ->n_chan) {
+ uint8_t trunc_reason = get_uint8(cell->payload + RELAY_HEADER_SIZE);
+ circuit_clear_cell_queue(circ, circ->n_chan);
+ channel_send_destroy(circ->n_circ_id, circ->n_chan,
+ trunc_reason);
+ circuit_set_n_circid_chan(circ, 0, NULL);
}
log_debug(LD_EXIT, "Processed 'truncate', replying.");
{
@@ -1268,7 +1480,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
"'truncated' unsupported at non-origin. Dropping.");
return 0;
}
- circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint);
+ circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint,
+ get_uint8(cell->payload + RELAY_HEADER_SIZE));
return 0;
case RELAY_COMMAND_CONNECTED:
if (conn) {
@@ -1285,7 +1498,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
if (layer_hint->package_window + CIRCWINDOW_INCREMENT >
CIRCWINDOW_START_MAX) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Bug/attack: unexpected sendme cell from exit relay. "
+ "Unexpected sendme cell from exit relay. "
"Closing circ.");
return -END_CIRC_REASON_TORPROTOCOL;
}
@@ -1297,8 +1510,9 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
if (circ->package_window + CIRCWINDOW_INCREMENT >
CIRCWINDOW_START_MAX) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Bug/attack: unexpected sendme cell from client. "
- "Closing circ.");
+ "Unexpected sendme cell from client. "
+ "Closing circ (window %d).",
+ circ->package_window);
return -END_CIRC_REASON_TORPROTOCOL;
}
circ->package_window += CIRCWINDOW_INCREMENT;
@@ -1406,21 +1620,22 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
size_t bytes_to_process, length;
char payload[CELL_PAYLOAD_SIZE];
circuit_t *circ;
- const unsigned domain = conn->_base.type == CONN_TYPE_AP ? LD_APP : LD_EXIT;
+ const unsigned domain = conn->base_.type == CONN_TYPE_AP ? LD_APP : LD_EXIT;
int sending_from_optimistic = 0;
- const int sending_optimistically =
- conn->_base.type == CONN_TYPE_AP &&
- conn->_base.state != AP_CONN_STATE_OPEN;
entry_connection_t *entry_conn =
- conn->_base.type == CONN_TYPE_AP ? EDGE_TO_ENTRY_CONN(conn) : NULL;
+ conn->base_.type == CONN_TYPE_AP ? EDGE_TO_ENTRY_CONN(conn) : NULL;
+ const int sending_optimistically =
+ entry_conn &&
+ conn->base_.type == CONN_TYPE_AP &&
+ conn->base_.state != AP_CONN_STATE_OPEN;
crypt_path_t *cpath_layer = conn->cpath_layer;
tor_assert(conn);
- if (conn->_base.marked_for_close) {
+ if (conn->base_.marked_for_close) {
log_warn(LD_BUG,
"called on conn that's already marked for close at %s:%d.",
- conn->_base.marked_for_close_file, conn->_base.marked_for_close);
+ conn->base_.marked_for_close_file, conn->base_.marked_for_close);
return 0;
}
@@ -1487,7 +1702,8 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
connection_fetch_from_buf(payload, length, TO_CONN(conn));
}
- log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s,
+ log_debug(domain,TOR_SOCKET_T_FORMAT": Packaging %d bytes (%d waiting).",
+ conn->base_.s,
(int)length, (int)connection_get_inbuf_len(TO_CONN(conn)));
if (sending_optimistically && !sending_from_optimistic) {
@@ -1553,9 +1769,9 @@ connection_edge_consider_sending_sendme(edge_connection_t *conn)
}
while (conn->deliver_window <= STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
- log_debug(conn->_base.type == CONN_TYPE_AP ?LD_APP:LD_EXIT,
+ log_debug(conn->base_.type == CONN_TYPE_AP ?LD_APP:LD_EXIT,
"Outbuf %d, Queuing stream sendme.",
- (int)conn->_base.outbuf_flushlen);
+ (int)conn->base_.outbuf_flushlen);
conn->deliver_window += STREAMWINDOW_INCREMENT;
if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME,
NULL, 0) < 0) {
@@ -1587,6 +1803,12 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
circ, layer_hint);
}
+void
+stream_choice_seed_weak_rng(void)
+{
+ crypto_seed_weak_rng(&stream_choice_rng);
+}
+
/** A helper function for circuit_resume_edge_reading() above.
* The arguments are the same, except that <b>conn</b> is the head
* of a linked list of edge streams that should each be considered.
@@ -1602,16 +1824,23 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
int cells_on_queue;
int cells_per_conn;
edge_connection_t *chosen_stream = NULL;
+ int max_to_package;
+
+ if (first_conn == NULL) {
+ /* Don't bother to try to do the rest of this if there are no connections
+ * to resume. */
+ return 0;
+ }
/* How many cells do we have space for? It will be the minimum of
* the number needed to exhaust the package window, and the minimum
* needed to fill the cell queue. */
- int max_to_package = circ->package_window;
+ max_to_package = circ->package_window;
if (CIRCUIT_IS_ORIGIN(circ)) {
- cells_on_queue = circ->n_conn_cells.n;
+ cells_on_queue = circ->n_chan_cells.n;
} else {
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
- cells_on_queue = or_circ->p_conn_cells.n;
+ cells_on_queue = or_circ->p_chan_cells.n;
}
if (CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue < max_to_package)
max_to_package = CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue;
@@ -1631,10 +1860,19 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
int num_streams = 0;
for (conn = first_conn; conn; conn = conn->next_stream) {
num_streams++;
- if ((tor_weak_random() % num_streams)==0)
+ if (tor_weak_random_one_in_n(&stream_choice_rng, num_streams)) {
chosen_stream = conn;
+ }
/* Invariant: chosen_stream has been chosen uniformly at random from
- * among the first num_streams streams on first_conn. */
+ * among the first num_streams streams on first_conn.
+ *
+ * (Note that we iterate over every stream on the circuit, so that after
+ * we've considered the first stream, we've chosen it with P=1; and
+ * after we consider the second stream, we've switched to it with P=1/2
+ * and stayed with the first stream with P=1/2; and after we've
+ * considered the third stream, we've switched to it with P=1/3 and
+ * remained with one of the first two streams with P=(2/3), giving each
+ * one P=(1/2)(2/3) )=(1/3).) */
}
}
@@ -1644,7 +1882,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
/* Activate reading starting from the chosen stream */
for (conn=chosen_stream; conn; conn = conn->next_stream) {
/* Start reading for the streams starting from here */
- if (conn->_base.marked_for_close || conn->package_window <= 0)
+ if (conn->base_.marked_for_close || conn->package_window <= 0)
continue;
if (!layer_hint || conn->cpath_layer == layer_hint) {
connection_start_reading(TO_CONN(conn));
@@ -1655,7 +1893,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
}
/* Go back and do the ones we skipped, circular-style */
for (conn = first_conn; conn != chosen_stream; conn = conn->next_stream) {
- if (conn->_base.marked_for_close || conn->package_window <= 0)
+ if (conn->base_.marked_for_close || conn->package_window <= 0)
continue;
if (!layer_hint || conn->cpath_layer == layer_hint) {
connection_start_reading(TO_CONN(conn));
@@ -1681,7 +1919,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
* package.
*/
for (conn=first_conn; conn; conn=conn->next_stream) {
- if (conn->_base.marked_for_close || conn->package_window <= 0)
+ if (conn->base_.marked_for_close || conn->package_window <= 0)
continue;
if (!layer_hint || conn->cpath_layer == layer_hint) {
int n = cells_per_conn, r;
@@ -1792,10 +2030,10 @@ circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint)
}
#ifdef ACTIVE_CIRCUITS_PARANOIA
-#define assert_active_circuits_ok_paranoid(conn) \
- assert_active_circuits_ok(conn)
+#define assert_cmux_ok_paranoid(chan) \
+ assert_circuit_mux_okay(chan)
#else
-#define assert_active_circuits_ok_paranoid(conn)
+#define assert_cmux_ok_paranoid(chan)
#endif
/** The total number of cells we have allocated from the memory pool. */
@@ -1850,12 +2088,19 @@ packed_cell_free_unchecked(packed_cell_t *cell)
/** Allocate and return a new packed_cell_t. */
static INLINE packed_cell_t *
-packed_cell_alloc(void)
+packed_cell_new(void)
{
++total_cells_allocated;
return mp_pool_get(cell_pool);
}
+/** Return a packed cell used outside by channel_t lower layer */
+void
+packed_cell_free(packed_cell_t *cell)
+{
+ packed_cell_free_unchecked(cell);
+}
+
/** Log current statistics for cell pool allocation at log level
* <b>severity</b>. */
void
@@ -1864,23 +2109,24 @@ dump_cell_pool_usage(int severity)
circuit_t *c;
int n_circs = 0;
int n_cells = 0;
- for (c = _circuit_get_global_list(); c; c = c->next) {
- n_cells += c->n_conn_cells.n;
+ for (c = circuit_get_global_list_(); c; c = c->next) {
+ n_cells += c->n_chan_cells.n;
if (!CIRCUIT_IS_ORIGIN(c))
- n_cells += TO_OR_CIRCUIT(c)->p_conn_cells.n;
+ n_cells += TO_OR_CIRCUIT(c)->p_chan_cells.n;
++n_circs;
}
- log(severity, LD_MM, "%d cells allocated on %d circuits. %d cells leaked.",
- n_cells, n_circs, (int)total_cells_allocated - n_cells);
+ tor_log(severity, LD_MM,
+ "%d cells allocated on %d circuits. %d cells leaked.",
+ n_cells, n_circs, (int)total_cells_allocated - n_cells);
mp_pool_log_status(cell_pool, severity);
}
/** Allocate a new copy of packed <b>cell</b>. */
static INLINE packed_cell_t *
-packed_cell_copy(const cell_t *cell)
+packed_cell_copy(const cell_t *cell, int wide_circ_ids)
{
- packed_cell_t *c = packed_cell_alloc();
- cell_pack(c, cell);
+ packed_cell_t *c = packed_cell_new();
+ cell_pack(c, cell, wide_circ_ids);
c->next = NULL;
return c;
}
@@ -1902,10 +2148,11 @@ cell_queue_append(cell_queue_t *queue, packed_cell_t *cell)
/** Append a newly allocated copy of <b>cell</b> to the end of <b>queue</b> */
void
-cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell)
+cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell,
+ int wide_circ_ids)
{
struct timeval now;
- packed_cell_t *copy = packed_cell_copy(cell);
+ packed_cell_t *copy = packed_cell_copy(cell, wide_circ_ids);
tor_gettimeofday_cached(&now);
copy->inserted_time = (uint32_t)tv_to_msec(&now);
@@ -2005,363 +2252,68 @@ cell_queues_check_size(void)
return 0;
}
-/** Return a pointer to the "next_active_on_{n,p}_conn" pointer of <b>circ</b>,
- * depending on whether <b>conn</b> matches n_conn or p_conn. */
-static INLINE circuit_t **
-next_circ_on_conn_p(circuit_t *circ, or_connection_t *conn)
-{
- tor_assert(circ);
- tor_assert(conn);
- if (conn == circ->n_conn) {
- return &circ->next_active_on_n_conn;
- } else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(conn == orcirc->p_conn);
- return &orcirc->next_active_on_p_conn;
- }
-}
-
-/** Return a pointer to the "prev_active_on_{n,p}_conn" pointer of <b>circ</b>,
- * depending on whether <b>conn</b> matches n_conn or p_conn. */
-static INLINE circuit_t **
-prev_circ_on_conn_p(circuit_t *circ, or_connection_t *conn)
-{
- tor_assert(circ);
- tor_assert(conn);
- if (conn == circ->n_conn) {
- return &circ->prev_active_on_n_conn;
- } else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(conn == orcirc->p_conn);
- return &orcirc->prev_active_on_p_conn;
- }
-}
-
-/** Helper for sorting cell_ewma_t values in their priority queue. */
-static int
-compare_cell_ewma_counts(const void *p1, const void *p2)
-{
- const cell_ewma_t *e1=p1, *e2=p2;
- if (e1->cell_count < e2->cell_count)
- return -1;
- else if (e1->cell_count > e2->cell_count)
- return 1;
- else
- return 0;
-}
-
-/** Given a cell_ewma_t, return a pointer to the circuit containing it. */
-static circuit_t *
-cell_ewma_to_circuit(cell_ewma_t *ewma)
-{
- if (ewma->is_for_p_conn) {
- /* This is an or_circuit_t's p_cell_ewma. */
- or_circuit_t *orcirc = SUBTYPE_P(ewma, or_circuit_t, p_cell_ewma);
- return TO_CIRCUIT(orcirc);
- } else {
- /* This is some circuit's n_cell_ewma. */
- return SUBTYPE_P(ewma, circuit_t, n_cell_ewma);
- }
-}
-
-/* ==== Functions for scaling cell_ewma_t ====
-
- When choosing which cells to relay first, we favor circuits that have been
- quiet recently. This gives better latency on connections that aren't
- pushing lots of data, and makes the network feel more interactive.
-
- Conceptually, we take an exponentially weighted mean average of the number
- of cells a circuit has sent, and allow active circuits (those with cells to
- relay) to send cells in reverse order of their exponentially-weighted mean
- average (EWMA) cell count. [That is, a cell sent N seconds ago 'counts'
- F^N times as much as a cell sent now, for 0<F<1.0, and we favor the
- circuit that has sent the fewest cells]
-
- If 'double' had infinite precision, we could do this simply by counting a
- cell sent at startup as having weight 1.0, and a cell sent N seconds later
- as having weight F^-N. This way, we would never need to re-scale
- any already-sent cells.
-
- To prevent double from overflowing, we could count a cell sent now as
- having weight 1.0 and a cell sent N seconds ago as having weight F^N.
- This, however, would mean we'd need to re-scale *ALL* old circuits every
- time we wanted to send a cell.
-
- So as a compromise, we divide time into 'ticks' (currently, 10-second
- increments) and say that a cell sent at the start of a current tick is
- worth 1.0, a cell sent N seconds before the start of the current tick is
- worth F^N, and a cell sent N seconds after the start of the current tick is
- worth F^-N. This way we don't overflow, and we don't need to constantly
- rescale.
- */
-
-/** How long does a tick last (seconds)? */
-#define EWMA_TICK_LEN 10
-
-/** The default per-tick scale factor, if it hasn't been overridden by a
- * consensus or a configuration setting. zero means "disabled". */
-#define EWMA_DEFAULT_HALFLIFE 0.0
-
-/** Given a timeval <b>now</b>, compute the cell_ewma tick in which it occurs
- * and the fraction of the tick that has elapsed between the start of the tick
- * and <b>now</b>. Return the former and store the latter in
- * *<b>remainder_out</b>.
- *
- * These tick values are not meant to be shared between Tor instances, or used
- * for other purposes. */
-static unsigned
-cell_ewma_tick_from_timeval(const struct timeval *now,
- double *remainder_out)
-{
- unsigned res = (unsigned) (now->tv_sec / EWMA_TICK_LEN);
- /* rem */
- double rem = (now->tv_sec % EWMA_TICK_LEN) +
- ((double)(now->tv_usec)) / 1.0e6;
- *remainder_out = rem / EWMA_TICK_LEN;
- return res;
-}
-
-/** Compute and return the current cell_ewma tick. */
-unsigned
-cell_ewma_get_tick(void)
-{
- return ((unsigned)approx_time() / EWMA_TICK_LEN);
-}
-
-/** The per-tick scale factor to be used when computing cell-count EWMA
- * values. (A cell sent N ticks before the start of the current tick
- * has value ewma_scale_factor ** N.)
+/**
+ * Update the number of cells available on the circuit's n_chan or p_chan's
+ * circuit mux.
*/
-static double ewma_scale_factor = 0.1;
-/* DOCDOC ewma_enabled */
-static int ewma_enabled = 0;
-
-/*DOCDOC*/
-#define EPSILON 0.00001
-/*DOCDOC*/
-#define LOG_ONEHALF -0.69314718055994529
-
-/** Adjust the global cell scale factor based on <b>options</b> */
void
-cell_ewma_set_scale_factor(const or_options_t *options,
- const networkstatus_t *consensus)
+update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
+ const char *file, int lineno)
{
- int32_t halflife_ms;
- double halflife;
- const char *source;
- if (options && options->CircuitPriorityHalflife >= -EPSILON) {
- halflife = options->CircuitPriorityHalflife;
- source = "CircuitPriorityHalflife in configuration";
- } else if (consensus && (halflife_ms = networkstatus_get_param(
- consensus, "CircuitPriorityHalflifeMsec",
- -1, -1, INT32_MAX)) >= 0) {
- halflife = ((double)halflife_ms)/1000.0;
- source = "CircuitPriorityHalflifeMsec in consensus";
- } else {
- halflife = EWMA_DEFAULT_HALFLIFE;
- source = "Default value";
- }
+ channel_t *chan = NULL;
+ or_circuit_t *or_circ = NULL;
+ circuitmux_t *cmux = NULL;
- if (halflife <= EPSILON) {
- /* The cell EWMA algorithm is disabled. */
- ewma_scale_factor = 0.1;
- ewma_enabled = 0;
- log_info(LD_OR,
- "Disabled cell_ewma algorithm because of value in %s",
- source);
- } else {
- /* convert halflife into halflife-per-tick. */
- halflife /= EWMA_TICK_LEN;
- /* compute per-tick scale factor. */
- ewma_scale_factor = exp( LOG_ONEHALF / halflife );
- ewma_enabled = 1;
- log_info(LD_OR,
- "Enabled cell_ewma algorithm because of value in %s; "
- "scale factor is %f per %d seconds",
- source, ewma_scale_factor, EWMA_TICK_LEN);
- }
-}
-
-/** Return the multiplier necessary to convert the value of a cell sent in
- * 'from_tick' to one sent in 'to_tick'. */
-static INLINE double
-get_scale_factor(unsigned from_tick, unsigned to_tick)
-{
- /* This math can wrap around, but that's okay: unsigned overflow is
- well-defined */
- int diff = (int)(to_tick - from_tick);
- return pow(ewma_scale_factor, diff);
-}
-
-/** Adjust the cell count of <b>ewma</b> so that it is scaled with respect to
- * <b>cur_tick</b> */
-static void
-scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick)
-{
- double factor = get_scale_factor(ewma->last_adjusted_tick, cur_tick);
- ewma->cell_count *= factor;
- ewma->last_adjusted_tick = cur_tick;
-}
-
-/** Adjust the cell count of every active circuit on <b>conn</b> so
- * that they are scaled with respect to <b>cur_tick</b> */
-static void
-scale_active_circuits(or_connection_t *conn, unsigned cur_tick)
-{
-
- double factor = get_scale_factor(
- conn->active_circuit_pqueue_last_recalibrated,
- cur_tick);
- /** Ordinarily it isn't okay to change the value of an element in a heap,
- * but it's okay here, since we are preserving the order. */
- SMARTLIST_FOREACH(conn->active_circuit_pqueue, cell_ewma_t *, e, {
- tor_assert(e->last_adjusted_tick ==
- conn->active_circuit_pqueue_last_recalibrated);
- e->cell_count *= factor;
- e->last_adjusted_tick = cur_tick;
- });
- conn->active_circuit_pqueue_last_recalibrated = cur_tick;
-}
-
-/** Rescale <b>ewma</b> to the same scale as <b>conn</b>, and add it to
- * <b>conn</b>'s priority queue of active circuits */
-static void
-add_cell_ewma_to_conn(or_connection_t *conn, cell_ewma_t *ewma)
-{
- tor_assert(ewma->heap_index == -1);
- scale_single_cell_ewma(ewma,
- conn->active_circuit_pqueue_last_recalibrated);
-
- smartlist_pqueue_add(conn->active_circuit_pqueue,
- compare_cell_ewma_counts,
- STRUCT_OFFSET(cell_ewma_t, heap_index),
- ewma);
-}
-
-/** Remove <b>ewma</b> from <b>conn</b>'s priority queue of active circuits */
-static void
-remove_cell_ewma_from_conn(or_connection_t *conn, cell_ewma_t *ewma)
-{
- tor_assert(ewma->heap_index != -1);
- smartlist_pqueue_remove(conn->active_circuit_pqueue,
- compare_cell_ewma_counts,
- STRUCT_OFFSET(cell_ewma_t, heap_index),
- ewma);
-}
-
-/** Remove and return the first cell_ewma_t from conn's priority queue of
- * active circuits. Requires that the priority queue is nonempty. */
-static cell_ewma_t *
-pop_first_cell_ewma_from_conn(or_connection_t *conn)
-{
- return smartlist_pqueue_pop(conn->active_circuit_pqueue,
- compare_cell_ewma_counts,
- STRUCT_OFFSET(cell_ewma_t, heap_index));
-}
-
-/** Add <b>circ</b> to the list of circuits with pending cells on
- * <b>conn</b>. No effect if <b>circ</b> is already linked. */
-void
-make_circuit_active_on_conn(circuit_t *circ, or_connection_t *conn)
-{
- circuit_t **nextp = next_circ_on_conn_p(circ, conn);
- circuit_t **prevp = prev_circ_on_conn_p(circ, conn);
-
- if (*nextp && *prevp) {
- /* Already active. */
- return;
- }
-
- assert_active_circuits_ok_paranoid(conn);
+ tor_assert(circ);
- if (! conn->active_circuits) {
- conn->active_circuits = circ;
- *prevp = *nextp = circ;
+ /* Okay, get the channel */
+ if (direction == CELL_DIRECTION_OUT) {
+ chan = circ->n_chan;
} else {
- circuit_t *head = conn->active_circuits;
- circuit_t *old_tail = *prev_circ_on_conn_p(head, conn);
- *next_circ_on_conn_p(old_tail, conn) = circ;
- *nextp = head;
- *prev_circ_on_conn_p(head, conn) = circ;
- *prevp = old_tail;
+ or_circ = TO_OR_CIRCUIT(circ);
+ chan = or_circ->p_chan;
}
- if (circ->n_conn == conn) {
- add_cell_ewma_to_conn(conn, &circ->n_cell_ewma);
- } else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(conn == orcirc->p_conn);
- add_cell_ewma_to_conn(conn, &orcirc->p_cell_ewma);
- }
+ tor_assert(chan);
+ tor_assert(chan->cmux);
- assert_active_circuits_ok_paranoid(conn);
-}
+ /* Now get the cmux */
+ cmux = chan->cmux;
-/** Remove <b>circ</b> from the list of circuits with pending cells on
- * <b>conn</b>. No effect if <b>circ</b> is already unlinked. */
-void
-make_circuit_inactive_on_conn(circuit_t *circ, or_connection_t *conn)
-{
- circuit_t **nextp = next_circ_on_conn_p(circ, conn);
- circuit_t **prevp = prev_circ_on_conn_p(circ, conn);
- circuit_t *next = *nextp, *prev = *prevp;
-
- if (!next && !prev) {
- /* Already inactive. */
+ /* Cmux sanity check */
+ if (! circuitmux_is_circuit_attached(cmux, circ)) {
+ log_warn(LD_BUG, "called on non-attachd circuit from %s:%d",
+ file, lineno);
return;
}
+ tor_assert(circuitmux_attached_circuit_direction(cmux, circ) == direction);
- assert_active_circuits_ok_paranoid(conn);
-
- tor_assert(next && prev);
- tor_assert(*prev_circ_on_conn_p(next, conn) == circ);
- tor_assert(*next_circ_on_conn_p(prev, conn) == circ);
+ assert_cmux_ok_paranoid(chan);
- if (next == circ) {
- conn->active_circuits = NULL;
- } else {
- *prev_circ_on_conn_p(next, conn) = prev;
- *next_circ_on_conn_p(prev, conn) = next;
- if (conn->active_circuits == circ)
- conn->active_circuits = next;
- }
- *prevp = *nextp = NULL;
-
- if (circ->n_conn == conn) {
- remove_cell_ewma_from_conn(conn, &circ->n_cell_ewma);
+ /* Update the number of cells we have for the circuit mux */
+ if (direction == CELL_DIRECTION_OUT) {
+ circuitmux_set_num_cells(cmux, circ, circ->n_chan_cells.n);
} else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(conn == orcirc->p_conn);
- remove_cell_ewma_from_conn(conn, &orcirc->p_cell_ewma);
+ circuitmux_set_num_cells(cmux, circ, or_circ->p_chan_cells.n);
}
- assert_active_circuits_ok_paranoid(conn);
+ assert_cmux_ok_paranoid(chan);
}
-/** Remove all circuits from the list of circuits with pending cells on
- * <b>conn</b>. */
+/** Remove all circuits from the cmux on <b>chan</b>. */
void
-connection_or_unlink_all_active_circs(or_connection_t *orconn)
+channel_unlink_all_circuits(channel_t *chan)
{
- circuit_t *head = orconn->active_circuits;
- circuit_t *cur = head;
- if (! head)
- return;
- do {
- circuit_t *next = *next_circ_on_conn_p(cur, orconn);
- *prev_circ_on_conn_p(cur, orconn) = NULL;
- *next_circ_on_conn_p(cur, orconn) = NULL;
- cur = next;
- } while (cur != head);
- orconn->active_circuits = NULL;
-
- SMARTLIST_FOREACH(orconn->active_circuit_pqueue, cell_ewma_t *, e,
- e->heap_index = -1);
- smartlist_clear(orconn->active_circuit_pqueue);
+ tor_assert(chan);
+ tor_assert(chan->cmux);
+
+ circuitmux_detach_all_circuits(chan->cmux);
+ chan->num_n_circuits = 0;
+ chan->num_p_circuits = 0;
}
/** Block (if <b>block</b> is true) or unblock (if <b>block</b> is false)
- * every edge connection that is using <b>circ</b> to write to <b>orconn</b>,
+ * every edge connection that is using <b>circ</b> to write to <b>chan</b>,
* and start or stop reading as appropriate.
*
* If <b>stream_id</b> is nonzero, block only the edge connection whose
@@ -2370,17 +2322,17 @@ connection_or_unlink_all_active_circs(or_connection_t *orconn)
* Returns the number of streams whose status we changed.
*/
static int
-set_streams_blocked_on_circ(circuit_t *circ, or_connection_t *orconn,
+set_streams_blocked_on_circ(circuit_t *circ, channel_t *chan,
int block, streamid_t stream_id)
{
edge_connection_t *edge = NULL;
int n = 0;
- if (circ->n_conn == orconn) {
- circ->streams_blocked_on_n_conn = block;
+ if (circ->n_chan == chan) {
+ circ->streams_blocked_on_n_chan = block;
if (CIRCUIT_IS_ORIGIN(circ))
edge = TO_ORIGIN_CIRCUIT(circ)->p_streams;
} else {
- circ->streams_blocked_on_p_conn = block;
+ circ->streams_blocked_on_p_chan = block;
tor_assert(!CIRCUIT_IS_ORIGIN(circ));
edge = TO_OR_CIRCUIT(circ)->n_streams;
}
@@ -2415,58 +2367,51 @@ set_streams_blocked_on_circ(circuit_t *circ, or_connection_t *orconn,
}
/** Pull as many cells as possible (but no more than <b>max</b>) from the
- * queue of the first active circuit on <b>conn</b>, and write them to
- * <b>conn</b>-&gt;outbuf. Return the number of cells written. Advance
+ * queue of the first active circuit on <b>chan</b>, and write them to
+ * <b>chan</b>-&gt;outbuf. Return the number of cells written. Advance
* the active circuit pointer to the next active circuit in the ring. */
int
-connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max,
- time_t now)
+channel_flush_from_first_active_circuit(channel_t *chan, int max)
{
- int n_flushed;
+ circuitmux_t *cmux = NULL;
+ int n_flushed = 0;
cell_queue_t *queue;
circuit_t *circ;
+ or_circuit_t *or_circ;
int streams_blocked;
-
- /* The current (hi-res) time */
- struct timeval now_hires;
-
- /* The EWMA cell counter for the circuit we're flushing. */
- cell_ewma_t *cell_ewma = NULL;
- double ewma_increment = -1;
-
- circ = conn->active_circuits;
- if (!circ) return 0;
- assert_active_circuits_ok_paranoid(conn);
-
- /* See if we're doing the ewma circuit selection algorithm. */
- if (ewma_enabled) {
- unsigned tick;
- double fractional_tick;
- tor_gettimeofday_cached(&now_hires);
- tick = cell_ewma_tick_from_timeval(&now_hires, &fractional_tick);
-
- if (tick != conn->active_circuit_pqueue_last_recalibrated) {
- scale_active_circuits(conn, tick);
+ packed_cell_t *cell;
+
+ /* Get the cmux */
+ tor_assert(chan);
+ tor_assert(chan->cmux);
+ cmux = chan->cmux;
+
+ /* Main loop: pick a circuit, send a cell, update the cmux */
+ while (n_flushed < max) {
+ circ = circuitmux_get_first_active_circuit(cmux);
+ /* If it returns NULL, no cells left to send */
+ if (!circ) break;
+ assert_cmux_ok_paranoid(chan);
+
+ if (circ->n_chan == chan) {
+ queue = &circ->n_chan_cells;
+ streams_blocked = circ->streams_blocked_on_n_chan;
+ } else {
+ or_circ = TO_OR_CIRCUIT(circ);
+ tor_assert(or_circ->p_chan == chan);
+ queue = &TO_OR_CIRCUIT(circ)->p_chan_cells;
+ streams_blocked = circ->streams_blocked_on_p_chan;
}
- ewma_increment = pow(ewma_scale_factor, -fractional_tick);
-
- cell_ewma = smartlist_get(conn->active_circuit_pqueue, 0);
- circ = cell_ewma_to_circuit(cell_ewma);
- }
-
- if (circ->n_conn == conn) {
- queue = &circ->n_conn_cells;
- streams_blocked = circ->streams_blocked_on_n_conn;
- } else {
- queue = &TO_OR_CIRCUIT(circ)->p_conn_cells;
- streams_blocked = circ->streams_blocked_on_p_conn;
- }
- tor_assert(*next_circ_on_conn_p(circ,conn));
+ /* Circuitmux told us this was active, so it should have cells */
+ tor_assert(queue->n > 0);
- for (n_flushed = 0; n_flushed < max && queue->head; ) {
- packed_cell_t *cell = cell_queue_pop(queue);
- tor_assert(*next_circ_on_conn_p(circ,conn));
+ /*
+ * Get just one cell here; once we've sent it, that can change the circuit
+ * selection, so we have to loop around for another even if this circuit
+ * has more than one.
+ */
+ cell = cell_queue_pop(queue);
/* Calculate the exact time that this cell has spent in the queue. */
if (get_options()->CellStatistics && !CIRCUIT_IS_ORIGIN(circ)) {
@@ -2482,8 +2427,8 @@ connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max,
"Looks like the CellStatistics option was "
"recently enabled.");
} else {
- or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
insertion_time_elem_t *elem = it_queue->first;
+ or_circ = TO_OR_CIRCUIT(circ);
cell_waiting_time =
(uint32_t)((flushed * 10L + SECONDS_IN_A_DAY * 1000L -
elem->insertion_time * 10L) %
@@ -2496,66 +2441,58 @@ connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max,
it_queue->last = NULL;
mp_pool_release(elem);
}
- orcirc->total_cell_waiting_time += cell_waiting_time;
- orcirc->processed_cells++;
+ or_circ->total_cell_waiting_time += cell_waiting_time;
+ or_circ->processed_cells++;
}
}
/* If we just flushed our queue and this circuit is used for a
* tunneled directory request, possibly advance its state. */
- if (queue->n == 0 && TO_CONN(conn)->dirreq_id)
- geoip_change_dirreq_state(TO_CONN(conn)->dirreq_id,
+ if (queue->n == 0 && chan->dirreq_id)
+ geoip_change_dirreq_state(chan->dirreq_id,
DIRREQ_TUNNELED,
DIRREQ_CIRC_QUEUE_FLUSHED);
- connection_write_to_buf(cell->body, CELL_NETWORK_SIZE, TO_CONN(conn));
+ /* Now send the cell */
+ channel_write_packed_cell(chan, cell);
+ cell = NULL;
- packed_cell_free_unchecked(cell);
+ /*
+ * Don't packed_cell_free_unchecked(cell) here because the channel will
+ * do so when it gets out of the channel queue (probably already did, in
+ * which case that was an immediate double-free bug).
+ */
+
+ /* Update the counter */
++n_flushed;
- if (cell_ewma) {
- cell_ewma_t *tmp;
- cell_ewma->cell_count += ewma_increment;
- /* We pop and re-add the cell_ewma_t here, not above, since we need to
- * re-add it immediately to keep the priority queue consistent with
- * the linked-list implementation */
- tmp = pop_first_cell_ewma_from_conn(conn);
- tor_assert(tmp == cell_ewma);
- add_cell_ewma_to_conn(conn, cell_ewma);
- }
- if (!ewma_enabled && circ != conn->active_circuits) {
- /* If this happens, the current circuit just got made inactive by
- * a call in connection_write_to_buf(). That's nothing to worry about:
- * circuit_make_inactive_on_conn() already advanced conn->active_circuits
- * for us.
- */
- assert_active_circuits_ok_paranoid(conn);
- goto done;
- }
- }
- tor_assert(*next_circ_on_conn_p(circ,conn));
- assert_active_circuits_ok_paranoid(conn);
- conn->active_circuits = *next_circ_on_conn_p(circ, conn);
- /* Is the cell queue low enough to unblock all the streams that are waiting
- * to write to this circuit? */
- if (streams_blocked && queue->n <= CELL_QUEUE_LOWWATER_SIZE)
- set_streams_blocked_on_circ(circ, conn, 0, 0); /* unblock streams */
+ /*
+ * Now update the cmux; tell it we've just sent a cell, and how many
+ * we have left.
+ */
+ circuitmux_notify_xmit_cells(cmux, circ, 1);
+ circuitmux_set_num_cells(cmux, circ, queue->n);
+ if (queue->n == 0)
+ log_debug(LD_GENERAL, "Made a circuit inactive.");
+
+ /* Is the cell queue low enough to unblock all the streams that are waiting
+ * to write to this circuit? */
+ if (streams_blocked && queue->n <= CELL_QUEUE_LOWWATER_SIZE)
+ set_streams_blocked_on_circ(circ, chan, 0, 0); /* unblock streams */
- /* Did we just run out of cells on this circuit's queue? */
- if (queue->n == 0) {
- log_debug(LD_GENERAL, "Made a circuit inactive.");
- make_circuit_inactive_on_conn(circ, conn);
+ /* If n_flushed < max still, loop around and pick another circuit */
}
- done:
- if (n_flushed)
- conn->timestamp_last_added_nonpadding = now;
+
+ /* Okay, we're done sending now */
+ assert_cmux_ok_paranoid(chan);
+
return n_flushed;
}
-/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>orconn</b>
+/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b>
* transmitting in <b>direction</b>. */
void
-append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
+append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
cell_t *cell, cell_direction_t direction,
streamid_t fromstream)
{
@@ -2567,12 +2504,12 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
return;
if (direction == CELL_DIRECTION_OUT) {
- queue = &circ->n_conn_cells;
- streams_blocked = circ->streams_blocked_on_n_conn;
+ queue = &circ->n_chan_cells;
+ streams_blocked = circ->streams_blocked_on_n_chan;
} else {
orcirc = TO_OR_CIRCUIT(circ);
- queue = &orcirc->p_conn_cells;
- streams_blocked = circ->streams_blocked_on_p_conn;
+ queue = &orcirc->p_chan_cells;
+ streams_blocked = circ->streams_blocked_on_p_chan;
}
/*
@@ -2580,18 +2517,23 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
*/
#if 0
/* Are we a middle circuit about to exceed ORCIRC_MAX_MIDDLE_CELLS? */
- if ((circ->n_conn != NULL) && CIRCUIT_IS_ORCIRC(circ)) {
+ if ((circ->n_chan != NULL) && CIRCUIT_IS_ORCIRC(circ)) {
orcirc = TO_OR_CIRCUIT(circ);
- if (orcirc->p_conn) {
+ if (orcirc->p_chan) {
if (queue->n + 1 >= ORCIRC_MAX_MIDDLE_CELLS) {
/* Queueing this cell would put queue over the cap */
log_warn(LD_CIRC,
"Got a cell exceeding the cap of %u in the %s direction "
- "on middle circ ID %u; killing the circuit.",
+ "on middle circ ID %u on chan ID " U64_FORMAT
+ "; killing the circuit.",
ORCIRC_MAX_MIDDLE_CELLS,
(direction == CELL_DIRECTION_OUT) ? "n" : "p",
(direction == CELL_DIRECTION_OUT) ?
- circ->n_circ_id : orcirc->p_circ_id);
+ circ->n_circ_id : orcirc->p_circ_id,
+ U64_PRINTF_ARG(
+ (direction == CELL_DIRECTION_OUT) ?
+ circ->n_chan->global_identifier :
+ orcirc->p_chan->global_identifier));
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
return;
}
@@ -2599,7 +2541,7 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
}
#endif
- cell_queue_append_packed_copy(queue, cell);
+ cell_queue_append_packed_copy(queue, cell, chan->wide_circ_ids);
if (PREDICT_UNLIKELY(cell_queues_check_size())) {
/* We ran the OOM handler */
@@ -2610,27 +2552,27 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
/* If we have too many cells on the circuit, we should stop reading from
* the edge streams for a while. */
if (!streams_blocked && queue->n >= CELL_QUEUE_HIGHWATER_SIZE)
- set_streams_blocked_on_circ(circ, orconn, 1, 0); /* block streams */
+ set_streams_blocked_on_circ(circ, chan, 1, 0); /* block streams */
if (streams_blocked && fromstream) {
/* This edge connection is apparently not blocked; block it. */
- set_streams_blocked_on_circ(circ, orconn, 1, fromstream);
+ set_streams_blocked_on_circ(circ, chan, 1, fromstream);
}
+ update_circuit_on_cmux(circ, direction);
if (queue->n == 1) {
- /* This was the first cell added to the queue. We need to make this
+ /* This was the first cell added to the queue. We just made this
* circuit active. */
log_debug(LD_GENERAL, "Made a circuit active.");
- make_circuit_active_on_conn(circ, orconn);
}
- if (! connection_get_outbuf_len(TO_CONN(orconn))) {
+ if (!channel_has_queued_writes(chan)) {
/* There is no data at all waiting to be sent on the outbuf. Add a
* cell, so that we can notice when it gets flushed, flushed_some can
* get called, and we can start putting more data onto the buffer then.
*/
log_debug(LD_GENERAL, "Primed a buffer.");
- connection_or_flush_from_first_active_circuit(orconn, 1, approx_time());
+ channel_flush_from_first_active_circuit(chan, 1);
}
}
@@ -2694,58 +2636,40 @@ decode_address_from_payload(tor_addr_t *addr_out, const uint8_t *payload,
return payload + 2 + payload[1];
}
-/** Remove all the cells queued on <b>circ</b> for <b>orconn</b>. */
+/** Remove all the cells queued on <b>circ</b> for <b>chan</b>. */
void
-circuit_clear_cell_queue(circuit_t *circ, or_connection_t *orconn)
+circuit_clear_cell_queue(circuit_t *circ, channel_t *chan)
{
cell_queue_t *queue;
- if (circ->n_conn == orconn) {
- queue = &circ->n_conn_cells;
+ cell_direction_t direction;
+
+ if (circ->n_chan == chan) {
+ queue = &circ->n_chan_cells;
+ direction = CELL_DIRECTION_OUT;
} else {
or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
- tor_assert(orcirc->p_conn == orconn);
- queue = &orcirc->p_conn_cells;
+ tor_assert(orcirc->p_chan == chan);
+ queue = &orcirc->p_chan_cells;
+ direction = CELL_DIRECTION_IN;
}
- if (queue->n)
- make_circuit_inactive_on_conn(circ,orconn);
-
+ /* Clear the queue */
cell_queue_clear(queue);
+
+ /* Update the cell counter in the cmux */
+ if (chan->cmux && circuitmux_is_circuit_attached(chan->cmux, circ))
+ update_circuit_on_cmux(circ, direction);
}
-/** Fail with an assert if the active circuits ring on <b>orconn</b> is
- * corrupt. */
+/** Fail with an assert if the circuit mux on chan is corrupt
+ */
void
-assert_active_circuits_ok(or_connection_t *orconn)
+assert_circuit_mux_okay(channel_t *chan)
{
- circuit_t *head = orconn->active_circuits;
- circuit_t *cur = head;
- int n = 0;
- if (! head)
- return;
- do {
- circuit_t *next = *next_circ_on_conn_p(cur, orconn);
- circuit_t *prev = *prev_circ_on_conn_p(cur, orconn);
- cell_ewma_t *ewma;
- tor_assert(next);
- tor_assert(prev);
- tor_assert(*next_circ_on_conn_p(prev, orconn) == cur);
- tor_assert(*prev_circ_on_conn_p(next, orconn) == cur);
- if (orconn == cur->n_conn) {
- ewma = &cur->n_cell_ewma;
- tor_assert(!ewma->is_for_p_conn);
- } else {
- ewma = &TO_OR_CIRCUIT(cur)->p_cell_ewma;
- tor_assert(ewma->is_for_p_conn);
- }
- tor_assert(ewma->heap_index != -1);
- tor_assert(ewma == smartlist_get(orconn->active_circuit_pqueue,
- ewma->heap_index));
- n++;
- cur = next;
- } while (cur != head);
-
- tor_assert(n == smartlist_len(orconn->active_circuit_pqueue));
+ tor_assert(chan);
+ tor_assert(chan->cmux);
+
+ circuitmux_assert_okay(chan->cmux);
}
/** Return 1 if we shouldn't restart reading on this circuit, even if
@@ -2755,9 +2679,9 @@ static int
circuit_queue_streams_are_blocked(circuit_t *circ)
{
if (CIRCUIT_IS_ORIGIN(circ)) {
- return circ->streams_blocked_on_n_conn;
+ return circ->streams_blocked_on_n_chan;
} else {
- return circ->streams_blocked_on_p_conn;
+ return circ->streams_blocked_on_p_chan;
}
}
diff --git a/src/or/relay.h b/src/or/relay.h
index c55813b33..1fef10a7d 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for relay.c.
**/
-#ifndef _TOR_RELAY_H
-#define _TOR_RELAY_H
+#ifndef TOR_RELAY_H
+#define TOR_RELAY_H
extern uint64_t stats_n_relay_cells_relayed;
extern uint64_t stats_n_relay_cells_delivered;
@@ -20,9 +20,15 @@ int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
void relay_header_pack(uint8_t *dest, const relay_header_t *src);
void relay_header_unpack(relay_header_t *dest, const uint8_t *src);
-int relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
+int relay_send_command_from_edge_(streamid_t stream_id, circuit_t *circ,
uint8_t relay_command, const char *payload,
- size_t payload_len, crypt_path_t *cpath_layer);
+ size_t payload_len, crypt_path_t *cpath_layer,
+ const char *filename, int lineno);
+#define relay_send_command_from_edge(stream_id, circ, relay_command, payload, \
+ payload_len, cpath_layer) \
+ relay_send_command_from_edge_((stream_id), (circ), (relay_command), \
+ (payload), (payload_len), (cpath_layer), \
+ __FILE__, __LINE__)
int connection_edge_send_command(edge_connection_t *fromconn,
uint8_t relay_command, const char *payload,
size_t payload_len);
@@ -42,32 +48,38 @@ void clean_cell_pool(void);
void dump_cell_pool_usage(int severity);
size_t packed_cell_mem_cost(void);
+/* For channeltls.c */
+void packed_cell_free(packed_cell_t *cell);
+
void cell_queue_clear(cell_queue_t *queue);
void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell);
-void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell);
+void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell,
+ int wide_circ_ids);
-void append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
+void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
cell_t *cell, cell_direction_t direction,
streamid_t fromstream);
-void connection_or_unlink_all_active_circs(or_connection_t *conn);
-int connection_or_flush_from_first_active_circuit(or_connection_t *conn,
- int max, time_t now);
-void assert_active_circuits_ok(or_connection_t *orconn);
-void make_circuit_inactive_on_conn(circuit_t *circ, or_connection_t *conn);
-void make_circuit_active_on_conn(circuit_t *circ, or_connection_t *conn);
+void channel_unlink_all_circuits(channel_t *chan);
+int channel_flush_from_first_active_circuit(channel_t *chan, int max);
+void assert_circuit_mux_okay(channel_t *chan);
+void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
+ const char *file, int lineno);
+#define update_circuit_on_cmux(circ, direction) \
+ update_circuit_on_cmux_((circ), (direction), SHORT_FILE__, __LINE__)
int append_address_to_payload(uint8_t *payload_out, const tor_addr_t *addr);
const uint8_t *decode_address_from_payload(tor_addr_t *addr_out,
const uint8_t *payload,
int payload_len);
-unsigned cell_ewma_get_tick(void);
-void cell_ewma_set_scale_factor(const or_options_t *options,
- const networkstatus_t *consensus);
-void circuit_clear_cell_queue(circuit_t *circ, or_connection_t *orconn);
+void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
+
+void stream_choice_seed_weak_rng(void);
#ifdef RELAY_PRIVATE
int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
crypt_path_t **layer_hint, char *recognized);
+int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
+ tor_addr_t *addr_out, int *ttl_out);
#endif
#endif
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 3a0cd1a66..bb4bd9bfd 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,6 +16,7 @@
#include "connection_edge.h"
#include "directory.h"
#include "main.h"
+#include "networkstatus.h"
#include "nodelist.h"
#include "relay.h"
#include "rendclient.h"
@@ -23,6 +24,7 @@
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
+#include "routerset.h"
static extend_info_t *rend_client_get_random_intro_impl(
const rend_cache_entry_t *rend_query,
@@ -43,7 +45,7 @@ rend_client_purge_state(void)
void
rend_client_introcirc_has_opened(origin_circuit_t *circ)
{
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
tor_assert(circ->cpath);
log_info(LD_REND,"introcirc is open");
@@ -56,7 +58,7 @@ rend_client_introcirc_has_opened(origin_circuit_t *circ)
static int
rend_client_send_establish_rendezvous(origin_circuit_t *circ)
{
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
tor_assert(circ->rend_data);
log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
@@ -65,6 +67,14 @@ rend_client_send_establish_rendezvous(origin_circuit_t *circ)
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return -1;
}
+
+ /* Set timestamp_dirty, because circuit_expire_building expects it,
+ * and the rend cookie also means we've used the circ. */
+ circ->base_.timestamp_dirty = time(NULL);
+
+ /* We've attempted to use this circuit. Probe it if we fail */
+ pathbias_count_use_attempt(circ);
+
if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
circ->rend_data->rend_cookie,
@@ -99,16 +109,17 @@ rend_client_reextend_intro_circuit(origin_circuit_t *circ)
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return -1;
}
+ // XXX: should we not re-extend if hs_circ_has_timed_out?
if (circ->remaining_relay_early_cells) {
log_info(LD_REND,
- "Re-extending circ %d, this time to %s.",
- circ->_base.n_circ_id,
+ "Re-extending circ %u, this time to %s.",
+ (unsigned)circ->base_.n_circ_id,
safe_str_client(extend_info_describe(extend_info)));
result = circuit_extend_to_new_exit(circ, extend_info);
} else {
log_info(LD_REND,
- "Closing intro circ %d (out of RELAY_EARLY cells).",
- circ->_base.n_circ_id);
+ "Closing intro circ %u (out of RELAY_EARLY cells).",
+ (unsigned)circ->base_.n_circ_id);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
/* connection_ap_handshake_attach_circuit will launch a new intro circ. */
result = 0;
@@ -117,6 +128,16 @@ rend_client_reextend_intro_circuit(origin_circuit_t *circ)
return result;
}
+/** Return true iff we should send timestamps in our INTRODUCE1 cells */
+static int
+rend_client_should_send_timestamp(void)
+{
+ if (get_options()->Support022HiddenServices >= 0)
+ return get_options()->Support022HiddenServices;
+
+ return networkstatus_get_param(NULL, "Support022HiddenServices", 1, 0, 1);
+}
+
/** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell
* down introcirc if possible.
*/
@@ -132,9 +153,10 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
crypt_path_t *cpath;
off_t dh_offset;
crypto_pk_t *intro_key = NULL;
+ int status = 0;
- tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY);
+ tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY);
tor_assert(introcirc->rend_data);
tor_assert(rendcirc->rend_data);
tor_assert(!rend_cmp_service_ids(introcirc->rend_data->onion_address,
@@ -161,7 +183,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
}
}
- return -1;
+ status = -1;
+ goto cleanup;
}
/* first 20 bytes of payload are the hash of Bob's pk */
@@ -184,13 +207,16 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
smartlist_len(entry->parsed->intro_nodes));
if (rend_client_reextend_intro_circuit(introcirc)) {
+ status = -2;
goto perm_err;
} else {
- return -1;
+ status = -1;
+ goto cleanup;
}
}
if (crypto_pk_get_digest(intro_key, payload)<0) {
log_warn(LD_BUG, "Internal error: couldn't hash public key.");
+ status = -2;
goto perm_err;
}
@@ -200,12 +226,14 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
cpath = rendcirc->build_state->pending_final_cpath =
tor_malloc_zero(sizeof(crypt_path_t));
cpath->magic = CRYPT_PATH_MAGIC;
- if (!(cpath->dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
+ if (!(cpath->rend_dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
+ status = -2;
goto perm_err;
}
- if (crypto_dh_generate_public(cpath->dh_handshake_state)<0) {
+ if (crypto_dh_generate_public(cpath->rend_dh_handshake_state)<0) {
log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
+ status = -2;
goto perm_err;
}
}
@@ -221,7 +249,14 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
REND_DESC_COOKIE_LEN);
v3_shift += 2+REND_DESC_COOKIE_LEN;
}
- set_uint32(tmp+v3_shift+1, htonl((uint32_t)time(NULL)));
+ if (rend_client_should_send_timestamp()) {
+ uint32_t now = (uint32_t)time(NULL);
+ now += 300;
+ now -= now % 600;
+ set_uint32(tmp+v3_shift+1, htonl(now));
+ } else {
+ set_uint32(tmp+v3_shift+1, 0);
+ }
v3_shift += 4;
} /* if version 2 only write version number */
else if (entry->parsed->protocols & (1<<2)) {
@@ -253,9 +288,10 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
}
- if (crypto_dh_get_public(cpath->dh_handshake_state, tmp+dh_offset,
+ if (crypto_dh_get_public(cpath->rend_dh_handshake_state, tmp+dh_offset,
DH_KEY_LEN)<0) {
log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
+ status = -2;
goto perm_err;
}
@@ -269,6 +305,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
PK_PKCS1_OAEP_PADDING, 0);
if (r<0) {
log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
+ status = -2;
goto perm_err;
}
@@ -288,7 +325,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
introcirc->cpath->prev)<0) {
/* introcirc is already marked for close. leave rendcirc alone. */
log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
- return -2;
+ status = -2;
+ goto cleanup;
}
/* Now, we wait for an ACK or NAK on this circuit. */
@@ -297,14 +335,21 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
/* Set timestamp_dirty, because circuit_expire_building expects it
* to specify when a circuit entered the _C_INTRODUCE_ACK_WAIT
* state. */
- introcirc->_base.timestamp_dirty = time(NULL);
+ introcirc->base_.timestamp_dirty = time(NULL);
+
+ pathbias_count_use_attempt(introcirc);
+
+ goto cleanup;
- return 0;
perm_err:
- if (!introcirc->_base.marked_for_close)
+ if (!introcirc->base_.marked_for_close)
circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
- return -2;
+ cleanup:
+ memwipe(payload, 0, sizeof(payload));
+ memwipe(tmp, 0, sizeof(tmp));
+
+ return status;
}
/** Called when a rendezvous circuit is open; sends a establish
@@ -312,7 +357,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
void
rend_client_rendcirc_has_opened(origin_circuit_t *circ)
{
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
log_info(LD_REND,"rendcirc is open");
@@ -322,6 +367,32 @@ rend_client_rendcirc_has_opened(origin_circuit_t *circ)
}
}
+/**
+ * Called to close other intro circuits we launched in parallel
+ * due to timeout.
+ */
+static void
+rend_client_close_other_intros(const char *onion_address)
+{
+ circuit_t *c;
+ /* abort parallel intro circs, if any */
+ for (c = circuit_get_global_list_(); c; c = c->next) {
+ if ((c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
+ c->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) &&
+ !c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) {
+ origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(c);
+ if (oc->rend_data &&
+ !rend_cmp_service_ids(onion_address,
+ oc->rend_data->onion_address)) {
+ log_info(LD_REND|LD_CIRC, "Closing introduction circuit %d that we "
+ "built in parallel (Purpose %d).", oc->global_identifier,
+ c->purpose);
+ circuit_mark_for_close(c, END_CIRC_REASON_TIMEOUT);
+ }
+ }
+ }
+}
+
/** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.
*/
int
@@ -331,10 +402,10 @@ rend_client_introduction_acked(origin_circuit_t *circ,
origin_circuit_t *rendcirc;
(void) request; // XXXX Use this.
- if (circ->_base.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
log_warn(LD_PROTOCOL,
- "Received REND_INTRODUCE_ACK on unexpected circuit %d.",
- circ->_base.n_circ_id);
+ "Received REND_INTRODUCE_ACK on unexpected circuit %u.",
+ (unsigned)circ->base_.n_circ_id);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
return -1;
}
@@ -345,6 +416,10 @@ rend_client_introduction_acked(origin_circuit_t *circ,
#endif
tor_assert(circ->rend_data);
+ /* For path bias: This circuit was used successfully. Valid
+ * nacks and acks count. */
+ pathbias_mark_use_success(circ);
+
if (request_len == 0) {
/* It's an ACK; the introduction point relayed our introduction request. */
/* Locate the rend circ which is waiting to hear about this ack,
@@ -361,7 +436,7 @@ rend_client_introduction_acked(origin_circuit_t *circ,
/* Set timestamp_dirty, because circuit_expire_building expects
* it to specify when a circuit entered the
* _C_REND_READY_INTRO_ACKED state. */
- rendcirc->_base.timestamp_dirty = time(NULL);
+ rendcirc->base_.timestamp_dirty = time(NULL);
} else {
log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
}
@@ -369,6 +444,9 @@ rend_client_introduction_acked(origin_circuit_t *circ,
circuit_change_purpose(TO_CIRCUIT(circ),
CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
+
+ /* close any other intros launched in parallel */
+ rend_client_close_other_intros(circ->rend_data->onion_address);
} else {
/* It's a NAK; the introduction point didn't relay our request. */
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING);
@@ -525,7 +603,7 @@ rend_client_purge_last_hid_serv_requests(void)
if (old_last_hid_serv_requests != NULL) {
log_info(LD_REND, "Purging client last-HS-desc-request-time table");
- strmap_free(old_last_hid_serv_requests, _tor_free);
+ strmap_free(old_last_hid_serv_requests, tor_free_);
}
}
@@ -602,7 +680,8 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query)
directory_initiate_command_routerstatus_rend(hs_dir,
DIR_PURPOSE_FETCH_RENDDESC_V2,
ROUTER_PURPOSE_GENERAL,
- !tor2web_mode, desc_id_base32,
+ tor2web_mode?DIRIND_ONEHOP:DIRIND_ANONYMOUS,
+ desc_id_base32,
NULL, 0, 0,
rend_query);
log_info(LD_REND, "Sending fetch request for v2 descriptor for "
@@ -659,10 +738,17 @@ rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
time(NULL), chosen_replica) < 0) {
log_warn(LD_REND, "Internal error: Computing v2 rendezvous "
"descriptor ID did not succeed.");
- return;
+ /*
+ * Hmm, can this write anything to descriptor_id and still fail?
+ * Let's clear it just to be safe.
+ *
+ * From here on, any returns should goto done which clears
+ * descriptor_id so we don't leave key-derived material on the stack.
+ */
+ goto done;
}
if (directory_get_from_hs_dir(descriptor_id, rend_query) != 0)
- return; /* either success or failure, but we're done */
+ goto done; /* either success or failure, but we're done */
}
/* If we come here, there are no hidden service directories left. */
log_info(LD_REND, "Could not pick one of the responsible hidden "
@@ -670,6 +756,10 @@ rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
"we already tried them all unsuccessfully.");
/* Close pending connections. */
rend_client_desc_trynow(rend_query->onion_address);
+
+ done:
+ memwipe(descriptor_id, 0, sizeof(descriptor_id));
+
return;
}
@@ -818,7 +908,7 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request,
(void) request;
(void) request_len;
/* we just got an ack for our establish-rendezvous. switch purposes. */
- if (circ->_base.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
"Closing circ.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
@@ -829,7 +919,14 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request,
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_READY);
/* Set timestamp_dirty, because circuit_expire_building expects it
* to specify when a circuit entered the _C_REND_READY state. */
- circ->_base.timestamp_dirty = time(NULL);
+ circ->base_.timestamp_dirty = time(NULL);
+
+ /* From a path bias point of view, this circuit is now successfully used.
+ * Waiting any longer opens us up to attacks from Bob. He could induce
+ * Alice to attempt to connect to his hidden service and never reply
+ * to her rend requests */
+ pathbias_mark_use_success(circ);
+
/* XXXX This is a pretty brute-force approach. It'd be better to
* attach only the connections that are waiting on this circuit, rather
* than trying to attach them all. See comments bug 743. */
@@ -847,8 +944,8 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
crypt_path_t *hop;
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
- if ((circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
- circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
+ if ((circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
+ circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
|| !circ->build_state->pending_final_cpath) {
log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
"expecting it. Closing.");
@@ -868,9 +965,9 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
tor_assert(circ->build_state);
tor_assert(circ->build_state->pending_final_cpath);
hop = circ->build_state->pending_final_cpath;
- tor_assert(hop->dh_handshake_state);
+ tor_assert(hop->rend_dh_handshake_state);
if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN,
- hop->dh_handshake_state, (char*)request,
+ hop->rend_dh_handshake_state, (char*)request,
DH_KEY_LEN,
keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
@@ -886,8 +983,8 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
goto err;
}
- crypto_dh_free(hop->dh_handshake_state);
- hop->dh_handshake_state = NULL;
+ crypto_dh_free(hop->rend_dh_handshake_state);
+ hop->rend_dh_handshake_state = NULL;
/* All is well. Extend the circuit. */
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_JOINED);
@@ -1172,11 +1269,11 @@ rend_parse_service_authorization(const or_options_t *options,
strmap_t *parsed = strmap_new();
smartlist_t *sl = smartlist_new();
rend_service_authorization_t *auth = NULL;
+ char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
+ char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_BASE64+2+1];
for (line = options->HidServAuth; line; line = line->next) {
char *onion_address, *descriptor_cookie;
- char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
- char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_BASE64+2+1];
int auth_type_val = 0;
auth = NULL;
SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
@@ -1222,7 +1319,7 @@ rend_parse_service_authorization(const or_options_t *options,
descriptor_cookie);
goto err;
}
- auth_type_val = (descriptor_cookie_tmp[16] >> 4) + 1;
+ auth_type_val = (((uint8_t)descriptor_cookie_tmp[16]) >> 4) + 1;
if (auth_type_val < 1 || auth_type_val > 2) {
log_warn(LD_CONFIG, "Authorization cookie has unknown authorization "
"type encoded.");
@@ -1253,6 +1350,8 @@ rend_parse_service_authorization(const or_options_t *options,
} else {
strmap_free(parsed, rend_service_authorization_strmap_item_free);
}
+ memwipe(descriptor_cookie_tmp, 0, sizeof(descriptor_cookie_tmp));
+ memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext));
return res;
}
diff --git a/src/or/rendclient.h b/src/or/rendclient.h
index 393b556e3..1f731d0ae 100644
--- a/src/or/rendclient.h
+++ b/src/or/rendclient.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for rendclient.c.
**/
-#ifndef _TOR_RENDCLIENT_H
-#define _TOR_RENDCLIENT_H
+#ifndef TOR_RENDCLIENT_H
+#define TOR_RENDCLIENT_H
void rend_client_purge_state(void);
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 76786e0fd..d1b49411c 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -439,7 +439,7 @@ rend_intro_point_free(rend_intro_point_t *intro)
crypto_pk_free(intro->intro_key);
if (intro->accepted_intro_rsa_parts != NULL) {
- digestmap_free(intro->accepted_intro_rsa_parts, _tor_free);
+ replaycache_free(intro->accepted_intro_rsa_parts);
}
tor_free(intro);
@@ -800,7 +800,7 @@ rend_cache_entry_free(rend_cache_entry_t *e)
/** Helper: deallocate a rend_cache_entry_t. (Used with strmap_free(), which
* requires a function pointer whose argument is void*). */
static void
-_rend_cache_entry_free(void *p)
+rend_cache_entry_free_(void *p)
{
rend_cache_entry_free(p);
}
@@ -809,8 +809,8 @@ _rend_cache_entry_free(void *p)
void
rend_cache_free_all(void)
{
- strmap_free(rend_cache, _rend_cache_entry_free);
- digestmap_free(rend_cache_v2_dir, _rend_cache_entry_free);
+ strmap_free(rend_cache, rend_cache_entry_free_);
+ digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_);
rend_cache = NULL;
rend_cache_v2_dir = NULL;
}
@@ -844,7 +844,7 @@ rend_cache_purge(void)
{
if (rend_cache) {
log_info(LD_REND, "Purging client/v0-HS-authority HS descriptor cache");
- strmap_free(rend_cache, _rend_cache_entry_free);
+ strmap_free(rend_cache, rend_cache_entry_free_);
}
rend_cache = strmap_new();
}
@@ -954,7 +954,7 @@ rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
return 1;
}
-/** <b>query</b> is a base-32'ed service id. If it's malformed, return -1.
+/** <b>query</b> is a base32'ed service id. If it's malformed, return -1.
* Else look it up.
* - If it is found, point *desc to it, and write its length into
* *desc_len, and return 1.
@@ -1476,13 +1476,6 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
command);
}
-/** Return the number of entries in our rendezvous descriptor cache. */
-int
-rend_cache_size(void)
-{
- return strmap_size(rend_cache);
-}
-
/** Allocate and return a new rend_data_t with the same
* contents as <b>query</b>. */
rend_data_t *
diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h
index be6bd13d2..f476593d2 100644
--- a/src/or/rendcommon.h
+++ b/src/or/rendcommon.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for rendcommon.c.
**/
-#ifndef _TOR_RENDCOMMON_H
-#define _TOR_RENDCOMMON_H
+#ifndef TOR_RENDCOMMON_H
+#define TOR_RENDCOMMON_H
/** Free all storage associated with <b>data</b> */
static INLINE void
@@ -49,7 +49,6 @@ int rend_cache_store(const char *desc, size_t desc_len, int published,
int rend_cache_store_v2_desc_as_client(const char *desc,
const rend_data_t *rend_query);
int rend_cache_store_v2_desc_as_dir(const char *desc);
-int rend_cache_size(void);
int rend_encode_v2_descriptors(smartlist_t *descs_out,
rend_service_descriptor_t *desc, time_t now,
uint8_t period, rend_auth_type_t auth_type,
diff --git a/src/or/rendmid.c b/src/or/rendmid.c
index bacd0ef93..1bd11f6dc 100644
--- a/src/or/rendmid.c
+++ b/src/or/rendmid.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -32,10 +32,10 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request,
int reason = END_CIRC_REASON_INTERNAL;
log_info(LD_REND,
- "Received an ESTABLISH_INTRO request on circuit %d",
- circ->p_circ_id);
+ "Received an ESTABLISH_INTRO request on circuit %u",
+ (unsigned) circ->p_circ_id);
- if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit.");
reason = END_CIRC_REASON_TORPROTOCOL;
@@ -56,8 +56,8 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request,
goto err;
}
- /* Next 20 bytes: Hash of handshake_digest | "INTRODUCE" */
- memcpy(buf, circ->handshake_digest, DIGEST_LEN);
+ /* Next 20 bytes: Hash of rend_circ_nonce | "INTRODUCE" */
+ memcpy(buf, circ->rend_circ_nonce, DIGEST_LEN);
memcpy(buf+DIGEST_LEN, "INTRODUCE", 9);
if (crypto_digest(expected_digest, buf, DIGEST_LEN+9) < 0) {
log_warn(LD_BUG, "Internal error computing digest.");
@@ -114,8 +114,8 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request,
memcpy(circ->rend_token, pk_digest, DIGEST_LEN);
log_info(LD_REND,
- "Established introduction point on circuit %d for service %s",
- circ->p_circ_id, safe_str(serviceid));
+ "Established introduction point on circuit %u for service %s",
+ (unsigned) circ->p_circ_id, safe_str(serviceid));
return 0;
truncated:
@@ -139,13 +139,13 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request,
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
char nak_body[1];
- log_info(LD_REND, "Received an INTRODUCE1 request on circuit %d",
- circ->p_circ_id);
+ log_info(LD_REND, "Received an INTRODUCE1 request on circuit %u",
+ (unsigned)circ->p_circ_id);
- if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
log_warn(LD_PROTOCOL,
- "Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.",
- circ->p_circ_id);
+ "Rejecting INTRODUCE1 on non-OR or non-edge circuit %u.",
+ (unsigned)circ->p_circ_id);
goto err;
}
@@ -155,9 +155,9 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request,
*/
if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+
DH_KEY_LEN+CIPHER_KEY_LEN+PKCS1_OAEP_PADDING_OVERHEAD)) {
- log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %d; "
+ log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %u; "
"responding with nack.",
- circ->p_circ_id);
+ (unsigned)circ->p_circ_id);
goto err;
}
@@ -168,17 +168,17 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request,
intro_circ = circuit_get_intro_point((char*)request);
if (!intro_circ) {
log_info(LD_REND,
- "No intro circ found for INTRODUCE1 cell (%s) from circuit %d; "
+ "No intro circ found for INTRODUCE1 cell (%s) from circuit %u; "
"responding with nack.",
- safe_str(serviceid), circ->p_circ_id);
+ safe_str(serviceid), (unsigned)circ->p_circ_id);
goto err;
}
log_info(LD_REND,
"Sending introduction request for service %s "
- "from circ %d to circ %d",
- safe_str(serviceid), circ->p_circ_id,
- intro_circ->p_circ_id);
+ "from circ %u to circ %u",
+ safe_str(serviceid), (unsigned)circ->p_circ_id,
+ (unsigned)intro_circ->p_circ_id);
/* Great. Now we just relay the cell down the circuit. */
if (relay_send_command_from_edge(0, TO_CIRCUIT(intro_circ),
@@ -221,10 +221,10 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
char hexid[9];
int reason = END_CIRC_REASON_TORPROTOCOL;
- log_info(LD_REND, "Received an ESTABLISH_RENDEZVOUS request on circuit %d",
- circ->p_circ_id);
+ log_info(LD_REND, "Received an ESTABLISH_RENDEZVOUS request on circuit %u",
+ (unsigned)circ->p_circ_id);
- if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
log_warn(LD_PROTOCOL,
"Tried to establish rendezvous on non-OR or non-edge circuit.");
goto err;
@@ -256,8 +256,8 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request,
base16_encode(hexid,9,(char*)request,4);
log_info(LD_REND,
- "Established rendezvous point on circuit %d for cookie %s",
- circ->p_circ_id, hexid);
+ "Established rendezvous point on circuit %u for cookie %s",
+ (unsigned)circ->p_circ_id, hexid);
return 0;
err:
@@ -277,18 +277,18 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
char hexid[9];
int reason = END_CIRC_REASON_INTERNAL;
- if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
+ if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
log_info(LD_REND,
- "Tried to complete rendezvous on non-OR or non-edge circuit %d.",
- circ->p_circ_id);
+ "Tried to complete rendezvous on non-OR or non-edge circuit %u.",
+ (unsigned)circ->p_circ_id);
reason = END_CIRC_REASON_TORPROTOCOL;
goto err;
}
if (request_len != REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Rejecting RENDEZVOUS1 cell with bad length (%d) on circuit %d.",
- (int)request_len, circ->p_circ_id);
+ "Rejecting RENDEZVOUS1 cell with bad length (%d) on circuit %u.",
+ (int)request_len, (unsigned)circ->p_circ_id);
reason = END_CIRC_REASON_TORPROTOCOL;
goto err;
}
@@ -296,8 +296,8 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
base16_encode(hexid, sizeof(hexid), (const char*)request, 4);
log_info(LD_REND,
- "Got request for rendezvous from circuit %d to cookie %s.",
- circ->p_circ_id, hexid);
+ "Got request for rendezvous from circuit %u to cookie %s.",
+ (unsigned)circ->p_circ_id, hexid);
rend_circ = circuit_get_rendezvous((char*)request);
if (!rend_circ) {
@@ -314,15 +314,15 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
(char*)(request+REND_COOKIE_LEN),
request_len-REND_COOKIE_LEN, NULL)) {
log_warn(LD_GENERAL,
- "Unable to send RENDEZVOUS2 cell to client on circuit %d.",
- rend_circ->p_circ_id);
+ "Unable to send RENDEZVOUS2 cell to client on circuit %u.",
+ (unsigned)rend_circ->p_circ_id);
goto err;
}
/* Join the circuits. */
log_info(LD_REND,
- "Completing rendezvous: circuit %d joins circuit %d (cookie %s)",
- circ->p_circ_id, rend_circ->p_circ_id, hexid);
+ "Completing rendezvous: circuit %u joins circuit %u (cookie %s)",
+ (unsigned)circ->p_circ_id, (unsigned)rend_circ->p_circ_id, hexid);
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_ESTABLISHED);
circuit_change_purpose(TO_CIRCUIT(rend_circ),
diff --git a/src/or/rendmid.h b/src/or/rendmid.h
index 0af6436de..310276ac9 100644
--- a/src/or/rendmid.h
+++ b/src/or/rendmid.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for rendmid.c.
**/
-#ifndef _TOR_RENDMID_H
-#define _TOR_RENDMID_H
+#ifndef TOR_RENDMID_H
+#define TOR_RENDMID_H
int rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request,
size_t request_len);
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index d235f089f..8a4a11e47 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -7,6 +7,8 @@
* \brief The hidden-service side of rendezvous functionality.
**/
+#define RENDSERVICE_PRIVATE
+
#include "or.h"
#include "circuitbuild.h"
#include "circuitlist.h"
@@ -21,16 +23,42 @@
#include "router.h"
#include "relay.h"
#include "rephist.h"
+#include "replaycache.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "routerset.h"
static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro,
const char *pk_digest);
static rend_intro_point_t *find_intro_point(origin_circuit_t *circ);
+static extend_info_t *find_rp_for_intro(
+ const rend_intro_cell_t *intro,
+ uint8_t *need_free_out, char **err_msg_out);
+
static int intro_point_accepted_intro_count(rend_intro_point_t *intro);
static int intro_point_should_expire_now(rend_intro_point_t *intro,
time_t now);
+struct rend_service_t;
+static int rend_service_load_keys(struct rend_service_t *s);
+static int rend_service_load_auth_keys(struct rend_service_t *s,
+ const char *hfname);
+
+static ssize_t rend_service_parse_intro_for_v0_or_v1(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out);
+static ssize_t rend_service_parse_intro_for_v2(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out);
+static ssize_t rend_service_parse_intro_for_v3(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out);
/** Represents the mapping from a virtual port of a rendezvous service to
* a real port on some IP.
@@ -60,7 +88,7 @@ typedef struct rend_service_port_config_t {
/** How many seconds should we wait for new HS descriptors to reach
* our clients before we close an expiring intro point? */
-#define INTRO_POINT_EXPIRATION_GRACE_PERIOD 5*60
+#define INTRO_POINT_EXPIRATION_GRACE_PERIOD (5*60)
/** Represents a single hidden service running at this OP. */
typedef struct rend_service_t {
@@ -91,16 +119,12 @@ typedef struct rend_service_t {
* up-to-date. */
time_t next_upload_time; /**< Scheduled next hidden service descriptor
* upload time. */
- /** Map from digests of Diffie-Hellman values INTRODUCE2 to time_t
- * of when they were received. Clients may send INTRODUCE1 cells
- * for the same rendezvous point through two or more different
- * introduction points; when they do, this digestmap keeps us from
- * launching multiple simultaneous attempts to connect to the same
- * rend point. */
- digestmap_t *accepted_intro_dh_parts;
- /** Time at which we last removed expired values from
- * accepted_intro_dh_parts. */
- time_t last_cleaned_accepted_intro_dh_parts;
+ /** Replay cache for Diffie-Hellman values of INTRODUCE2 cells, to
+ * detect repeats. Clients may send INTRODUCE1 cells for the same
+ * rendezvous point through two or more different introduction points;
+ * when they do, this keeps us from launching multiple simultaneous attempts
+ * to connect to the same rend point. */
+ replaycache_t *accepted_intro_dh_parts;
} rend_service_t;
/** A list of rend_service_t's for services run on this OP.
@@ -135,7 +159,9 @@ rend_authorized_client_free(rend_authorized_client_t *client)
return;
if (client->client_key)
crypto_pk_free(client->client_key);
+ tor_strclear(client->client_name);
tor_free(client->client_name);
+ memwipe(client->descriptor_cookie, 0, sizeof(client->descriptor_cookie));
tor_free(client);
}
@@ -171,7 +197,9 @@ rend_service_free(rend_service_t *service)
rend_authorized_client_free(c););
smartlist_free(service->clients);
}
- digestmap_free(service->accepted_intro_dh_parts, _tor_free);
+ if (service->accepted_intro_dh_parts) {
+ replaycache_free(service->accepted_intro_dh_parts);
+ }
tor_free(service);
}
@@ -244,8 +272,8 @@ rend_add_service(rend_service_t *service)
service->directory);
for (i = 0; i < smartlist_len(service->ports); ++i) {
p = smartlist_get(service->ports, i);
- log_debug(LD_REND,"Service maps port %d to %s:%d",
- p->virtual_port, fmt_addr(&p->real_addr), p->real_port);
+ log_debug(LD_REND,"Service maps port %d to %s",
+ p->virtual_port, fmt_addrport(&p->real_addr, p->real_port));
}
}
}
@@ -515,7 +543,7 @@ rend_config_services(const or_options_t *options, int validate_only)
/* XXXX it would be nicer if we had a nicer abstraction to use here,
* so we could just iterate over the list of services to close, but
* once again, this isn't critical-path code. */
- for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
if (!circ->marked_for_close &&
circ->state == CIRCUIT_STATE_OPEN &&
(circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -565,6 +593,7 @@ rend_service_update_descriptor(rend_service_t *service)
d = service->desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
d->pk = crypto_pk_dup_key(service->private_key);
d->timestamp = time(NULL);
+ d->timestamp -= d->timestamp % 3600; /* Round down to nearest hour */
d->intro_nodes = smartlist_new();
/* Support intro protocols 2 and 3. */
d->protocols = (1 << 2) + (1 << 3);
@@ -582,7 +611,7 @@ rend_service_update_descriptor(rend_service_t *service)
}
circ = find_intro_circuit(intro_svc, service->pk_digest);
- if (!circ || circ->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) {
+ if (!circ || circ->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) {
/* This intro point's circuit isn't finished yet. Don't list it. */
continue;
}
@@ -609,231 +638,274 @@ rend_service_update_descriptor(rend_service_t *service)
/** Load and/or generate private keys for all hidden services, possibly
* including keys for client authorization. Return 0 on success, -1 on
- * failure.
- */
+ * failure. */
int
-rend_service_load_keys(void)
+rend_service_load_all_keys(void)
{
- int r = 0;
- char fname[512];
- char buf[1500];
-
SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, s) {
if (s->private_key)
continue;
log_info(LD_REND, "Loading hidden-service keys from \"%s\"",
s->directory);
- /* Check/create directory */
- if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0)
+ if (rend_service_load_keys(s) < 0)
return -1;
+ } SMARTLIST_FOREACH_END(s);
+
+ return 0;
+}
+
+/** Load and/or generate private keys for the hidden service <b>s</b>,
+ * possibly including keys for client authorization. Return 0 on success, -1
+ * on failure. */
+static int
+rend_service_load_keys(rend_service_t *s)
+{
+ char fname[512];
+ char buf[128];
+
+ /* Check/create directory */
+ if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0)
+ return -1;
+
+ /* Load key */
+ if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
+ strlcat(fname,PATH_SEPARATOR"private_key",sizeof(fname))
+ >= sizeof(fname)) {
+ log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".",
+ s->directory);
+ return -1;
+ }
+ s->private_key = init_key_from_file(fname, 1, LOG_ERR);
+ if (!s->private_key)
+ return -1;
+
+ /* Create service file */
+ if (rend_get_service_id(s->private_key, s->service_id)<0) {
+ log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
+ return -1;
+ }
+ if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) {
+ log_warn(LD_BUG, "Couldn't compute hash of public key.");
+ return -1;
+ }
+ if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
+ strlcat(fname,PATH_SEPARATOR"hostname",sizeof(fname))
+ >= sizeof(fname)) {
+ log_warn(LD_CONFIG, "Directory name too long to store hostname file:"
+ " \"%s\".", s->directory);
+ return -1;
+ }
+
+ tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id);
+ if (write_str_to_file(fname,buf,0)<0) {
+ log_warn(LD_CONFIG, "Could not write onion address to hostname file.");
+ memwipe(buf, 0, sizeof(buf));
+ return -1;
+ }
+ memwipe(buf, 0, sizeof(buf));
- /* Load key */
- if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
- strlcat(fname,PATH_SEPARATOR"private_key",sizeof(fname))
- >= sizeof(fname)) {
- log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".",
- s->directory);
+ /* If client authorization is configured, load or generate keys. */
+ if (s->auth_type != REND_NO_AUTH) {
+ if (rend_service_load_auth_keys(s, fname) < 0)
return -1;
+ }
+
+ return 0;
+}
+
+/** Load and/or generate client authorization keys for the hidden service
+ * <b>s</b>, which stores its hostname in <b>hfname</b>. Return 0 on success,
+ * -1 on failure. */
+static int
+rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
+{
+ int r = 0;
+ char cfname[512];
+ char *client_keys_str = NULL;
+ strmap_t *parsed_clients = strmap_new();
+ FILE *cfile, *hfile;
+ open_file_t *open_cfile = NULL, *open_hfile = NULL;
+ char extended_desc_cookie[REND_DESC_COOKIE_LEN+1];
+ char desc_cook_out[3*REND_DESC_COOKIE_LEN_BASE64+1];
+ char service_id[16+1];
+ char buf[1500];
+
+ /* Load client keys and descriptor cookies, if available. */
+ if (tor_snprintf(cfname, sizeof(cfname), "%s"PATH_SEPARATOR"client_keys",
+ s->directory)<0) {
+ log_warn(LD_CONFIG, "Directory name too long to store client keys "
+ "file: \"%s\".", s->directory);
+ goto err;
+ }
+ client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL);
+ if (client_keys_str) {
+ if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) {
+ log_warn(LD_CONFIG, "Previously stored client_keys file could not "
+ "be parsed.");
+ goto err;
+ } else {
+ log_info(LD_CONFIG, "Parsed %d previously stored client entries.",
+ strmap_size(parsed_clients));
}
- s->private_key = init_key_from_file(fname, 1, LOG_ERR);
- if (!s->private_key)
- return -1;
+ }
- /* Create service file */
- if (rend_get_service_id(s->private_key, s->service_id)<0) {
- log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
- return -1;
+ /* Prepare client_keys and hostname files. */
+ if (!(cfile = start_writing_to_stdio_file(cfname,
+ OPEN_FLAGS_REPLACE | O_TEXT,
+ 0600, &open_cfile))) {
+ log_warn(LD_CONFIG, "Could not open client_keys file %s",
+ escaped(cfname));
+ goto err;
+ }
+
+ if (!(hfile = start_writing_to_stdio_file(hfname,
+ OPEN_FLAGS_REPLACE | O_TEXT,
+ 0600, &open_hfile))) {
+ log_warn(LD_CONFIG, "Could not open hostname file %s", escaped(hfname));
+ goto err;
+ }
+
+ /* Either use loaded keys for configured clients or generate new
+ * ones if a client is new. */
+ SMARTLIST_FOREACH_BEGIN(s->clients, rend_authorized_client_t *, client) {
+ rend_authorized_client_t *parsed =
+ strmap_get(parsed_clients, client->client_name);
+ int written;
+ size_t len;
+ /* Copy descriptor cookie from parsed entry or create new one. */
+ if (parsed) {
+ memcpy(client->descriptor_cookie, parsed->descriptor_cookie,
+ REND_DESC_COOKIE_LEN);
+ } else {
+ crypto_rand(client->descriptor_cookie, REND_DESC_COOKIE_LEN);
}
- if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) {
- log_warn(LD_BUG, "Couldn't compute hash of public key.");
- return -1;
+ if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
+ client->descriptor_cookie,
+ REND_DESC_COOKIE_LEN) < 0) {
+ log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
+ goto err;
}
- if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
- strlcat(fname,PATH_SEPARATOR"hostname",sizeof(fname))
- >= sizeof(fname)) {
- log_warn(LD_CONFIG, "Directory name too long to store hostname file:"
- " \"%s\".", s->directory);
- return -1;
+ /* Copy client key from parsed entry or create new one if required. */
+ if (parsed && parsed->client_key) {
+ client->client_key = crypto_pk_dup_key(parsed->client_key);
+ } else if (s->auth_type == REND_STEALTH_AUTH) {
+ /* Create private key for client. */
+ crypto_pk_t *prkey = NULL;
+ if (!(prkey = crypto_pk_new())) {
+ log_warn(LD_BUG,"Error constructing client key");
+ goto err;
+ }
+ if (crypto_pk_generate_key(prkey)) {
+ log_warn(LD_BUG,"Error generating client key");
+ crypto_pk_free(prkey);
+ goto err;
+ }
+ if (crypto_pk_check_key(prkey) <= 0) {
+ log_warn(LD_BUG,"Generated client key seems invalid");
+ crypto_pk_free(prkey);
+ goto err;
+ }
+ client->client_key = prkey;
}
- tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id);
- if (write_str_to_file(fname,buf,0)<0) {
- log_warn(LD_CONFIG, "Could not write onion address to hostname file.");
- return -1;
+ /* Add entry to client_keys file. */
+ desc_cook_out[strlen(desc_cook_out)-1] = '\0'; /* Remove newline. */
+ written = tor_snprintf(buf, sizeof(buf),
+ "client-name %s\ndescriptor-cookie %s\n",
+ client->client_name, desc_cook_out);
+ if (written < 0) {
+ log_warn(LD_BUG, "Could not write client entry.");
+ goto err;
}
-
- /* If client authorization is configured, load or generate keys. */
- if (s->auth_type != REND_NO_AUTH) {
- char *client_keys_str = NULL;
- strmap_t *parsed_clients = strmap_new();
- char cfname[512];
- FILE *cfile, *hfile;
- open_file_t *open_cfile = NULL, *open_hfile = NULL;
-
- /* Load client keys and descriptor cookies, if available. */
- if (tor_snprintf(cfname, sizeof(cfname), "%s"PATH_SEPARATOR"client_keys",
- s->directory)<0) {
- log_warn(LD_CONFIG, "Directory name too long to store client keys "
- "file: \"%s\".", s->directory);
+ if (client->client_key) {
+ char *client_key_out = NULL;
+ if (crypto_pk_write_private_key_to_string(client->client_key,
+ &client_key_out, &len) != 0) {
+ log_warn(LD_BUG, "Internal error: "
+ "crypto_pk_write_private_key_to_string() failed.");
goto err;
}
- client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL);
- if (client_keys_str) {
- if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) {
- log_warn(LD_CONFIG, "Previously stored client_keys file could not "
- "be parsed.");
- goto err;
- } else {
- log_info(LD_CONFIG, "Parsed %d previously stored client entries.",
- strmap_size(parsed_clients));
- tor_free(client_keys_str);
- }
- }
-
- /* Prepare client_keys and hostname files. */
- if (!(cfile = start_writing_to_stdio_file(cfname,
- OPEN_FLAGS_REPLACE | O_TEXT,
- 0600, &open_cfile))) {
- log_warn(LD_CONFIG, "Could not open client_keys file %s",
- escaped(cfname));
+ if (rend_get_service_id(client->client_key, service_id)<0) {
+ log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
+ /*
+ * len is string length, not buffer length, but last byte is NUL
+ * anyway.
+ */
+ memwipe(client_key_out, 0, len);
+ tor_free(client_key_out);
goto err;
}
- if (!(hfile = start_writing_to_stdio_file(fname,
- OPEN_FLAGS_REPLACE | O_TEXT,
- 0600, &open_hfile))) {
- log_warn(LD_CONFIG, "Could not open hostname file %s", escaped(fname));
+ written = tor_snprintf(buf + written, sizeof(buf) - written,
+ "client-key\n%s", client_key_out);
+ memwipe(client_key_out, 0, len);
+ tor_free(client_key_out);
+ if (written < 0) {
+ log_warn(LD_BUG, "Could not write client entry.");
goto err;
}
+ }
- /* Either use loaded keys for configured clients or generate new
- * ones if a client is new. */
- SMARTLIST_FOREACH_BEGIN(s->clients, rend_authorized_client_t *, client)
- {
- char desc_cook_out[3*REND_DESC_COOKIE_LEN_BASE64+1];
- char service_id[16+1];
- rend_authorized_client_t *parsed =
- strmap_get(parsed_clients, client->client_name);
- int written;
- size_t len;
- /* Copy descriptor cookie from parsed entry or create new one. */
- if (parsed) {
- memcpy(client->descriptor_cookie, parsed->descriptor_cookie,
- REND_DESC_COOKIE_LEN);
- } else {
- crypto_rand(client->descriptor_cookie, REND_DESC_COOKIE_LEN);
- }
- if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
- client->descriptor_cookie,
- REND_DESC_COOKIE_LEN) < 0) {
- log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
- return -1;
- }
- /* Copy client key from parsed entry or create new one if required. */
- if (parsed && parsed->client_key) {
- client->client_key = crypto_pk_dup_key(parsed->client_key);
- } else if (s->auth_type == REND_STEALTH_AUTH) {
- /* Create private key for client. */
- crypto_pk_t *prkey = NULL;
- if (!(prkey = crypto_pk_new())) {
- log_warn(LD_BUG,"Error constructing client key");
- goto err;
- }
- if (crypto_pk_generate_key(prkey)) {
- log_warn(LD_BUG,"Error generating client key");
- crypto_pk_free(prkey);
- goto err;
- }
- if (crypto_pk_check_key(prkey) <= 0) {
- log_warn(LD_BUG,"Generated client key seems invalid");
- crypto_pk_free(prkey);
- goto err;
- }
- client->client_key = prkey;
- }
- /* Add entry to client_keys file. */
- desc_cook_out[strlen(desc_cook_out)-1] = '\0'; /* Remove newline. */
- written = tor_snprintf(buf, sizeof(buf),
- "client-name %s\ndescriptor-cookie %s\n",
- client->client_name, desc_cook_out);
- if (written < 0) {
- log_warn(LD_BUG, "Could not write client entry.");
- goto err;
- }
- if (client->client_key) {
- char *client_key_out = NULL;
- crypto_pk_write_private_key_to_string(client->client_key,
- &client_key_out, &len);
- if (rend_get_service_id(client->client_key, service_id)<0) {
- log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
- tor_free(client_key_out);
- goto err;
- }
- written = tor_snprintf(buf + written, sizeof(buf) - written,
- "client-key\n%s", client_key_out);
- tor_free(client_key_out);
- if (written < 0) {
- log_warn(LD_BUG, "Could not write client entry.");
- goto err;
- }
- }
-
- if (fputs(buf, cfile) < 0) {
- log_warn(LD_FS, "Could not append client entry to file: %s",
- strerror(errno));
- goto err;
- }
-
- /* Add line to hostname file. */
- if (s->auth_type == REND_BASIC_AUTH) {
- /* Remove == signs (newline has been removed above). */
- desc_cook_out[strlen(desc_cook_out)-2] = '\0';
- tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
- s->service_id, desc_cook_out, client->client_name);
- } else {
- char extended_desc_cookie[REND_DESC_COOKIE_LEN+1];
- memcpy(extended_desc_cookie, client->descriptor_cookie,
- REND_DESC_COOKIE_LEN);
- extended_desc_cookie[REND_DESC_COOKIE_LEN] =
- ((int)s->auth_type - 1) << 4;
- if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
- extended_desc_cookie,
- REND_DESC_COOKIE_LEN+1) < 0) {
- log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- goto err;
- }
- desc_cook_out[strlen(desc_cook_out)-3] = '\0'; /* Remove A= and
- newline. */
- tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
- service_id, desc_cook_out, client->client_name);
- }
+ if (fputs(buf, cfile) < 0) {
+ log_warn(LD_FS, "Could not append client entry to file: %s",
+ strerror(errno));
+ goto err;
+ }
- if (fputs(buf, hfile)<0) {
- log_warn(LD_FS, "Could not append host entry to file: %s",
- strerror(errno));
- goto err;
- }
+ /* Add line to hostname file. */
+ if (s->auth_type == REND_BASIC_AUTH) {
+ /* Remove == signs (newline has been removed above). */
+ desc_cook_out[strlen(desc_cook_out)-2] = '\0';
+ tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
+ s->service_id, desc_cook_out, client->client_name);
+ } else {
+ memcpy(extended_desc_cookie, client->descriptor_cookie,
+ REND_DESC_COOKIE_LEN);
+ extended_desc_cookie[REND_DESC_COOKIE_LEN] =
+ ((int)s->auth_type - 1) << 4;
+ if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
+ extended_desc_cookie,
+ REND_DESC_COOKIE_LEN+1) < 0) {
+ log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
+ goto err;
}
- SMARTLIST_FOREACH_END(client);
+ desc_cook_out[strlen(desc_cook_out)-3] = '\0'; /* Remove A= and
+ newline. */
+ tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
+ service_id, desc_cook_out, client->client_name);
+ }
- goto done;
- err:
- r = -1;
- done:
- tor_free(client_keys_str);
- strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
- if (r<0) {
- if (open_cfile)
- abort_writing_to_file(open_cfile);
- if (open_hfile)
- abort_writing_to_file(open_hfile);
- return r;
- } else {
- finish_writing_to_file(open_cfile);
- finish_writing_to_file(open_hfile);
- }
+ if (fputs(buf, hfile)<0) {
+ log_warn(LD_FS, "Could not append host entry to file: %s",
+ strerror(errno));
+ goto err;
}
- } SMARTLIST_FOREACH_END(s);
+ } SMARTLIST_FOREACH_END(client);
+
+ finish_writing_to_file(open_cfile);
+ finish_writing_to_file(open_hfile);
+
+ goto done;
+ err:
+ r = -1;
+ if (open_cfile)
+ abort_writing_to_file(open_cfile);
+ if (open_hfile)
+ abort_writing_to_file(open_hfile);
+ done:
+ if (client_keys_str) {
+ tor_strclear(client_keys_str);
+ tor_free(client_keys_str);
+ }
+ strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
+
+ memwipe(cfname, 0, sizeof(cfname));
+
+ /* Clear stack buffers that held key-derived material. */
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(desc_cook_out, 0, sizeof(desc_cook_out));
+ memwipe(service_id, 0, sizeof(service_id));
+ memwipe(extended_desc_cookie, 0, sizeof(extended_desc_cookie));
+
return r;
}
@@ -860,7 +932,7 @@ rend_service_requires_uptime(rend_service_t *service)
for (i=0; i < smartlist_len(service->ports); ++i) {
p = smartlist_get(service->ports, i);
- if (smartlist_string_num_isin(get_options()->LongLivedPorts,
+ if (smartlist_contains_int_as_string(get_options()->LongLivedPorts,
p->virtual_port))
return 1;
}
@@ -906,26 +978,6 @@ rend_check_authorization(rend_service_t *service,
return 1;
}
-/** Remove elements from <b>service</b>'s replay cache that are old enough to
- * be noticed by timestamp checking. */
-static void
-clean_accepted_intro_dh_parts(rend_service_t *service, time_t now)
-{
- const time_t cutoff = now - REND_REPLAY_TIME_INTERVAL;
-
- service->last_cleaned_accepted_intro_dh_parts = now;
- if (!service->accepted_intro_dh_parts)
- return;
-
- DIGESTMAP_FOREACH_MODIFY(service->accepted_intro_dh_parts, digest,
- time_t *, t) {
- if (*t < cutoff) {
- tor_free(t);
- MAP_DEL_CURRENT(digest);
- }
- } DIGESTMAP_FOREACH_END;
-}
-
/** Called when <b>intro</b> will soon be removed from
* <b>service</b>'s list of intro points. */
static void
@@ -1033,42 +1085,51 @@ rend_service_note_removing_intro_point(rend_service_t *service,
/** Respond to an INTRODUCE2 cell by launching a circuit to the chosen
* rendezvous point.
*/
- /* XXXX024 this function sure could use some organizing. -RD */
int
rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
size_t request_len)
{
- char *ptr, *r_cookie;
- extend_info_t *extend_info = NULL;
+ /* Global status stuff */
+ int status = 0, result;
+ const or_options_t *options = get_options();
+ char *err_msg = NULL;
+ const char *stage_descr = NULL;
+ int reason = END_CIRC_REASON_TORPROTOCOL;
+ /* Service/circuit/key stuff we can learn before parsing */
+ char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
+ rend_service_t *service = NULL;
+ rend_intro_point_t *intro_point = NULL;
+ crypto_pk_t *intro_key = NULL;
+ /* Parsed cell */
+ rend_intro_cell_t *parsed_req = NULL;
+ /* Rendezvous point */
+ extend_info_t *rp = NULL;
+ /*
+ * We need to look up and construct the extend_info_t for v0 and v1,
+ * but all the info is in the cell and it's constructed by the parser
+ * for v2 and v3, so freeing it would be a double-free. Use this to
+ * keep track of whether we should free it.
+ */
+ uint8_t need_rp_free = 0;
+ /* XXX not handled yet */
char buf[RELAY_PAYLOAD_SIZE];
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; /* Holds KH, Df, Db, Kf, Kb */
- rend_service_t *service;
- rend_intro_point_t *intro_point;
- int r, i, v3_shift = 0;
- size_t len, keylen;
+ int i;
crypto_dh_t *dh = NULL;
origin_circuit_t *launched = NULL;
crypt_path_t *cpath = NULL;
- char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
char hexcookie[9];
int circ_needs_uptime;
- int reason = END_CIRC_REASON_TORPROTOCOL;
- crypto_pk_t *intro_key;
- char intro_key_digest[DIGEST_LEN];
- int auth_type;
- size_t auth_len = 0;
- char auth_data[REND_DESC_COOKIE_LEN];
- crypto_digest_t *digest = NULL;
time_t now = time(NULL);
- char diffie_hellman_hash[DIGEST_LEN];
- time_t *access_time;
- const or_options_t *options = get_options();
+ time_t elapsed;
+ int replay;
- if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) {
+ /* Do some initial validation and logging before we parse the cell */
+ if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) {
log_warn(LD_PROTOCOL,
- "Got an INTRODUCE2 over a non-introduction circuit %d.",
- circuit->_base.n_circ_id);
- return -1;
+ "Got an INTRODUCE2 over a non-introduction circuit %u.",
+ (unsigned) circuit->base_.n_circ_id);
+ goto err;
}
#ifndef NON_ANONYMOUS_MODE_ENABLED
@@ -1076,218 +1137,150 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
#endif
tor_assert(circuit->rend_data);
+ /* We'll use this in a bazillion log messages */
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
- log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.",
- escaped(serviceid), circuit->_base.n_circ_id);
-
- /* min key length plus digest length plus nickname length */
- if (request_len < DIGEST_LEN+REND_COOKIE_LEN+(MAX_NICKNAME_LEN+1)+
- DH_KEY_LEN+42) {
- log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.",
- circuit->_base.n_circ_id);
- return -1;
- }
/* look up service depending on circuit. */
- service = rend_service_get_by_pk_digest(
- circuit->rend_data->rend_pk_digest);
+ service =
+ rend_service_get_by_pk_digest(circuit->rend_data->rend_pk_digest);
if (!service) {
- log_warn(LD_BUG, "Internal error: Got an INTRODUCE2 cell on an intro "
+ log_warn(LD_BUG,
+ "Internal error: Got an INTRODUCE2 cell on an intro "
"circ for an unrecognized service %s.",
escaped(serviceid));
- return -1;
- }
-
- /* use intro key instead of service key. */
- intro_key = circuit->intro_key;
-
- /* first DIGEST_LEN bytes of request is intro or service pk digest */
- crypto_pk_get_digest(intro_key, intro_key_digest);
- if (tor_memneq(intro_key_digest, request, DIGEST_LEN)) {
- base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- (char*)request, REND_SERVICE_ID_LEN);
- log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).",
- escaped(serviceid));
- return -1;
- }
-
- keylen = crypto_pk_keysize(intro_key);
- if (request_len < keylen+DIGEST_LEN) {
- log_warn(LD_PROTOCOL,
- "PK-encrypted portion of INTRODUCE2 cell was truncated.");
- return -1;
+ goto err;
}
intro_point = find_intro_point(circuit);
if (intro_point == NULL) {
- log_warn(LD_BUG, "Internal error: Got an INTRODUCE2 cell on an intro circ "
- "(for service %s) with no corresponding rend_intro_point_t.",
+ log_warn(LD_BUG,
+ "Internal error: Got an INTRODUCE2 cell on an "
+ "intro circ (for service %s) with no corresponding "
+ "rend_intro_point_t.",
escaped(serviceid));
- return -1;
- }
-
- if (!service->accepted_intro_dh_parts)
- service->accepted_intro_dh_parts = digestmap_new();
-
- if (!intro_point->accepted_intro_rsa_parts)
- intro_point->accepted_intro_rsa_parts = digestmap_new();
-
- {
- char pkpart_digest[DIGEST_LEN];
- /* Check for replay of PK-encrypted portion. */
- crypto_digest(pkpart_digest, (char*)request+DIGEST_LEN, keylen);
- access_time = digestmap_get(intro_point->accepted_intro_rsa_parts,
- pkpart_digest);
- if (access_time != NULL) {
- log_warn(LD_REND, "Possible replay detected! We received an "
- "INTRODUCE2 cell with same PK-encrypted part %d seconds ago. "
- "Dropping cell.", (int)(now-*access_time));
- return -1;
- }
- access_time = tor_malloc(sizeof(time_t));
- *access_time = now;
- digestmap_set(intro_point->accepted_intro_rsa_parts,
- pkpart_digest, access_time);
- }
-
- /* Next N bytes is encrypted with service key */
- note_crypto_pk_op(REND_SERVER);
- r = crypto_pk_private_hybrid_decrypt(
- intro_key,buf,sizeof(buf),
- (char*)(request+DIGEST_LEN),request_len-DIGEST_LEN,
- PK_PKCS1_OAEP_PADDING,1);
- if (r<0) {
- log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 cell.");
- return -1;
+ goto err;
}
- len = r;
- if (*buf == 3) {
- /* Version 3 INTRODUCE2 cell. */
- v3_shift = 1;
- auth_type = buf[1];
- switch (auth_type) {
- case REND_BASIC_AUTH:
- /* fall through */
- case REND_STEALTH_AUTH:
- auth_len = ntohs(get_uint16(buf+2));
- if (auth_len != REND_DESC_COOKIE_LEN) {
- log_info(LD_REND, "Wrong auth data size %d, should be %d.",
- (int)auth_len, REND_DESC_COOKIE_LEN);
- return -1;
- }
- memcpy(auth_data, buf+4, sizeof(auth_data));
- v3_shift += 2+REND_DESC_COOKIE_LEN;
- break;
- case REND_NO_AUTH:
- break;
- default:
- log_info(LD_REND, "Unknown authorization type '%d'", auth_type);
- }
- /* Skip the timestamp field. We no longer use it. */
- v3_shift += 4;
- }
- if (*buf == 2 || *buf == 3) {
- /* Version 2 INTRODUCE2 cell. */
- int klen;
- extend_info = tor_malloc_zero(sizeof(extend_info_t));
- tor_addr_from_ipv4n(&extend_info->addr, get_uint32(buf+v3_shift+1));
- extend_info->port = ntohs(get_uint16(buf+v3_shift+5));
- memcpy(extend_info->identity_digest, buf+v3_shift+7,
- DIGEST_LEN);
- extend_info->nickname[0] = '$';
- base16_encode(extend_info->nickname+1, sizeof(extend_info->nickname)-1,
- extend_info->identity_digest, DIGEST_LEN);
-
- klen = ntohs(get_uint16(buf+v3_shift+7+DIGEST_LEN));
- if ((int)len != v3_shift+7+DIGEST_LEN+2+klen+20+128) {
- log_warn(LD_PROTOCOL, "Bad length %u for version %d INTRODUCE2 cell.",
- (int)len, *buf);
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
- }
- extend_info->onion_key =
- crypto_pk_asn1_decode(buf+v3_shift+7+DIGEST_LEN+2, klen);
- if (!extend_info->onion_key) {
- log_warn(LD_PROTOCOL, "Error decoding onion key in version %d "
- "INTRODUCE2 cell.", *buf);
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
- }
- ptr = buf+v3_shift+7+DIGEST_LEN+2+klen;
- len -= v3_shift+7+DIGEST_LEN+2+klen;
- } else {
- char *rp_nickname;
- size_t nickname_field_len;
- const node_t *node;
- int version;
- if (*buf == 1) {
- rp_nickname = buf+1;
- nickname_field_len = MAX_HEX_NICKNAME_LEN+1;
- version = 1;
- } else {
- nickname_field_len = MAX_NICKNAME_LEN+1;
- rp_nickname = buf;
- version = 0;
- }
- ptr=memchr(rp_nickname,0,nickname_field_len);
- if (!ptr || ptr == rp_nickname) {
- log_warn(LD_PROTOCOL,
- "Couldn't find a nul-padded nickname in INTRODUCE2 cell.");
- return -1;
- }
- if ((version == 0 && !is_legal_nickname(rp_nickname)) ||
- (version == 1 && !is_legal_nickname_or_hexdigest(rp_nickname))) {
- log_warn(LD_PROTOCOL, "Bad nickname in INTRODUCE2 cell.");
- return -1;
- }
- /* Okay, now we know that a nickname is at the start of the buffer. */
- ptr = rp_nickname+nickname_field_len;
- len -= nickname_field_len;
- len -= rp_nickname - buf; /* also remove header space used by version, if
- * any */
- node = node_get_by_nickname(rp_nickname, 0);
- if (!node) {
- log_info(LD_REND, "Couldn't find router %s named in introduce2 cell.",
- escaped_safe_str_client(rp_nickname));
- /* XXXX Add a no-such-router reason? */
- reason = END_CIRC_REASON_TORPROTOCOL;
- goto err;
- }
+ log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %u.",
+ escaped(serviceid), (unsigned)circuit->base_.n_circ_id);
- extend_info = extend_info_from_node(node, 0);
- }
+ /* use intro key instead of service key. */
+ intro_key = circuit->intro_key;
- if (len != REND_COOKIE_LEN+DH_KEY_LEN) {
- log_warn(LD_PROTOCOL, "Bad length %u for INTRODUCE2 cell.", (int)len);
- reason = END_CIRC_REASON_TORPROTOCOL;
+ tor_free(err_msg);
+ stage_descr = NULL;
+
+ stage_descr = "early parsing";
+ /* Early parsing pass (get pk, ciphertext); type 2 is INTRODUCE2 */
+ parsed_req =
+ rend_service_begin_parse_intro(request, request_len, 2, &err_msg);
+ if (!parsed_req) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %u.", err_msg,
+ (unsigned)circuit->base_.n_circ_id);
+ tor_free(err_msg);
+ }
+
+ stage_descr = "early validation";
+ /* Early validation of pk/ciphertext part */
+ result = rend_service_validate_intro_early(parsed_req, &err_msg);
+ if (result < 0) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %u.", err_msg,
+ (unsigned)circuit->base_.n_circ_id);
+ tor_free(err_msg);
+ }
+
+ /* make sure service replay caches are present */
+ if (!service->accepted_intro_dh_parts) {
+ service->accepted_intro_dh_parts =
+ replaycache_new(REND_REPLAY_TIME_INTERVAL,
+ REND_REPLAY_TIME_INTERVAL);
+ }
+
+ if (!intro_point->accepted_intro_rsa_parts) {
+ intro_point->accepted_intro_rsa_parts = replaycache_new(0, 0);
+ }
+
+ /* check for replay of PK-encrypted portion. */
+ replay = replaycache_add_test_and_elapsed(
+ intro_point->accepted_intro_rsa_parts,
+ parsed_req->ciphertext, (int)parsed_req->ciphertext_len,
+ &elapsed);
+
+ if (replay) {
+ log_warn(LD_REND,
+ "Possible replay detected! We received an "
+ "INTRODUCE2 cell with same PK-encrypted part %d "
+ "seconds ago. Dropping cell.",
+ (int)elapsed);
goto err;
}
+ stage_descr = "decryption";
+ /* Now try to decrypt it */
+ result = rend_service_decrypt_intro(parsed_req, intro_key, &err_msg);
+ if (result < 0) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %u.", err_msg,
+ (unsigned)circuit->base_.n_circ_id);
+ tor_free(err_msg);
+ }
+
+ stage_descr = "late parsing";
+ /* Parse the plaintext */
+ result = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
+ if (result < 0) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %u.", err_msg,
+ (unsigned)circuit->base_.n_circ_id);
+ tor_free(err_msg);
+ }
+
+ stage_descr = "late validation";
+ /* Validate the parsed plaintext parts */
+ result = rend_service_validate_intro_late(parsed_req, &err_msg);
+ if (result < 0) {
+ goto log_error;
+ } else if (err_msg) {
+ log_info(LD_REND, "%s on circ %u.", err_msg,
+ (unsigned)circuit->base_.n_circ_id);
+ tor_free(err_msg);
+ }
+ stage_descr = NULL;
+
+ /* Increment INTRODUCE2 counter */
+ ++(intro_point->accepted_introduce2_count);
+
+ /* Find the rendezvous point */
+ rp = find_rp_for_intro(parsed_req, &need_rp_free, &err_msg);
+ if (!rp)
+ goto log_error;
+
/* Check if we'd refuse to talk to this router */
if (options->StrictNodes &&
- routerset_contains_extendinfo(options->ExcludeNodes, extend_info)) {
+ routerset_contains_extendinfo(options->ExcludeNodes, rp)) {
log_warn(LD_REND, "Client asked to rendezvous at a relay that we "
"exclude, and StrictNodes is set. Refusing service.");
reason = END_CIRC_REASON_INTERNAL; /* XXX might leak why we refused */
goto err;
}
- r_cookie = ptr;
- base16_encode(hexcookie,9,r_cookie,4);
-
- /* Determine hash of Diffie-Hellman, part 1 to detect replays. */
- digest = crypto_digest_new();
- crypto_digest_add_bytes(digest, ptr+REND_COOKIE_LEN, DH_KEY_LEN);
- crypto_digest_get_digest(digest, diffie_hellman_hash, DIGEST_LEN);
- crypto_digest_free(digest);
+ base16_encode(hexcookie, 9, (const char *)(parsed_req->rc), 4);
/* Check whether there is a past request with the same Diffie-Hellman,
* part 1. */
- access_time = digestmap_get(service->accepted_intro_dh_parts,
- diffie_hellman_hash);
- if (access_time != NULL) {
+ replay = replaycache_add_test_and_elapsed(
+ service->accepted_intro_dh_parts,
+ parsed_req->dh, DH_KEY_LEN,
+ &elapsed);
+
+ if (replay) {
/* A Tor client will send a new INTRODUCE1 cell with the same rend
* cookie and DH public key as its previous one if its intro circ
* times out while in state CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT .
@@ -1299,25 +1292,15 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
"INTRODUCE2 cell with same first part of "
"Diffie-Hellman handshake %d seconds ago. Dropping "
"cell.",
- (int) (now - *access_time));
+ (int) elapsed);
goto err;
}
- /* Add request to access history, including time and hash of Diffie-Hellman,
- * part 1, and possibly remove requests from the history that are older than
- * one hour. */
- access_time = tor_malloc(sizeof(time_t));
- *access_time = now;
- digestmap_set(service->accepted_intro_dh_parts,
- diffie_hellman_hash, access_time);
- if (service->last_cleaned_accepted_intro_dh_parts + REND_REPLAY_TIME_INTERVAL
- < now)
- clean_accepted_intro_dh_parts(service, now);
-
/* If the service performs client authorization, check included auth data. */
if (service->clients) {
- if (auth_len > 0) {
- if (rend_check_authorization(service, auth_data)) {
+ if (parsed_req->version == 3 && parsed_req->u.v3.auth_len > 0) {
+ if (rend_check_authorization(service,
+ (const char*)parsed_req->u.v3.auth_data)) {
log_info(LD_REND, "Authorization data in INTRODUCE2 cell are valid.");
} else {
log_info(LD_REND, "The authorization data that are contained in "
@@ -1341,7 +1324,8 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
- if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, ptr+REND_COOKIE_LEN,
+ if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh,
+ (char *)(parsed_req->dh),
DH_KEY_LEN, keys,
DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
log_warn(LD_BUG, "Internal error: couldn't complete DH handshake");
@@ -1360,7 +1344,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL;
if (circ_needs_uptime) flags |= CIRCLAUNCH_NEED_UPTIME;
launched = circuit_launch_by_extend_info(
- CIRCUIT_PURPOSE_S_CONNECT_REND, extend_info, flags);
+ CIRCUIT_PURPOSE_S_CONNECT_REND, rp, flags);
if (launched)
break;
@@ -1368,7 +1352,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
if (!launched) { /* give up */
log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous "
"point %s for service %s.",
- safe_str_client(extend_info_describe(extend_info)),
+ safe_str_client(extend_info_describe(rp)),
serviceid);
reason = END_CIRC_REASON_CONNECTFAILED;
goto err;
@@ -1376,7 +1360,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
log_info(LD_REND,
"Accepted intro; launching circuit to %s "
"(cookie %s) for service %s.",
- safe_str_client(extend_info_describe(extend_info)),
+ safe_str_client(extend_info_describe(rp)),
hexcookie, serviceid);
tor_assert(launched->build_state);
/* Fill in the circuit's state. */
@@ -1384,7 +1368,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
memcpy(launched->rend_data->rend_pk_digest,
circuit->rend_data->rend_pk_digest,
DIGEST_LEN);
- memcpy(launched->rend_data->rend_cookie, r_cookie, REND_COOKIE_LEN);
+ memcpy(launched->rend_data->rend_cookie, parsed_req->rc, REND_COOKIE_LEN);
strlcpy(launched->rend_data->onion_address, service->service_id,
sizeof(launched->rend_data->onion_address));
@@ -1397,24 +1381,875 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
cpath->magic = CRYPT_PATH_MAGIC;
launched->build_state->expiry_time = now + MAX_REND_TIMEOUT;
- cpath->dh_handshake_state = dh;
+ cpath->rend_dh_handshake_state = dh;
dh = NULL;
if (circuit_init_cpath_crypto(cpath,keys+DIGEST_LEN,1)<0)
goto err;
- memcpy(cpath->handshake_digest, keys, DIGEST_LEN);
- if (extend_info) extend_info_free(extend_info);
+ memcpy(cpath->rend_circ_nonce, keys, DIGEST_LEN);
- memwipe(keys, 0, sizeof(keys));
- return 0;
+ goto done;
+
+ log_error:
+ if (!err_msg) {
+ if (stage_descr) {
+ tor_asprintf(&err_msg,
+ "unknown %s error for INTRODUCE2", stage_descr);
+ } else {
+ err_msg = tor_strdup("unknown error for INTRODUCE2");
+ }
+ }
+
+ log_warn(LD_REND, "%s on circ %u", err_msg,
+ (unsigned)circuit->base_.n_circ_id);
err:
- memwipe(keys, 0, sizeof(keys));
+ status = -1;
if (dh) crypto_dh_free(dh);
- if (launched)
+ if (launched) {
circuit_mark_for_close(TO_CIRCUIT(launched), reason);
- if (extend_info) extend_info_free(extend_info);
+ }
+ tor_free(err_msg);
+
+ done:
+ memwipe(keys, 0, sizeof(keys));
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(serviceid, 0, sizeof(serviceid));
+ memwipe(hexcookie, 0, sizeof(hexcookie));
+
+ /* Free the parsed cell */
+ if (parsed_req) {
+ rend_service_free_intro(parsed_req);
+ parsed_req = NULL;
+ }
+
+ /* Free rp if we must */
+ if (need_rp_free) extend_info_free(rp);
+
+ return status;
+}
+
+/** Given a parsed and decrypted INTRODUCE2, find the rendezvous point or
+ * return NULL and an error string if we can't.
+ */
+
+static extend_info_t *
+find_rp_for_intro(const rend_intro_cell_t *intro,
+ uint8_t *need_free_out, char **err_msg_out)
+{
+ extend_info_t *rp = NULL;
+ char *err_msg = NULL;
+ const char *rp_nickname = NULL;
+ const node_t *node = NULL;
+ uint8_t need_free = 0;
+
+ if (!intro || !need_free_out) {
+ if (err_msg_out)
+ err_msg = tor_strdup("Bad parameters to find_rp_for_intro()");
+
+ goto err;
+ }
+
+ if (intro->version == 0 || intro->version == 1) {
+ if (intro->version == 1) rp_nickname = (const char *)(intro->u.v1.rp);
+ else rp_nickname = (const char *)(intro->u.v0.rp);
+
+ node = node_get_by_nickname(rp_nickname, 0);
+ if (!node) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "Couldn't find router %s named in INTRODUCE2 cell",
+ escaped_safe_str_client(rp_nickname));
+ }
+
+ goto err;
+ }
+
+ rp = extend_info_from_node(node, 0);
+ if (!rp) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "Could build extend_info_t for router %s named "
+ "in INTRODUCE2 cell",
+ escaped_safe_str_client(rp_nickname));
+ }
+
+ goto err;
+ } else {
+ need_free = 1;
+ }
+ } else if (intro->version == 2) {
+ rp = intro->u.v2.extend_info;
+ } else if (intro->version == 3) {
+ rp = intro->u.v3.extend_info;
+ } else {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "Unknown version %d in INTRODUCE2 cell",
+ (int)(intro->version));
+ }
+
+ goto err;
+ }
+
+ goto done;
+
+ err:
+ if (err_msg_out) *err_msg_out = err_msg;
+ else tor_free(err_msg);
+
+ done:
+ if (rp && need_free_out) *need_free_out = need_free;
+
+ return rp;
+}
+
+/** Remove unnecessary parts from a rend_intro_cell_t - the ciphertext if
+ * already decrypted, the plaintext too if already parsed
+ */
+
+void
+rend_service_compact_intro(rend_intro_cell_t *request)
+{
+ if (!request) return;
+
+ if ((request->plaintext && request->plaintext_len > 0) ||
+ request->parsed) {
+ tor_free(request->ciphertext);
+ request->ciphertext_len = 0;
+ }
+
+ if (request->parsed) {
+ tor_free(request->plaintext);
+ request->plaintext_len = 0;
+ }
+}
+
+/** Free a parsed INTRODUCE1 or INTRODUCE2 cell that was allocated by
+ * rend_service_parse_intro().
+ */
+void
+rend_service_free_intro(rend_intro_cell_t *request)
+{
+ if (!request) {
+ log_info(LD_BUG, "rend_service_free_intro() called with NULL request!");
+ return;
+ }
+
+ /* Free ciphertext */
+ tor_free(request->ciphertext);
+ request->ciphertext_len = 0;
+
+ /* Have plaintext? */
+ if (request->plaintext) {
+ /* Zero it out just to be safe */
+ memwipe(request->plaintext, 0, request->plaintext_len);
+ tor_free(request->plaintext);
+ request->plaintext_len = 0;
+ }
+
+ /* Have parsed plaintext? */
+ if (request->parsed) {
+ switch (request->version) {
+ case 0:
+ case 1:
+ /*
+ * Nothing more to do; these formats have no further pointers
+ * in them.
+ */
+ break;
+ case 2:
+ extend_info_free(request->u.v2.extend_info);
+ request->u.v2.extend_info = NULL;
+ break;
+ case 3:
+ if (request->u.v3.auth_data) {
+ memwipe(request->u.v3.auth_data, 0, request->u.v3.auth_len);
+ tor_free(request->u.v3.auth_data);
+ }
+
+ extend_info_free(request->u.v3.extend_info);
+ request->u.v3.extend_info = NULL;
+ break;
+ default:
+ log_info(LD_BUG,
+ "rend_service_free_intro() saw unknown protocol "
+ "version %d.",
+ request->version);
+ }
+ }
+
+ /* Zero it out to make sure sensitive stuff doesn't hang around in memory */
+ memwipe(request, 0, sizeof(*request));
+
+ tor_free(request);
+}
+
+/** Parse an INTRODUCE1 or INTRODUCE2 cell into a newly allocated
+ * rend_intro_cell_t structure. Free it with rend_service_free_intro()
+ * when finished. The type parameter should be 1 or 2 to indicate whether
+ * this is INTRODUCE1 or INTRODUCE2. This parses only the non-encrypted
+ * parts; after this, call rend_service_decrypt_intro() with a key, then
+ * rend_service_parse_intro_plaintext() to finish parsing. The optional
+ * err_msg_out parameter is set to a string suitable for log output
+ * if parsing fails. This function does some validation, but only
+ * that which depends solely on the contents of the cell and the
+ * key; it can be unit-tested. Further validation is done in
+ * rend_service_validate_intro().
+ */
+
+rend_intro_cell_t *
+rend_service_begin_parse_intro(const uint8_t *request,
+ size_t request_len,
+ uint8_t type,
+ char **err_msg_out)
+{
+ rend_intro_cell_t *rv = NULL;
+ char *err_msg = NULL;
+
+ if (!request || request_len <= 0) goto err;
+ if (!(type == 1 || type == 2)) goto err;
+
+ /* First, check that the cell is long enough to be a sensible INTRODUCE */
+
+ /* min key length plus digest length plus nickname length */
+ if (request_len <
+ (DIGEST_LEN + REND_COOKIE_LEN + (MAX_NICKNAME_LEN + 1) +
+ DH_KEY_LEN + 42)) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "got a truncated INTRODUCE%d cell",
+ (int)type);
+ }
+ goto err;
+ }
+
+ /* Allocate a new parsed cell structure */
+ rv = tor_malloc_zero(sizeof(*rv));
+
+ /* Set the type */
+ rv->type = type;
+
+ /* Copy in the ID */
+ memcpy(rv->pk, request, DIGEST_LEN);
+
+ /* Copy in the ciphertext */
+ rv->ciphertext = tor_malloc(request_len - DIGEST_LEN);
+ memcpy(rv->ciphertext, request + DIGEST_LEN, request_len - DIGEST_LEN);
+ rv->ciphertext_len = request_len - DIGEST_LEN;
+
+ goto done;
+
+ err:
+ if (rv) rend_service_free_intro(rv);
+ rv = NULL;
+ if (err_msg_out && !err_msg) {
+ tor_asprintf(&err_msg,
+ "unknown INTRODUCE%d error",
+ (int)type);
+ }
+
+ done:
+ if (err_msg_out) *err_msg_out = err_msg;
+ else tor_free(err_msg);
+
+ return rv;
+}
+
+/** Parse the version-specific parts of a v0 or v1 INTRODUCE1 or INTRODUCE2
+ * cell
+ */
+
+static ssize_t
+rend_service_parse_intro_for_v0_or_v1(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out)
+{
+ const char *rp_nickname, *endptr;
+ size_t nickname_field_len, ver_specific_len;
+
+ if (intro->version == 1) {
+ ver_specific_len = MAX_HEX_NICKNAME_LEN + 2;
+ rp_nickname = ((const char *)buf) + 1;
+ nickname_field_len = MAX_HEX_NICKNAME_LEN + 1;
+ } else if (intro->version == 0) {
+ ver_specific_len = MAX_NICKNAME_LEN + 1;
+ rp_nickname = (const char *)buf;
+ nickname_field_len = MAX_NICKNAME_LEN + 1;
+ } else {
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "rend_service_parse_intro_for_v0_or_v1() called with "
+ "bad version %d on INTRODUCE%d cell (this is a bug)",
+ intro->version,
+ (int)(intro->type));
+ goto err;
+ }
+
+ if (plaintext_len < ver_specific_len) {
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "short plaintext of encrypted part in v1 INTRODUCE%d "
+ "cell (%lu bytes, needed %lu)",
+ (int)(intro->type),
+ (unsigned long)plaintext_len,
+ (unsigned long)ver_specific_len);
+ goto err;
+ }
+
+ endptr = memchr(rp_nickname, 0, nickname_field_len);
+ if (!endptr || endptr == rp_nickname) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "couldn't find a nul-padded nickname in "
+ "INTRODUCE%d cell",
+ (int)(intro->type));
+ }
+ goto err;
+ }
+
+ if ((intro->version == 0 &&
+ !is_legal_nickname(rp_nickname)) ||
+ (intro->version == 1 &&
+ !is_legal_nickname_or_hexdigest(rp_nickname))) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "bad nickname in INTRODUCE%d cell",
+ (int)(intro->type));
+ }
+ goto err;
+ }
+
+ if (intro->version == 1) {
+ memcpy(intro->u.v1.rp, rp_nickname, endptr - rp_nickname + 1);
+ } else {
+ memcpy(intro->u.v0.rp, rp_nickname, endptr - rp_nickname + 1);
+ }
+
+ return ver_specific_len;
+
+ err:
+ return -1;
+}
+
+/** Parse the version-specific parts of a v2 INTRODUCE1 or INTRODUCE2 cell
+ */
+
+static ssize_t
+rend_service_parse_intro_for_v2(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out)
+{
+ unsigned int klen;
+ extend_info_t *extend_info = NULL;
+ ssize_t ver_specific_len;
+
+ /*
+ * We accept version 3 too so that the v3 parser can call this with
+ * and adjusted buffer for the latter part of a v3 cell, which is
+ * identical to a v2 cell.
+ */
+ if (!(intro->version == 2 ||
+ intro->version == 3)) {
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "rend_service_parse_intro_for_v2() called with "
+ "bad version %d on INTRODUCE%d cell (this is a bug)",
+ intro->version,
+ (int)(intro->type));
+ goto err;
+ }
+
+ /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */
+ if (plaintext_len < 7 + DIGEST_LEN + 2) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "truncated plaintext of encrypted parted of "
+ "version %d INTRODUCE%d cell",
+ intro->version,
+ (int)(intro->type));
+ }
+
+ goto err;
+ }
+
+ extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ tor_addr_from_ipv4n(&extend_info->addr, get_uint32(buf + 1));
+ extend_info->port = ntohs(get_uint16(buf + 5));
+ memcpy(extend_info->identity_digest, buf + 7, DIGEST_LEN);
+ extend_info->nickname[0] = '$';
+ base16_encode(extend_info->nickname + 1, sizeof(extend_info->nickname) - 1,
+ extend_info->identity_digest, DIGEST_LEN);
+ klen = ntohs(get_uint16(buf + 7 + DIGEST_LEN));
+
+ /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */
+ if (plaintext_len < 7 + DIGEST_LEN + 2 + klen) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "truncated plaintext of encrypted parted of "
+ "version %d INTRODUCE%d cell",
+ intro->version,
+ (int)(intro->type));
+ }
+
+ goto err;
+ }
+
+ extend_info->onion_key =
+ crypto_pk_asn1_decode((const char *)(buf + 7 + DIGEST_LEN + 2), klen);
+ if (!extend_info->onion_key) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "error decoding onion key in version %d "
+ "INTRODUCE%d cell",
+ intro->version,
+ (intro->type));
+ }
+
+ goto err;
+ }
+
+ ver_specific_len = 7+DIGEST_LEN+2+klen;
+
+ if (intro->version == 2) intro->u.v2.extend_info = extend_info;
+ else intro->u.v3.extend_info = extend_info;
+
+ return ver_specific_len;
+
+ err:
+ extend_info_free(extend_info);
+
+ return -1;
+}
+
+/** Parse the version-specific parts of a v3 INTRODUCE1 or INTRODUCE2 cell
+ */
+
+static ssize_t
+rend_service_parse_intro_for_v3(
+ rend_intro_cell_t *intro,
+ const uint8_t *buf,
+ size_t plaintext_len,
+ char **err_msg_out)
+{
+ ssize_t adjust, v2_ver_specific_len, ts_offset;
+
+ /* This should only be called on v3 cells */
+ if (intro->version != 3) {
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "rend_service_parse_intro_for_v3() called with "
+ "bad version %d on INTRODUCE%d cell (this is a bug)",
+ intro->version,
+ (int)(intro->type));
+ goto err;
+ }
+
+ /*
+ * Check that we have at least enough to get auth_len:
+ *
+ * 1 octet for version, 1 for auth_type, 2 for auth_len
+ */
+ if (plaintext_len < 4) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "truncated plaintext of encrypted parted of "
+ "version %d INTRODUCE%d cell",
+ intro->version,
+ (int)(intro->type));
+ }
+
+ goto err;
+ }
+
+ /*
+ * The rend_client_send_introduction() function over in rendclient.c is
+ * broken (i.e., fails to match the spec) in such a way that we can't
+ * change it without breaking the protocol. Specifically, it doesn't
+ * emit auth_len when auth-type is REND_NO_AUTH, so everything is off
+ * by two bytes after that. Calculate ts_offset and do everything from
+ * the timestamp on relative to that to handle this dain bramage.
+ */
+
+ intro->u.v3.auth_type = buf[1];
+ if (intro->u.v3.auth_type != REND_NO_AUTH) {
+ intro->u.v3.auth_len = ntohs(get_uint16(buf + 2));
+ ts_offset = 4 + intro->u.v3.auth_len;
+ } else {
+ intro->u.v3.auth_len = 0;
+ ts_offset = 2;
+ }
+
+ /* Check that auth len makes sense for this auth type */
+ if (intro->u.v3.auth_type == REND_BASIC_AUTH ||
+ intro->u.v3.auth_type == REND_STEALTH_AUTH) {
+ if (intro->u.v3.auth_len != REND_DESC_COOKIE_LEN) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "wrong auth data size %d for INTRODUCE%d cell, "
+ "should be %d",
+ (int)(intro->u.v3.auth_len),
+ (int)(intro->type),
+ REND_DESC_COOKIE_LEN);
+ }
+
+ goto err;
+ }
+ }
+
+ /* Check that we actually have everything up through the timestamp */
+ if (plaintext_len < (size_t)(ts_offset)+4) {
+ if (err_msg_out) {
+ tor_asprintf(err_msg_out,
+ "truncated plaintext of encrypted parted of "
+ "version %d INTRODUCE%d cell",
+ intro->version,
+ (int)(intro->type));
+ }
+
+ goto err;
+ }
+
+ if (intro->u.v3.auth_type != REND_NO_AUTH &&
+ intro->u.v3.auth_len > 0) {
+ /* Okay, we can go ahead and copy auth_data */
+ intro->u.v3.auth_data = tor_malloc(intro->u.v3.auth_len);
+ /*
+ * We know we had an auth_len field in this case, so 4 is
+ * always right.
+ */
+ memcpy(intro->u.v3.auth_data, buf + 4, intro->u.v3.auth_len);
+ }
+
+ /*
+ * From here on, the format is as in v2, so we call the v2 parser with
+ * adjusted buffer and length. We are 4 + ts_offset octets in, but the
+ * v2 parser expects to skip over a version byte at the start, so we
+ * adjust by 3 + ts_offset.
+ */
+ adjust = 3 + ts_offset;
+
+ v2_ver_specific_len =
+ rend_service_parse_intro_for_v2(intro,
+ buf + adjust, plaintext_len - adjust,
+ err_msg_out);
+
+ /* Success in v2 parser */
+ if (v2_ver_specific_len >= 0) return v2_ver_specific_len + adjust;
+ /* Failure in v2 parser; it will have provided an err_msg */
+ else return v2_ver_specific_len;
+
+ err:
return -1;
}
+/** Table of parser functions for version-specific parts of an INTRODUCE2
+ * cell.
+ */
+
+static ssize_t
+ (*intro_version_handlers[])(
+ rend_intro_cell_t *,
+ const uint8_t *,
+ size_t,
+ char **) =
+{ rend_service_parse_intro_for_v0_or_v1,
+ rend_service_parse_intro_for_v0_or_v1,
+ rend_service_parse_intro_for_v2,
+ rend_service_parse_intro_for_v3 };
+
+/** Decrypt the encrypted part of an INTRODUCE1 or INTRODUCE2 cell,
+ * return 0 if successful, or < 0 and write an error message to
+ * *err_msg_out if provided.
+ */
+
+int
+rend_service_decrypt_intro(
+ rend_intro_cell_t *intro,
+ crypto_pk_t *key,
+ char **err_msg_out)
+{
+ char *err_msg = NULL;
+ uint8_t key_digest[DIGEST_LEN];
+ char service_id[REND_SERVICE_ID_LEN_BASE32+1];
+ ssize_t key_len;
+ uint8_t buf[RELAY_PAYLOAD_SIZE];
+ int result, status = 0;
+
+ if (!intro || !key) {
+ if (err_msg_out) {
+ err_msg =
+ tor_strdup("rend_service_decrypt_intro() called with bad "
+ "parameters");
+ }
+
+ status = -2;
+ goto err;
+ }
+
+ /* Make sure we have ciphertext */
+ if (!(intro->ciphertext) || intro->ciphertext_len <= 0) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "rend_intro_cell_t was missing ciphertext for "
+ "INTRODUCE%d cell",
+ (int)(intro->type));
+ }
+ status = -3;
+ goto err;
+ }
+
+ /* Check that this cell actually matches this service key */
+
+ /* first DIGEST_LEN bytes of request is intro or service pk digest */
+ crypto_pk_get_digest(key, (char *)key_digest);
+ if (tor_memneq(key_digest, intro->pk, DIGEST_LEN)) {
+ if (err_msg_out) {
+ base32_encode(service_id, REND_SERVICE_ID_LEN_BASE32 + 1,
+ (char*)(intro->pk), REND_SERVICE_ID_LEN);
+ tor_asprintf(&err_msg,
+ "got an INTRODUCE%d cell for the wrong service (%s)",
+ (int)(intro->type),
+ escaped(service_id));
+ }
+
+ status = -4;
+ goto err;
+ }
+
+ /* Make sure the encrypted part is long enough to decrypt */
+
+ key_len = crypto_pk_keysize(key);
+ if (intro->ciphertext_len < key_len) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "got an INTRODUCE%d cell with a truncated PK-encrypted "
+ "part",
+ (int)(intro->type));
+ }
+
+ status = -5;
+ goto err;
+ }
+
+ /* Decrypt the encrypted part */
+
+ note_crypto_pk_op(REND_SERVER);
+ result =
+ crypto_pk_private_hybrid_decrypt(
+ key, (char *)buf, sizeof(buf),
+ (const char *)(intro->ciphertext), intro->ciphertext_len,
+ PK_PKCS1_OAEP_PADDING, 1);
+ if (result < 0) {
+ if (err_msg_out) {
+ tor_asprintf(&err_msg,
+ "couldn't decrypt INTRODUCE%d cell",
+ (int)(intro->type));
+ }
+ status = -6;
+ goto err;
+ }
+ intro->plaintext_len = result;
+ intro->plaintext = tor_malloc(intro->plaintext_len);
+ memcpy(intro->plaintext, buf, intro->plaintext_len);
+
+ goto done;
+
+ err:
+ if (err_msg_out && !err_msg) {
+ tor_asprintf(&err_msg,
+ "unknown INTRODUCE%d error decrypting encrypted part",
+ (int)(intro->type));
+ }
+ if (status >= 0) status = -1;
+
+ done:
+ if (err_msg_out) *err_msg_out = err_msg;
+ else tor_free(err_msg);
+
+ /* clean up potentially sensitive material */
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(key_digest, 0, sizeof(key_digest));
+ memwipe(service_id, 0, sizeof(service_id));
+
+ return status;
+}
+
+/** Parse the plaintext of the encrypted part of an INTRODUCE1 or
+ * INTRODUCE2 cell, return 0 if successful, or < 0 and write an error
+ * message to *err_msg_out if provided.
+ */
+
+int
+rend_service_parse_intro_plaintext(
+ rend_intro_cell_t *intro,
+ char **err_msg_out)
+{
+ char *err_msg = NULL;
+ ssize_t ver_specific_len, ver_invariant_len;
+ uint8_t version;
+ int status = 0;
+
+ if (!intro) {
+ if (err_msg_out) {
+ err_msg =
+ tor_strdup("rend_service_parse_intro_plaintext() called with NULL "
+ "rend_intro_cell_t");
+ }
+
+ status = -2;
+ goto err;
+ }
+
+ /* Check that we have plaintext */
+ if (!(intro->plaintext) || intro->plaintext_len <= 0) {
+ if (err_msg_out) {
+ err_msg = tor_strdup("rend_intro_cell_t was missing plaintext");
+ }
+ status = -3;
+ goto err;
+ }
+
+ /* In all formats except v0, the first byte is a version number */
+ version = intro->plaintext[0];
+
+ /* v0 has no version byte (stupid...), so handle it as a fallback */
+ if (version > 3) version = 0;
+
+ /* Copy the version into the parsed cell structure */
+ intro->version = version;
+
+ /* Call the version-specific parser from the table */
+ ver_specific_len =
+ intro_version_handlers[version](intro,
+ intro->plaintext, intro->plaintext_len,
+ &err_msg);
+ if (ver_specific_len < 0) {
+ status = -4;
+ goto err;
+ }
+
+ /** The rendezvous cookie and Diffie-Hellman stuff are version-invariant
+ * and at the end of the plaintext of the encrypted part of the cell.
+ */
+
+ ver_invariant_len = intro->plaintext_len - ver_specific_len;
+ if (ver_invariant_len < REND_COOKIE_LEN + DH_KEY_LEN) {
+ tor_asprintf(&err_msg,
+ "decrypted plaintext of INTRODUCE%d cell was truncated (%ld bytes)",
+ (int)(intro->type),
+ (long)(intro->plaintext_len));
+ status = -5;
+ goto err;
+ } else if (ver_invariant_len > REND_COOKIE_LEN + DH_KEY_LEN) {
+ tor_asprintf(&err_msg,
+ "decrypted plaintext of INTRODUCE%d cell was too long (%ld bytes)",
+ (int)(intro->type),
+ (long)(intro->plaintext_len));
+ status = -6;
+ } else {
+ memcpy(intro->rc,
+ intro->plaintext + ver_specific_len,
+ REND_COOKIE_LEN);
+ memcpy(intro->dh,
+ intro->plaintext + ver_specific_len + REND_COOKIE_LEN,
+ DH_KEY_LEN);
+ }
+
+ /* Flag it as being fully parsed */
+ intro->parsed = 1;
+
+ goto done;
+
+ err:
+ if (err_msg_out && !err_msg) {
+ tor_asprintf(&err_msg,
+ "unknown INTRODUCE%d error parsing encrypted part",
+ (int)(intro->type));
+ }
+ if (status >= 0) status = -1;
+
+ done:
+ if (err_msg_out) *err_msg_out = err_msg;
+ else tor_free(err_msg);
+
+ return status;
+}
+
+/** Do validity checks on a parsed intro cell before decryption; some of
+ * these are not done in rend_service_begin_parse_intro() itself because
+ * they depend on a lot of other state and would make it hard to unit test.
+ * Returns >= 0 if successful or < 0 if the intro cell is invalid, and
+ * optionally writes out an error message for logging. If an err_msg
+ * pointer is provided, it is the caller's responsibility to free any
+ * provided message.
+ */
+
+int
+rend_service_validate_intro_early(const rend_intro_cell_t *intro,
+ char **err_msg_out)
+{
+ int status = 0;
+
+ if (!intro) {
+ if (err_msg_out)
+ *err_msg_out =
+ tor_strdup("NULL intro cell passed to "
+ "rend_service_validate_intro_early()");
+
+ status = -1;
+ goto err;
+ }
+
+ /* TODO */
+
+ err:
+ return status;
+}
+
+/** Do validity checks on a parsed intro cell after decryption; some of
+ * these are not done in rend_service_parse_intro_plaintext() itself because
+ * they depend on a lot of other state and would make it hard to unit test.
+ * Returns >= 0 if successful or < 0 if the intro cell is invalid, and
+ * optionally writes out an error message for logging. If an err_msg
+ * pointer is provided, it is the caller's responsibility to free any
+ * provided message.
+ */
+
+int
+rend_service_validate_intro_late(const rend_intro_cell_t *intro,
+ char **err_msg_out)
+{
+ int status = 0;
+
+ if (!intro) {
+ if (err_msg_out)
+ *err_msg_out =
+ tor_strdup("NULL intro cell passed to "
+ "rend_service_validate_intro_late()");
+
+ status = -1;
+ goto err;
+ }
+
+ if (intro->version == 3 && intro->parsed) {
+ if (!(intro->u.v3.auth_type == REND_NO_AUTH ||
+ intro->u.v3.auth_type == REND_BASIC_AUTH ||
+ intro->u.v3.auth_type == REND_STEALTH_AUTH)) {
+ /* This is an informative message, not an error, as in the old code */
+ if (err_msg_out)
+ tor_asprintf(err_msg_out,
+ "unknown authorization type %d",
+ intro->u.v3.auth_type);
+ }
+ }
+
+ err:
+ return status;
+}
+
/** Called when we fail building a rendezvous circuit at some point other
* than the last hop: launches a new circuit to the same rendezvous point.
*/
@@ -1424,7 +2259,7 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
origin_circuit_t *newcirc;
cpath_build_state_t *newstate, *oldstate;
- tor_assert(oldcirc->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+ tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
/* Don't relaunch the same rend circ twice. */
if (oldcirc->hs_service_side_rend_circ_has_been_relaunched) {
@@ -1529,7 +2364,7 @@ rend_service_launch_establish_intro(rend_service_t *service,
sizeof(launched->rend_data->onion_address));
memcpy(launched->rend_data->rend_pk_digest, service->pk_digest, DIGEST_LEN);
launched->intro_key = crypto_pk_dup_key(intro->intro_key);
- if (launched->_base.state == CIRCUIT_STATE_OPEN)
+ if (launched->base_.state == CIRCUIT_STATE_OPEN)
rend_service_intro_has_opened(launched);
return 0;
}
@@ -1541,7 +2376,7 @@ count_established_intro_points(const char *query)
{
int num_ipos = 0;
circuit_t *circ;
- for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
if (!circ->marked_for_close &&
circ->state == CIRCUIT_STATE_OPEN &&
(circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -1570,7 +2405,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
int reason = END_CIRC_REASON_TORPROTOCOL;
crypto_pk_t *intro_key;
- tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
+ tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
#ifndef NON_ANONYMOUS_MODE_ENABLED
tor_assert(!(circuit->build_state->onehop_tunnel));
#endif
@@ -1583,8 +2418,8 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
service = rend_service_get_by_pk_digest(
circuit->rend_data->rend_pk_digest);
if (!service) {
- log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.",
- serviceid, circuit->_base.n_circ_id);
+ log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %u.",
+ serviceid, (unsigned)circuit->base_.n_circ_id);
reason = END_CIRC_REASON_NOSUCHSERVICE;
goto err;
}
@@ -1600,8 +2435,8 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
this case, we might as well close the thing. */
log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
"circuit, but we already have enough. Closing it.");
- circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_NONE);
- return;
+ reason = END_CIRC_REASON_NONE;
+ goto err;
} else {
tor_assert(circuit->build_state->is_internal);
log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
@@ -1622,13 +2457,13 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
}
circuit_has_opened(circuit);
- return;
+ goto done;
}
}
log_info(LD_REND,
- "Established circuit %d as introduction point for service %s",
- circuit->_base.n_circ_id, serviceid);
+ "Established circuit %u as introduction point for service %s",
+ (unsigned)circuit->base_.n_circ_id, serviceid);
/* Use the intro key instead of the service key in ESTABLISH_INTRO. */
intro_key = circuit->intro_key;
@@ -1643,7 +2478,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
len = r;
set_uint16(buf, htons((uint16_t)len));
len += 2;
- memcpy(auth, circuit->cpath->prev->handshake_digest, DIGEST_LEN);
+ memcpy(auth, circuit->cpath->prev->rend_circ_nonce, DIGEST_LEN);
memcpy(auth+DIGEST_LEN, "INTRODUCE", 9);
if (crypto_digest(buf+len, auth, DIGEST_LEN+9))
goto err;
@@ -1662,15 +2497,25 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
RELAY_COMMAND_ESTABLISH_INTRO,
buf, len, circuit->cpath->prev)<0) {
log_info(LD_GENERAL,
- "Couldn't send introduction request for service %s on circuit %d",
- serviceid, circuit->_base.n_circ_id);
+ "Couldn't send introduction request for service %s on circuit %u",
+ serviceid, (unsigned)circuit->base_.n_circ_id);
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
- return;
+ /* We've attempted to use this circuit */
+ pathbias_count_use_attempt(circuit);
+
+ goto done;
+
err:
circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
+ done:
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(auth, 0, sizeof(auth));
+ memwipe(serviceid, 0, sizeof(serviceid));
+
+ return;
}
/** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
@@ -1686,7 +2531,7 @@ rend_service_intro_established(origin_circuit_t *circuit,
(void) request;
(void) request_len;
- if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
+ if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
log_warn(LD_PROTOCOL,
"received INTRO_ESTABLISHED cell on non-intro circuit.");
goto err;
@@ -1695,8 +2540,8 @@ rend_service_intro_established(origin_circuit_t *circuit,
service = rend_service_get_by_pk_digest(
circuit->rend_data->rend_pk_digest);
if (!service) {
- log_warn(LD_REND, "Unknown service on introduction circuit %d.",
- circuit->_base.n_circ_id);
+ log_warn(LD_REND, "Unknown service on introduction circuit %u.",
+ (unsigned)circuit->base_.n_circ_id);
goto err;
}
service->desc_is_dirty = time(NULL);
@@ -1705,8 +2550,12 @@ rend_service_intro_established(origin_circuit_t *circuit,
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32 + 1,
circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
log_info(LD_REND,
- "Received INTRO_ESTABLISHED cell on circuit %d for service %s",
- circuit->_base.n_circ_id, serviceid);
+ "Received INTRO_ESTABLISHED cell on circuit %u for service %s",
+ (unsigned)circuit->base_.n_circ_id, serviceid);
+
+ /* Getting a valid INTRODUCE_ESTABLISHED means we've successfully
+ * used the circ */
+ pathbias_mark_use_success(circuit);
return 0;
err:
@@ -1727,13 +2576,21 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
char hexcookie[9];
int reason;
- tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+ tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
tor_assert(circuit->cpath);
tor_assert(circuit->build_state);
#ifndef NON_ANONYMOUS_MODE_ENABLED
tor_assert(!(circuit->build_state->onehop_tunnel));
#endif
tor_assert(circuit->rend_data);
+
+ /* Declare the circuit dirty to avoid reuse, and for path-bias */
+ if (!circuit->base_.timestamp_dirty)
+ circuit->base_.timestamp_dirty = time(NULL);
+
+ /* This may be redundant */
+ pathbias_count_use_attempt(circuit);
+
hop = circuit->build_state->service_pending_final_cpath_ref->cpath;
base16_encode(hexcookie,9,circuit->rend_data->rend_cookie,4);
@@ -1741,9 +2598,9 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
log_info(LD_REND,
- "Done building circuit %d to rendezvous with "
+ "Done building circuit %u to rendezvous with "
"cookie %s for service %s",
- circuit->_base.n_circ_id, hexcookie, serviceid);
+ (unsigned)circuit->base_.n_circ_id, hexcookie, serviceid);
/* Clear the 'in-progress HS circ has timed out' flag for
* consistency with what happens on the client side; this line has
@@ -1777,13 +2634,13 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
/* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
memcpy(buf, circuit->rend_data->rend_cookie, REND_COOKIE_LEN);
- if (crypto_dh_get_public(hop->dh_handshake_state,
+ if (crypto_dh_get_public(hop->rend_dh_handshake_state,
buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
log_warn(LD_GENERAL,"Couldn't get DH public key.");
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
- memcpy(buf+REND_COOKIE_LEN+DH_KEY_LEN, hop->handshake_digest,
+ memcpy(buf+REND_COOKIE_LEN+DH_KEY_LEN, hop->rend_circ_nonce,
DIGEST_LEN);
/* Send the cell */
@@ -1796,8 +2653,8 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
goto err;
}
- crypto_dh_free(hop->dh_handshake_state);
- hop->dh_handshake_state = NULL;
+ crypto_dh_free(hop->rend_dh_handshake_state);
+ hop->rend_dh_handshake_state = NULL;
/* Append the cpath entry. */
hop->state = CPATH_STATE_OPEN;
@@ -1813,9 +2670,16 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
/* Change the circuit purpose. */
circuit_change_purpose(TO_CIRCUIT(circuit), CIRCUIT_PURPOSE_S_REND_JOINED);
- return;
+ goto done;
+
err:
circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
+ done:
+ memwipe(buf, 0, sizeof(buf));
+ memwipe(serviceid, 0, sizeof(serviceid));
+ memwipe(hexcookie, 0, sizeof(hexcookie));
+
+ return;
}
/*
@@ -1876,7 +2740,7 @@ find_intro_point(origin_circuit_t *circ)
if (service == NULL) return NULL;
SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro_point,
- if (crypto_pk_cmp_keys(intro_point->intro_key, circ->intro_key) == 0) {
+ if (crypto_pk_eq_keys(intro_point->intro_key, circ->intro_key)) {
return intro_point;
});
@@ -1912,7 +2776,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
char *hs_dir_ip;
const node_t *node;
hs_dir = smartlist_get(responsible_dirs, j);
- if (smartlist_digest_isin(renddesc->successful_uploads,
+ if (smartlist_contains_digest(renddesc->successful_uploads,
hs_dir->identity_digest))
/* Don't upload descriptor if we succeeded in doing so last time. */
continue;
@@ -1929,7 +2793,8 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
directory_initiate_command_routerstatus(hs_dir,
DIR_PURPOSE_UPLOAD_RENDDESC_V2,
ROUTER_PURPOSE_GENERAL,
- 1, NULL, desc->desc_str,
+ DIRIND_ANONYMOUS, NULL,
+ desc->desc_str,
strlen(desc->desc_str), 0);
base32_encode(desc_id_base32, sizeof(desc_id_base32),
desc->desc_id, DIGEST_LEN);
@@ -1946,7 +2811,8 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
hs_dir->or_port);
tor_free(hs_dir_ip);
/* Remember successful upload to this router for next time. */
- if (!smartlist_digest_isin(successful_uploads, hs_dir->identity_digest))
+ if (!smartlist_contains_digest(successful_uploads,
+ hs_dir->identity_digest))
smartlist_add(successful_uploads, hs_dir->identity_digest);
}
smartlist_clear(responsible_dirs);
@@ -1964,7 +2830,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
if (!renddesc->successful_uploads)
renddesc->successful_uploads = smartlist_new();
SMARTLIST_FOREACH(successful_uploads, const char *, c, {
- if (!smartlist_digest_isin(renddesc->successful_uploads, c)) {
+ if (!smartlist_contains_digest(renddesc->successful_uploads, c)) {
char *hsdir_id = tor_memdup(c, DIGEST_LEN);
smartlist_add(renddesc->successful_uploads, hsdir_id);
}
@@ -2091,11 +2957,7 @@ upload_service_descriptor(rend_service_t *service)
static int
intro_point_accepted_intro_count(rend_intro_point_t *intro)
{
- if (intro->accepted_intro_rsa_parts == NULL) {
- return 0;
- } else {
- return digestmap_size(intro->accepted_intro_rsa_parts);
- }
+ return intro->accepted_introduce2_count;
}
/** Return non-zero iff <b>intro</b> should 'expire' now (i.e. we
@@ -2201,7 +3063,8 @@ rend_services_introduce(void)
if (intro->time_expiring + INTRO_POINT_EXPIRATION_GRACE_PERIOD > now) {
/* This intro point has completely expired. Remove it, and
* mark the circuit for close if it's still alive. */
- if (intro_circ != NULL) {
+ if (intro_circ != NULL &&
+ intro_circ->base_.purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) {
circuit_mark_for_close(TO_CIRCUIT(intro_circ),
END_CIRC_REASON_FINISHED);
}
@@ -2299,7 +3162,7 @@ rend_services_introduce(void)
j < (int)n_intro_points_to_open;
++j) { /* XXXX remove casts */
router_crn_flags_t flags = CRN_NEED_UPTIME|CRN_NEED_DESC;
- if (get_options()->_AllowInvalid & ALLOW_INVALID_INTRODUCTION)
+ if (get_options()->AllowInvalid_ & ALLOW_INVALID_INTRODUCTION)
flags |= CRN_ALLOW_INVALID;
node = router_choose_random_node(intro_nodes,
options->ExcludeNodes, flags);
@@ -2436,7 +3299,7 @@ rend_service_dump_stats(int severity)
for (i=0; i < smartlist_len(rend_service_list); ++i) {
service = smartlist_get(rend_service_list, i);
- log(severity, LD_GENERAL, "Service configured in \"%s\":",
+ tor_log(severity, LD_GENERAL, "Service configured in \"%s\":",
service->directory);
for (j=0; j < smartlist_len(service->intro_nodes); ++j) {
intro = smartlist_get(service->intro_nodes, j);
@@ -2444,12 +3307,12 @@ rend_service_dump_stats(int severity)
circ = find_intro_circuit(intro, service->pk_digest);
if (!circ) {
- log(severity, LD_GENERAL, " Intro point %d at %s: no circuit",
+ tor_log(severity, LD_GENERAL, " Intro point %d at %s: no circuit",
j, safe_name);
continue;
}
- log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s",
- j, safe_name, circuit_state_to_string(circ->_base.state));
+ tor_log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s",
+ j, safe_name, circuit_state_to_string(circ->base_.state));
}
}
}
@@ -2468,7 +3331,7 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
smartlist_t *matching_ports;
rend_service_port_config_t *chosen_port;
- tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
+ tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
tor_assert(circ->rend_data);
log_debug(LD_REND,"beginning to hunt for addr/port");
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
@@ -2477,26 +3340,26 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
circ->rend_data->rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
- "rendezvous circuit %d; closing.",
- serviceid, circ->_base.n_circ_id);
+ "rendezvous circuit %u; closing.",
+ serviceid, (unsigned)circ->base_.n_circ_id);
return -1;
}
matching_ports = smartlist_new();
SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p,
{
- if (conn->_base.port == p->virtual_port) {
+ if (conn->base_.port == p->virtual_port) {
smartlist_add(matching_ports, p);
}
});
chosen_port = smartlist_choose(matching_ports);
smartlist_free(matching_ports);
if (chosen_port) {
- tor_addr_copy(&conn->_base.addr, &chosen_port->real_addr);
- conn->_base.port = chosen_port->real_port;
+ tor_addr_copy(&conn->base_.addr, &chosen_port->real_addr);
+ conn->base_.port = chosen_port->real_port;
return 0;
}
log_info(LD_REND, "No virtual port mapping exists for port %d on service %s",
- conn->_base.port,serviceid);
+ conn->base_.port,serviceid);
return -1;
}
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index e5848785a..caf88a3d6 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,12 +9,68 @@
* \brief Header file for rendservice.c.
**/
-#ifndef _TOR_RENDSERVICE_H
-#define _TOR_RENDSERVICE_H
+#ifndef TOR_RENDSERVICE_H
+#define TOR_RENDSERVICE_H
+
+#include "or.h"
+
+typedef struct rend_intro_cell_s rend_intro_cell_t;
+
+#ifdef RENDSERVICE_PRIVATE
+
+/* This can be used for both INTRODUCE1 and INTRODUCE2 */
+
+struct rend_intro_cell_s {
+ /* Is this an INTRODUCE1 or INTRODUCE2? (set to 1 or 2) */
+ uint8_t type;
+ /* Public key digest */
+ uint8_t pk[DIGEST_LEN];
+ /* Optionally, store ciphertext here */
+ uint8_t *ciphertext;
+ ssize_t ciphertext_len;
+ /* Optionally, store plaintext */
+ uint8_t *plaintext;
+ ssize_t plaintext_len;
+ /* Have we parsed the plaintext? */
+ uint8_t parsed;
+ /* intro protocol version (0, 1, 2 or 3) */
+ uint8_t version;
+ /* Version-specific parts */
+ union {
+ struct {
+ /* Rendezvous point nickname */
+ uint8_t rp[20];
+ } v0;
+ struct {
+ /* Rendezvous point nickname or hex-encoded key digest */
+ uint8_t rp[42];
+ } v1;
+ struct {
+ /* The extend_info_t struct has everything v2 uses */
+ extend_info_t *extend_info;
+ } v2;
+ struct {
+ /* Auth type used */
+ uint8_t auth_type;
+ /* Length of auth data */
+ uint16_t auth_len;
+ /* Auth data */
+ uint8_t *auth_data;
+ /* Rendezvous point's IP address/port, identity digest and onion key */
+ extend_info_t *extend_info;
+ } v3;
+ } u;
+ /* Rendezvous cookie */
+ uint8_t rc[REND_COOKIE_LEN];
+ /* Diffie-Hellman data */
+ uint8_t dh[DH_KEY_LEN];
+};
+
+#endif
int num_rend_services(void);
int rend_config_services(const or_options_t *options, int validate_only);
-int rend_service_load_keys(void);
+int rend_service_load_all_keys(void);
void rend_services_introduce(void);
void rend_consider_services_upload(time_t now);
void rend_hsdir_routers_changed(void);
@@ -27,6 +83,21 @@ int rend_service_intro_established(origin_circuit_t *circuit,
void rend_service_rendezvous_has_opened(origin_circuit_t *circuit);
int rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
size_t request_len);
+void rend_service_compact_intro(rend_intro_cell_t *request);
+int rend_service_decrypt_intro(rend_intro_cell_t *request,
+ crypto_pk_t *key,
+ char **err_msg_out);
+void rend_service_free_intro(rend_intro_cell_t *request);
+rend_intro_cell_t * rend_service_begin_parse_intro(const uint8_t *request,
+ size_t request_len,
+ uint8_t type,
+ char **err_msg_out);
+int rend_service_parse_intro_plaintext(rend_intro_cell_t *intro,
+ char **err_msg_out);
+int rend_service_validate_intro_early(const rend_intro_cell_t *intro,
+ char **err_msg_out);
+int rend_service_validate_intro_late(const rend_intro_cell_t *intro,
+ char **err_msg_out);
void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
int rend_service_set_connection_addr_port(edge_connection_t *conn,
origin_circuit_t *circ);
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 3b0d9dd35..2948bf8f0 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -160,7 +160,7 @@ get_link_history(const char *from_id, const char *to_id)
/** Helper: free storage held by a single link history entry. */
static void
-_free_link_history(void *val)
+free_link_history_(void *val)
{
rephist_total_alloc -= sizeof(link_history_t);
tor_free(val);
@@ -171,7 +171,7 @@ static void
free_or_history(void *_hist)
{
or_history_t *hist = _hist;
- digestmap_free(hist->link_history_map, _free_link_history);
+ digestmap_free(hist->link_history_map, free_link_history_);
rephist_total_alloc -= sizeof(or_history_t);
rephist_total_num--;
tor_free(hist);
@@ -310,9 +310,10 @@ rep_hist_note_router_reachable(const char *id, const tor_addr_t *at_addr,
tor_assert(hist);
tor_assert((!at_addr && !at_port) || (at_addr && at_port));
- addr_changed = at_addr &&
+ addr_changed = at_addr && !tor_addr_is_null(&hist->last_reached_addr) &&
tor_addr_compare(at_addr, &hist->last_reached_addr, CMP_EXACT) != 0;
- port_changed = at_port && at_port != hist->last_reached_port;
+ port_changed = at_port && hist->last_reached_port &&
+ at_port != hist->last_reached_port;
if (!started_tracking_stability)
started_tracking_stability = time(NULL);
@@ -422,6 +423,21 @@ rep_hist_note_router_unreachable(const char *id, time_t when)
}
}
+/** Mark a router with ID <b>id</b> as non-Running, and retroactively declare
+ * that it has never been running: give it no stability and no WFU. */
+void
+rep_hist_make_router_pessimal(const char *id, time_t when)
+{
+ or_history_t *hist = get_or_history(id);
+ tor_assert(hist);
+
+ rep_hist_note_router_unreachable(id, when);
+ mark_or_down(hist, when, 1);
+
+ hist->weighted_run_length = 0;
+ hist->weighted_uptime = 0;
+}
+
/** Helper: Discount all old MTBF data, if it is time to do so. Return
* the time at which we should next discount MTBF data. */
time_t
@@ -648,7 +664,7 @@ rep_hist_dump_stats(time_t now, int severity)
rep_history_clean(now - get_options()->RephistTrackTime);
- log(severity, LD_HIST, "--------------- Dumping history information:");
+ tor_log(severity, LD_HIST, "--------------- Dumping history information:");
for (orhist_it = digestmap_iter_init(history_map);
!digestmap_iter_done(orhist_it);
@@ -673,7 +689,7 @@ rep_hist_dump_stats(time_t now, int severity)
} else {
uptime=1.0;
}
- log(severity, LD_HIST,
+ tor_log(severity, LD_HIST,
"OR %s [%s]: %ld/%ld good connections; uptime %ld/%ld sec (%.2f%%); "
"wmtbf %lu:%02lu:%02lu",
name1, hexdigest1,
@@ -707,7 +723,7 @@ rep_hist_dump_stats(time_t now, int severity)
else
len += ret;
}
- log(severity, LD_HIST, "%s", buffer);
+ tor_log(severity, LD_HIST, "%s", buffer);
}
}
}
@@ -1136,7 +1152,7 @@ rep_hist_load_mtbf_data(time_t now)
wfu_timebuf[0] = '\0';
if (format == 1) {
- n = sscanf(line, "%40s %ld %lf S=%10s %8s",
+ n = tor_sscanf(line, "%40s %ld %lf S=%10s %8s",
hexbuf, &wrl, &trw, mtbf_timebuf, mtbf_timebuf+11);
if (n != 3 && n != 5) {
log_warn(LD_HIST, "Couldn't scan line %s", escaped(line));
@@ -1153,7 +1169,7 @@ rep_hist_load_mtbf_data(time_t now)
wfu_idx = find_next_with(lines, i+1, "+WFU ");
if (mtbf_idx >= 0) {
const char *mtbfline = smartlist_get(lines, mtbf_idx);
- n = sscanf(mtbfline, "+MTBF %lu %lf S=%10s %8s",
+ n = tor_sscanf(mtbfline, "+MTBF %lu %lf S=%10s %8s",
&wrl, &trw, mtbf_timebuf, mtbf_timebuf+11);
if (n == 2 || n == 4) {
have_mtbf = 1;
@@ -1164,7 +1180,7 @@ rep_hist_load_mtbf_data(time_t now)
}
if (wfu_idx >= 0) {
const char *wfuline = smartlist_get(lines, wfu_idx);
- n = sscanf(wfuline, "+WFU %lu %lu S=%10s %8s",
+ n = tor_sscanf(wfuline, "+WFU %lu %lu S=%10s %8s",
&wt_uptime, &total_wt_time,
wfu_timebuf, wfu_timebuf+11);
if (n == 2 || n == 4) {
@@ -1531,10 +1547,10 @@ rep_hist_get_bandwidth_lines(void)
const char *desc = NULL;
size_t len;
- /* opt [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
+ /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
/* The n,n,n part above. Largest representation of a uint64_t is 20 chars
* long, plus the comma. */
-#define MAX_HIST_VALUE_LEN 21*NUM_TOTALS
+#define MAX_HIST_VALUE_LEN (21*NUM_TOTALS)
len = (67+MAX_HIST_VALUE_LEN)*4;
buf = tor_malloc_zero(len);
cp = buf;
@@ -2042,7 +2058,7 @@ note_crypto_pk_op(pk_op_t operation)
void
dump_pk_ops(int severity)
{
- log(severity, LD_HIST,
+ tor_log(severity, LD_HIST,
"PK operations: %lu directory objects signed, "
"%lu directory objects verified, "
"%lu routerdescs signed, "
@@ -2131,7 +2147,7 @@ rep_hist_exit_stats_term(void)
* but works fine for sorting an array of port numbers, which is what we use
* it for. */
static int
-_compare_int(const void *x, const void *y)
+compare_int_(const void *x, const void *y)
{
return (*(int*)x - *(int*)y);
}
@@ -2218,7 +2234,7 @@ rep_hist_format_exit_stats(time_t now)
other_streams = total_streams;
/* Sort the ports; this puts them out of sync with top_bytes, but we
* won't be using top_bytes again anyway */
- qsort(top_ports, top_elements, sizeof(int), _compare_int);
+ qsort(top_ports, top_elements, sizeof(int), compare_int_);
for (j = 0; j < top_elements; j++) {
cur_port = top_ports[j];
if (exit_bytes_written[cur_port] > 0) {
@@ -2440,7 +2456,7 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
/** Sorting helper: return -1, 1, or 0 based on comparison of two
* circ_buffer_stats_t */
static int
-_buffer_stats_compare_entries(const void **_a, const void **_b)
+buffer_stats_compare_entries_(const void **_a, const void **_b)
{
const circ_buffer_stats_t *a = *_a, *b = *_b;
if (a->processed_cells < b->processed_cells)
@@ -2505,7 +2521,7 @@ rep_hist_format_buffer_stats(time_t now)
number_of_circuits = smartlist_len(circuits_for_buffer_stats);
if (number_of_circuits > 0) {
smartlist_sort(circuits_for_buffer_stats,
- _buffer_stats_compare_entries);
+ buffer_stats_compare_entries_);
i = 0;
SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
circ_buffer_stats_t *, stat)
@@ -2590,7 +2606,7 @@ rep_hist_buffer_stats_write(time_t now)
goto done; /* Not ready to write */
/* Add open circuits to the history. */
- for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
rep_hist_buffer_stats_add_circ(circ, now);
}
@@ -2995,6 +3011,46 @@ rep_hist_conn_stats_write(time_t now)
return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
}
+/** Internal statistics to track how many requests of each type of
+ * handshake we've received, and how many we've completed. Useful for
+ * seeing trends in cpu load.
+ * @{ */
+static int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
+static int onion_handshakes_completed[MAX_ONION_HANDSHAKE_TYPE+1] = {0};
+/**@}*/
+
+/** A new onionskin (using the <b>type</b> handshake) has arrived. */
+void
+rep_hist_note_circuit_handshake_requested(uint16_t type)
+{
+ if (type <= MAX_ONION_HANDSHAKE_TYPE)
+ onion_handshakes_requested[type]++;
+}
+
+/** We've sent an onionskin (using the <b>type</b> handshake) to a
+ * cpuworker. */
+void
+rep_hist_note_circuit_handshake_completed(uint16_t type)
+{
+ if (type <= MAX_ONION_HANDSHAKE_TYPE)
+ onion_handshakes_completed[type]++;
+}
+
+/** Log our onionskin statistics since the last time we were called. */
+void
+rep_hist_log_circuit_handshake_stats(time_t now)
+{
+ (void)now;
+ log_notice(LD_HIST, "Circuit handshake stats since last time: "
+ "%d/%d TAP, %d/%d NTor.",
+ onion_handshakes_completed[ONION_HANDSHAKE_TYPE_TAP],
+ onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP],
+ onion_handshakes_completed[ONION_HANDSHAKE_TYPE_NTOR],
+ onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR]);
+ memset(onion_handshakes_completed, 0, sizeof(onion_handshakes_completed));
+ memset(onion_handshakes_requested, 0, sizeof(onion_handshakes_requested));
+}
+
/** Free all storage held by the OR/link history caches, by the
* bandwidth history arrays, by the port history, or by statistics . */
void
@@ -3003,6 +3059,8 @@ rep_hist_free_all(void)
digestmap_free(history_map, free_or_history);
tor_free(read_array);
tor_free(write_array);
+ tor_free(dir_read_array);
+ tor_free(dir_write_array);
tor_free(last_stability_doc);
tor_free(exit_bytes_read);
tor_free(exit_bytes_written);
diff --git a/src/or/rephist.h b/src/or/rephist.h
index d47724edb..de824749b 100644
--- a/src/or/rephist.h
+++ b/src/or/rephist.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for rephist.c.
**/
-#ifndef _TOR_REPHIST_H
-#define _TOR_REPHIST_H
+#ifndef TOR_REPHIST_H
+#define TOR_REPHIST_H
void rep_hist_init(void);
void rep_hist_note_connect_failed(const char* nickname, time_t when);
@@ -24,6 +24,8 @@ void rep_hist_dump_stats(time_t now, int severity);
void rep_hist_note_bytes_read(size_t num_bytes, time_t when);
void rep_hist_note_bytes_written(size_t num_bytes, time_t when);
+void rep_hist_make_router_pessimal(const char *id, time_t when);
+
void rep_hist_note_dir_bytes_read(size_t num_bytes, time_t when);
void rep_hist_note_dir_bytes_written(size_t num_bytes, time_t when);
@@ -62,8 +64,6 @@ int rep_hist_circbuilding_dormant(time_t now);
void note_crypto_pk_op(pk_op_t operation);
void dump_pk_ops(int severity);
-void rep_hist_free_all(void);
-
void rep_hist_exit_stats_init(time_t now);
void rep_hist_reset_exit_stats(time_t now);
void rep_hist_exit_stats_term(void);
@@ -96,5 +96,11 @@ char *rep_hist_format_conn_stats(time_t now);
time_t rep_hist_conn_stats_write(time_t now);
void rep_hist_conn_stats_term(void);
+void rep_hist_note_circuit_handshake_requested(uint16_t type);
+void rep_hist_note_circuit_handshake_completed(uint16_t type);
+void rep_hist_log_circuit_handshake_stats(time_t now);
+
+void rep_hist_free_all(void);
+
#endif
diff --git a/src/or/replaycache.c b/src/or/replaycache.c
new file mode 100644
index 000000000..59b98489b
--- /dev/null
+++ b/src/or/replaycache.c
@@ -0,0 +1,215 @@
+ /* Copyright (c) 2012-2013, The Tor Project, Inc. */
+ /* See LICENSE for licensing information */
+
+/*
+ * \file replaycache.c
+ *
+ * \brief Self-scrubbing replay cache for rendservice.c
+ */
+
+#define REPLAYCACHE_PRIVATE
+
+#include "or.h"
+#include "replaycache.h"
+
+/** Free the replaycache r and all of its entries.
+ */
+
+void
+replaycache_free(replaycache_t *r)
+{
+ if (!r) {
+ log_info(LD_BUG, "replaycache_free() called on NULL");
+ return;
+ }
+
+ if (r->digests_seen) digestmap_free(r->digests_seen, tor_free_);
+
+ tor_free(r);
+}
+
+/** Allocate a new, empty replay detection cache, where horizon is the time
+ * for entries to age out and interval is the time after which the cache
+ * should be scrubbed for old entries.
+ */
+
+replaycache_t *
+replaycache_new(time_t horizon, time_t interval)
+{
+ replaycache_t *r = NULL;
+
+ if (horizon < 0) {
+ log_info(LD_BUG, "replaycache_new() called with negative"
+ " horizon parameter");
+ goto err;
+ }
+
+ if (interval < 0) {
+ log_info(LD_BUG, "replaycache_new() called with negative interval"
+ " parameter");
+ interval = 0;
+ }
+
+ r = tor_malloc(sizeof(*r));
+ r->scrub_interval = interval;
+ r->scrubbed = 0;
+ r->horizon = horizon;
+ r->digests_seen = digestmap_new();
+
+ err:
+ return r;
+}
+
+/** See documentation for replaycache_add_and_test()
+ */
+
+int
+replaycache_add_and_test_internal(
+ time_t present, replaycache_t *r, const void *data, int len,
+ time_t *elapsed)
+{
+ int rv = 0;
+ char digest[DIGEST_LEN];
+ time_t *access_time;
+
+ /* sanity check */
+ if (present <= 0 || !r || !data || len <= 0) {
+ log_info(LD_BUG, "replaycache_add_and_test_internal() called with stupid"
+ " parameters; please fix this.");
+ goto done;
+ }
+
+ /* compute digest */
+ crypto_digest(digest, (const char *)data, len);
+
+ /* check map */
+ access_time = digestmap_get(r->digests_seen, digest);
+
+ /* seen before? */
+ if (access_time != NULL) {
+ /*
+ * If it's far enough in the past, no hit. If the horizon is zero, we
+ * never expire.
+ */
+ if (*access_time >= present - r->horizon || r->horizon == 0) {
+ /* replay cache hit, return 1 */
+ rv = 1;
+ /* If we want to output an elapsed time, do so */
+ if (elapsed) {
+ if (present >= *access_time) {
+ *elapsed = present - *access_time;
+ } else {
+ /* We shouldn't really be seeing hits from the future, but... */
+ *elapsed = 0;
+ }
+ }
+ }
+ /*
+ * If it's ahead of the cached time, update
+ */
+ if (*access_time < present) {
+ *access_time = present;
+ }
+ } else {
+ /* No, so no hit and update the digest map with the current time */
+ access_time = tor_malloc(sizeof(*access_time));
+ *access_time = present;
+ digestmap_set(r->digests_seen, digest, access_time);
+ }
+
+ /* now scrub the cache if it's time */
+ replaycache_scrub_if_needed_internal(present, r);
+
+ done:
+ return rv;
+}
+
+/** See documentation for replaycache_scrub_if_needed()
+ */
+
+void
+replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r)
+{
+ digestmap_iter_t *itr = NULL;
+ const char *digest;
+ void *valp;
+ time_t *access_time;
+ char scrub_this;
+
+ /* sanity check */
+ if (!r || !(r->digests_seen)) {
+ log_info(LD_BUG, "replaycache_scrub_if_needed_internal() called with"
+ " stupid parameters; please fix this.");
+ return;
+ }
+
+ /* scrub time yet? (scrubbed == 0 indicates never scrubbed before) */
+ if (present - r->scrubbed < r->scrub_interval && r->scrubbed > 0) return;
+
+ /* if we're never expiring, don't bother scrubbing */
+ if (r->horizon == 0) return;
+
+ /* okay, scrub time */
+ itr = digestmap_iter_init(r->digests_seen);
+ while (!digestmap_iter_done(itr)) {
+ scrub_this = 0;
+ digestmap_iter_get(itr, &digest, &valp);
+ access_time = (time_t *)valp;
+ if (access_time) {
+ /* aged out yet? */
+ if (*access_time < present - r->horizon) scrub_this = 1;
+ } else {
+ /* Buh? Get rid of it, anyway */
+ log_info(LD_BUG, "replaycache_scrub_if_needed_internal() saw a NULL"
+ " entry in the digestmap.");
+ scrub_this = 1;
+ }
+
+ if (scrub_this) {
+ /* Advance the iterator and remove this one */
+ itr = digestmap_iter_next_rmv(r->digests_seen, itr);
+ /* Free the value removed */
+ tor_free(access_time);
+ } else {
+ /* Just advance the iterator */
+ itr = digestmap_iter_next(r->digests_seen, itr);
+ }
+ }
+
+ /* update scrubbed timestamp */
+ if (present > r->scrubbed) r->scrubbed = present;
+}
+
+/** Test the buffer of length len point to by data against the replay cache r;
+ * the digest of the buffer will be added to the cache at the current time,
+ * and the function will return 1 if it was already seen within the cache's
+ * horizon, or 0 otherwise.
+ */
+
+int
+replaycache_add_and_test(replaycache_t *r, const void *data, int len)
+{
+ return replaycache_add_and_test_internal(time(NULL), r, data, len, NULL);
+}
+
+/** Like replaycache_add_and_test(), but if it's a hit also return the time
+ * elapsed since this digest was last seen.
+ */
+
+int
+replaycache_add_test_and_elapsed(
+ replaycache_t *r, const void *data, int len, time_t *elapsed)
+{
+ return replaycache_add_and_test_internal(time(NULL), r, data, len, elapsed);
+}
+
+/** Scrub aged entries out of r if sufficiently long has elapsed since r was
+ * last scrubbed.
+ */
+
+void
+replaycache_scrub_if_needed(replaycache_t *r)
+{
+ replaycache_scrub_if_needed_internal(time(NULL), r);
+}
+
diff --git a/src/or/replaycache.h b/src/or/replaycache.h
new file mode 100644
index 000000000..de20cab62
--- /dev/null
+++ b/src/or/replaycache.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file replaycache.h
+ * \brief Header file for replaycache.c.
+ **/
+
+#ifndef TOR_REPLAYCACHE_H
+#define TOR_REPLAYCACHE_H
+
+typedef struct replaycache_s replaycache_t;
+
+#ifdef REPLAYCACHE_PRIVATE
+
+struct replaycache_s {
+ /* Scrub interval */
+ time_t scrub_interval;
+ /* Last scrubbed */
+ time_t scrubbed;
+ /*
+ * Horizon
+ * (don't return true on digests in the cache but older than this)
+ */
+ time_t horizon;
+ /*
+ * Digest map: keys are digests, values are times the digest was last seen
+ */
+ digestmap_t *digests_seen;
+};
+
+#endif /* REPLAYCACHE_PRIVATE */
+
+/* replaycache_t free/new */
+
+void replaycache_free(replaycache_t *r);
+replaycache_t * replaycache_new(time_t horizon, time_t interval);
+
+#ifdef REPLAYCACHE_PRIVATE
+
+/*
+ * replaycache_t internal functions:
+ *
+ * These take the time to treat as the present as an argument for easy unit
+ * testing. For everything else, use the wrappers below instead.
+ */
+
+int replaycache_add_and_test_internal(
+ time_t present, replaycache_t *r, const void *data, int len,
+ time_t *elapsed);
+void replaycache_scrub_if_needed_internal(
+ time_t present, replaycache_t *r);
+
+#endif /* REPLAYCACHE_PRIVATE */
+
+/*
+ * replaycache_t methods
+ */
+
+int replaycache_add_and_test(replaycache_t *r, const void *data, int len);
+int replaycache_add_test_and_elapsed(
+ replaycache_t *r, const void *data, int len, time_t *elapsed);
+void replaycache_scrub_if_needed(replaycache_t *r);
+
+#endif
+
diff --git a/src/or/router.c b/src/or/router.c
index a3459aec7..eabd9c3f5 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTER_PRIVATE
@@ -13,6 +13,7 @@
#include "config.h"
#include "connection.h"
#include "control.h"
+#include "crypto_curve25519.h"
#include "directory.h"
#include "dirserv.h"
#include "dns.h"
@@ -27,6 +28,9 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "statefile.h"
+#include "transports.h"
+#include "routerset.h"
/**
* \file router.c
@@ -51,6 +55,13 @@ static crypto_pk_t *onionkey=NULL;
/** Previous private onionskin decryption key: used to decode CREATE cells
* generated by clients that have an older version of our descriptor. */
static crypto_pk_t *lastonionkey=NULL;
+#ifdef CURVE25519_ENABLED
+/** Current private ntor secret key: used to perform the ntor handshake. */
+static curve25519_keypair_t curve25519_onion_key;
+/** Previous private ntor secret key: used to perform the ntor handshake
+ * with clients that have an older version of our descriptor. */
+static curve25519_keypair_t last_curve25519_onion_key;
+#endif
/** Private server "identity key": used to sign directory info and TLS
* certificates. Never changes. */
static crypto_pk_t *server_identitykey=NULL;
@@ -84,7 +95,7 @@ static authority_cert_t *legacy_key_certificate = NULL;
static void
set_onion_key(crypto_pk_t *k)
{
- if (onionkey && !crypto_pk_cmp_keys(onionkey, k)) {
+ if (onionkey && crypto_pk_eq_keys(onionkey, k)) {
/* k is already our onion key; free it and return */
crypto_pk_free(k);
return;
@@ -123,6 +134,55 @@ dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last)
tor_mutex_release(key_lock);
}
+#ifdef CURVE25519_ENABLED
+/** Return the current secret onion key for the ntor handshake. Must only
+ * be called from the main thread. */
+static const curve25519_keypair_t *
+get_current_curve25519_keypair(void)
+{
+ return &curve25519_onion_key;
+}
+/** Return a map from KEYID (the key itself) to keypairs for use in the ntor
+ * handshake. Must only be called from the main thread. */
+di_digest256_map_t *
+construct_ntor_key_map(void)
+{
+ di_digest256_map_t *m = NULL;
+
+ dimap_add_entry(&m,
+ curve25519_onion_key.pubkey.public_key,
+ tor_memdup(&curve25519_onion_key,
+ sizeof(curve25519_keypair_t)));
+ if (!tor_mem_is_zero((const char*)
+ last_curve25519_onion_key.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN)) {
+ dimap_add_entry(&m,
+ last_curve25519_onion_key.pubkey.public_key,
+ tor_memdup(&last_curve25519_onion_key,
+ sizeof(curve25519_keypair_t)));
+ }
+
+ return m;
+}
+/** Helper used to deallocate a di_digest256_map_t returned by
+ * construct_ntor_key_map. */
+static void
+ntor_key_map_free_helper(void *arg)
+{
+ curve25519_keypair_t *k = arg;
+ memwipe(k, 0, sizeof(*k));
+ tor_free(k);
+}
+/** Release all storage from a keymap returned by construct_ntor_key_map. */
+void
+ntor_key_map_free(di_digest256_map_t *map)
+{
+ if (!map)
+ return;
+ dimap_free(map, ntor_key_map_free_helper);
+}
+#endif
+
/** Return the time when the onion key was last set. This is either the time
* when the process launched, or the time of the most recent key rotation since
* the process launched.
@@ -152,12 +212,11 @@ assert_identity_keys_ok(void)
if (public_server_mode(get_options())) {
/* assert that we have set the client and server keys to be equal */
tor_assert(server_identitykey);
- tor_assert(0==crypto_pk_cmp_keys(client_identitykey, server_identitykey));
+ tor_assert(crypto_pk_eq_keys(client_identitykey, server_identitykey));
} else {
/* assert that we have set the client and server keys to be unequal */
if (server_identitykey)
- tor_assert(0!=crypto_pk_cmp_keys(client_identitykey,
- server_identitykey));
+ tor_assert(!crypto_pk_eq_keys(client_identitykey, server_identitykey));
}
}
@@ -251,11 +310,18 @@ void
rotate_onion_key(void)
{
char *fname, *fname_prev;
- crypto_pk_t *prkey;
+ crypto_pk_t *prkey = NULL;
or_state_t *state = get_or_state();
+#ifdef CURVE25519_ENABLED
+ curve25519_keypair_t new_curve25519_keypair;
+#endif
time_t now;
fname = get_datadir_fname2("keys", "secret_onion_key");
fname_prev = get_datadir_fname2("keys", "secret_onion_key.old");
+ if (file_status(fname) == FN_FILE) {
+ if (replace_file(fname, fname_prev))
+ goto error;
+ }
if (!(prkey = crypto_pk_new())) {
log_err(LD_GENERAL,"Error constructing rotated onion key");
goto error;
@@ -264,19 +330,38 @@ rotate_onion_key(void)
log_err(LD_BUG,"Error generating onion key");
goto error;
}
+ if (crypto_pk_write_private_key_to_filename(prkey, fname)) {
+ log_err(LD_FS,"Couldn't write generated onion key to \"%s\".", fname);
+ goto error;
+ }
+#ifdef CURVE25519_ENABLED
+ tor_free(fname);
+ tor_free(fname_prev);
+ fname = get_datadir_fname2("keys", "secret_onion_key_ntor");
+ fname_prev = get_datadir_fname2("keys", "secret_onion_key_ntor.old");
+ if (curve25519_keypair_generate(&new_curve25519_keypair, 1) < 0)
+ goto error;
if (file_status(fname) == FN_FILE) {
if (replace_file(fname, fname_prev))
goto error;
}
- if (crypto_pk_write_private_key_to_filename(prkey, fname)) {
- log_err(LD_FS,"Couldn't write generated onion key to \"%s\".", fname);
+ if (curve25519_keypair_write_to_file(&new_curve25519_keypair, fname,
+ "onion") < 0) {
+ log_err(LD_FS,"Couldn't write curve25519 onion key to \"%s\".",fname);
goto error;
}
+#endif
log_info(LD_GENERAL, "Rotating onion key");
tor_mutex_acquire(key_lock);
crypto_pk_free(lastonionkey);
lastonionkey = onionkey;
onionkey = prkey;
+#ifdef CURVE25519_ENABLED
+ memcpy(&last_curve25519_onion_key, &curve25519_onion_key,
+ sizeof(curve25519_keypair_t));
+ memcpy(&curve25519_onion_key, &new_curve25519_keypair,
+ sizeof(curve25519_keypair_t));
+#endif
now = time(NULL);
state->LastRotatedOnionKey = onionkey_set_at = now;
tor_mutex_release(key_lock);
@@ -288,6 +373,9 @@ rotate_onion_key(void)
if (prkey)
crypto_pk_free(prkey);
done:
+#ifdef CURVE25519_ENABLED
+ memwipe(&new_curve25519_keypair, 0, sizeof(new_curve25519_keypair));
+#endif
tor_free(fname);
tor_free(fname_prev);
}
@@ -303,14 +391,14 @@ init_key_from_file(const char *fname, int generate, int severity)
crypto_pk_t *prkey = NULL;
if (!(prkey = crypto_pk_new())) {
- log(severity, LD_GENERAL,"Error constructing key");
+ tor_log(severity, LD_GENERAL,"Error constructing key");
goto error;
}
switch (file_status(fname)) {
case FN_DIR:
case FN_ERROR:
- log(severity, LD_FS,"Can't read key from \"%s\"", fname);
+ tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname);
goto error;
case FN_NOENT:
if (generate) {
@@ -318,8 +406,8 @@ init_key_from_file(const char *fname, int generate, int severity)
if (try_locking(get_options(), 0)<0) {
/* Make sure that --list-fingerprint only creates new keys
* if there is no possibility for a deadlock. */
- log(severity, LD_FS, "Another Tor process has locked \"%s\". Not "
- "writing any new keys.", fname);
+ tor_log(severity, LD_FS, "Another Tor process has locked \"%s\". "
+ "Not writing any new keys.", fname);
/*XXXX The 'other process' might make a key in a second or two;
* maybe we should wait for it. */
goto error;
@@ -328,16 +416,16 @@ init_key_from_file(const char *fname, int generate, int severity)
log_info(LD_GENERAL, "No key found in \"%s\"; generating fresh key.",
fname);
if (crypto_pk_generate_key(prkey)) {
- log(severity, LD_GENERAL,"Error generating onion key");
+ tor_log(severity, LD_GENERAL,"Error generating onion key");
goto error;
}
if (crypto_pk_check_key(prkey) <= 0) {
- log(severity, LD_GENERAL,"Generated key seems invalid");
+ tor_log(severity, LD_GENERAL,"Generated key seems invalid");
goto error;
}
log_info(LD_GENERAL, "Generated key seems valid");
if (crypto_pk_write_private_key_to_filename(prkey, fname)) {
- log(severity, LD_FS,
+ tor_log(severity, LD_FS,
"Couldn't write generated key to \"%s\".", fname);
goto error;
}
@@ -347,7 +435,7 @@ init_key_from_file(const char *fname, int generate, int severity)
return prkey;
case FN_FILE:
if (crypto_pk_read_private_key_from_filename(prkey, fname)) {
- log(severity, LD_GENERAL,"Error loading private key.");
+ tor_log(severity, LD_GENERAL,"Error loading private key.");
goto error;
}
return prkey;
@@ -361,6 +449,77 @@ init_key_from_file(const char *fname, int generate, int severity)
return NULL;
}
+#ifdef CURVE25519_ENABLED
+/** Load a curve25519 keypair from the file <b>fname</b>, writing it into
+ * <b>keys_out</b>. If the file isn't found and <b>generate</b> is true,
+ * create a new keypair and write it into the file. If there are errors, log
+ * them at level <b>severity</b>. Generate files using <b>tag</b> in their
+ * ASCII wrapper. */
+static int
+init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out,
+ const char *fname,
+ int generate,
+ int severity,
+ const char *tag)
+{
+ switch (file_status(fname)) {
+ case FN_DIR:
+ case FN_ERROR:
+ tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname);
+ goto error;
+ case FN_NOENT:
+ if (generate) {
+ if (!have_lockfile()) {
+ if (try_locking(get_options(), 0)<0) {
+ /* Make sure that --list-fingerprint only creates new keys
+ * if there is no possibility for a deadlock. */
+ tor_log(severity, LD_FS, "Another Tor process has locked \"%s\". "
+ "Not writing any new keys.", fname);
+ /*XXXX The 'other process' might make a key in a second or two;
+ * maybe we should wait for it. */
+ goto error;
+ }
+ }
+ log_info(LD_GENERAL, "No key found in \"%s\"; generating fresh key.",
+ fname);
+ if (curve25519_keypair_generate(keys_out, 1) < 0)
+ goto error;
+ if (curve25519_keypair_write_to_file(keys_out, fname, tag)<0) {
+ tor_log(severity, LD_FS,
+ "Couldn't write generated key to \"%s\".", fname);
+ memset(keys_out, 0, sizeof(*keys_out));
+ goto error;
+ }
+ } else {
+ log_info(LD_GENERAL, "No key found in \"%s\"", fname);
+ }
+ return 0;
+ case FN_FILE:
+ {
+ char *tag_in=NULL;
+ if (curve25519_keypair_read_from_file(keys_out, &tag_in, fname) < 0) {
+ tor_log(severity, LD_GENERAL,"Error loading private key.");
+ tor_free(tag_in);
+ goto error;
+ }
+ if (!tag_in || strcmp(tag_in, tag)) {
+ tor_log(severity, LD_GENERAL,"Unexpected tag %s on private key.",
+ escaped(tag_in));
+ tor_free(tag_in);
+ goto error;
+ }
+ tor_free(tag_in);
+ return 0;
+ }
+ default:
+ tor_assert(0);
+ }
+
+ error:
+ return -1;
+}
+#endif
+
/** Try to load the vote-signing private key and certificate for being a v3
* directory authority, and make sure they match. If <b>legacy</b>, load a
* legacy key/cert set for emergency key migration; otherwise load the regular
@@ -397,7 +556,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out,
log_warn(LD_DIR, "Unable to parse certificate in %s", fname);
goto done;
}
- if (crypto_pk_cmp_keys(signing_key, parsed->signing_key) != 0) {
+ if (!crypto_pk_eq_keys(signing_key, parsed->signing_key)) {
log_warn(LD_DIR, "Stored signing key does not match signing key in "
"certificate");
goto done;
@@ -472,14 +631,14 @@ v3_authority_check_key_expiry(void)
return;
if (time_left <= 0) {
- log(badness, LD_DIR, "Your v3 authority certificate has expired."
- " Generate a new one NOW.");
+ tor_log(badness, LD_DIR, "Your v3 authority certificate has expired."
+ " Generate a new one NOW.");
} else if (time_left <= 24*60*60) {
- log(badness, LD_DIR, "Your v3 authority certificate expires in %d hours;"
- " Generate a new one NOW.", time_left/(60*60));
+ tor_log(badness, LD_DIR, "Your v3 authority certificate expires in %d "
+ "hours; Generate a new one NOW.", time_left/(60*60));
} else {
- log(badness, LD_DIR, "Your v3 authority certificate expires in %d days;"
- " Generate a new one soon.", time_left/(24*60*60));
+ tor_log(badness, LD_DIR, "Your v3 authority certificate expires in %d "
+ "days; Generate a new one soon.", time_left/(24*60*60));
}
last_warned = now;
}
@@ -489,11 +648,39 @@ v3_authority_check_key_expiry(void)
int
router_initialize_tls_context(void)
{
- return tor_tls_context_init(public_server_mode(get_options()),
+ unsigned int flags = 0;
+ const or_options_t *options = get_options();
+ int lifetime = options->SSLKeyLifetime;
+ if (public_server_mode(options))
+ flags |= TOR_TLS_CTX_IS_PUBLIC_SERVER;
+ if (options->TLSECGroup) {
+ if (!strcasecmp(options->TLSECGroup, "P256"))
+ flags |= TOR_TLS_CTX_USE_ECDHE_P256;
+ else if (!strcasecmp(options->TLSECGroup, "P224"))
+ flags |= TOR_TLS_CTX_USE_ECDHE_P224;
+ }
+ if (!lifetime) { /* we should guess a good ssl cert lifetime */
+
+ /* choose between 5 and 365 days, and round to the day */
+ lifetime = 5*24*3600 + crypto_rand_int(361*24*3600);
+ lifetime -= lifetime % (24*3600);
+
+ if (crypto_rand_int(2)) {
+ /* Half the time we expire at midnight, and half the time we expire
+ * one second before midnight. (Some CAs wobble their expiry times a
+ * bit in practice, perhaps to reduce collision attacks; see ticket
+ * 8443 for details about observed certs in the wild.) */
+ lifetime--;
+ }
+ }
+
+ /* It's ok to pass lifetime in as an unsigned int, since
+ * config_parse_interval() checked it. */
+ return tor_tls_context_init(flags,
get_tlsclient_identity_key(),
- server_mode(get_options()) ?
+ server_mode(options) ?
get_server_identity_key() : NULL,
- MAX_SSL_KEY_LIFETIME_ADVERTISED);
+ (unsigned int)lifetime);
}
/** Initialize all OR private keys, and the TLS context, as necessary.
@@ -515,7 +702,7 @@ init_keys(void)
const or_options_t *options = get_options();
dirinfo_type_t type;
time_t now = time(NULL);
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
int v3_digest_set = 0;
authority_cert_t *cert = NULL;
@@ -628,12 +815,35 @@ init_keys(void)
keydir = get_datadir_fname2("keys", "secret_onion_key.old");
if (!lastonionkey && file_status(keydir) == FN_FILE) {
- prkey = init_key_from_file(keydir, 1, LOG_ERR);
+ prkey = init_key_from_file(keydir, 1, LOG_ERR); /* XXXX Why 1? */
if (prkey)
lastonionkey = prkey;
}
tor_free(keydir);
+#ifdef CURVE25519_ENABLED
+ {
+ /* 2b. Load curve25519 onion keys. */
+ int r;
+ keydir = get_datadir_fname2("keys", "secret_onion_key_ntor");
+ r = init_curve25519_keypair_from_file(&curve25519_onion_key,
+ keydir, 1, LOG_ERR, "onion");
+ tor_free(keydir);
+ if (r<0)
+ return -1;
+
+ keydir = get_datadir_fname2("keys", "secret_onion_key_ntor.old");
+ if (tor_mem_is_zero((const char *)
+ last_curve25519_onion_key.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN) &&
+ file_status(keydir) == FN_FILE) {
+ init_curve25519_keypair_from_file(&last_curve25519_onion_key,
+ keydir, 0, LOG_ERR, "onion");
+ }
+ tor_free(keydir);
+ }
+#endif
+
/* 3. Initialize link key and TLS context. */
if (router_initialize_tls_context() < 0) {
log_err(LD_GENERAL,"Error initializing TLS context");
@@ -671,7 +881,7 @@ init_keys(void)
* we don't really need new keys yet so the descriptor doesn't
* change and the old one is still fresh. */
log_info(LD_GENERAL, "Couldn't add own descriptor to directory "
- "after key init: %s. This is usually not a problem.",
+ "after key init: %s This is usually not a problem.",
m?m:"<unknown error>");
}
}
@@ -709,7 +919,7 @@ init_keys(void)
tor_free(cp);
tor_free(keydir);
- log(LOG_NOTICE, LD_GENERAL,
+ log_notice(LD_GENERAL,
"Your Tor server's identity key fingerprint is '%s %s'",
options->Nickname, fingerprint);
if (!authdir_mode(options))
@@ -730,35 +940,37 @@ init_keys(void)
ds = router_get_trusteddirserver_by_digest(digest);
if (!ds) {
- ds = add_trusted_dir_server(options->Nickname, NULL,
+ ds = trusted_dir_server_new(options->Nickname, NULL,
router_get_advertised_dir_port(options, 0),
router_get_advertised_or_port(options),
digest,
v3_digest,
- type);
+ type, 0.0);
if (!ds) {
log_err(LD_GENERAL,"We want to be a directory authority, but we "
"couldn't add ourselves to the authority list. Failing.");
return -1;
}
+ dir_server_add(ds);
}
if (ds->type != type) {
log_warn(LD_DIR, "Configured authority type does not match authority "
- "type in DirServer list. Adjusting. (%d v %d)",
+ "type in DirAuthority list. Adjusting. (%d v %d)",
type, ds->type);
ds->type = type;
}
if (v3_digest_set && (ds->type & V3_DIRINFO) &&
tor_memneq(v3_digest, ds->v3_identity_digest, DIGEST_LEN)) {
log_warn(LD_DIR, "V3 identity key does not match identity declared in "
- "DirServer line. Adjusting.");
+ "DirAuthority line. Adjusting.");
memcpy(ds->v3_identity_digest, v3_digest, DIGEST_LEN);
}
if (cert) { /* add my own cert to the list of known certs */
log_info(LD_DIR, "adding my own v3 cert");
if (trusted_dirs_load_certs_from_string(
- cert->cache_info.signed_descriptor_body, 0, 0)<0) {
+ cert->cache_info.signed_descriptor_body,
+ TRUSTED_DIRS_CERTS_SRC_SELF, 0)<0) {
log_warn(LD_DIR, "Unable to parse my own v3 cert! Failing.");
return -1;
}
@@ -868,10 +1080,10 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port)
if (advertising != new_choice) {
if (new_choice == 1) {
- log(LOG_NOTICE, LD_DIR, "Advertising DirPort as %d", dir_port);
+ log_notice(LD_DIR, "Advertising DirPort as %d", dir_port);
} else {
tor_assert(reason);
- log(LOG_NOTICE, LD_DIR, "Not advertising DirPort (Reason: %s)", reason);
+ log_notice(LD_DIR, "Not advertising DirPort (Reason: %s)", reason);
}
advertising = new_choice;
}
@@ -879,6 +1091,22 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port)
return advertising ? dir_port : 0;
}
+/** Allocate and return a new extend_info_t that can be used to build
+ * a circuit to or through the router <b>r</b>. Use the primary
+ * address of the router unless <b>for_direct_connect</b> is true, in
+ * which case the preferred address is used instead. */
+static extend_info_t *
+extend_info_from_router(const routerinfo_t *r)
+{
+ tor_addr_port_t ap;
+ tor_assert(r);
+
+ router_get_prim_orport(r, &ap);
+ return extend_info_new(r->nickname, r->cache_info.identity_digest,
+ r->onion_pkey, r->onion_curve25519_pkey,
+ &ap.addr, ap.port);
+}
+
/** Some time has passed, or we just got new directory information.
* See if we currently believe our ORPort or DirPort to be
* unreachable. If so, launch a new test for it.
@@ -907,25 +1135,21 @@ consider_testing_reachability(int test_or, int test_dir)
if (test_or || test_dir) {
#define SELF_EXCLUDED_WARN_INTERVAL 3600
static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL);
- char *msg;
- if ((msg = rate_limit_log(&warning_limit, approx_time()))) {
- log_warn(LD_CIRC, "Can't peform self-tests for this relay: we have "
+ log_fn_ratelim(&warning_limit, LOG_WARN, LD_CIRC,
+ "Can't peform self-tests for this relay: we have "
"listed ourself in ExcludeNodes, and StrictNodes is set. "
"We cannot learn whether we are usable, and will not "
- "be able to advertise ourself.%s", msg);
- tor_free(msg);
- }
+ "be able to advertise ourself.");
}
return;
}
if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
- extend_info_t *ei;
+ extend_info_t *ei = extend_info_from_router(me);
+ /* XXX IPv6 self testing */
log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
!orport_reachable ? "reachability" : "bandwidth",
me->address, me->or_port);
- /* XXX IPv6 self testing IPv6 orports will need pref_addr */
- ei = extend_info_from_router(me, 0);
circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
extend_info_free(ei);
@@ -939,11 +1163,10 @@ consider_testing_reachability(int test_or, int test_dir)
/* ask myself, via tor, for my server descriptor. */
directory_initiate_command(me->address, &addr,
me->or_port, me->dir_port,
- 0, /* does not matter */
- 0, me->cache_info.identity_digest,
+ me->cache_info.identity_digest,
DIR_PURPOSE_FETCH_SERVERDESC,
ROUTER_PURPOSE_GENERAL,
- 1, "authority.z", NULL, 0, 0);
+ DIRIND_ANON_DIRPORT, "authority.z", NULL, 0, 0);
}
}
@@ -955,7 +1178,7 @@ router_orport_found_reachable(void)
if (!can_reach_or_port && me) {
log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
"the outside. Excellent.%s",
- get_options()->_PublishServerDescriptor != NO_DIRINFO ?
+ get_options()->PublishServerDescriptor_ != NO_DIRINFO ?
" Publishing server descriptor." : "");
can_reach_or_port = 1;
mark_my_descriptor_dirty("ORPort found reachable");
@@ -987,7 +1210,8 @@ router_dirport_found_reachable(void)
void
router_perform_bandwidth_test(int num_circs, time_t now)
{
- int num_cells = (int)(get_options()->BandwidthRate * 10 / CELL_NETWORK_SIZE);
+ int num_cells = (int)(get_options()->BandwidthRate * 10 /
+ CELL_MAX_NETWORK_SIZE);
int max_cells = num_cells < CIRCWINDOW_START ?
num_cells : CIRCWINDOW_START;
int cells_per_circuit = max_cells / num_circs;
@@ -998,9 +1222,9 @@ router_perform_bandwidth_test(int num_circs, time_t now)
CIRCUIT_PURPOSE_TESTING))) {
/* dump cells_per_circuit drop cells onto this circ */
int i = cells_per_circuit;
- if (circ->_base.state != CIRCUIT_STATE_OPEN)
+ if (circ->base_.state != CIRCUIT_STATE_OPEN)
continue;
- circ->_base.timestamp_dirty = now;
+ circ->base_.timestamp_dirty = now;
while (i-- > 0) {
if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
RELAY_COMMAND_DROP,
@@ -1194,7 +1418,7 @@ decide_if_publishable_server(void)
if (options->ClientOnly)
return 0;
- if (options->_PublishServerDescriptor == NO_DIRINFO)
+ if (options->PublishServerDescriptor_ == NO_DIRINFO)
return 0;
if (!server_mode(options))
return 0;
@@ -1236,13 +1460,18 @@ consider_publishable_server(int force)
/** XXX not a very good interface. it's not reliable when there are
multiple listeners. */
uint16_t
-router_get_active_listener_port_by_type(int listener_type)
+router_get_active_listener_port_by_type_af(int listener_type,
+ sa_family_t family)
{
/* Iterate all connections, find one of the right kind and return
the port. Not very sophisticated or fast, but effective. */
- const connection_t *c = connection_get_by_type(listener_type);
- if (c)
- return c->port;
+ smartlist_t *conns = get_connection_array();
+ SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
+ if (conn->type == listener_type && !conn->marked_for_close &&
+ conn->socket_family == family) {
+ return conn->port;
+ }
+ } SMARTLIST_FOREACH_END(conn);
return 0;
}
@@ -1254,13 +1483,24 @@ router_get_active_listener_port_by_type(int listener_type)
uint16_t
router_get_advertised_or_port(const or_options_t *options)
{
- int port = get_primary_or_port();
+ return router_get_advertised_or_port_by_af(options, AF_INET);
+}
+
+/** As router_get_advertised_or_port(), but allows an address family argument.
+ */
+uint16_t
+router_get_advertised_or_port_by_af(const or_options_t *options,
+ sa_family_t family)
+{
+ int port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ family);
(void)options;
/* If the port is in 'auto' mode, we have to use
router_get_listener_port_by_type(). */
if (port == CFG_AUTO_PORT)
- return router_get_active_listener_port_by_type(CONN_TYPE_OR_LISTENER);
+ return router_get_active_listener_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ family);
return port;
}
@@ -1280,7 +1520,8 @@ router_get_advertised_dir_port(const or_options_t *options, uint16_t dirport)
return dirport;
if (dirport_configured == CFG_AUTO_PORT)
- return router_get_active_listener_port_by_type(CONN_TYPE_DIR_LISTENER);
+ return router_get_active_listener_port_by_type_af(CONN_TYPE_DIR_LISTENER,
+ AF_INET);
return dirport_configured;
}
@@ -1315,7 +1556,7 @@ router_upload_dir_desc_to_dirservers(int force)
extrainfo_t *ei;
char *msg;
size_t desc_len, extra_len = 0, total_len;
- dirinfo_type_t auth = get_options()->_PublishServerDescriptor;
+ dirinfo_type_t auth = get_options()->PublishServerDescriptor_;
ri = router_get_my_routerinfo();
if (!ri) {
@@ -1355,22 +1596,34 @@ router_upload_dir_desc_to_dirservers(int force)
* conn. Return 0 if we accept; non-0 if we reject.
*/
int
-router_compare_to_my_exit_policy(edge_connection_t *conn)
+router_compare_to_my_exit_policy(const tor_addr_t *addr, uint16_t port)
{
if (!router_get_my_routerinfo()) /* make sure desc_routerinfo exists */
return -1;
/* make sure it's resolved to something. this way we can't get a
'maybe' below. */
- if (tor_addr_is_null(&conn->_base.addr))
+ if (tor_addr_is_null(addr))
return -1;
- /* XXXX IPv6 */
- if (tor_addr_family(&conn->_base.addr) != AF_INET)
+ /* look at desc_routerinfo->exit_policy for both the v4 and the v6
+ * policies. The exit_policy field in desc_routerinfo is a bit unusual,
+ * in that it contains IPv6 and IPv6 entries. We don't want to look
+ * at desc_routerinfio->ipv6_exit_policy, since that's a port summary. */
+ if ((tor_addr_family(addr) == AF_INET ||
+ tor_addr_family(addr) == AF_INET6)) {
+ return compare_tor_addr_to_addr_policy(addr, port,
+ desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED;
+#if 0
+ } else if (tor_addr_family(addr) == AF_INET6) {
+ return get_options()->IPv6Exit &&
+ desc_routerinfo->ipv6_exit_policy &&
+ compare_tor_addr_to_short_policy(addr, port,
+ desc_routerinfo->ipv6_exit_policy) != ADDR_POLICY_ACCEPTED;
+#endif
+ } else {
return -1;
-
- return compare_tor_addr_to_addr_policy(&conn->_base.addr, conn->_base.port,
- desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED;
+ }
}
/** Return true iff my exit policy is reject *:*. Return -1 if we don't
@@ -1393,6 +1646,13 @@ router_digest_is_me(const char *digest)
tor_memeq(server_identitykey_digest, digest, DIGEST_LEN));
}
+/** Return my identity digest. */
+const uint8_t *
+router_get_my_id_digest(void)
+{
+ return (const uint8_t *)server_identitykey_digest;
+}
+
/** Return true iff I'm a server and <b>digest</b> is equal to
* my identity digest. */
int
@@ -1488,7 +1748,9 @@ static int router_guess_address_from_dir_headers(uint32_t *guess);
int
router_pick_published_address(const or_options_t *options, uint32_t *addr)
{
- if (resolve_my_address(LOG_INFO, options, addr, NULL) < 0) {
+ *addr = get_last_resolved_addr();
+ if (!*addr &&
+ resolve_my_address(LOG_INFO, options, addr, NULL, NULL) < 0) {
log_info(LD_CONFIG, "Could not determine our address locally. "
"Checking if directory headers provide any hints.");
if (router_guess_address_from_dir_headers(addr) < 0) {
@@ -1539,13 +1801,19 @@ router_rebuild_descriptor(int force)
ri->cache_info.published_on = time(NULL);
ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from
* main thread */
- if (options->BridgeRelay) {
- /* For now, only bridges advertise an ipv6 or-address. And only one. */
+#ifdef CURVE25519_ENABLED
+ ri->onion_curve25519_pkey =
+ tor_memdup(&get_current_curve25519_keypair()->pubkey,
+ sizeof(curve25519_public_key_t));
+#endif
+
+ /* For now, at most one IPv6 or-address is being advertised. */
+ {
const port_cfg_t *ipv6_orport = NULL;
SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
if (p->type == CONN_TYPE_OR_LISTENER &&
! p->no_advertise &&
- ! p->ipv4_only &&
+ ! p->bind_ipv4_only &&
tor_addr_family(&p->addr) == AF_INET6) {
if (! tor_addr_is_internal(&p->addr, 0)) {
ipv6_orport = p;
@@ -1565,6 +1833,7 @@ router_rebuild_descriptor(int force)
ri->ipv6_orport = ipv6_orport->port;
}
}
+
ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
if (crypto_pk_get_digest(ri->identity_pkey,
ri->cache_info.identity_digest)<0) {
@@ -1587,11 +1856,20 @@ router_rebuild_descriptor(int force)
policies_exit_policy_append_reject_star(&ri->exit_policy);
} else {
policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy,
+ options->IPv6Exit,
options->ExitPolicyRejectPrivate,
ri->address, !options->BridgeRelay);
}
ri->policy_is_reject_star =
- policy_is_reject_star(ri->exit_policy);
+ policy_is_reject_star(ri->exit_policy, AF_INET) &&
+ policy_is_reject_star(ri->exit_policy, AF_INET6);
+
+ if (options->IPv6Exit) {
+ char *p_tmp = policy_summarize(ri->exit_policy, AF_INET6);
+ if (p_tmp)
+ ri->ipv6_exit_policy = parse_short_policy(p_tmp);
+ tor_free(p_tmp);
+ }
#if 0
/* XXXX NM NM I belive this is safe to remove */
@@ -1615,7 +1893,7 @@ router_rebuild_descriptor(int force)
member = node_get_by_nickname(name, 1);
if (!member) {
int is_legal = is_legal_nickname_or_hexdigest(name);
- if (!smartlist_string_isin(warned_nonexistent_family, name) &&
+ if (!smartlist_contains_string(warned_nonexistent_family, name) &&
!is_legal_hexdigest(name)) {
if (is_legal)
log_warn(LD_CONFIG,
@@ -1641,7 +1919,7 @@ router_rebuild_descriptor(int force)
base16_encode(fp+1,HEX_DIGEST_LEN+1,
member->identity, DIGEST_LEN);
smartlist_add(ri->declared_family, fp);
- if (smartlist_string_isin(warned_nonexistent_family, name))
+ if (smartlist_contains_string(warned_nonexistent_family, name))
smartlist_string_remove(warned_nonexistent_family, name);
}
skip:
@@ -1684,9 +1962,8 @@ router_rebuild_descriptor(int force)
/* ri was allocated with tor_malloc_zero, so there is no need to
* zero ri->cache_info.extra_info_digest here. */
}
- ri->cache_info.signed_descriptor_body = tor_malloc(8192);
- if (router_dump_router_to_string(ri->cache_info.signed_descriptor_body, 8192,
- ri, get_server_identity_key()) < 0) {
+ if (! (ri->cache_info.signed_descriptor_body = router_dump_router_to_string(
+ ri, get_server_identity_key()))) {
log_warn(LD_BUG, "Couldn't generate router descriptor.");
routerinfo_free(ri);
extrainfo_free(ei);
@@ -1783,7 +2060,7 @@ void
mark_my_descriptor_dirty(const char *reason)
{
const or_options_t *options = get_options();
- if (server_mode(options) && options->_PublishServerDescriptor)
+ if (server_mode(options) && options->PublishServerDescriptor_)
log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason);
desc_clean_since = 0;
if (!desc_dirty_reason)
@@ -1853,6 +2130,9 @@ check_descriptor_ipaddress_changed(time_t now)
{
uint32_t prev, cur;
const or_options_t *options = get_options();
+ const char *method = NULL;
+ char *hostname = NULL;
+
(void) now;
if (!desc_routerinfo)
@@ -1860,18 +2140,29 @@ check_descriptor_ipaddress_changed(time_t now)
/* XXXX ipv6 */
prev = desc_routerinfo->addr;
- if (resolve_my_address(LOG_INFO, options, &cur, NULL) < 0) {
+ if (resolve_my_address(LOG_INFO, options, &cur, &method, &hostname) < 0) {
log_info(LD_CONFIG,"options->Address didn't resolve into an IP.");
return;
}
if (prev != cur) {
+ char *source;
tor_addr_t tmp_prev, tmp_cur;
+
tor_addr_from_ipv4h(&tmp_prev, prev);
tor_addr_from_ipv4h(&tmp_cur, cur);
- log_addr_has_changed(LOG_NOTICE, &tmp_prev, &tmp_cur, "resolve");
+
+ tor_asprintf(&source, "METHOD=%s%s%s", method,
+ hostname ? " HOSTNAME=" : "",
+ hostname ? hostname : "");
+
+ log_addr_has_changed(LOG_NOTICE, &tmp_prev, &tmp_cur, source);
+ tor_free(source);
+
ip_address_changed(0);
}
+
+ tor_free(hostname);
}
/** The most recently guessed value of our IP address, based on directory
@@ -1905,7 +2196,9 @@ router_new_address_suggestion(const char *suggestion,
}
/* XXXX ipv6 */
- if (resolve_my_address(LOG_INFO, options, &cur, NULL) >= 0) {
+ cur = get_last_resolved_addr();
+ if (cur ||
+ resolve_my_address(LOG_INFO, options, &cur, NULL, NULL) >= 0) {
/* We're all set -- we already know our address. Great. */
tor_addr_from_ipv4h(&last_guessed_ip, cur); /* store it in case we
need it later */
@@ -1915,7 +2208,7 @@ router_new_address_suggestion(const char *suggestion,
/* Don't believe anybody who says our IP is, say, 127.0.0.1. */
return;
}
- if (tor_addr_eq(&d_conn->_base.addr, &addr)) {
+ if (tor_addr_eq(&d_conn->base_.addr, &addr)) {
/* Don't believe anybody who says our IP is their IP. */
log_debug(LD_DIR, "A directory server told us our IP address is %s, "
"but he's just reporting his own IP address. Ignoring.",
@@ -1931,7 +2224,7 @@ router_new_address_suggestion(const char *suggestion,
"EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV",
suggestion);
log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr,
- d_conn->_base.address);
+ d_conn->base_.address);
ip_address_changed(0);
tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor()
will fetch it */
@@ -1970,55 +2263,54 @@ get_platform_str(char *platform, size_t len)
#define DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
/** OR only: Given a routerinfo for this router, and an identity key to sign
- * with, encode the routerinfo as a signed server descriptor and write the
- * result into <b>s</b>, using at most <b>maxlen</b> bytes. Return -1 on
- * failure, and the number of bytes used on success.
+ * with, encode the routerinfo as a signed server descriptor and return a new
+ * string encoding the result, or NULL on failure.
*/
-int
-router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
+char *
+router_dump_router_to_string(routerinfo_t *router,
crypto_pk_t *ident_key)
{
- char *onion_pkey; /* Onion key, PEM-encoded. */
- char *identity_pkey; /* Identity key, PEM-encoded. */
+ /* XXXX025 Make this look entirely at its arguments, and not at globals.
+ */
+ char *onion_pkey = NULL; /* Onion key, PEM-encoded. */
+ char *identity_pkey = NULL; /* Identity key, PEM-encoded. */
char digest[DIGEST_LEN];
char published[ISO_TIME_LEN+1];
char fingerprint[FINGERPRINT_LEN+1];
int has_extra_info_digest;
char extra_info_digest[HEX_DIGEST_LEN+1];
size_t onion_pkeylen, identity_pkeylen;
- size_t written;
- int result=0;
- addr_policy_t *tmpe;
- char *family_line;
+ char *family_line = NULL;
char *extra_or_address = NULL;
const or_options_t *options = get_options();
+ smartlist_t *chunks = NULL;
+ char *output = NULL;
/* Make sure the identity key matches the one in the routerinfo. */
- if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) {
+ if (!crypto_pk_eq_keys(ident_key, router->identity_pkey)) {
log_warn(LD_BUG,"Tried to sign a router with a private key that didn't "
"match router's public key!");
- return -1;
+ goto err;
}
/* record our fingerprint, so we can include it in the descriptor */
if (crypto_pk_get_fingerprint(router->identity_pkey, fingerprint, 1)<0) {
log_err(LD_BUG,"Error computing fingerprint");
- return -1;
+ goto err;
}
/* PEM-encode the onion key */
if (crypto_pk_write_public_key_to_string(router->onion_pkey,
&onion_pkey,&onion_pkeylen)<0) {
log_warn(LD_BUG,"write onion_pkey to string failed!");
- return -1;
+ goto err;
}
/* PEM-encode the identity key */
if (crypto_pk_write_public_key_to_string(router->identity_pkey,
&identity_pkey,&identity_pkeylen)<0) {
log_warn(LD_BUG,"write identity_pkey to string failed!");
- tor_free(onion_pkey);
- return -1;
+ goto err;
}
/* Encode the publication time. */
@@ -2053,14 +2345,15 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
}
}
+ chunks = smartlist_new();
/* Generate the easy portion of the router descriptor. */
- result = tor_snprintf(s, maxlen,
+ smartlist_add_asprintf(chunks,
"router %s %s %d 0 %d\n"
"%s"
"platform %s\n"
- "opt protocols Link 1 2 Circuit 1\n"
+ "protocols Link 1 2 Circuit 1\n"
"published %s\n"
- "opt fingerprint %s\n"
+ "fingerprint %s\n"
"uptime %ld\n"
"bandwidth %d %d %d\n"
"%s%s%s%s"
@@ -2079,113 +2372,115 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
(int) router->bandwidthrate,
(int) router->bandwidthburst,
(int) router->bandwidthcapacity,
- has_extra_info_digest ? "opt extra-info-digest " : "",
+ has_extra_info_digest ? "extra-info-digest " : "",
has_extra_info_digest ? extra_info_digest : "",
has_extra_info_digest ? "\n" : "",
- options->DownloadExtraInfo ? "opt caches-extra-info\n" : "",
+ options->DownloadExtraInfo ? "caches-extra-info\n" : "",
onion_pkey, identity_pkey,
family_line,
- we_are_hibernating() ? "opt hibernating 1\n" : "",
- options->HidServDirectoryV2 ? "opt hidden-service-dir\n" : "",
- options->AllowSingleHopExits ? "opt allow-single-hop-exits\n" : "");
-
- tor_free(family_line);
- tor_free(onion_pkey);
- tor_free(identity_pkey);
- tor_free(extra_or_address);
-
- if (result < 0) {
- log_warn(LD_BUG,"descriptor snprintf #1 ran out of room!");
- return -1;
- }
- /* From now on, we use 'written' to remember the current length of 's'. */
- written = result;
+ we_are_hibernating() ? "hibernating 1\n" : "",
+ options->HidServDirectoryV2 ? "hidden-service-dir\n" : "",
+ options->AllowSingleHopExits ? "allow-single-hop-exits\n" : "");
if (options->ContactInfo && strlen(options->ContactInfo)) {
const char *ci = options->ContactInfo;
if (strchr(ci, '\n') || strchr(ci, '\r'))
ci = escaped(ci);
- result = tor_snprintf(s+written,maxlen-written, "contact %s\n", ci);
- if (result<0) {
- log_warn(LD_BUG,"descriptor snprintf #2 ran out of room!");
- return -1;
- }
- written += result;
+ smartlist_add_asprintf(chunks, "contact %s\n", ci);
}
+#ifdef CURVE25519_ENABLED
+ if (router->onion_curve25519_pkey) {
+ char kbuf[128];
+ base64_encode(kbuf, sizeof(kbuf),
+ (const char *)router->onion_curve25519_pkey->public_key,
+ CURVE25519_PUBKEY_LEN);
+ smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
+ }
+#endif
+
/* Write the exit policy to the end of 's'. */
if (!router->exit_policy || !smartlist_len(router->exit_policy)) {
- strlcat(s+written, "reject *:*\n", maxlen-written);
- written += strlen("reject *:*\n");
- tmpe = NULL;
+ smartlist_add(chunks, tor_strdup("reject *:*\n"));
} else if (router->exit_policy) {
int i;
for (i = 0; i < smartlist_len(router->exit_policy); ++i) {
- tmpe = smartlist_get(router->exit_policy, i);
- result = policy_write_item(s+written, maxlen-written, tmpe, 1);
+ char pbuf[POLICY_BUF_LEN];
+ addr_policy_t *tmpe = smartlist_get(router->exit_policy, i);
+ int result;
+ if (tor_addr_family(&tmpe->addr) == AF_INET6)
+ continue; /* Don't include IPv6 parts of address policy */
+ result = policy_write_item(pbuf, POLICY_BUF_LEN, tmpe, 1);
if (result < 0) {
log_warn(LD_BUG,"descriptor policy_write_item ran out of room!");
- return -1;
- }
- tor_assert(result == (int)strlen(s+written));
- written += result;
- if (written+2 > maxlen) {
- log_warn(LD_BUG,"descriptor policy_write_item ran out of room (2)!");
- return -1;
+ goto err;
}
- s[written++] = '\n';
+ smartlist_add_asprintf(chunks, "%s\n", pbuf);
}
}
- if (written + DIROBJ_MAX_SIG_LEN > maxlen) {
- /* Not enough room for signature. */
- log_warn(LD_BUG,"not enough room left in descriptor for signature!");
- return -1;
+ if (router->ipv6_exit_policy) {
+ char *p6 = write_short_policy(router->ipv6_exit_policy);
+ if (p6 && strcmp(p6, "reject 1-65535")) {
+ smartlist_add_asprintf(chunks,
+ "ipv6-policy %s\n", p6);
+ }
+ tor_free(p6);
}
/* Sign the descriptor */
- strlcpy(s+written, "router-signature\n", maxlen-written);
- written += strlen(s+written);
- s[written] = '\0';
- if (router_get_router_hash(s, strlen(s), digest) < 0) {
- return -1;
- }
+ smartlist_add(chunks, tor_strdup("router-signature\n"));
+
+ crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1);
note_crypto_pk_op(SIGN_RTR);
- if (router_append_dirobj_signature(s+written,maxlen-written,
- digest,DIGEST_LEN,ident_key)<0) {
- log_warn(LD_BUG, "Couldn't sign router descriptor");
- return -1;
+ {
+ char *sig;
+ if (!(sig = router_get_dirobj_signature(digest, DIGEST_LEN, ident_key))) {
+ log_warn(LD_BUG, "Couldn't sign router descriptor");
+ goto err;
+ }
+ smartlist_add(chunks, sig);
}
- written += strlen(s+written);
- if (written+2 > maxlen) {
- log_warn(LD_BUG,"Not enough room to finish descriptor.");
- return -1;
- }
/* include a last '\n' */
- s[written] = '\n';
- s[written+1] = 0;
+ smartlist_add(chunks, tor_strdup("\n"));
+
+ output = smartlist_join_strings(chunks, "", 0, NULL);
#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
{
char *s_dup;
const char *cp;
routerinfo_t *ri_tmp;
- cp = s_dup = tor_strdup(s);
+ cp = s_dup = tor_strdup(output);
ri_tmp = router_parse_entry_from_string(cp, NULL, 1, 0, NULL);
if (!ri_tmp) {
log_err(LD_BUG,
"We just generated a router descriptor we can't parse.");
- log_err(LD_BUG, "Descriptor was: <<%s>>", s);
- return -1;
+ log_err(LD_BUG, "Descriptor was: <<%s>>", output);
+ goto err;
}
tor_free(s_dup);
routerinfo_free(ri_tmp);
}
#endif
- return (int)written+1;
+ goto done;
+
+ err:
+ tor_free(output); /* sets output to NULL */
+ done:
+ if (chunks) {
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+ }
+ tor_free(family_line);
+ tor_free(onion_pkey);
+ tor_free(identity_pkey);
+ tor_free(extra_or_address);
+
+ return output;
}
/** Copy the primary (IPv4) OR port (IP address and TCP port) for
@@ -2198,40 +2493,24 @@ router_get_prim_orport(const routerinfo_t *router, tor_addr_port_t *ap_out)
ap_out->port = router->or_port;
}
-/** Return 1 if we prefer the IPv6 address and OR TCP port of
- * <b>router</b>, else 0.
- *
- * We prefer the IPv6 address if the router has one and
- * i) the routerinfo_t says so
- * or
- * ii) the router has no IPv4 address. */
+/** Return 1 if any of <b>router</b>'s addresses are <b>addr</b>.
+ * Otherwise return 0. */
int
-router_ipv6_preferred(const routerinfo_t *router)
+router_has_addr(const routerinfo_t *router, const tor_addr_t *addr)
{
- return (!tor_addr_is_null(&router->ipv6_addr)
- && (router->ipv6_preferred || router->addr == 0));
-}
-
-/** Copy the preferred OR port (IP address and TCP port) for
- * <b>router</b> into *<b>addr_out</b>. */
-void
-router_get_pref_orport(const routerinfo_t *router, tor_addr_port_t *ap_out)
-{
- if (router_ipv6_preferred(router))
- router_get_pref_ipv6_orport(router, ap_out);
- else
- router_get_prim_orport(router, ap_out);
+ return
+ tor_addr_eq_ipv4h(addr, router->addr) ||
+ tor_addr_eq(&router->ipv6_addr, addr);
}
-/** Copy the preferred IPv6 OR port (IP address and TCP port) for
- * <b>router</b> into *<b>ap_out</b>. */
-void
-router_get_pref_ipv6_orport(const routerinfo_t *router,
- tor_addr_port_t *ap_out)
+int
+router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport)
{
- tor_assert(ap_out != NULL);
- tor_addr_copy(&ap_out->addr, &router->ipv6_addr);
- ap_out->port = router->ipv6_orport;
+ return
+ (tor_addr_eq_ipv4h(&orport->addr, router->addr) &&
+ orport->port == router->or_port) ||
+ (tor_addr_eq(&orport->addr, &router->ipv6_addr) &&
+ orport->port == router->ipv6_orport);
}
/** Load the contents of <b>filename</b>, find the last line starting with
@@ -2316,9 +2595,12 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
tor_free(bandwidth_usage);
smartlist_add(chunks, pre);
- if (geoip_is_loaded()) {
- smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", geoip_db_digest());
- }
+ if (geoip_is_loaded(AF_INET))
+ smartlist_add_asprintf(chunks, "geoip-db-digest %s\n",
+ geoip_db_digest(AF_INET));
+ if (geoip_is_loaded(AF_INET6))
+ smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n",
+ geoip_db_digest(AF_INET6));
if (options->ExtraInfoStatistics && write_stats_to_extrainfo) {
log_info(LD_GENERAL, "Adding stats to extra-info descriptor.");
@@ -2349,6 +2631,13 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
}
}
+ /* Add information about the pluggable transports we support. */
+ if (options->ServerTransportPlugin) {
+ char *pluggable_transports = pt_get_extra_info_descriptor_string();
+ if (pluggable_transports)
+ smartlist_add(chunks, pluggable_transports);
+ }
+
if (should_record_bridge_info(options) && write_stats_to_extrainfo) {
const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
if (bridge_stats) {
@@ -2431,7 +2720,9 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
return result;
}
-/** Return true iff <b>s</b> is a legally valid server nickname. */
+/** Return true iff <b>s</b> is a valid server nickname. (That is, a string
+ * containing between 1 and MAX_NICKNAME_LEN characters from
+ * LEGAL_NICKNAME_CHARACTERS.) */
int
is_legal_nickname(const char *s)
{
@@ -2442,7 +2733,7 @@ is_legal_nickname(const char *s)
strspn(s,LEGAL_NICKNAME_CHARACTERS) == len;
}
-/** Return true iff <b>s</b> is a legally valid server nickname or
+/** Return true iff <b>s</b> is a valid server nickname or
* hex-encoded identity-key digest. */
int
is_legal_nickname_or_hexdigest(const char *s)
@@ -2453,8 +2744,11 @@ is_legal_nickname_or_hexdigest(const char *s)
return is_legal_hexdigest(s);
}
-/** Return true iff <b>s</b> is a legally valid hex-encoded identity-key
- * digest. */
+/** Return true iff <b>s</b> is a valid hex-encoded identity-key
+ * digest. (That is, an optional $, followed by 40 hex characters,
+ * followed by either nothing, or = or ~ followed by a nickname, or
+ * a character other than =, ~, or a hex character.)
+ */
int
is_legal_hexdigest(const char *s)
{
@@ -2677,23 +2971,6 @@ router_get_verbose_nickname(char *buf, const routerinfo_t *router)
strlcpy(buf+1+HEX_DIGEST_LEN+1, router->nickname, MAX_NICKNAME_LEN+1);
}
-/** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the
- * verbose representation of the identity of <b>router</b>. The format is:
- * A dollar sign.
- * The upper-case hexadecimal encoding of the SHA1 hash of router's identity.
- * A "=" if the router is named; a "~" if it is not.
- * The router's nickname.
- **/
-void
-routerstatus_get_verbose_nickname(char *buf, const routerstatus_t *router)
-{
- buf[0] = '$';
- base16_encode(buf+1, HEX_DIGEST_LEN+1, router->identity_digest,
- DIGEST_LEN);
- buf[1+HEX_DIGEST_LEN] = router->is_named ? '=' : '~';
- strlcpy(buf+1+HEX_DIGEST_LEN+1, router->nickname, MAX_NICKNAME_LEN+1);
-}
-
/** Forget that we have issued any router-related warnings, so that we'll
* warn again if we see the same errors. */
void
@@ -2752,9 +3029,41 @@ router_free_all(void)
crypto_pk_free(legacy_signing_key);
authority_cert_free(legacy_key_certificate);
+#ifdef CURVE25519_ENABLED
+ memwipe(&curve25519_onion_key, 0, sizeof(curve25519_onion_key));
+ memwipe(&last_curve25519_onion_key, 0, sizeof(last_curve25519_onion_key));
+#endif
+
if (warned_nonexistent_family) {
SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp));
smartlist_free(warned_nonexistent_family);
}
}
+/** Return a smartlist of tor_addr_port_t's with all the OR ports of
+ <b>ri</b>. Note that freeing of the items in the list as well as
+ the smartlist itself is the callers responsibility.
+
+ XXX duplicating code from node_get_all_orports(). */
+smartlist_t *
+router_get_all_orports(const routerinfo_t *ri)
+{
+ smartlist_t *sl = smartlist_new();
+ tor_assert(ri);
+
+ if (ri->addr != 0) {
+ tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
+ tor_addr_from_ipv4h(&ap->addr, ri->addr);
+ ap->port = ri->or_port;
+ smartlist_add(sl, ap);
+ }
+ if (!tor_addr_is_null(&ri->ipv6_addr)) {
+ tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
+ tor_addr_copy(&ap->addr, &ri->ipv6_addr);
+ ap->port = ri->or_port;
+ smartlist_add(sl, ap);
+ }
+
+ return sl;
+}
+
diff --git a/src/or/router.h b/src/or/router.h
index 69805d6f2..60095d087 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,8 +9,8 @@
* \brief Header file for router.c.
**/
-#ifndef _TOR_ROUTER_H
-#define _TOR_ROUTER_H
+#ifndef TOR_ROUTER_H
+#define TOR_ROUTER_H
crypto_pk_t *get_onion_key(void);
time_t get_onion_key_set_at(void);
@@ -30,6 +30,11 @@ crypto_pk_t *init_key_from_file(const char *fname, int generate,
int severity);
void v3_authority_check_key_expiry(void);
+#ifdef CURVE25519_ENABLED
+di_digest256_map_t *construct_ntor_key_map(void);
+void ntor_key_map_free(di_digest256_map_t *map);
+#endif
+
int router_initialize_tls_context(void);
int init_keys(void);
@@ -53,8 +58,11 @@ int authdir_mode_publishes_statuses(const or_options_t *options);
int authdir_mode_tests_reachability(const or_options_t *options);
int authdir_mode_bridge(const or_options_t *options);
-uint16_t router_get_active_listener_port_by_type(int listener_type);
+uint16_t router_get_active_listener_port_by_type_af(int listener_type,
+ sa_family_t family);
uint16_t router_get_advertised_or_port(const or_options_t *options);
+uint16_t router_get_advertised_or_port_by_af(const or_options_t *options,
+ sa_family_t family);
uint16_t router_get_advertised_dir_port(const or_options_t *options,
uint16_t dirport);
@@ -72,20 +80,21 @@ void check_descriptor_bandwidth_changed(time_t now);
void check_descriptor_ipaddress_changed(time_t now);
void router_new_address_suggestion(const char *suggestion,
const dir_connection_t *d_conn);
-int router_compare_to_my_exit_policy(edge_connection_t *conn);
+int router_compare_to_my_exit_policy(const tor_addr_t *addr, uint16_t port);
int router_my_exit_policy_is_reject_star(void);
const routerinfo_t *router_get_my_routerinfo(void);
extrainfo_t *router_get_my_extrainfo(void);
const char *router_get_my_descriptor(void);
const char *router_get_descriptor_gen_reason(void);
int router_digest_is_me(const char *digest);
+const uint8_t *router_get_my_id_digest(void);
int router_extrainfo_digest_is_me(const char *digest);
int router_is_me(const routerinfo_t *router);
int router_fingerprint_is_me(const char *fp);
int router_pick_published_address(const or_options_t *options, uint32_t *addr);
int router_rebuild_descriptor(int force);
-int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
- crypto_pk_t *ident_key);
+char *router_dump_router_to_string(routerinfo_t *router,
+ crypto_pk_t *ident_key);
void router_get_prim_orport(const routerinfo_t *router,
tor_addr_port_t *addr_port_out);
void router_get_pref_orport(const routerinfo_t *router,
@@ -93,6 +102,9 @@ void router_get_pref_orport(const routerinfo_t *router,
void router_get_pref_ipv6_orport(const routerinfo_t *router,
tor_addr_port_t *addr_port_out);
int router_ipv6_preferred(const routerinfo_t *router);
+int router_has_addr(const routerinfo_t *router, const tor_addr_t *addr);
+int router_has_orport(const routerinfo_t *router,
+ const tor_addr_port_t *orport);
int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo,
crypto_pk_t *ident_key);
int is_legal_nickname(const char *s);
@@ -123,8 +135,6 @@ const char *routerstatus_describe(const routerstatus_t *ri);
const char *extend_info_describe(const extend_info_t *ei);
void router_get_verbose_nickname(char *buf, const routerinfo_t *router);
-void routerstatus_get_verbose_nickname(char *buf,
- const routerstatus_t *router);
void router_reset_warnings(void);
void router_reset_reachability(void);
void router_free_all(void);
@@ -132,6 +142,8 @@ void router_free_all(void);
const char *router_purpose_to_string(uint8_t p);
uint8_t router_purpose_from_string(const char *s);
+smartlist_t *router_get_all_orports(const routerinfo_t *ri);
+
#ifdef ROUTER_PRIVATE
/* Used only by router.c and test.c */
void get_platform_str(char *platform, size_t len);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 3c39e362d..c28de24b6 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,14 +11,17 @@
* servers.
**/
+#define ROUTERLIST_PRIVATE
#include "or.h"
-#include "circuitbuild.h"
+#include "circuitstats.h"
#include "config.h"
#include "connection.h"
#include "control.h"
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
+#include "entrynodes.h"
+#include "fp_pair.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
@@ -33,55 +36,81 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "routerset.h"
// #define DEBUG_ROUTERLIST
/****************************************************************************/
+DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
+DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
+DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
+DECLARE_TYPED_DIGESTMAP_FNS(dsmap_, digest_ds_map_t, download_status_t)
+#define SDMAP_FOREACH(map, keyvar, valvar) \
+ DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
+ valvar)
+#define RIMAP_FOREACH(map, keyvar, valvar) \
+ DIGESTMAP_FOREACH(rimap_to_digestmap(map), keyvar, routerinfo_t *, valvar)
+#define EIMAP_FOREACH(map, keyvar, valvar) \
+ DIGESTMAP_FOREACH(eimap_to_digestmap(map), keyvar, extrainfo_t *, valvar)
+#define DSMAP_FOREACH(map, keyvar, valvar) \
+ DIGESTMAP_FOREACH(dsmap_to_digestmap(map), keyvar, download_status_t *, \
+ valvar)
+
+/* Forward declaration for cert_list_t */
+typedef struct cert_list_t cert_list_t;
+
/* static function prototypes */
+static int compute_weighted_bandwidths(const smartlist_t *sl,
+ bandwidth_weight_rule_t rule,
+ u64_dbl_t **bandwidths_out);
static const routerstatus_t *router_pick_directory_server_impl(
dirinfo_type_t auth, int flags);
static const routerstatus_t *router_pick_trusteddirserver_impl(
- dirinfo_type_t auth, int flags, int *n_busy_out);
-static void mark_all_trusteddirservers_up(void);
-static int router_nickname_matches(const routerinfo_t *router,
- const char *nickname);
-static int node_nickname_matches(const node_t *router,
- const char *nickname);
-static void trusted_dir_server_free(trusted_dir_server_t *ds);
+ const smartlist_t *sourcelist, dirinfo_type_t auth,
+ int flags, int *n_busy_out);
+static const routerstatus_t *router_pick_dirserver_generic(
+ smartlist_t *sourcelist,
+ dirinfo_type_t type, int flags);
+static void mark_all_dirservers_up(smartlist_t *server_list);
+static void dir_server_free(dir_server_t *ds);
static int signed_desc_digest_is_recognized(signed_descriptor_t *desc);
-static void update_router_have_minimum_dir_info(void);
static const char *signed_descriptor_get_body_impl(
const signed_descriptor_t *desc,
int with_annotations);
static void list_pending_downloads(digestmap_t *result,
int purpose, const char *prefix);
+static void list_pending_fpsk_downloads(fp_pair_map_t *result);
static void launch_dummy_descriptor_download_as_needed(time_t now,
const or_options_t *options);
-
-DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
-DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
-DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
-#define SDMAP_FOREACH(map, keyvar, valvar) \
- DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
- valvar)
-#define RIMAP_FOREACH(map, keyvar, valvar) \
- DIGESTMAP_FOREACH(rimap_to_digestmap(map), keyvar, routerinfo_t *, valvar)
-#define EIMAP_FOREACH(map, keyvar, valvar) \
- DIGESTMAP_FOREACH(eimap_to_digestmap(map), keyvar, extrainfo_t *, valvar)
+static void download_status_reset_by_sk_in_cl(cert_list_t *cl,
+ const char *digest);
+static int download_status_is_ready_by_sk_in_cl(cert_list_t *cl,
+ const char *digest,
+ time_t now, int max_failures);
/****************************************************************************/
-/** Global list of a trusted_dir_server_t object for each trusted directory
- * server. */
+/** Global list of a dir_server_t object for each directory
+ * authority. */
static smartlist_t *trusted_dir_servers = NULL;
+/** Global list of dir_server_t objects for all directory authorities
+ * and all fallback directory servers. */
+static smartlist_t *fallback_dir_servers = NULL;
/** List of for a given authority, and download status for latest certificate.
*/
-typedef struct cert_list_t {
- download_status_t dl_status;
+struct cert_list_t {
+ /*
+ * The keys of download status map are cert->signing_key_digest for pending
+ * downloads by (identity digest/signing key digest) pair; functions such
+ * as authority_cert_get_by_digest() already assume these are unique.
+ */
+ struct digest_ds_map_t *dl_status_map;
+ /* There is also a dlstatus for the download by identity key only */
+ download_status_t dl_status_by_id;
smartlist_t *certs;
-} cert_list_t;
+};
/** Map from v3 identity key digest to cert_list_t. */
static digestmap_t *trusted_dir_certs = NULL;
/** True iff any key certificate in at least one member of
@@ -119,12 +148,78 @@ get_n_authorities(dirinfo_type_t type)
int n = 0;
if (!trusted_dir_servers)
return 0;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ds,
if (ds->type & type)
++n);
return n;
}
+/** Reset the download status of a specified element in a dsmap */
+static void
+download_status_reset_by_sk_in_cl(cert_list_t *cl, const char *digest)
+{
+ download_status_t *dlstatus = NULL;
+
+ tor_assert(cl);
+ tor_assert(digest);
+
+ /* Make sure we have a dsmap */
+ if (!(cl->dl_status_map)) {
+ cl->dl_status_map = dsmap_new();
+ }
+ /* Look for a download_status_t in the map with this digest */
+ dlstatus = dsmap_get(cl->dl_status_map, digest);
+ /* Got one? */
+ if (!dlstatus) {
+ /* Insert before we reset */
+ dlstatus = tor_malloc_zero(sizeof(*dlstatus));
+ dsmap_set(cl->dl_status_map, digest, dlstatus);
+ }
+ tor_assert(dlstatus);
+ /* Go ahead and reset it */
+ download_status_reset(dlstatus);
+}
+
+/**
+ * Return true if the download for this signing key digest in cl is ready
+ * to be re-attempted.
+ */
+static int
+download_status_is_ready_by_sk_in_cl(cert_list_t *cl,
+ const char *digest,
+ time_t now, int max_failures)
+{
+ int rv = 0;
+ download_status_t *dlstatus = NULL;
+
+ tor_assert(cl);
+ tor_assert(digest);
+
+ /* Make sure we have a dsmap */
+ if (!(cl->dl_status_map)) {
+ cl->dl_status_map = dsmap_new();
+ }
+ /* Look for a download_status_t in the map with this digest */
+ dlstatus = dsmap_get(cl->dl_status_map, digest);
+ /* Got one? */
+ if (dlstatus) {
+ /* Use download_status_is_ready() */
+ rv = download_status_is_ready(dlstatus, now, max_failures);
+ } else {
+ /*
+ * If we don't know anything about it, return 1, since we haven't
+ * tried this one before. We need to create a new entry here,
+ * too.
+ */
+ dlstatus = tor_malloc_zero(sizeof(*dlstatus));
+ download_status_reset(dlstatus);
+ dsmap_set(cl->dl_status_map, digest, dlstatus);
+ rv = 1;
+ }
+
+ return rv;
+}
+
#define get_n_v2_authorities() get_n_authorities(V2_DIRINFO)
/** Helper: Return the cert_list_t for an authority whose authority ID is
@@ -138,13 +233,35 @@ get_cert_list(const char *id_digest)
cl = digestmap_get(trusted_dir_certs, id_digest);
if (!cl) {
cl = tor_malloc_zero(sizeof(cert_list_t));
- cl->dl_status.schedule = DL_SCHED_CONSENSUS;
+ cl->dl_status_by_id.schedule = DL_SCHED_CONSENSUS;
cl->certs = smartlist_new();
+ cl->dl_status_map = dsmap_new();
digestmap_set(trusted_dir_certs, id_digest, cl);
}
return cl;
}
+/** Release all space held by a cert_list_t */
+static void
+cert_list_free(cert_list_t *cl)
+{
+ if (!cl)
+ return;
+
+ SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
+ authority_cert_free(cert));
+ smartlist_free(cl->certs);
+ dsmap_free(cl->dl_status_map, tor_free_);
+ tor_free(cl);
+}
+
+/** Wrapper for cert_list_free so we can pass it to digestmap_free */
+static void
+cert_list_free_(void *cl)
+{
+ cert_list_free(cl);
+}
+
/** Reload the cached v3 key certificates from the cached-certs file in
* the data directory. Return 0 on success, -1 on failure. */
int
@@ -159,7 +276,9 @@ trusted_dirs_reload_certs(void)
tor_free(filename);
if (!contents)
return 0;
- r = trusted_dirs_load_certs_from_string(contents, 1, 1);
+ r = trusted_dirs_load_certs_from_string(
+ contents,
+ TRUSTED_DIRS_CERTS_SRC_FROM_STORE, 1);
tor_free(contents);
return r;
}
@@ -182,17 +301,23 @@ already_have_cert(authority_cert_t *cert)
}
/** Load a bunch of new key certificates from the string <b>contents</b>. If
- * <b>from_store</b> is true, the certificates are from the cache, and we
- * don't need to flush them to disk. If <b>flush</b> is true, we need
- * to flush any changed certificates to disk now. Return 0 on success, -1
- * if any certs fail to parse. */
+ * <b>source</b> is TRUSTED_DIRS_CERTS_SRC_FROM_STORE, the certificates are
+ * from the cache, and we don't need to flush them to disk. If we are a
+ * dirauth loading our own cert, source is TRUSTED_DIRS_CERTS_SRC_SELF.
+ * Otherwise, source is download type: TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST
+ * or TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST. If <b>flush</b> is true, we
+ * need to flush any changed certificates to disk now. Return 0 on success,
+ * -1 if any certs fail to parse.
+ */
+
int
-trusted_dirs_load_certs_from_string(const char *contents, int from_store,
+trusted_dirs_load_certs_from_string(const char *contents, int source,
int flush)
{
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
const char *s, *eos;
int failure_code = 0;
+ int from_store = (source == TRUSTED_DIRS_CERTS_SRC_FROM_STORE);
for (s = contents; *s; s = eos) {
authority_cert_t *cert = authority_cert_parse_from_string(s, &eos);
@@ -213,9 +338,13 @@ trusted_dirs_load_certs_from_string(const char *contents, int from_store,
from_store ? "cached" : "downloaded",
ds ? ds->nickname : "an old or new authority");
- /* a duplicate on a download should be treated as a failure, since it
- * probably means we wanted a different secret key or we are trying to
- * replace an expired cert that has not in fact been updated. */
+ /*
+ * A duplicate on download should be treated as a failure, so we call
+ * authority_cert_dl_failed() to reset the download status to make sure
+ * we can't try again. Since we've implemented the fp-sk mechanism
+ * to download certs by signing key, this should be much rarer than it
+ * was and is perhaps cause for concern.
+ */
if (!from_store) {
if (authdir_mode(get_options())) {
log_warn(LD_DIR,
@@ -229,7 +358,18 @@ trusted_dirs_load_certs_from_string(const char *contents, int from_store,
ds ? ds->nickname : "an old or new authority");
}
- authority_cert_dl_failed(cert->cache_info.identity_digest, 404);
+ /*
+ * This is where we care about the source; authority_cert_dl_failed()
+ * needs to know whether the download was by fp or (fp,sk) pair to
+ * twiddle the right bit in the download map.
+ */
+ if (source == TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST) {
+ authority_cert_dl_failed(cert->cache_info.identity_digest,
+ NULL, 404);
+ } else if (source == TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST) {
+ authority_cert_dl_failed(cert->cache_info.identity_digest,
+ cert->signing_key_digest, 404);
+ }
}
authority_cert_free(cert);
@@ -329,7 +469,6 @@ trusted_dirs_remove_old_certs(void)
time_t now = time(NULL);
#define DEAD_CERT_LIFETIME (2*24*60*60)
#define OLD_CERT_LIFETIME (7*24*60*60)
-#define CERT_EXPIRY_SKEW (60*60)
if (!trusted_dir_certs)
return;
@@ -445,17 +584,53 @@ authority_cert_get_all(smartlist_t *certs_out)
}
/** Called when an attempt to download a certificate with the authority with
- * ID <b>id_digest</b> fails with HTTP response code <b>status</b>: remember
- * the failure, so we don't try again immediately. */
+ * ID <b>id_digest</b> and, if not NULL, signed with key signing_key_digest
+ * fails with HTTP response code <b>status</b>: remember the failure, so we
+ * don't try again immediately. */
void
-authority_cert_dl_failed(const char *id_digest, int status)
+authority_cert_dl_failed(const char *id_digest,
+ const char *signing_key_digest, int status)
{
cert_list_t *cl;
+ download_status_t *dlstatus = NULL;
+ char id_digest_str[2*DIGEST_LEN+1];
+ char sk_digest_str[2*DIGEST_LEN+1];
+
if (!trusted_dir_certs ||
!(cl = digestmap_get(trusted_dir_certs, id_digest)))
return;
- download_status_failed(&cl->dl_status, status);
+ /*
+ * Are we noting a failed download of the latest cert for the id digest,
+ * or of a download by (id, signing key) digest pair?
+ */
+ if (!signing_key_digest) {
+ /* Just by id digest */
+ download_status_failed(&cl->dl_status_by_id, status);
+ } else {
+ /* Reset by (id, signing key) digest pair
+ *
+ * Look for a download_status_t in the map with this digest
+ */
+ dlstatus = dsmap_get(cl->dl_status_map, signing_key_digest);
+ /* Got one? */
+ if (dlstatus) {
+ download_status_failed(dlstatus, status);
+ } else {
+ /*
+ * Do this rather than hex_str(), since hex_str clobbers
+ * old results and we call twice in the param list.
+ */
+ base16_encode(id_digest_str, sizeof(id_digest_str),
+ id_digest, DIGEST_LEN);
+ base16_encode(sk_digest_str, sizeof(sk_digest_str),
+ signing_key_digest, DIGEST_LEN);
+ log_warn(LD_BUG,
+ "Got failure for cert fetch with (fp,sk) = (%s,%s), with "
+ "status %d, but knew nothing about the download.",
+ id_digest_str, sk_digest_str, status);
+ }
+ }
}
/** Return true iff when we've been getting enough failures when trying to
@@ -471,7 +646,7 @@ authority_cert_dl_looks_uncertain(const char *id_digest)
!(cl = digestmap_get(trusted_dir_certs, id_digest)))
return 0;
- n_failures = download_status_get_n_failures(&cl->dl_status);
+ n_failures = download_status_get_n_failures(&cl->dl_status_by_id);
return n_failures >= N_AUTH_CERT_DL_FAILURES_TO_BUG_USER;
}
@@ -487,20 +662,88 @@ authority_cert_dl_looks_uncertain(const char *id_digest)
void
authority_certs_fetch_missing(networkstatus_t *status, time_t now)
{
- digestmap_t *pending;
+ /*
+ * The pending_id digestmap tracks pending certificate downloads by
+ * identity digest; the pending_cert digestmap tracks pending downloads
+ * by (identity digest, signing key digest) pairs.
+ */
+ digestmap_t *pending_id;
+ fp_pair_map_t *pending_cert;
authority_cert_t *cert;
- smartlist_t *missing_digests;
+ /*
+ * The missing_id_digests smartlist will hold a list of id digests
+ * we want to fetch the newest cert for; the missing_cert_digests
+ * smartlist will hold a list of fp_pair_t with an identity and
+ * signing key digest.
+ */
+ smartlist_t *missing_cert_digests, *missing_id_digests;
char *resource = NULL;
cert_list_t *cl;
const int cache = directory_caches_unknown_auth_certs(get_options());
+ fp_pair_t *fp_tmp = NULL;
+ char id_digest_str[2*DIGEST_LEN+1];
+ char sk_digest_str[2*DIGEST_LEN+1];
if (should_delay_dir_fetches(get_options()))
return;
- pending = digestmap_new();
- missing_digests = smartlist_new();
+ pending_cert = fp_pair_map_new();
+ pending_id = digestmap_new();
+ missing_cert_digests = smartlist_new();
+ missing_id_digests = smartlist_new();
+
+ /*
+ * First, we get the lists of already pending downloads so we don't
+ * duplicate effort.
+ */
+ list_pending_downloads(pending_id, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
+ list_pending_fpsk_downloads(pending_cert);
- list_pending_downloads(pending, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
+ /*
+ * Now, we download any trusted authority certs we don't have by
+ * identity digest only. This gets the latest cert for that authority.
+ */
+ SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ds) {
+ int found = 0;
+ if (!(ds->type & V3_DIRINFO))
+ continue;
+ if (smartlist_contains_digest(missing_id_digests,
+ ds->v3_identity_digest))
+ continue;
+ cl = get_cert_list(ds->v3_identity_digest);
+ SMARTLIST_FOREACH_BEGIN(cl->certs, authority_cert_t *, cert) {
+ if (now < cert->expires) {
+ /* It's not expired, and we weren't looking for something to
+ * verify a consensus with. Call it done. */
+ download_status_reset(&(cl->dl_status_by_id));
+ /* No sense trying to download it specifically by signing key hash */
+ download_status_reset_by_sk_in_cl(cl, cert->signing_key_digest);
+ found = 1;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(cert);
+ if (!found &&
+ download_status_is_ready(&(cl->dl_status_by_id), now,
+ MAX_CERT_DL_FAILURES) &&
+ !digestmap_get(pending_id, ds->v3_identity_digest)) {
+ log_info(LD_DIR,
+ "No current certificate known for authority %s "
+ "(ID digest %s); launching request.",
+ ds->nickname, hex_str(ds->v3_identity_digest, DIGEST_LEN));
+ smartlist_add(missing_id_digests, ds->v3_identity_digest);
+ }
+ } SMARTLIST_FOREACH_END(ds);
+
+ /*
+ * Next, if we have a consensus, scan through it and look for anything
+ * signed with a key from a cert we don't have. Those get downloaded
+ * by (fp,sk) pair, but if we don't know any certs at all for the fp
+ * (identity digest), and it's one of the trusted dir server certs
+ * we started off above or a pending download in pending_id, don't
+ * try to get it yet. Most likely, the one we'll get for that will
+ * have the right signing key too, and we'd just be downloading
+ * redundantly.
+ */
if (status) {
SMARTLIST_FOREACH_BEGIN(status->voters, networkstatus_voter_info_t *,
voter) {
@@ -510,84 +753,164 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
if (!cache &&
!trusteddirserver_get_by_v3_auth_digest(voter->identity_digest))
continue; /* We are not a cache, and we don't know this authority.*/
+
+ /*
+ * If we don't know *any* cert for this authority, and a download by ID
+ * is pending or we added it to missing_id_digests above, skip this
+ * one for now to avoid duplicate downloads.
+ */
cl = get_cert_list(voter->identity_digest);
+ if (smartlist_len(cl->certs) == 0) {
+ /* We have no certs at all for this one */
+
+ /* Do we have a download of one pending? */
+ if (digestmap_get(pending_id, voter->identity_digest))
+ continue;
+
+ /*
+ * Are we about to launch a download of one due to the trusted
+ * dir server check above?
+ */
+ if (smartlist_contains_digest(missing_id_digests,
+ voter->identity_digest))
+ continue;
+ }
+
SMARTLIST_FOREACH_BEGIN(voter->sigs, document_signature_t *, sig) {
cert = authority_cert_get_by_digests(voter->identity_digest,
sig->signing_key_digest);
if (cert) {
if (now < cert->expires)
- download_status_reset(&cl->dl_status);
+ download_status_reset_by_sk_in_cl(cl, sig->signing_key_digest);
continue;
}
- if (download_status_is_ready(&cl->dl_status, now,
- MAX_CERT_DL_FAILURES) &&
- !digestmap_get(pending, voter->identity_digest)) {
- log_info(LD_DIR, "We're missing a certificate from authority "
- "with signing key %s: launching request.",
- hex_str(sig->signing_key_digest, DIGEST_LEN));
- smartlist_add(missing_digests, sig->identity_digest);
+ if (download_status_is_ready_by_sk_in_cl(
+ cl, sig->signing_key_digest,
+ now, MAX_CERT_DL_FAILURES) &&
+ !fp_pair_map_get_by_digests(pending_cert,
+ voter->identity_digest,
+ sig->signing_key_digest)) {
+ /*
+ * Do this rather than hex_str(), since hex_str clobbers
+ * old results and we call twice in the param list.
+ */
+ base16_encode(id_digest_str, sizeof(id_digest_str),
+ voter->identity_digest, DIGEST_LEN);
+ base16_encode(sk_digest_str, sizeof(sk_digest_str),
+ sig->signing_key_digest, DIGEST_LEN);
+
+ if (voter->nickname) {
+ log_info(LD_DIR,
+ "We're missing a certificate from authority %s "
+ "(ID digest %s) with signing key %s: "
+ "launching request.",
+ voter->nickname, id_digest_str, sk_digest_str);
+ } else {
+ log_info(LD_DIR,
+ "We're missing a certificate from authority ID digest "
+ "%s with signing key %s: launching request.",
+ id_digest_str, sk_digest_str);
+ }
+
+ /* Allocate a new fp_pair_t to append */
+ fp_tmp = tor_malloc(sizeof(*fp_tmp));
+ memcpy(fp_tmp->first, voter->identity_digest, sizeof(fp_tmp->first));
+ memcpy(fp_tmp->second, sig->signing_key_digest,
+ sizeof(fp_tmp->second));
+ smartlist_add(missing_cert_digests, fp_tmp);
}
} SMARTLIST_FOREACH_END(sig);
} SMARTLIST_FOREACH_END(voter);
}
- SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, ds) {
- int found = 0;
- if (!(ds->type & V3_DIRINFO))
- continue;
- if (smartlist_digest_isin(missing_digests, ds->v3_identity_digest))
- continue;
- cl = get_cert_list(ds->v3_identity_digest);
- SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert, {
- if (now < cert->expires) {
- /* It's not expired, and we weren't looking for something to
- * verify a consensus with. Call it done. */
- download_status_reset(&cl->dl_status);
- found = 1;
- break;
- }
- });
- if (!found &&
- download_status_is_ready(&cl->dl_status, now,MAX_CERT_DL_FAILURES) &&
- !digestmap_get(pending, ds->v3_identity_digest)) {
- log_info(LD_DIR, "No current certificate known for authority %s; "
- "launching request.", ds->nickname);
- smartlist_add(missing_digests, ds->v3_identity_digest);
- }
- } SMARTLIST_FOREACH_END(ds);
- if (!smartlist_len(missing_digests)) {
- goto done;
- } else {
+ /* Do downloads by identity digest */
+ if (smartlist_len(missing_id_digests) > 0) {
+ int need_plus = 0;
smartlist_t *fps = smartlist_new();
+
smartlist_add(fps, tor_strdup("fp/"));
- SMARTLIST_FOREACH(missing_digests, const char *, d, {
- char *fp;
- if (digestmap_get(pending, d))
- continue;
- fp = tor_malloc(HEX_DIGEST_LEN+2);
- base16_encode(fp, HEX_DIGEST_LEN+1, d, DIGEST_LEN);
- fp[HEX_DIGEST_LEN] = '+';
- fp[HEX_DIGEST_LEN+1] = '\0';
- smartlist_add(fps, fp);
- });
- if (smartlist_len(fps) == 1) {
- /* we didn't add any: they were all pending */
- SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
- smartlist_free(fps);
- goto done;
+
+ SMARTLIST_FOREACH_BEGIN(missing_id_digests, const char *, d) {
+ char *fp = NULL;
+
+ if (digestmap_get(pending_id, d))
+ continue;
+
+ base16_encode(id_digest_str, sizeof(id_digest_str),
+ d, DIGEST_LEN);
+
+ if (need_plus) {
+ tor_asprintf(&fp, "+%s", id_digest_str);
+ } else {
+ /* No need for tor_asprintf() in this case; first one gets no '+' */
+ fp = tor_strdup(id_digest_str);
+ need_plus = 1;
+ }
+
+ smartlist_add(fps, fp);
+ } SMARTLIST_FOREACH_END(d);
+
+ if (smartlist_len(fps) > 1) {
+ resource = smartlist_join_strings(fps, "", 0, NULL);
+ directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
+ resource, PDS_RETRY_IF_NO_SERVERS);
+ tor_free(resource);
}
- resource = smartlist_join_strings(fps, "", 0, NULL);
- resource[strlen(resource)-1] = '\0';
+ /* else we didn't add any: they were all pending */
+
SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
smartlist_free(fps);
}
- directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
- resource, PDS_RETRY_IF_NO_SERVERS);
- done:
- tor_free(resource);
- smartlist_free(missing_digests);
- digestmap_free(pending, NULL);
+ /* Do downloads by identity digest/signing key pair */
+ if (smartlist_len(missing_cert_digests) > 0) {
+ int need_plus = 0;
+ smartlist_t *fp_pairs = smartlist_new();
+
+ smartlist_add(fp_pairs, tor_strdup("fp-sk/"));
+
+ SMARTLIST_FOREACH_BEGIN(missing_cert_digests, const fp_pair_t *, d) {
+ char *fp_pair = NULL;
+
+ if (fp_pair_map_get(pending_cert, d))
+ continue;
+
+ /* Construct string encodings of the digests */
+ base16_encode(id_digest_str, sizeof(id_digest_str),
+ d->first, DIGEST_LEN);
+ base16_encode(sk_digest_str, sizeof(sk_digest_str),
+ d->second, DIGEST_LEN);
+
+ /* Now tor_asprintf() */
+ if (need_plus) {
+ tor_asprintf(&fp_pair, "+%s-%s", id_digest_str, sk_digest_str);
+ } else {
+ /* First one in the list doesn't get a '+' */
+ tor_asprintf(&fp_pair, "%s-%s", id_digest_str, sk_digest_str);
+ need_plus = 1;
+ }
+
+ /* Add it to the list of pairs to request */
+ smartlist_add(fp_pairs, fp_pair);
+ } SMARTLIST_FOREACH_END(d);
+
+ if (smartlist_len(fp_pairs) > 1) {
+ resource = smartlist_join_strings(fp_pairs, "", 0, NULL);
+ directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
+ resource, PDS_RETRY_IF_NO_SERVERS);
+ tor_free(resource);
+ }
+ /* else they were all pending */
+
+ SMARTLIST_FOREACH(fp_pairs, char *, p, tor_free(p));
+ smartlist_free(fp_pairs);
+ }
+
+ smartlist_free(missing_id_digests);
+ SMARTLIST_FOREACH(missing_cert_digests, fp_pair_t *, p, tor_free(p));
+ smartlist_free(missing_cert_digests);
+ digestmap_free(pending_id, NULL);
+ fp_pair_map_free(pending_cert, NULL);
}
/* Router descriptor storage.
@@ -655,7 +978,7 @@ signed_desc_append_to_journal(signed_descriptor_t *desc,
* signed_descriptor_t* in *<b>a</b> is older, the same age as, or newer than
* the signed_descriptor_t* in *<b>b</b>. */
static int
-_compare_signed_descriptors_by_age(const void **_a, const void **_b)
+compare_signed_descriptors_by_age_(const void **_a, const void **_b)
{
const signed_descriptor_t *r1 = *_a, *r2 = *_b;
return (int)(r1->published_on - r2->published_on);
@@ -728,7 +1051,7 @@ router_rebuild_store(int flags, desc_store_t *store)
smartlist_add(signed_descriptors, &ri->cache_info));
}
- smartlist_sort(signed_descriptors, _compare_signed_descriptors_by_age);
+ smartlist_sort(signed_descriptors, compare_signed_descriptors_by_age_);
/* Now, add the appropriate members to chunk_list */
SMARTLIST_FOREACH_BEGIN(signed_descriptors, signed_descriptor_t *, sd) {
@@ -914,11 +1237,11 @@ router_reload_router_list(void)
return 0;
}
-/** Return a smartlist containing a list of trusted_dir_server_t * for all
+/** Return a smartlist containing a list of dir_server_t * for all
* known trusted dirservers. Callers must not modify the list or its
* contents.
*/
-smartlist_t *
+const smartlist_t *
router_get_trusted_dir_servers(void)
{
if (!trusted_dir_servers)
@@ -927,6 +1250,15 @@ router_get_trusted_dir_servers(void)
return trusted_dir_servers;
}
+const smartlist_t *
+router_get_fallback_dir_servers(void)
+{
+ if (!fallback_dir_servers)
+ fallback_dir_servers = smartlist_new();
+
+ return fallback_dir_servers;
+}
+
/** Try to find a running dirserver that supports operations of <b>type</b>.
*
* If there are no running dirservers in our routerlist and the
@@ -947,7 +1279,7 @@ router_pick_directory_server(dirinfo_type_t type, int flags)
{
const routerstatus_t *choice;
if (get_options()->PreferTunneledDirConns)
- flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
+ flags |= PDS_PREFER_TUNNELED_DIR_CONNS_;
if (!routerlist)
return NULL;
@@ -960,7 +1292,7 @@ router_pick_directory_server(dirinfo_type_t type, int flags)
"No reachable router entries for dirservers. "
"Trying them all again.");
/* mark all authdirservers as up again */
- mark_all_trusteddirservers_up();
+ mark_all_dirservers_up(fallback_dir_servers);
/* try again */
choice = router_pick_directory_server_impl(type, flags);
return choice;
@@ -995,7 +1327,7 @@ router_get_my_share_of_directory_requests(double *v2_share_out,
}
}
- if (rs->version_supports_v3_dir) {
+ {
sl_last_total_weighted_bw = 0;
router_pick_directory_server(V3_DIRINFO, pds_flags);
if (sl_last_total_weighted_bw != 0) {
@@ -1007,16 +1339,16 @@ router_get_my_share_of_directory_requests(double *v2_share_out,
return 0;
}
-/** Return the trusted_dir_server_t for the directory authority whose identity
+/** Return the dir_server_t for the directory authority whose identity
* key hashes to <b>digest</b>, or NULL if no such authority is known.
*/
-trusted_dir_server_t *
+dir_server_t *
router_get_trusteddirserver_by_digest(const char *digest)
{
if (!trusted_dir_servers)
return NULL;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ds,
{
if (tor_memeq(ds->digest, digest, DIGEST_LEN))
return ds;
@@ -1025,17 +1357,35 @@ router_get_trusteddirserver_by_digest(const char *digest)
return NULL;
}
-/** Return the trusted_dir_server_t for the directory authority whose
+/** Return the dir_server_t for the fallback dirserver whose identity
+ * key hashes to <b>digest</b>, or NULL if no such authority is known.
+ */
+dir_server_t *
+router_get_fallback_dirserver_by_digest(const char *digest)
+{
+ if (!trusted_dir_servers)
+ return NULL;
+
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ds,
+ {
+ if (tor_memeq(ds->digest, digest, DIGEST_LEN))
+ return ds;
+ });
+
+ return NULL;
+}
+
+/** Return the dir_server_t for the directory authority whose
* v3 identity key hashes to <b>digest</b>, or NULL if no such authority
* is known.
*/
-trusted_dir_server_t *
+dir_server_t *
trusteddirserver_get_by_v3_auth_digest(const char *digest)
{
if (!trusted_dir_servers)
return NULL;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ds,
{
if (tor_memeq(ds->v3_identity_digest, digest, DIGEST_LEN) &&
(ds->type & V3_DIRINFO))
@@ -1045,18 +1395,37 @@ trusteddirserver_get_by_v3_auth_digest(const char *digest)
return NULL;
}
-/** Try to find a running trusted dirserver. Flags are as for
+/** Try to find a running directory authority. Flags are as for
* router_pick_directory_server.
*/
const routerstatus_t *
router_pick_trusteddirserver(dirinfo_type_t type, int flags)
{
+ return router_pick_dirserver_generic(trusted_dir_servers, type, flags);
+}
+
+/** Try to find a running fallback directory Flags are as for
+ * router_pick_directory_server.
+ */
+const routerstatus_t *
+router_pick_fallback_dirserver(dirinfo_type_t type, int flags)
+{
+ return router_pick_dirserver_generic(fallback_dir_servers, type, flags);
+}
+
+/** Try to find a running fallback directory Flags are as for
+ * router_pick_directory_server.
+ */
+static const routerstatus_t *
+router_pick_dirserver_generic(smartlist_t *sourcelist,
+ dirinfo_type_t type, int flags)
+{
const routerstatus_t *choice;
int busy = 0;
if (get_options()->PreferTunneledDirConns)
- flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
+ flags |= PDS_PREFER_TUNNELED_DIR_CONNS_;
- choice = router_pick_trusteddirserver_impl(type, flags, &busy);
+ choice = router_pick_trusteddirserver_impl(sourcelist, type, flags, &busy);
if (choice || !(flags & PDS_RETRY_IF_NO_SERVERS))
return choice;
if (busy) {
@@ -1069,9 +1438,9 @@ router_pick_trusteddirserver(dirinfo_type_t type, int flags)
}
log_info(LD_DIR,
- "No trusted dirservers are reachable. Trying them all again.");
- mark_all_trusteddirservers_up();
- return router_pick_trusteddirserver_impl(type, flags, NULL);
+ "No dirservers are reachable. Trying them all again.");
+ mark_all_dirservers_up(sourcelist);
+ return router_pick_trusteddirserver_impl(sourcelist, type, flags, NULL);
}
/** How long do we avoid using a directory server after it's given us a 503? */
@@ -1081,7 +1450,7 @@ router_pick_trusteddirserver(dirinfo_type_t type, int flags)
* routerlist. Arguments are as for router_pick_directory_server(), except
* that RETRY_IF_NO_SERVERS is ignored, and:
*
- * If the _PDS_PREFER_TUNNELED_DIR_CONNS flag is set, prefer directory servers
+ * If the PDS_PREFER_TUNNELED_DIR_CONNS_ flag is set, prefer directory servers
* that we can use with BEGINDIR.
*/
static const routerstatus_t *
@@ -1096,7 +1465,8 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
const networkstatus_t *consensus = networkstatus_get_latest_consensus();
int requireother = ! (flags & PDS_ALLOW_SELF);
int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
- int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
+ int prefer_tunnel = (flags & PDS_PREFER_TUNNELED_DIR_CONNS_);
+ int for_guard = (flags & PDS_FOR_GUARD);
int try_excluding = 1, n_excluded = 0;
if (!consensus)
@@ -1127,12 +1497,6 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
continue;
if (requireother && router_digest_is_me(node->identity))
continue;
- if (type & V3_DIRINFO) {
- if (!(status->version_supports_v3_dir ||
- router_digest_is_trusted_dir_type(node->identity,
- V3_DIRINFO)))
- continue;
- }
is_trusted = router_digest_is_trusted_dir(node->identity);
if ((type & V2_DIRINFO) && !(node->rs->is_v2_dir || is_trusted))
continue;
@@ -1142,6 +1506,8 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
if ((type & MICRODESC_DIRINFO) && !is_trusted &&
!node->rs->version_supports_microdesc_cache)
continue;
+ if (for_guard && node->using_as_guard)
+ continue; /* Don't make the same node a guard twice. */
if (try_excluding &&
routerset_contains_routerstatus(options->ExcludeNodes, status,
country)) {
@@ -1155,7 +1521,6 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
if (prefer_tunnel &&
- status->version_supports_begindir &&
(!fascistfirewall ||
fascist_firewall_allows_address_or(&addr, status->or_port)))
smartlist_add(is_trusted ? trusted_tunnel :
@@ -1203,28 +1568,56 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
return result ? result->rs : NULL;
}
-/** Choose randomly from among the trusted dirservers that are up. Flags
- * are as for router_pick_directory_server_impl().
+/** Pick a random element from a list of dir_server_t, weighting by their
+ * <b>weight</b> field. */
+static const dir_server_t *
+dirserver_choose_by_weight(const smartlist_t *servers, double authority_weight)
+{
+ int n = smartlist_len(servers);
+ int i;
+ u64_dbl_t *weights;
+ const dir_server_t *ds;
+
+ weights = tor_malloc(sizeof(u64_dbl_t) * n);
+ for (i = 0; i < n; ++i) {
+ ds = smartlist_get(servers, i);
+ weights[i].dbl = ds->weight;
+ if (ds->is_authority)
+ weights[i].dbl *= authority_weight;
+ }
+
+ scale_array_elements_to_u64(weights, n, NULL);
+ i = choose_array_element_by_weight(weights, n);
+ tor_free(weights);
+ return (i < 0) ? NULL : smartlist_get(servers, i);
+}
+
+/** Choose randomly from among the dir_server_ts in sourcelist that
+ * are up. Flags are as for router_pick_directory_server_impl().
*/
static const routerstatus_t *
-router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
+router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
+ dirinfo_type_t type, int flags,
int *n_busy_out)
{
const or_options_t *options = get_options();
smartlist_t *direct, *tunnel;
smartlist_t *overloaded_direct, *overloaded_tunnel;
const routerinfo_t *me = router_get_my_routerinfo();
- const routerstatus_t *result;
+ const routerstatus_t *result = NULL;
time_t now = time(NULL);
const int requireother = ! (flags & PDS_ALLOW_SELF);
const int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
- const int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
+ const int prefer_tunnel = (flags & PDS_PREFER_TUNNELED_DIR_CONNS_);
const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH);
const int no_microdesc_fetching =(flags & PDS_NO_EXISTING_MICRODESC_FETCH);
+ const double auth_weight = (sourcelist == fallback_dir_servers) ?
+ options->DirAuthorityFallbackRate : 1.0;
+ smartlist_t *pick_from;
int n_busy = 0;
int try_excluding = 1, n_excluded = 0;
- if (!trusted_dir_servers)
+ if (!sourcelist)
return NULL;
retry_without_exclude:
@@ -1234,7 +1627,7 @@ router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, d)
+ SMARTLIST_FOREACH_BEGIN(sourcelist, const dir_server_t *, d)
{
int is_overloaded =
d->fake_status.last_dir_503_at + DIR_503_TIMEOUT > now;
@@ -1280,23 +1673,29 @@ router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
d->or_port &&
(!fascistfirewall ||
fascist_firewall_allows_address_or(&addr, d->or_port)))
- smartlist_add(is_overloaded ? overloaded_tunnel : tunnel,
- &d->fake_status);
+ smartlist_add(is_overloaded ? overloaded_tunnel : tunnel, (void*)d);
else if (!fascistfirewall ||
fascist_firewall_allows_address_dir(&addr, d->dir_port))
- smartlist_add(is_overloaded ? overloaded_direct : direct,
- &d->fake_status);
+ smartlist_add(is_overloaded ? overloaded_direct : direct, (void*)d);
}
SMARTLIST_FOREACH_END(d);
if (smartlist_len(tunnel)) {
- result = smartlist_choose(tunnel);
+ pick_from = tunnel;
} else if (smartlist_len(overloaded_tunnel)) {
- result = smartlist_choose(overloaded_tunnel);
+ pick_from = overloaded_tunnel;
} else if (smartlist_len(direct)) {
- result = smartlist_choose(direct);
+ pick_from = direct;
} else {
- result = smartlist_choose(overloaded_direct);
+ pick_from = overloaded_direct;
+ }
+
+ {
+ const dir_server_t *selection =
+ dirserver_choose_by_weight(pick_from, auth_weight);
+
+ if (selection)
+ result = &selection->fake_status;
}
if (n_busy_out)
@@ -1318,19 +1717,19 @@ router_pick_trusteddirserver_impl(dirinfo_type_t type, int flags,
return result;
}
-/** Go through and mark the authoritative dirservers as up. */
+/** Mark as running every dir_server_t in <b>server_list</b>. */
static void
-mark_all_trusteddirservers_up(void)
+mark_all_dirservers_up(smartlist_t *server_list)
{
- SMARTLIST_FOREACH(nodelist_get_list(), node_t *, node, {
- if (router_digest_is_trusted_dir(node->identity))
- node->is_running = 1;
- });
- if (trusted_dir_servers) {
- SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, dir) {
+ if (server_list) {
+ SMARTLIST_FOREACH_BEGIN(server_list, dir_server_t *, dir) {
routerstatus_t *rs;
+ node_t *node;
dir->is_running = 1;
download_status_reset(&dir->v2_ns_dl_status);
+ node = node_get_mutable_by_id(dir->digest);
+ if (node)
+ node->is_running = 1;
rs = router_get_mutable_consensus_status_by_id(dir->digest);
if (rs) {
rs->last_dir_503_at = 0;
@@ -1343,9 +1742,11 @@ mark_all_trusteddirservers_up(void)
/** Return true iff r1 and r2 have the same address and OR port. */
int
-routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2)
+routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2)
{
- return r1->addr == r2->addr && r1->or_port == r2->or_port;
+ return r1->addr == r2->addr && r1->or_port == r2->or_port &&
+ tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) &&
+ r1->ipv6_orport == r2->ipv6_orport;
}
/** Reset all internal variables used to count failed downloads of network
@@ -1353,89 +1754,7 @@ routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2)
void
router_reset_status_download_failures(void)
{
- mark_all_trusteddirservers_up();
-}
-
-/** Return true iff router1 and router2 have similar enough network addresses
- * that we should treat them as being in the same family */
-static INLINE int
-addrs_in_same_network_family(const tor_addr_t *a1,
- const tor_addr_t *a2)
-{
- /* XXXX MOVE ? */
- return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC);
-}
-
-/**
- * Add all the family of <b>node</b>, including <b>node</b> itself, to
- * the smartlist <b>sl</b>.
- *
- * This is used to make sure we don't pick siblings in a single path, or
- * pick more than one relay from a family for our entry guard list.
- * Note that a node may be added to <b>sl</b> more than once if it is
- * part of <b>node</b>'s family for more than one reason.
- */
-void
-nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
-{
- /* XXXX MOVE */
- const smartlist_t *all_nodes = nodelist_get_list();
- const smartlist_t *declared_family;
- const or_options_t *options = get_options();
-
- tor_assert(node);
-
- declared_family = node_get_declared_family(node);
-
- /* Let's make sure that we have the node itself, if it's a real node. */
- {
- const node_t *real_node = node_get_by_id(node->identity);
- if (real_node)
- smartlist_add(sl, (node_t*)real_node);
- }
-
- /* First, add any nodes with similar network addresses. */
- if (options->EnforceDistinctSubnets) {
- tor_addr_t node_addr;
- node_get_addr(node, &node_addr);
-
- SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) {
- tor_addr_t a;
- node_get_addr(node2, &a);
- if (addrs_in_same_network_family(&a, &node_addr))
- smartlist_add(sl, (void*)node2);
- } SMARTLIST_FOREACH_END(node2);
- }
-
- /* Now, add all nodes in the declared_family of this node, if they
- * also declare this node to be in their family. */
- if (declared_family) {
- /* Add every r such that router declares familyness with node, and node
- * declares familyhood with router. */
- SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) {
- const node_t *node2;
- const smartlist_t *family2;
- if (!(node2 = node_get_by_nickname(name, 0)))
- continue;
- if (!(family2 = node_get_declared_family(node2)))
- continue;
- SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) {
- if (node_nickname_matches(node, name2)) {
- smartlist_add(sl, (void*)node2);
- break;
- }
- } SMARTLIST_FOREACH_END(name2);
- } SMARTLIST_FOREACH_END(name);
- }
-
- /* If the user declared any families locally, honor those too. */
- if (options->NodeFamilySets) {
- SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
- if (routerset_contains_node(rs, node)) {
- routerset_get_all_nodes(sl, rs, NULL, 0);
- }
- });
- }
+ mark_all_dirservers_up(fallback_dir_servers);
}
/** Given a <b>router</b>, add every node_t in its family (including the
@@ -1459,83 +1778,6 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router)
nodelist_add_node_and_family(sl, node);
}
-/** Return true iff <b>node</b> is named by some nickname in <b>lst</b>. */
-static INLINE int
-node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node)
-{
- /* XXXX MOVE */
- if (!lst) return 0;
- SMARTLIST_FOREACH(lst, const char *, name, {
- if (node_nickname_matches(node, name))
- return 1;
- });
- return 0;
-}
-
-/** Return true iff r1 and r2 are in the same family, but not the same
- * router. */
-int
-nodes_in_same_family(const node_t *node1, const node_t *node2)
-{
- /* XXXX MOVE */
- const or_options_t *options = get_options();
-
- /* Are they in the same family because of their addresses? */
- if (options->EnforceDistinctSubnets) {
- tor_addr_t a1, a2;
- node_get_addr(node1, &a1);
- node_get_addr(node2, &a2);
- if (addrs_in_same_network_family(&a1, &a2))
- return 1;
- }
-
- /* Are they in the same family because the agree they are? */
- {
- const smartlist_t *f1, *f2;
- f1 = node_get_declared_family(node1);
- f2 = node_get_declared_family(node2);
- if (f1 && f2 &&
- node_in_nickname_smartlist(f1, node2) &&
- node_in_nickname_smartlist(f2, node1))
- return 1;
- }
-
- /* Are they in the same option because the user says they are? */
- if (options->NodeFamilySets) {
- SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
- if (routerset_contains_node(rs, node1) &&
- routerset_contains_node(rs, node2))
- return 1;
- });
- }
-
- return 0;
-}
-
-/** Return 1 iff any member of the (possibly NULL) comma-separated list
- * <b>list</b> is an acceptable nickname or hexdigest for <b>router</b>. Else
- * return 0.
- */
-int
-router_nickname_is_in_list(const routerinfo_t *router, const char *list)
-{
- smartlist_t *nickname_list;
- int v = 0;
-
- if (!list)
- return 0; /* definitely not */
- tor_assert(router);
-
- nickname_list = smartlist_new();
- smartlist_split_string(nickname_list, list, ",",
- SPLIT_SKIP_SPACE|SPLIT_STRIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- SMARTLIST_FOREACH(nickname_list, const char *, cp,
- if (router_nickname_matches(router, cp)) {v=1;break;});
- SMARTLIST_FOREACH(nickname_list, char *, cp, tor_free(cp));
- smartlist_free(nickname_list);
- return v;
-}
-
/** Add every suitable node from our nodelist to <b>sl</b>, so that
* we can pick a node for a circuit.
*/
@@ -1575,56 +1817,6 @@ routerlist_find_my_routerinfo(void)
return NULL;
}
-/** Find a router that's up, that has this IP address, and
- * that allows exit to this address:port, or return NULL if there
- * isn't a good one.
- * Don't exit enclave to excluded relays -- it wouldn't actually
- * hurt anything, but this way there are fewer confused users.
- */
-const node_t *
-router_find_exact_exit_enclave(const char *address, uint16_t port)
-{/*XXXX MOVE*/
- uint32_t addr;
- struct in_addr in;
- tor_addr_t a;
- const or_options_t *options = get_options();
-
- if (!tor_inet_aton(address, &in))
- return NULL; /* it's not an IP already */
- addr = ntohl(in.s_addr);
-
- tor_addr_from_ipv4h(&a, addr);
-
- SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
- if (node_get_addr_ipv4h(node) == addr &&
- node->is_running &&
- compare_tor_addr_to_node_policy(&a, port, node) ==
- ADDR_POLICY_ACCEPTED &&
- !routerset_contains_node(options->_ExcludeExitNodesUnion, node))
- return node;
- });
- return NULL;
-}
-
-/** Return 1 if <b>router</b> is not suitable for these parameters, else 0.
- * If <b>need_uptime</b> is non-zero, we require a minimum uptime.
- * If <b>need_capacity</b> is non-zero, we require a minimum advertised
- * bandwidth.
- * If <b>need_guard</b>, we require that the router is a possible entry guard.
- */
-int
-node_is_unreliable(const node_t *node, int need_uptime,
- int need_capacity, int need_guard)
-{
- if (need_uptime && !node->is_stable)
- return 1;
- if (need_capacity && !node->is_fast)
- return 1;
- if (need_guard && !node->is_possible_guard)
- return 1;
- return 0;
-}
-
/** Return the smaller of the router's configured BandwidthRate
* and its advertised capacity. */
uint32_t
@@ -1652,6 +1844,92 @@ router_get_advertised_bandwidth_capped(const routerinfo_t *router)
return result;
}
+/** Given an array of double/uint64_t unions that are currently being used as
+ * doubles, convert them to uint64_t, and try to scale them linearly so as to
+ * much of the range of uint64_t. If <b>total_out</b> is provided, set it to
+ * the sum of all elements in the array _before_ scaling. */
+/* private */ void
+scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
+ uint64_t *total_out)
+{
+ double total = 0.0;
+ double scale_factor;
+ int i;
+ /* big, but far away from overflowing an int64_t */
+#define SCALE_TO_U64_MAX (INT64_MAX / 4)
+
+ for (i = 0; i < n_entries; ++i)
+ total += entries[i].dbl;
+
+ scale_factor = SCALE_TO_U64_MAX / total;
+
+ for (i = 0; i < n_entries; ++i)
+ entries[i].u64 = tor_llround(entries[i].dbl * scale_factor);
+
+ if (total_out)
+ *total_out = (uint64_t) total;
+
+#undef SCALE_TO_U64_MAX
+}
+
+/** Time-invariant 64-bit greater-than; works on two integers in the range
+ * (0,INT64_MAX). */
+#if SIZEOF_VOID_P == 8
+#define gt_i64_timei(a,b) ((a) > (b))
+#else
+static INLINE int
+gt_i64_timei(uint64_t a, uint64_t b)
+{
+ int64_t diff = (int64_t) (b - a);
+ int res = diff >> 63;
+ return res & 1;
+}
+#endif
+
+/** Pick a random element of <b>n_entries</b>-element array <b>entries</b>,
+ * choosing each element with a probability proportional to its (uint64_t)
+ * value, and return the index of that element. If all elements are 0, choose
+ * an index at random. Return -1 on error.
+ */
+/* private */ int
+choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries)
+{
+ int i, i_chosen=-1, n_chosen=0;
+ uint64_t total_so_far = 0;
+ uint64_t rand_val;
+ uint64_t total = 0;
+
+ for (i = 0; i < n_entries; ++i)
+ total += entries[i].u64;
+
+ if (n_entries < 1)
+ return -1;
+
+ if (total == 0)
+ return crypto_rand_int(n_entries);
+
+ tor_assert(total < INT64_MAX);
+
+ rand_val = crypto_rand_uint64(total);
+
+ for (i = 0; i < n_entries; ++i) {
+ total_so_far += entries[i].u64;
+ if (gt_i64_timei(total_so_far, rand_val)) {
+ i_chosen = i;
+ n_chosen++;
+ /* Set rand_val to INT64_MAX rather than stopping the loop. This way,
+ * the time we spend in the loop does not leak which element we chose. */
+ rand_val = INT64_MAX;
+ }
+ }
+ tor_assert(total_so_far == total);
+ tor_assert(n_chosen == 1);
+ tor_assert(i_chosen >= 0);
+ tor_assert(i_chosen < n_entries);
+
+ return i_chosen;
+}
+
/** When weighting bridges, enforce these values as lower and upper
* bound for believable bandwidth, because there is no way for us
* to verify a bridge's bandwidth currently. */
@@ -1698,20 +1976,40 @@ kb_to_bytes(uint32_t bw)
* guards proportionally less.
*/
static const node_t *
-smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
+smartlist_choose_node_by_bandwidth_weights(const smartlist_t *sl,
bandwidth_weight_rule_t rule)
{
+ u64_dbl_t *bandwidths=NULL;
+
+ if (compute_weighted_bandwidths(sl, rule, &bandwidths) < 0)
+ return NULL;
+
+ scale_array_elements_to_u64(bandwidths, smartlist_len(sl),
+ &sl_last_total_weighted_bw);
+
+ {
+ int idx = choose_array_element_by_weight(bandwidths,
+ smartlist_len(sl));
+ tor_free(bandwidths);
+ return idx < 0 ? NULL : smartlist_get(sl, idx);
+ }
+}
+
+/** Given a list of routers and a weighting rule as in
+ * smartlist_choose_node_by_bandwidth_weights, compute weighted bandwidth
+ * values for each node and store them in a freshly allocated
+ * *<b>bandwidths_out</b> of the same length as <b>sl</b>, and holding results
+ * as doubles. Return 0 on success, -1 on failure. */
+static int
+compute_weighted_bandwidths(const smartlist_t *sl,
+ bandwidth_weight_rule_t rule,
+ u64_dbl_t **bandwidths_out)
+{
int64_t weight_scale;
- int64_t rand_bw;
double Wg = -1, Wm = -1, We = -1, Wd = -1;
double Wgb = -1, Wmb = -1, Web = -1, Wdb = -1;
- double weighted_bw = 0, unweighted_bw = 0;
- double *bandwidths;
- double tmp = 0;
- unsigned int i;
- unsigned int i_chosen;
- unsigned int i_has_been_chosen;
- int have_unknown = 0; /* true iff sl contains element not in consensus. */
+ uint64_t weighted_bw = 0;
+ u64_dbl_t *bandwidths;
/* Can't choose exit and guard at same time */
tor_assert(rule == NO_WEIGHTING ||
@@ -1725,10 +2023,10 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
"Empty routerlist passed in to consensus weight node "
"selection for rule %s",
bandwidth_weight_rule_to_string(rule));
- return NULL;
+ return -1;
}
- weight_scale = circuit_build_times_get_bw_scale(NULL);
+ weight_scale = networkstatus_get_weight_scale_param(NULL);
if (rule == WEIGHT_FOR_GUARD) {
Wg = networkstatus_get_bw_weight(NULL, "Wgg", -1);
@@ -1779,7 +2077,7 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
log_debug(LD_CIRC,
"Got negative bandwidth weights. Defaulting to old selection"
" algorithm.");
- return NULL; // Use old algorithm.
+ return -1; // Use old algorithm.
}
Wg /= weight_scale;
@@ -1792,7 +2090,7 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
Web /= weight_scale;
Wdb /= weight_scale;
- bandwidths = tor_malloc_zero(sizeof(double)*smartlist_len(sl));
+ bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl));
// Cycle through smartlist and total the bandwidth.
SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
@@ -1809,13 +2107,12 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
log_warn(LD_BUG,
"Consensus is not listing bandwidths. Defaulting back to "
"old router selection algorithm.");
- return NULL;
+ return -1;
}
- this_bw = kb_to_bytes(node->rs->bandwidth);
+ this_bw = kb_to_bytes(node->rs->bandwidth_kb);
} else if (node->ri) {
/* bridge or other descriptor not in our consensus */
this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
- have_unknown = 1;
} else {
/* We can't use this one. */
continue;
@@ -1831,72 +2128,65 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
} else { // middle
weight = (is_dir ? Wmb*Wm : Wm);
}
-
- bandwidths[node_sl_idx] = weight*this_bw;
- weighted_bw += weight*this_bw;
- unweighted_bw += this_bw;
+ /* These should be impossible; but overflows here would be bad, so let's
+ * make sure. */
+ if (this_bw < 0)
+ this_bw = 0;
+ if (weight < 0.0)
+ weight = 0.0;
+
+ bandwidths[node_sl_idx].dbl = weight*this_bw + 0.5;
if (is_me)
- sl_last_weighted_bw_of_me = weight*this_bw;
+ sl_last_weighted_bw_of_me = (uint64_t) bandwidths[node_sl_idx].dbl;
} SMARTLIST_FOREACH_END(node);
- /* XXXX this is a kludge to expose these values. */
- sl_last_total_weighted_bw = weighted_bw;
-
- log_debug(LD_CIRC, "Choosing node for rule %s based on weights "
- "Wg=%f Wm=%f We=%f Wd=%f with total bw %f",
+ log_debug(LD_CIRC, "Generated weighted bandwidths for rule %s based "
+ "on weights "
+ "Wg=%f Wm=%f We=%f Wd=%f with total bw "U64_FORMAT,
bandwidth_weight_rule_to_string(rule),
- Wg, Wm, We, Wd, weighted_bw);
-
- /* If there is no bandwidth, choose at random */
- if (DBL_TO_U64(weighted_bw) == 0) {
- /* Don't warn when using bridges/relays not in the consensus */
- if (!have_unknown) {
-#define ZERO_BANDWIDTH_WARNING_INTERVAL (15)
- static ratelim_t zero_bandwidth_warning_limit =
- RATELIM_INIT(ZERO_BANDWIDTH_WARNING_INTERVAL);
- char *msg;
- if ((msg = rate_limit_log(&zero_bandwidth_warning_limit,
- approx_time()))) {
- log_warn(LD_CIRC,
- "Weighted bandwidth is %f in node selection for rule %s "
- "(unweighted was %f) %s",
- weighted_bw, bandwidth_weight_rule_to_string(rule),
- unweighted_bw, msg);
- }
- }
- tor_free(bandwidths);
- return smartlist_choose(sl);
- }
+ Wg, Wm, We, Wd, U64_PRINTF_ARG(weighted_bw));
- rand_bw = crypto_rand_uint64(DBL_TO_U64(weighted_bw));
- rand_bw++; /* crypto_rand_uint64() counts from 0, and we need to count
- * from 1 below. See bug 1203 for details. */
+ *bandwidths_out = bandwidths;
- /* Last, count through sl until we get to the element we picked */
- i_chosen = (unsigned)smartlist_len(sl);
- i_has_been_chosen = 0;
- tmp = 0.0;
- for (i=0; i < (unsigned)smartlist_len(sl); i++) {
- tmp += bandwidths[i];
- if (tmp >= rand_bw && !i_has_been_chosen) {
- i_chosen = i;
- i_has_been_chosen = 1;
- }
- }
- i = i_chosen;
+ return 0;
+}
+
+/** For all nodes in <b>sl</b>, return the fraction of those nodes, weighted
+ * by their weighted bandwidths with rule <b>rule</b>, for which we have
+ * descriptors. */
+double
+frac_nodes_with_descriptors(const smartlist_t *sl,
+ bandwidth_weight_rule_t rule)
+{
+ u64_dbl_t *bandwidths = NULL;
+ double total, present;
- if (i == (unsigned)smartlist_len(sl)) {
- /* This was once possible due to round-off error, but shouldn't be able
- * to occur any longer. */
- tor_fragile_assert();
- --i;
- log_warn(LD_BUG, "Round-off error in computing bandwidth had an effect on "
- " which router we chose. Please tell the developers. "
- "%f " U64_FORMAT " %f", tmp, U64_PRINTF_ARG(rand_bw),
- weighted_bw);
+ if (smartlist_len(sl) == 0)
+ return 0.0;
+
+ if (compute_weighted_bandwidths(sl, rule, &bandwidths) < 0) {
+ int n_with_descs = 0;
+ SMARTLIST_FOREACH(sl, const node_t *, node, {
+ if (node_has_descriptor(node))
+ n_with_descs++;
+ });
+ return ((double)n_with_descs) / (double)smartlist_len(sl);
}
+
+ total = present = 0.0;
+ SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
+ const double bw = bandwidths[node_sl_idx].dbl;
+ total += bw;
+ if (node_has_descriptor(node))
+ present += bw;
+ } SMARTLIST_FOREACH_END(node);
+
tor_free(bandwidths);
- return smartlist_get(sl, i);
+
+ if (total < 1.0)
+ return 0;
+
+ return present / total;
}
/** Helper function:
@@ -1913,21 +2203,20 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
* guards proportionally less.
*/
static const node_t *
-smartlist_choose_node_by_bandwidth(smartlist_t *sl,
+smartlist_choose_node_by_bandwidth(const smartlist_t *sl,
bandwidth_weight_rule_t rule)
{
unsigned int i;
- unsigned int i_chosen;
- unsigned int i_has_been_chosen;
- int32_t *bandwidths;
+ u64_dbl_t *bandwidths;
int is_exit;
int is_guard;
- uint64_t total_nonexit_bw = 0, total_exit_bw = 0, total_bw = 0;
- uint64_t total_nonguard_bw = 0, total_guard_bw = 0;
- uint64_t rand_bw, tmp;
+ int is_fast;
+ double total_nonexit_bw = 0, total_exit_bw = 0;
+ double total_nonguard_bw = 0, total_guard_bw = 0;
double exit_weight;
double guard_weight;
int n_unknown = 0;
+ bitarray_t *fast_bits;
bitarray_t *exit_bits;
bitarray_t *guard_bits;
int me_idx = -1;
@@ -1951,10 +2240,9 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
}
/* First count the total bandwidth weight, and make a list
- * of each value. <0 means "unknown; no routerinfo." We use the
- * bits of negative values to remember whether the router was fast (-x)&1
- * and whether it was an exit (-x)&2 or guard (-x)&4. Yes, it's a hack. */
- bandwidths = tor_malloc(sizeof(int32_t)*smartlist_len(sl));
+ * of each value. We use UINT64_MAX to indicate "unknown". */
+ bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl));
+ fast_bits = bitarray_init_zero(smartlist_len(sl));
exit_bits = bitarray_init_zero(smartlist_len(sl));
guard_bits = bitarray_init_zero(smartlist_len(sl));
@@ -1962,7 +2250,6 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
/* first, learn what bandwidth we think i has */
int is_known = 1;
- int32_t flags = 0;
uint32_t this_bw = 0;
i = node_sl_idx;
@@ -1973,14 +2260,9 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
is_guard = node->is_possible_guard;
if (node->rs) {
if (node->rs->has_bandwidth) {
- this_bw = kb_to_bytes(node->rs->bandwidth);
+ this_bw = kb_to_bytes(node->rs->bandwidth_kb);
} else { /* guess */
- /* XXX024 once consensuses always list bandwidths, we can take
- * this guessing business out. -RD */
is_known = 0;
- flags = node->rs->is_fast ? 1 : 0;
- flags |= is_exit ? 2 : 0;
- flags |= is_guard ? 4 : 0;
}
} else if (node->ri) {
/* Must be a bridge if we're willing to use it */
@@ -1991,12 +2273,11 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
bitarray_set(exit_bits, i);
if (is_guard)
bitarray_set(guard_bits, i);
+ if (node->is_fast)
+ bitarray_set(fast_bits, i);
+
if (is_known) {
- bandwidths[i] = (int32_t) this_bw;
- /* Casting this_bw to int32_t is safe because both kb_to_bytes
- and bridge_get_advertised_bandwidth_bounded limit it to below
- INT32_MAX. */
- tor_assert(bandwidths[i] >= 0);
+ bandwidths[i].dbl = this_bw;
if (is_guard)
total_guard_bw += this_bw;
else
@@ -2007,14 +2288,16 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
total_nonexit_bw += this_bw;
} else {
++n_unknown;
- bandwidths[node_sl_idx] = -flags;
+ bandwidths[i].dbl = -1.0;
}
} SMARTLIST_FOREACH_END(node);
+#define EPSILON .1
+
/* Now, fill in the unknown values. */
if (n_unknown) {
int32_t avg_fast, avg_slow;
- if (total_exit_bw+total_nonexit_bw) {
+ if (total_exit_bw+total_nonexit_bw < EPSILON) {
/* if there's some bandwidth, there's at least one known router,
* so no worries about div by 0 here */
int n_known = smartlist_len(sl)-n_unknown;
@@ -2025,26 +2308,27 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
avg_slow = 20000;
}
for (i=0; i<(unsigned)smartlist_len(sl); ++i) {
- int32_t bw = bandwidths[i];
- if (bw>=0)
+ if (bandwidths[i].dbl >= 0.0)
continue;
- is_exit = ((-bw)&2);
- is_guard = ((-bw)&4);
- bandwidths[i] = ((-bw)&1) ? avg_fast : avg_slow;
+ is_fast = bitarray_is_set(fast_bits, i);
+ is_exit = bitarray_is_set(exit_bits, i);
+ is_guard = bitarray_is_set(guard_bits, i);
+ bandwidths[i].dbl = is_fast ? avg_fast : avg_slow;
if (is_exit)
- total_exit_bw += bandwidths[i];
+ total_exit_bw += bandwidths[i].dbl;
else
- total_nonexit_bw += bandwidths[i];
+ total_nonexit_bw += bandwidths[i].dbl;
if (is_guard)
- total_guard_bw += bandwidths[i];
+ total_guard_bw += bandwidths[i].dbl;
else
- total_nonguard_bw += bandwidths[i];
+ total_nonguard_bw += bandwidths[i].dbl;
}
}
/* If there's no bandwidth at all, pick at random. */
- if (!(total_exit_bw+total_nonexit_bw)) {
+ if (total_exit_bw+total_nonexit_bw < EPSILON) {
tor_free(bandwidths);
+ tor_free(fast_bits);
tor_free(exit_bits);
tor_free(guard_bits);
return smartlist_choose(sl);
@@ -2059,12 +2343,12 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
* For detailed derivation of this formula, see
* http://archives.seul.org/or/dev/Jul-2007/msg00056.html
*/
- if (rule == WEIGHT_FOR_EXIT || !total_exit_bw)
+ if (rule == WEIGHT_FOR_EXIT || total_exit_bw<EPSILON)
exit_weight = 1.0;
else
exit_weight = 1.0 - all_bw/(3.0*exit_bw);
- if (rule == WEIGHT_FOR_GUARD || !total_guard_bw)
+ if (rule == WEIGHT_FOR_GUARD || total_guard_bw<EPSILON)
guard_weight = 1.0;
else
guard_weight = 1.0 - all_bw/(3.0*guard_bw);
@@ -2075,29 +2359,25 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
if (guard_weight <= 0.0)
guard_weight = 0.0;
- total_bw = 0;
sl_last_weighted_bw_of_me = 0;
for (i=0; i < (unsigned)smartlist_len(sl); i++) {
- uint64_t bw;
+ tor_assert(bandwidths[i].dbl >= 0.0);
+
is_exit = bitarray_is_set(exit_bits, i);
is_guard = bitarray_is_set(guard_bits, i);
if (is_exit && is_guard)
- bw = ((uint64_t)(bandwidths[i] * exit_weight * guard_weight));
+ bandwidths[i].dbl *= exit_weight * guard_weight;
else if (is_guard)
- bw = ((uint64_t)(bandwidths[i] * guard_weight));
+ bandwidths[i].dbl *= guard_weight;
else if (is_exit)
- bw = ((uint64_t)(bandwidths[i] * exit_weight));
- else
- bw = bandwidths[i];
- total_bw += bw;
+ bandwidths[i].dbl *= exit_weight;
+
if (i == (unsigned) me_idx)
- sl_last_weighted_bw_of_me = bw;
+ sl_last_weighted_bw_of_me = (uint64_t) bandwidths[i].dbl;
}
}
- /* XXXX this is a kludge to expose these values. */
- sl_last_total_weighted_bw = total_bw;
-
+#if 0
log_debug(LD_CIRC, "Total weighted bw = "U64_FORMAT
", exit bw = "U64_FORMAT
", nonexit bw = "U64_FORMAT", exit weight = %f "
@@ -2110,56 +2390,26 @@ smartlist_choose_node_by_bandwidth(smartlist_t *sl,
exit_weight, (int)(rule == WEIGHT_FOR_EXIT),
U64_PRINTF_ARG(total_guard_bw), U64_PRINTF_ARG(total_nonguard_bw),
guard_weight, (int)(rule == WEIGHT_FOR_GUARD));
+#endif
- /* Almost done: choose a random value from the bandwidth weights. */
- rand_bw = crypto_rand_uint64(total_bw);
- rand_bw++; /* crypto_rand_uint64() counts from 0, and we need to count
- * from 1 below. See bug 1203 for details. */
-
- /* Last, count through sl until we get to the element we picked */
- tmp = 0;
- i_chosen = (unsigned)smartlist_len(sl);
- i_has_been_chosen = 0;
- for (i=0; i < (unsigned)smartlist_len(sl); i++) {
- is_exit = bitarray_is_set(exit_bits, i);
- is_guard = bitarray_is_set(guard_bits, i);
-
- /* Weights can be 0 if not counting guards/exits */
- if (is_exit && is_guard)
- tmp += ((uint64_t)(bandwidths[i] * exit_weight * guard_weight));
- else if (is_guard)
- tmp += ((uint64_t)(bandwidths[i] * guard_weight));
- else if (is_exit)
- tmp += ((uint64_t)(bandwidths[i] * exit_weight));
- else
- tmp += bandwidths[i];
+ scale_array_elements_to_u64(bandwidths, smartlist_len(sl),
+ &sl_last_total_weighted_bw);
- if (tmp >= rand_bw && !i_has_been_chosen) {
- i_chosen = i;
- i_has_been_chosen = 1;
- }
- }
- i = i_chosen;
- if (i == (unsigned)smartlist_len(sl)) {
- /* This was once possible due to round-off error, but shouldn't be able
- * to occur any longer. */
- tor_fragile_assert();
- --i;
- log_warn(LD_BUG, "Round-off error in computing bandwidth had an effect on "
- " which router we chose. Please tell the developers. "
- U64_FORMAT " " U64_FORMAT " " U64_FORMAT, U64_PRINTF_ARG(tmp),
- U64_PRINTF_ARG(rand_bw), U64_PRINTF_ARG(total_bw));
+ {
+ int idx = choose_array_element_by_weight(bandwidths,
+ smartlist_len(sl));
+ tor_free(bandwidths);
+ tor_free(fast_bits);
+ tor_free(exit_bits);
+ tor_free(guard_bits);
+ return idx < 0 ? NULL : smartlist_get(sl, idx);
}
- tor_free(bandwidths);
- tor_free(exit_bits);
- tor_free(guard_bits);
- return smartlist_get(sl, i);
}
/** Choose a random element of status list <b>sl</b>, weighted by
* the advertised bandwidth of each node */
const node_t *
-node_sl_choose_by_bandwidth(smartlist_t *sl,
+node_sl_choose_by_bandwidth(const smartlist_t *sl,
bandwidth_weight_rule_t rule)
{ /*XXXX MOVE */
const node_t *ret;
@@ -2306,7 +2556,7 @@ hex_digest_nickname_decode(const char *hexdigest,
* combination of a router, encoded in hexadecimal, matches <b>hexdigest</b>
* (which is optionally prefixed with a single dollar sign). Return false if
* <b>hexdigest</b> is malformed, or it doesn't match. */
-static int
+int
hex_digest_nickname_matches(const char *hexdigest, const char *identity_digest,
const char *nickname, int is_named)
{
@@ -2354,141 +2604,6 @@ router_hex_digest_matches(const routerinfo_t *router, const char *hexdigest)
router_is_named(router));
}
-/** Return true if <b>router</b>'s nickname matches <b>nickname</b>
- * (case-insensitive), or if <b>router's</b> identity key digest
- * matches a hexadecimal value stored in <b>nickname</b>. Return
- * false otherwise. */
-static int
-router_nickname_matches(const routerinfo_t *router, const char *nickname)
-{
- if (nickname[0]!='$' && !strcasecmp(router->nickname, nickname))
- return 1;
- return router_hex_digest_matches(router, nickname);
-}
-
-/** Return true if <b>node</b>'s nickname matches <b>nickname</b>
- * (case-insensitive), or if <b>node's</b> identity key digest
- * matches a hexadecimal value stored in <b>nickname</b>. Return
- * false otherwise. */
-static int
-node_nickname_matches(const node_t *node, const char *nickname)
-{
- const char *n = node_get_nickname(node);
- if (n && nickname[0]!='$' && !strcasecmp(n, nickname))
- return 1;
- return hex_digest_nickname_matches(nickname,
- node->identity,
- n,
- node_is_named(node));
-}
-
-/** Return the router in our routerlist whose (case-insensitive)
- * nickname or (case-sensitive) hexadecimal key digest is
- * <b>nickname</b>. Return NULL if no such router is known.
- */
-const routerinfo_t *
-router_get_by_nickname(const char *nickname, int warn_if_unnamed)
-{
-#if 1
- const node_t *node = node_get_by_nickname(nickname, warn_if_unnamed);
- if (node)
- return node->ri;
- else
- return NULL;
-#else
- int maybedigest;
- char digest[DIGEST_LEN];
- routerinfo_t *best_match=NULL;
- int n_matches = 0;
- const char *named_digest = NULL;
-
- tor_assert(nickname);
- if (!routerlist)
- return NULL;
- if (nickname[0] == '$')
- return router_get_by_hexdigest(nickname);
- if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME))
- return NULL;
-
- maybedigest = (strlen(nickname) >= HEX_DIGEST_LEN) &&
- (base16_decode(digest,DIGEST_LEN,nickname,HEX_DIGEST_LEN) == 0);
-
- if ((named_digest = networkstatus_get_router_digest_by_nickname(nickname))) {
- return rimap_get(routerlist->identity_map, named_digest);
- }
- if (networkstatus_nickname_is_unnamed(nickname))
- return NULL;
-
- /* If we reach this point, there's no canonical value for the nickname. */
-
- SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
- {
- if (!strcasecmp(router->nickname, nickname)) {
- ++n_matches;
- if (n_matches <= 1 || router->is_running)
- best_match = router;
- } else if (maybedigest &&
- tor_memeq(digest, router->cache_info.identity_digest,
- DIGEST_LEN)) {
- if (router_hex_digest_matches(router, nickname))
- return router;
- /* If we reach this point, we have a ID=name syntax that matches the
- * identity but not the name. That isn't an acceptable match. */
- }
- });
-
- if (best_match) {
- if (warn_if_unnamed && n_matches > 1) {
- smartlist_t *fps = smartlist_new();
- int any_unwarned = 0;
- SMARTLIST_FOREACH_BEGIN(routerlist->routers, routerinfo_t *, router) {
- routerstatus_t *rs;
- char fp[HEX_DIGEST_LEN+1];
- if (strcasecmp(router->nickname, nickname))
- continue;
- rs = router_get_mutable_consensus_status_by_id(
- router->cache_info.identity_digest);
- if (rs && !rs->name_lookup_warned) {
- rs->name_lookup_warned = 1;
- any_unwarned = 1;
- }
- base16_encode(fp, sizeof(fp),
- router->cache_info.identity_digest, DIGEST_LEN);
- smartlist_add_asprintf(fps, "\"$%s\" for the one at %s:%d",
- fp, router->address, router->or_port);
- } SMARTLIST_FOREACH_END(router);
- if (any_unwarned) {
- char *alternatives = smartlist_join_strings(fps, "; ",0,NULL);
- log_warn(LD_CONFIG,
- "There are multiple matches for the nickname \"%s\","
- " but none is listed as named by the directory authorities. "
- "Choosing one arbitrarily. If you meant one in particular, "
- "you should say %s.", nickname, alternatives);
- tor_free(alternatives);
- }
- SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
- smartlist_free(fps);
- } else if (warn_if_unnamed) {
- routerstatus_t *rs = router_get_mutable_consensus_status_by_id(
- best_match->cache_info.identity_digest);
- if (rs && !rs->name_lookup_warned) {
- char fp[HEX_DIGEST_LEN+1];
- base16_encode(fp, sizeof(fp),
- best_match->cache_info.identity_digest, DIGEST_LEN);
- log_warn(LD_CONFIG, "You specified a server \"%s\" by name, but this "
- "name is not registered, so it could be used by any server, "
- "not just the one you meant. "
- "To make sure you get the same server in the future, refer to "
- "it by key, as \"$%s\".", nickname, fp);
- rs->name_lookup_warned = 1;
- }
- }
- return best_match;
- }
- return NULL;
-#endif
-}
-
/** Return true iff <b>digest</b> is the digest of the identity key of a
* trusted directory matching at least one bit of <b>type</b>. If <b>type</b>
* is zero, any authority is okay. */
@@ -2499,7 +2614,7 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
return 0;
if (authdir_mode(get_options()) && router_digest_is_me(digest))
return 1;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ent,
if (tor_memeq(digest, ent->digest, DIGEST_LEN)) {
return (!type) || ((type & ent->type) != 0);
});
@@ -2513,7 +2628,7 @@ router_addr_is_trusted_dir(uint32_t addr)
{
if (!trusted_dir_servers)
return 0;
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
+ SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ent,
if (ent->addr == addr)
return 1;
);
@@ -2535,18 +2650,6 @@ hexdigest_to_digest(const char *hexdigest, char *digest)
return 0;
}
-/** Return the router in our routerlist whose hexadecimal key digest
- * is <b>hexdigest</b>. Return NULL if no such router is known. */
-const routerinfo_t *
-router_get_by_hexdigest(const char *hexdigest)
-{
- if (is_legal_nickname(hexdigest))
- return NULL;
-
- /* It's not a legal nickname, so it must be a hexdigest or nothing. */
- return router_get_by_nickname(hexdigest, 1);
-}
-
/** As router_get_by_id_digest,but return a pointer that you're allowed to
* modify */
routerinfo_t *
@@ -2721,6 +2824,7 @@ routerinfo_free(routerinfo_t *router)
tor_free(router->contact_info);
if (router->onion_pkey)
crypto_pk_free(router->onion_pkey);
+ tor_free(router->onion_curve25519_pkey);
if (router->identity_pkey)
crypto_pk_free(router->identity_pkey);
if (router->declared_family) {
@@ -2728,6 +2832,7 @@ routerinfo_free(routerinfo_t *router)
smartlist_free(router->declared_family);
}
addr_policy_list_free(router->exit_policy);
+ short_policy_free(router->ipv6_exit_policy);
memset(router, 77, sizeof(routerinfo_t));
@@ -2778,7 +2883,7 @@ signed_descriptor_from_routerinfo(routerinfo_t *ri)
/** Helper: free the storage held by the extrainfo_t in <b>e</b>. */
static void
-_extrainfo_free(void *e)
+extrainfo_free_(void *e)
{
extrainfo_free(e);
}
@@ -2792,7 +2897,7 @@ routerlist_free(routerlist_t *rl)
rimap_free(rl->identity_map, NULL);
sdmap_free(rl->desc_digest_map, NULL);
sdmap_free(rl->desc_by_eid_map, NULL);
- eimap_free(rl->extra_info_map, _extrainfo_free);
+ eimap_free(rl->extra_info_map, extrainfo_free_);
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
routerinfo_free(r));
SMARTLIST_FOREACH(rl->old_routers, signed_descriptor_t *, sd,
@@ -2822,7 +2927,7 @@ dump_routerlist_mem_usage(int severity)
SMARTLIST_FOREACH(routerlist->old_routers, signed_descriptor_t *, sd,
olddescs += sd->signed_descriptor_len);
- log(severity, LD_DIR,
+ tor_log(severity, LD_DIR,
"In %d live descriptors: "U64_FORMAT" bytes. "
"In %d old descriptors: "U64_FORMAT" bytes.",
smartlist_len(routerlist->routers), U64_PRINTF_ARG(livedescs),
@@ -2834,7 +2939,7 @@ dump_routerlist_mem_usage(int severity)
* <b>ri</b>. Return the index of <b>ri</b> in <b>sl</b>, or -1 if <b>ri</b>
* is not in <b>sl</b>. */
static INLINE int
-_routerlist_find_elt(smartlist_t *sl, void *ri, int idx)
+routerlist_find_elt_(smartlist_t *sl, void *ri, int idx)
{
if (idx < 0) {
idx = -1;
@@ -2890,7 +2995,7 @@ routerlist_insert(routerlist_t *rl, routerinfo_t *ri)
&ri->cache_info);
smartlist_add(rl->routers, ri);
ri->cache_info.routerlist_index = smartlist_len(rl->routers) - 1;
- nodelist_add_routerinfo(ri);
+ nodelist_set_routerinfo(ri, NULL);
router_dir_info_changed();
#ifdef DEBUG_ROUTERLIST
routerlist_assert_ok(rl);
@@ -3119,8 +3224,11 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old,
tor_assert(0 <= idx && idx < smartlist_len(rl->routers));
tor_assert(smartlist_get(rl->routers, idx) == ri_old);
- nodelist_remove_routerinfo(ri_old);
- nodelist_add_routerinfo(ri_new);
+ {
+ routerinfo_t *ri_old_tmp=NULL;
+ nodelist_set_routerinfo(ri_new, &ri_old_tmp);
+ tor_assert(ri_old == ri_old_tmp);
+ }
router_dir_info_changed();
if (idx >= 0) {
@@ -3128,7 +3236,7 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old,
ri_old->cache_info.routerlist_index = -1;
ri_new->cache_info.routerlist_index = idx;
/* Check that ri_old is not in rl->routers anymore: */
- tor_assert( _routerlist_find_elt(rl->routers, ri_old, -1) == -1 );
+ tor_assert( routerlist_find_elt_(rl->routers, ri_old, -1) == -1 );
} else {
log_warn(LD_BUG, "Appending entry from routerlist_replace.");
routerlist_insert(rl, ri_new);
@@ -3232,20 +3340,12 @@ routerlist_free_all(void)
smartlist_free(warned_nicknames);
warned_nicknames = NULL;
}
- if (trusted_dir_servers) {
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
- trusted_dir_server_free(ds));
- smartlist_free(trusted_dir_servers);
- trusted_dir_servers = NULL;
- }
+ clear_dir_servers();
+ smartlist_free(trusted_dir_servers);
+ smartlist_free(fallback_dir_servers);
+ trusted_dir_servers = fallback_dir_servers = NULL;
if (trusted_dir_certs) {
- DIGESTMAP_FOREACH(trusted_dir_certs, key, cert_list_t *, cl) {
- SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
- authority_cert_free(cert));
- smartlist_free(cl->certs);
- tor_free(cl);
- } DIGESTMAP_FOREACH_END;
- digestmap_free(trusted_dir_certs, NULL);
+ digestmap_free(trusted_dir_certs, cert_list_free_);
trusted_dir_certs = NULL;
}
}
@@ -3263,33 +3363,6 @@ routerlist_reset_warnings(void)
networkstatus_reset_warnings();
}
-/** Mark the router with ID <b>digest</b> as running or non-running
- * in our routerlist. */
-void
-router_set_status(const char *digest, int up)
-{
- node_t *node;
- tor_assert(digest);
-
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
- if (tor_memeq(d->digest, digest, DIGEST_LEN))
- d->is_running = up);
-
- node = node_get_mutable_by_id(digest);
- if (node) {
-#if 0
- log_debug(LD_DIR,"Marking router %s as %s.",
- node_describe(node), up ? "up" : "down");
-#endif
- if (!up && node_is_me(node) && !net_is_disabled())
- log_warn(LD_NET, "We just marked ourself as down. Are your external "
- "addresses reachable?");
- node->is_running = up;
- }
-
- router_dir_info_changed();
-}
-
/** Add <b>router</b> to the routerlist, if we don't already have it. Replace
* older entries (if any) with the same key. Note: Callers should not hold
* their pointers to <b>router</b> if this function fails; <b>router</b>
@@ -3457,11 +3530,6 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
/* Same key, and either new, or listed in the consensus. */
log_debug(LD_DIR, "Replacing entry for router %s",
router_describe(router));
- if (routers_have_same_or_addr(router, old_router)) {
- /* these carry over when the address and orport are unchanged. */
- router->last_reachable = old_router->last_reachable;
- router->testing_since = old_router->testing_since;
- }
routerlist_replace(routerlist, old_router, router);
if (!from_cache) {
signed_desc_append_to_journal(&router->cache_info,
@@ -3522,7 +3590,7 @@ router_add_extrainfo_to_routerlist(extrainfo_t *ei, const char **msg,
* signed_descriptor_t* in *<b>a</b> has an identity digest preceding, equal
* to, or later than that of *<b>b</b>. */
static int
-_compare_old_routers_by_identity(const void **_a, const void **_b)
+compare_old_routers_by_identity_(const void **_a, const void **_b)
{
int i;
const signed_descriptor_t *r1 = *_a, *r2 = *_b;
@@ -3542,7 +3610,7 @@ struct duration_idx_t {
/** Sorting helper: compare two duration_idx_t by their duration. */
static int
-_compare_duration_idx(const void *_d1, const void *_d2)
+compare_duration_idx_(const void *_d1, const void *_d2)
{
const struct duration_idx_t *d1 = _d1;
const struct duration_idx_t *d2 = _d2;
@@ -3595,7 +3663,7 @@ routerlist_remove_old_cached_routers_with_id(time_t now,
signed_descriptor_t *r_next;
lifespans[i-lo].idx = i;
if (r->last_listed_as_valid_until >= now ||
- (retain && digestset_isin(retain, r->signed_descriptor_digest))) {
+ (retain && digestset_contains(retain, r->signed_descriptor_digest))) {
must_keep[i-lo] = 1;
}
if (i < hi) {
@@ -3619,7 +3687,7 @@ routerlist_remove_old_cached_routers_with_id(time_t now,
* the duration of liveness, and remove the ones we're not already going to
* remove based on how long they were alive.
**/
- qsort(lifespans, n, sizeof(struct duration_idx_t), _compare_duration_idx);
+ qsort(lifespans, n, sizeof(struct duration_idx_t), compare_duration_idx_);
for (i = 0; i < n && n_rmv < n_extra; ++i) {
if (!must_keep[lifespans[i].idx-lo] && !lifespans[i].old) {
rmv[lifespans[i].idx-lo] = 1;
@@ -3729,7 +3797,7 @@ routerlist_remove_old_routers(void)
router = smartlist_get(routerlist->routers, i);
if (router->cache_info.published_on <= cutoff &&
router->cache_info.last_listed_as_valid_until < now &&
- !digestset_isin(retain,
+ !digestset_contains(retain,
router->cache_info.signed_descriptor_digest)) {
/* Too old: remove it. (If we're a cache, just move it into
* old_routers.) */
@@ -3750,7 +3818,7 @@ routerlist_remove_old_routers(void)
sd = smartlist_get(routerlist->old_routers, i);
if (sd->published_on <= cutoff &&
sd->last_listed_as_valid_until < now &&
- !digestset_isin(retain, sd->signed_descriptor_digest)) {
+ !digestset_contains(retain, sd->signed_descriptor_digest)) {
/* Too old. Remove it. */
routerlist_remove_old(routerlist, sd, i--);
}
@@ -3773,7 +3841,7 @@ routerlist_remove_old_routers(void)
goto done;
/* Sort by identity, then fix indices. */
- smartlist_sort(routerlist->old_routers, _compare_old_routers_by_identity);
+ smartlist_sort(routerlist->old_routers, compare_old_routers_by_identity_);
/* Fix indices. */
for (i = 0; i < smartlist_len(routerlist->old_routers); ++i) {
signed_descriptor_t *r = smartlist_get(routerlist->old_routers, i);
@@ -3929,7 +3997,7 @@ router_load_routers_from_string(const char *s, const char *eos,
ri->cache_info.signed_descriptor_digest :
ri->cache_info.identity_digest,
DIGEST_LEN);
- if (smartlist_string_isin(requested_fingerprints, fp)) {
+ if (smartlist_contains_string(requested_fingerprints, fp)) {
smartlist_string_remove(requested_fingerprints, fp);
} else {
char *requested =
@@ -4068,27 +4136,6 @@ routerlist_retry_directory_downloads(time_t now)
update_all_descriptor_downloads(now);
}
-/** Return 1 if all running sufficiently-stable routers we can use will reject
- * addr:port, return 0 if any might accept it. */
-int
-router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
- int need_uptime)
-{ /* XXXX MOVE */
- addr_policy_result_t r;
-
- SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
- if (node->is_running &&
- !node_is_unreliable(node, need_uptime, 0, 0)) {
-
- r = compare_tor_addr_to_node_policy(addr, port, node);
-
- if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
- return 0; /* this one could be ok. good enough. */
- }
- } SMARTLIST_FOREACH_END(node);
- return 1; /* all will reject. */
-}
-
/** Return true iff <b>router</b> does not permit exit streams.
*/
int
@@ -4097,47 +4144,47 @@ router_exit_policy_rejects_all(const routerinfo_t *router)
return router->policy_is_reject_star;
}
-/** Add to the list of authoritative directory servers one at
- * <b>address</b>:<b>port</b>, with identity key <b>digest</b>. If
- * <b>address</b> is NULL, add ourself. Return the new trusted directory
- * server entry on success or NULL if we couldn't add it. */
-trusted_dir_server_t *
-add_trusted_dir_server(const char *nickname, const char *address,
- uint16_t dir_port, uint16_t or_port,
- const char *digest, const char *v3_auth_digest,
- dirinfo_type_t type)
-{
- trusted_dir_server_t *ent;
+/** Create an directory server at <b>address</b>:<b>port</b>, with OR identity
+ * key <b>digest</b>. If <b>address</b> is NULL, add ourself. If
+ * <b>is_authority</b>, this is a directory authority. Return the new
+ * directory server entry on success or NULL on failure. */
+static dir_server_t *
+dir_server_new(int is_authority,
+ const char *nickname,
+ const tor_addr_t *addr,
+ const char *hostname,
+ uint16_t dir_port, uint16_t or_port,
+ const char *digest, const char *v3_auth_digest,
+ dirinfo_type_t type,
+ double weight)
+{
+ dir_server_t *ent;
uint32_t a;
- char *hostname = NULL;
- if (!trusted_dir_servers)
- trusted_dir_servers = smartlist_new();
+ char *hostname_ = NULL;
- if (!address) { /* The address is us; we should guess. */
- if (resolve_my_address(LOG_WARN, get_options(), &a, &hostname) < 0) {
- log_warn(LD_CONFIG,
- "Couldn't find a suitable address when adding ourself as a "
- "trusted directory server.");
- return NULL;
- }
- } else {
- if (tor_lookup_hostname(address, &a)) {
- log_warn(LD_CONFIG,
- "Unable to lookup address for directory server at '%s'",
- address);
- return NULL;
- }
- hostname = tor_strdup(address);
- }
+ if (weight < 0)
+ return NULL;
+
+ if (tor_addr_family(addr) == AF_INET)
+ a = tor_addr_to_ipv4h(addr);
+ else
+ return NULL; /*XXXX Support IPv6 */
+
+ if (!hostname)
+ hostname_ = tor_dup_addr(addr);
+ else
+ hostname_ = tor_strdup(hostname);
- ent = tor_malloc_zero(sizeof(trusted_dir_server_t));
+ ent = tor_malloc_zero(sizeof(dir_server_t));
ent->nickname = nickname ? tor_strdup(nickname) : NULL;
- ent->address = hostname;
+ ent->address = hostname_;
ent->addr = a;
ent->dir_port = dir_port;
ent->or_port = or_port;
ent->is_running = 1;
+ ent->is_authority = is_authority;
ent->type = type;
+ ent->weight = weight;
memcpy(ent->digest, digest, DIGEST_LEN);
if (v3_auth_digest && (type & V3_DIRINFO))
memcpy(ent->v3_identity_digest, v3_auth_digest, DIGEST_LEN);
@@ -4159,14 +4206,78 @@ add_trusted_dir_server(const char *nickname, const char *address,
ent->fake_status.dir_port = ent->dir_port;
ent->fake_status.or_port = ent->or_port;
- if (ent->or_port)
- ent->fake_status.version_supports_begindir = 1;
+ return ent;
+}
- ent->fake_status.version_supports_conditional_consensus = 1;
+/** Create an authoritative directory server at
+ * <b>address</b>:<b>port</b>, with identity key <b>digest</b>. If
+ * <b>address</b> is NULL, add ourself. Return the new trusted directory
+ * server entry on success or NULL if we couldn't add it. */
+dir_server_t *
+trusted_dir_server_new(const char *nickname, const char *address,
+ uint16_t dir_port, uint16_t or_port,
+ const char *digest, const char *v3_auth_digest,
+ dirinfo_type_t type, double weight)
+{
+ uint32_t a;
+ tor_addr_t addr;
+ char *hostname=NULL;
+ dir_server_t *result;
- smartlist_add(trusted_dir_servers, ent);
+ if (!address) { /* The address is us; we should guess. */
+ if (resolve_my_address(LOG_WARN, get_options(),
+ &a, NULL, &hostname) < 0) {
+ log_warn(LD_CONFIG,
+ "Couldn't find a suitable address when adding ourself as a "
+ "trusted directory server.");
+ return NULL;
+ }
+ if (!hostname)
+ hostname = tor_dup_ip(a);
+ } else {
+ if (tor_lookup_hostname(address, &a)) {
+ log_warn(LD_CONFIG,
+ "Unable to lookup address for directory server at '%s'",
+ address);
+ return NULL;
+ }
+ hostname = tor_strdup(address);
+ }
+ tor_addr_from_ipv4h(&addr, a);
+
+ result = dir_server_new(1, nickname, &addr, hostname,
+ dir_port, or_port, digest,
+ v3_auth_digest, type, weight);
+ tor_free(hostname);
+ return result;
+}
+
+/** Return a new dir_server_t for a fallback directory server at
+ * <b>addr</b>:<b>or_port</b>/<b>dir_port</b>, with identity key digest
+ * <b>id_digest</b> */
+dir_server_t *
+fallback_dir_server_new(const tor_addr_t *addr,
+ uint16_t dir_port, uint16_t or_port,
+ const char *id_digest, double weight)
+{
+ return dir_server_new(0, NULL, addr, NULL, dir_port, or_port, id_digest,
+ NULL, ALL_DIRINFO, weight);
+}
+
+/** Add a directory server to the global list(s). */
+void
+dir_server_add(dir_server_t *ent)
+{
+ if (!trusted_dir_servers)
+ trusted_dir_servers = smartlist_new();
+ if (!fallback_dir_servers)
+ fallback_dir_servers = smartlist_new();
+
+ if (ent->is_authority)
+ smartlist_add(trusted_dir_servers, ent);
+
+ smartlist_add(fallback_dir_servers, ent);
router_dir_info_changed();
- return ent;
}
/** Free storage held in <b>cert</b>. */
@@ -4185,7 +4296,7 @@ authority_cert_free(authority_cert_t *cert)
/** Free storage held in <b>ds</b>. */
static void
-trusted_dir_server_free(trusted_dir_server_t *ds)
+dir_server_free(dir_server_t *ds)
{
if (!ds)
return;
@@ -4196,13 +4307,18 @@ trusted_dir_server_free(trusted_dir_server_t *ds)
tor_free(ds);
}
-/** Remove all members from the list of trusted dir servers. */
+/** Remove all members from the list of dir servers. */
void
-clear_trusted_dir_servers(void)
+clear_dir_servers(void)
{
+ if (fallback_dir_servers) {
+ SMARTLIST_FOREACH(fallback_dir_servers, dir_server_t *, ent,
+ dir_server_free(ent));
+ smartlist_clear(fallback_dir_servers);
+ } else {
+ fallback_dir_servers = smartlist_new();
+ }
if (trusted_dir_servers) {
- SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
- trusted_dir_server_free(ent));
smartlist_clear(trusted_dir_servers);
} else {
trusted_dir_servers = smartlist_new();
@@ -4210,17 +4326,6 @@ clear_trusted_dir_servers(void)
router_dir_info_changed();
}
-/** Return 1 if any trusted dir server supports v1 directories,
- * else return 0. */
-int
-any_trusted_dir_is_v1_authority(void)
-{
- if (trusted_dir_servers)
- return get_n_authorities(V1_DIRINFO) > 0;
-
- return 0;
-}
-
/** For every current directory connection whose purpose is <b>purpose</b>,
* and where the resource being downloaded begins with <b>prefix</b>, split
* rest of the resource into base16 fingerprints (or base64 fingerprints if
@@ -4283,6 +4388,41 @@ list_pending_microdesc_downloads(digestmap_t *result)
list_pending_downloads(result, DIR_PURPOSE_FETCH_MICRODESC, "d/");
}
+/** For every certificate we are currently downloading by (identity digest,
+ * signing key digest) pair, set result[fp_pair] to (void *1).
+ */
+static void
+list_pending_fpsk_downloads(fp_pair_map_t *result)
+{
+ const char *pfx = "fp-sk/";
+ smartlist_t *tmp;
+ smartlist_t *conns;
+ const char *resource;
+
+ tor_assert(result);
+
+ tmp = smartlist_new();
+ conns = get_connection_array();
+
+ SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
+ if (conn->type == CONN_TYPE_DIR &&
+ conn->purpose == DIR_PURPOSE_FETCH_CERTIFICATE &&
+ !conn->marked_for_close) {
+ resource = TO_DIR_CONN(conn)->requested_resource;
+ if (!strcmpstart(resource, pfx))
+ dir_split_resource_into_fingerprint_pairs(resource + strlen(pfx),
+ tmp);
+ }
+ } SMARTLIST_FOREACH_END(conn);
+
+ SMARTLIST_FOREACH_BEGIN(tmp, fp_pair_t *, fp) {
+ fp_pair_map_set(result, fp, (void*)1);
+ tor_free(fp);
+ } SMARTLIST_FOREACH_END(fp);
+
+ smartlist_free(tmp);
+}
+
/** Launch downloads for all the descriptors whose digests or digests256
* are listed as digests[i] for lo <= i < hi. (Lo and hi may be out of
* range.) If <b>source</b> is given, download from <b>source</b>;
@@ -4338,7 +4478,7 @@ initiate_descriptor_downloads(const routerstatus_t *source,
/* We know which authority we want. */
directory_initiate_command_routerstatus(source, purpose,
ROUTER_PURPOSE_GENERAL,
- 0, /* not private */
+ DIRIND_ONEHOP,
resource, NULL, 0, 0);
} else {
directory_get_from_dirserver(purpose, ROUTER_PURPOSE_GENERAL, resource,
@@ -4347,30 +4487,6 @@ initiate_descriptor_downloads(const routerstatus_t *source,
tor_free(resource);
}
-/** Return 0 if this routerstatus is obsolete, too new, isn't
- * running, or otherwise not a descriptor that we would make any
- * use of even if we had it. Else return 1. */
-static INLINE int
-client_would_use_router(const routerstatus_t *rs, time_t now,
- const or_options_t *options)
-{
- if (!rs->is_flagged_running && !options->FetchUselessDescriptors) {
- /* If we had this router descriptor, we wouldn't even bother using it.
- * But, if we want to have a complete list, fetch it anyway. */
- return 0;
- }
- if (rs->published_on + options->TestingEstimatedDescriptorPropagationTime
- > now) {
- /* Most caches probably don't have this descriptor yet. */
- return 0;
- }
- if (rs->published_on + OLD_ROUTER_DESC_MAX_AGE < now) {
- /* We'd drop it immediately for being too old. */
- return 0;
- }
- return 1;
-}
-
/** Max amount of hashes to download per request.
* Since squid does not like URLs >= 4096 bytes we limit it to 96.
* 4096 - strlen(http://255.255.255.255/tor/server/d/.z) == 4058
@@ -4440,11 +4556,6 @@ launch_descriptor_downloads(int purpose,
}
}
}
- /* XXX should we consider having even the dir mirrors delay
- * a little bit, so we don't load the authorities as much? -RD
- * I don't think so. If we do, clients that want those descriptors may
- * not actually find them if the caches haven't got them yet. -NM
- */
if (! should_delay && n_downloadable) {
int i, n_per_request;
@@ -4484,9 +4595,9 @@ launch_descriptor_downloads(int purpose,
rtr_plural = "s";
log_info(LD_DIR,
- "Launching %d request%s for %d router%s, %d at a time",
- CEIL_DIV(n_downloadable, n_per_request),
- req_plural, n_downloadable, rtr_plural, n_per_request);
+ "Launching %d request%s for %d %s%s, %d at a time",
+ CEIL_DIV(n_downloadable, n_per_request), req_plural,
+ n_downloadable, descname, rtr_plural, n_per_request);
smartlist_sort_digests(downloadable);
for (i=0; i < n_downloadable; i += n_per_request) {
initiate_descriptor_downloads(source, purpose,
@@ -4537,7 +4648,7 @@ update_router_descriptor_cache_downloads_v2(time_t now)
*/
n_download = 0;
SMARTLIST_FOREACH_BEGIN(networkstatus_v2_list, networkstatus_v2_t *, ns) {
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
smartlist_t *dl;
dl = downloadable[ns_sl_idx] = smartlist_new();
download_from[ns_sl_idx] = smartlist_new();
@@ -4612,7 +4723,7 @@ update_router_descriptor_cache_downloads_v2(time_t now)
/* Now, we can actually launch our requests. */
for (i=0; i<n; ++i) {
networkstatus_v2_t *ns = smartlist_get(networkstatus_v2_list, i);
- trusted_dir_server_t *ds =
+ dir_server_t *ds =
router_get_trusteddirserver_by_digest(ns->identity_digest);
smartlist_t *dl = download_from[i];
int pds_flags = PDS_RETRY_IF_NO_SERVERS;
@@ -4665,7 +4776,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
if (is_vote) {
/* where's it from, so we know whom to ask for descriptors */
- trusted_dir_server_t *ds;
+ dir_server_t *ds;
networkstatus_voter_info_t *voter = smartlist_get(consensus->voters, 0);
tor_assert(voter);
ds = trusteddirserver_get_by_v3_auth_digest(voter->identity_digest);
@@ -4689,7 +4800,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
sd->signed_descriptor_digest, DIGEST_LEN)) {
/* We have a descriptor with this digest, but either there is no
* entry in routerlist with the same ID (!ri), or there is one,
- * but the identity digest differs (memcmp).
+ * but the identity digest differs (memneq).
*/
smartlist_add(no_longer_old, sd);
++n_in_oldrouters; /* We have it in old_routers. */
@@ -4888,230 +4999,6 @@ update_extrainfo_downloads(time_t now)
smartlist_free(wanted);
}
-/** True iff, the last time we checked whether we had enough directory info
- * to build circuits, the answer was "yes". */
-static int have_min_dir_info = 0;
-/** True iff enough has changed since the last time we checked whether we had
- * enough directory info to build circuits that our old answer can no longer
- * be trusted. */
-static int need_to_update_have_min_dir_info = 1;
-/** String describing what we're missing before we have enough directory
- * info. */
-static char dir_info_status[128] = "";
-
-/** Return true iff we have enough networkstatus and router information to
- * start building circuits. Right now, this means "more than half the
- * networkstatus documents, and at least 1/4 of expected routers." */
-//XXX should consider whether we have enough exiting nodes here.
-int
-router_have_minimum_dir_info(void)
-{
- if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) {
- update_router_have_minimum_dir_info();
- need_to_update_have_min_dir_info = 0;
- }
- return have_min_dir_info;
-}
-
-/** Called when our internal view of the directory has changed. This can be
- * when the authorities change, networkstatuses change, the list of routerdescs
- * changes, or number of running routers changes.
- */
-void
-router_dir_info_changed(void)
-{
- need_to_update_have_min_dir_info = 1;
- rend_hsdir_routers_changed();
-}
-
-/** Return a string describing what we're missing before we have enough
- * directory info. */
-const char *
-get_dir_info_status_string(void)
-{
- return dir_info_status;
-}
-
-/** Iterate over the servers listed in <b>consensus</b>, and count how many of
- * them seem like ones we'd use, and how many of <em>those</em> we have
- * descriptors for. Store the former in *<b>num_usable</b> and the latter in
- * *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those
- * routers in <b>in_set</b>. If <b>exit_only</b> is true, only consider nodes
- * with the Exit flag.
- */
-static void
-count_usable_descriptors(int *num_present, int *num_usable,
- const networkstatus_t *consensus,
- const or_options_t *options, time_t now,
- routerset_t *in_set, int exit_only)
-{
- const int md = (consensus->flavor == FLAV_MICRODESC);
- *num_present = 0, *num_usable=0;
-
- SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs)
- {
- if (exit_only && ! rs->is_exit)
- continue;
- if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
- continue;
- if (client_would_use_router(rs, now, options)) {
- const char * const digest = rs->descriptor_digest;
- int present;
- ++*num_usable; /* the consensus says we want it. */
- if (md)
- present = NULL != microdesc_cache_lookup_by_digest256(NULL, digest);
- else
- present = NULL != router_get_by_descriptor_digest(digest);
- if (present) {
- /* we have the descriptor listed in the consensus. */
- ++*num_present;
- }
- }
- }
- SMARTLIST_FOREACH_END(rs);
-
- log_debug(LD_DIR, "%d usable, %d present.", *num_usable, *num_present);
-}
-
-/** We just fetched a new set of descriptors. Compute how far through
- * the "loading descriptors" bootstrapping phase we are, so we can inform
- * the controller of our progress. */
-int
-count_loading_descriptors_progress(void)
-{
- int num_present = 0, num_usable=0;
- time_t now = time(NULL);
- const networkstatus_t *consensus =
- networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
- double fraction;
-
- if (!consensus)
- return 0; /* can't count descriptors if we have no list of them */
-
- count_usable_descriptors(&num_present, &num_usable,
- consensus, get_options(), now, NULL, 0);
-
- if (num_usable == 0)
- return 0; /* don't div by 0 */
- fraction = num_present / (num_usable/4.);
- if (fraction > 1.0)
- return 0; /* it's not the number of descriptors holding us back */
- return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int)
- (fraction*(BOOTSTRAP_STATUS_CONN_OR-1 -
- BOOTSTRAP_STATUS_LOADING_DESCRIPTORS));
-}
-
-/** Change the value of have_min_dir_info, setting it true iff we have enough
- * network and router information to build circuits. Clear the value of
- * need_to_update_have_min_dir_info. */
-static void
-update_router_have_minimum_dir_info(void)
-{
- int num_present = 0, num_usable=0;
- int num_exit_present = 0, num_exit_usable = 0;
- time_t now = time(NULL);
- int res;
- const or_options_t *options = get_options();
- const networkstatus_t *consensus =
- networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor());
- int using_md;
-
- if (!consensus) {
- if (!networkstatus_get_latest_consensus())
- strlcpy(dir_info_status, "We have no usable consensus.",
- sizeof(dir_info_status));
- else
- strlcpy(dir_info_status, "We have no recent usable consensus.",
- sizeof(dir_info_status));
- res = 0;
- goto done;
- }
-
- if (should_delay_dir_fetches(get_options())) {
- log_notice(LD_DIR, "no known bridge descriptors running yet; stalling");
- strlcpy(dir_info_status, "No live bridge descriptors.",
- sizeof(dir_info_status));
- res = 0;
- goto done;
- }
-
- using_md = consensus->flavor == FLAV_MICRODESC;
-
- count_usable_descriptors(&num_present, &num_usable, consensus, options, now,
- NULL, 0);
- count_usable_descriptors(&num_exit_present, &num_exit_usable,
- consensus, options, now, options->ExitNodes, 1);
-
-/* What fraction of desired server descriptors do we need before we will
- * build circuits? */
-#define FRAC_USABLE_NEEDED .75
-/* What fraction of desired _exit_ server descriptors do we need before we
- * will build circuits? */
-#define FRAC_EXIT_USABLE_NEEDED .5
-
- if (num_present < num_usable * FRAC_USABLE_NEEDED) {
- tor_snprintf(dir_info_status, sizeof(dir_info_status),
- "We have only %d/%d usable %sdescriptors.",
- num_present, num_usable, using_md ? "micro" : "");
- res = 0;
- control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
- goto done;
- } else if (num_present < 2) {
- tor_snprintf(dir_info_status, sizeof(dir_info_status),
- "Only %d %sdescriptor%s here and believed reachable!",
- num_present, using_md ? "micro" : "", num_present ? "" : "s");
- res = 0;
- goto done;
- } else if (num_exit_present < num_exit_usable * FRAC_EXIT_USABLE_NEEDED) {
- tor_snprintf(dir_info_status, sizeof(dir_info_status),
- "We have only %d/%d usable exit node descriptors.",
- num_exit_present, num_exit_usable);
- res = 0;
- control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
- goto done;
- }
-
- /* Check for entry nodes. */
- if (options->EntryNodes) {
- count_usable_descriptors(&num_present, &num_usable, consensus, options,
- now, options->EntryNodes, 0);
-
- if (!num_usable || !num_present) {
- tor_snprintf(dir_info_status, sizeof(dir_info_status),
- "We have only %d/%d usable entry node %sdescriptors.",
- num_present, num_usable, using_md?"micro":"");
- res = 0;
- goto done;
- }
- }
-
- res = 1;
-
- done:
- if (res && !have_min_dir_info) {
- log(LOG_NOTICE, LD_DIR,
- "We now have enough directory information to build circuits.");
- control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
- control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0);
- }
- if (!res && have_min_dir_info) {
- int quiet = directory_too_idle_to_fetch_descriptors(options, now);
- log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
- "Our directory information is no longer up-to-date "
- "enough to build circuits: %s", dir_info_status);
-
- /* a) make us log when we next complete a circuit, so we know when Tor
- * is back up and usable, and b) disable some activities that Tor
- * should only do while circuits are working, like reachability tests
- * and fetching bridge descriptors only over circuits. */
- can_complete_circuit = 0;
-
- control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO");
- }
- have_min_dir_info = res;
- need_to_update_have_min_dir_info = 0;
-}
-
/** Reset the descriptor download failure count on all routers, so that we
* can retry any long-failed routers immediately.
*/
@@ -5164,8 +5051,8 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
r1->ipv6_orport != r2->ipv6_orport ||
r1->dir_port != r2->dir_port ||
r1->purpose != r2->purpose ||
- crypto_pk_cmp_keys(r1->onion_pkey, r2->onion_pkey) ||
- crypto_pk_cmp_keys(r1->identity_pkey, r2->identity_pkey) ||
+ !crypto_pk_eq_keys(r1->onion_pkey, r2->onion_pkey) ||
+ !crypto_pk_eq_keys(r1->identity_pkey, r2->identity_pkey) ||
strcasecmp(r1->platform, r2->platform) ||
(r1->contact_info && !r2->contact_info) || /* contact_info is optional */
(!r1->contact_info && r2->contact_info) ||
@@ -5410,7 +5297,7 @@ esc_router_info(const routerinfo_t *router)
/** Helper for sorting: compare two routerinfos by their identity
* digest. */
static int
-_compare_routerinfo_by_id_digest(const void **a, const void **b)
+compare_routerinfo_by_id_digest_(const void **a, const void **b)
{
routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b;
return fast_memcmp(first->cache_info.identity_digest,
@@ -5422,153 +5309,10 @@ _compare_routerinfo_by_id_digest(const void **a, const void **b)
void
routers_sort_by_identity(smartlist_t *routers)
{
- smartlist_sort(routers, _compare_routerinfo_by_id_digest);
-}
-
-/** A routerset specifies constraints on a set of possible routerinfos, based
- * on their names, identities, or addresses. It is optimized for determining
- * whether a router is a member or not, in O(1+P) time, where P is the number
- * of address policy constraints. */
-struct routerset_t {
- /** A list of strings for the elements of the policy. Each string is either
- * a nickname, a hexadecimal identity fingerprint, or an address policy. A
- * router belongs to the set if its nickname OR its identity OR its address
- * matches an entry here. */
- smartlist_t *list;
- /** A map from lowercase nicknames of routers in the set to (void*)1 */
- strmap_t *names;
- /** A map from identity digests routers in the set to (void*)1 */
- digestmap_t *digests;
- /** An address policy for routers in the set. For implementation reasons,
- * a router belongs to the set if it is _rejected_ by this policy. */
- smartlist_t *policies;
-
- /** A human-readable description of what this routerset is for. Used in
- * log messages. */
- char *description;
-
- /** A list of the country codes in this set. */
- smartlist_t *country_names;
- /** Total number of countries we knew about when we built <b>countries</b>.*/
- int n_countries;
- /** Bit array mapping the return value of geoip_get_country() to 1 iff the
- * country is a member of this routerset. Note that we MUST call
- * routerset_refresh_countries() whenever the geoip country list is
- * reloaded. */
- bitarray_t *countries;
-};
-
-/** Return a new empty routerset. */
-routerset_t *
-routerset_new(void)
-{
- routerset_t *result = tor_malloc_zero(sizeof(routerset_t));
- result->list = smartlist_new();
- result->names = strmap_new();
- result->digests = digestmap_new();
- result->policies = smartlist_new();
- result->country_names = smartlist_new();
- return result;
-}
-
-/** If <b>c</b> is a country code in the form {cc}, return a newly allocated
- * string holding the "cc" part. Else, return NULL. */
-static char *
-routerset_get_countryname(const char *c)
-{
- char *country;
-
- if (strlen(c) < 4 || c[0] !='{' || c[3] !='}')
- return NULL;
-
- country = tor_strndup(c+1, 2);
- tor_strlower(country);
- return country;
-}
-
-/** Update the routerset's <b>countries</b> bitarray_t. Called whenever
- * the GeoIP database is reloaded.
- */
-void
-routerset_refresh_countries(routerset_t *target)
-{
- int cc;
- bitarray_free(target->countries);
-
- if (!geoip_is_loaded()) {
- target->countries = NULL;
- target->n_countries = 0;
- return;
- }
- target->n_countries = geoip_get_n_countries();
- target->countries = bitarray_init_zero(target->n_countries);
- SMARTLIST_FOREACH_BEGIN(target->country_names, const char *, country) {
- cc = geoip_get_country(country);
- if (cc >= 0) {
- tor_assert(cc < target->n_countries);
- bitarray_set(target->countries, cc);
- } else {
- log(LOG_WARN, LD_CONFIG, "Country code '%s' is not recognized.",
- country);
- }
- } SMARTLIST_FOREACH_END(country);
+ smartlist_sort(routers, compare_routerinfo_by_id_digest_);
}
-/** Parse the string <b>s</b> to create a set of routerset entries, and add
- * them to <b>target</b>. In log messages, refer to the string as
- * <b>description</b>. Return 0 on success, -1 on failure.
- *
- * Three kinds of elements are allowed in routersets: nicknames, IP address
- * patterns, and fingerprints. They may be surrounded by optional space, and
- * must be separated by commas.
- */
-int
-routerset_parse(routerset_t *target, const char *s, const char *description)
-{
- int r = 0;
- int added_countries = 0;
- char *countryname;
- smartlist_t *list = smartlist_new();
- smartlist_split_string(list, s, ",",
- SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0);
- SMARTLIST_FOREACH_BEGIN(list, char *, nick) {
- addr_policy_t *p;
- if (is_legal_hexdigest(nick)) {
- char d[DIGEST_LEN];
- if (*nick == '$')
- ++nick;
- log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description);
- base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN);
- digestmap_set(target->digests, d, (void*)1);
- } else if (is_legal_nickname(nick)) {
- log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description);
- strmap_set_lc(target->names, nick, (void*)1);
- } else if ((countryname = routerset_get_countryname(nick)) != NULL) {
- log_debug(LD_CONFIG, "Adding country %s to %s", nick,
- description);
- smartlist_add(target->country_names, countryname);
- added_countries = 1;
- } else if ((strchr(nick,'.') || strchr(nick, '*')) &&
- (p = router_parse_addr_policy_item_from_string(
- nick, ADDR_POLICY_REJECT))) {
- log_debug(LD_CONFIG, "Adding address %s to %s", nick, description);
- smartlist_add(target->policies, p);
- } else {
- log_warn(LD_CONFIG, "Entry '%s' in %s is misformed.", nick,
- description);
- r = -1;
- tor_free(nick);
- SMARTLIST_DEL_CURRENT(list, nick);
- }
- } SMARTLIST_FOREACH_END(nick);
- smartlist_add_all(target->list, list);
- smartlist_free(list);
- if (added_countries)
- routerset_refresh_countries(target);
- return r;
-}
-
-/** Called when we change a node set, or when we reload the geoip list:
+/** Called when we change a node set, or when we reload the geoip IPv4 list:
* recompute all country info in all configuration node sets and in the
* routerlist. */
void
@@ -5584,303 +5328,12 @@ refresh_all_country_info(void)
routerset_refresh_countries(options->ExcludeNodes);
if (options->ExcludeExitNodes)
routerset_refresh_countries(options->ExcludeExitNodes);
- if (options->_ExcludeExitNodesUnion)
- routerset_refresh_countries(options->_ExcludeExitNodesUnion);
+ if (options->ExcludeExitNodesUnion_)
+ routerset_refresh_countries(options->ExcludeExitNodesUnion_);
nodelist_refresh_countries();
}
-/** Add all members of the set <b>source</b> to <b>target</b>. */
-void
-routerset_union(routerset_t *target, const routerset_t *source)
-{
- char *s;
- tor_assert(target);
- if (!source || !source->list)
- return;
- s = routerset_to_string(source);
- routerset_parse(target, s, "other routerset");
- tor_free(s);
-}
-
-/** Return true iff <b>set</b> lists only nicknames and digests, and includes
- * no IP ranges or countries. */
-int
-routerset_is_list(const routerset_t *set)
-{
- return smartlist_len(set->country_names) == 0 &&
- smartlist_len(set->policies) == 0;
-}
-
-/** Return true iff we need a GeoIP IP-to-country database to make sense of
- * <b>set</b>. */
-int
-routerset_needs_geoip(const routerset_t *set)
-{
- return set && smartlist_len(set->country_names);
-}
-
-/** Return true iff there are no entries in <b>set</b>. */
-int
-routerset_is_empty(const routerset_t *set)
-{
- return !set || smartlist_len(set->list) == 0;
-}
-
-/** Helper. Return true iff <b>set</b> contains a router based on the other
- * provided fields. Return higher values for more specific subentries: a
- * single router is more specific than an address range of routers, which is
- * more specific in turn than a country code.
- *
- * (If country is -1, then we take the country
- * from addr.) */
-static int
-routerset_contains(const routerset_t *set, const tor_addr_t *addr,
- uint16_t orport,
- const char *nickname, const char *id_digest,
- country_t country)
-{
- if (!set || !set->list)
- return 0;
- if (nickname && strmap_get_lc(set->names, nickname))
- return 4;
- if (id_digest && digestmap_get(set->digests, id_digest))
- return 4;
- if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies)
- == ADDR_POLICY_REJECTED)
- return 3;
- if (set->countries) {
- if (country < 0 && addr)
- country = geoip_get_country_by_ip(tor_addr_to_ipv4h(addr));
-
- if (country >= 0 && country < set->n_countries &&
- bitarray_is_set(set->countries, country))
- return 2;
- }
- return 0;
-}
-
-/** Return true iff we can tell that <b>ei</b> is a member of <b>set</b>. */
-int
-routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei)
-{
- return routerset_contains(set,
- &ei->addr,
- ei->port,
- ei->nickname,
- ei->identity_digest,
- -1 /*country*/);
-}
-
-/** Return true iff <b>ri</b> is in <b>set</b>. If country is <b>-1</b>, we
- * look up the country. */
-int
-routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
- country_t country)
-{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ri->addr);
- return routerset_contains(set,
- &addr,
- ri->or_port,
- ri->nickname,
- ri->cache_info.identity_digest,
- country);
-}
-
-/** Return true iff <b>rs</b> is in <b>set</b>. If country is <b>-1</b>, we
- * look up the country. */
-int
-routerset_contains_routerstatus(const routerset_t *set,
- const routerstatus_t *rs,
- country_t country)
-{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, rs->addr);
- return routerset_contains(set,
- &addr,
- rs->or_port,
- rs->nickname,
- rs->identity_digest,
- country);
-}
-
-/** Return true iff <b>node</b> is in <b>set</b>. */
-int
-routerset_contains_node(const routerset_t *set, const node_t *node)
-{
- if (node->rs)
- return routerset_contains_routerstatus(set, node->rs, node->country);
- else if (node->ri)
- return routerset_contains_router(set, node->ri, node->country);
- else
- return 0;
-}
-
-/** Add every known node_t that is a member of <b>routerset</b> to
- * <b>out</b>, but never add any that are part of <b>excludeset</b>.
- * If <b>running_only</b>, only add the running ones. */
-void
-routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
- const routerset_t *excludeset, int running_only)
-{ /* XXXX MOVE */
- tor_assert(out);
- if (!routerset || !routerset->list)
- return;
-
- if (routerset_is_list(routerset)) {
- /* No routers are specified by type; all are given by name or digest.
- * we can do a lookup in O(len(routerset)). */
- SMARTLIST_FOREACH(routerset->list, const char *, name, {
- const node_t *node = node_get_by_nickname(name, 1);
- if (node) {
- if (!running_only || node->is_running)
- if (!routerset_contains_node(excludeset, node))
- smartlist_add(out, (void*)node);
- }
- });
- } else {
- /* We need to iterate over the routerlist to get all the ones of the
- * right kind. */
- smartlist_t *nodes = nodelist_get_list();
- SMARTLIST_FOREACH(nodes, const node_t *, node, {
- if (running_only && !node->is_running)
- continue;
- if (routerset_contains_node(routerset, node) &&
- !routerset_contains_node(excludeset, node))
- smartlist_add(out, (void*)node);
- });
- }
-}
-
-#if 0
-/** Add to <b>target</b> every node_t from <b>source</b> except:
- *
- * 1) Don't add it if <b>include</b> is non-empty and the relay isn't in
- * <b>include</b>; and
- * 2) Don't add it if <b>exclude</b> is non-empty and the relay is
- * excluded in a more specific fashion by <b>exclude</b>.
- * 3) If <b>running_only</b>, don't add non-running routers.
- */
-void
-routersets_get_node_disjunction(smartlist_t *target,
- const smartlist_t *source,
- const routerset_t *include,
- const routerset_t *exclude, int running_only)
-{
- SMARTLIST_FOREACH(source, const node_t *, node, {
- int include_result;
- if (running_only && !node->is_running)
- continue;
- if (!routerset_is_empty(include))
- include_result = routerset_contains_node(include, node);
- else
- include_result = 1;
-
- if (include_result) {
- int exclude_result = routerset_contains_node(exclude, node);
- if (include_result >= exclude_result)
- smartlist_add(target, (void*)node);
- }
- });
-}
-#endif
-
-/** Remove every node_t from <b>lst</b> that is in <b>routerset</b>. */
-void
-routerset_subtract_nodes(smartlist_t *lst, const routerset_t *routerset)
-{ /*XXXX MOVE ? */
- tor_assert(lst);
- if (!routerset)
- return;
- SMARTLIST_FOREACH(lst, const node_t *, node, {
- if (routerset_contains_node(routerset, node)) {
- //log_debug(LD_DIR, "Subtracting %s",r->nickname);
- SMARTLIST_DEL_CURRENT(lst, node);
- }
- });
-}
-
-/** Return a new string that when parsed by routerset_parse_string() will
- * yield <b>set</b>. */
-char *
-routerset_to_string(const routerset_t *set)
-{
- if (!set || !set->list)
- return tor_strdup("");
- return smartlist_join_strings(set->list, ",", 0, NULL);
-}
-
-/** Helper: return true iff old and new are both NULL, or both non-NULL
- * equal routersets. */
-int
-routerset_equal(const routerset_t *old, const routerset_t *new)
-{
- if (routerset_is_empty(old) && routerset_is_empty(new)) {
- /* Two empty sets are equal */
- return 1;
- } else if (routerset_is_empty(old) || routerset_is_empty(new)) {
- /* An empty set is equal to nothing else. */
- return 0;
- }
- tor_assert(old != NULL);
- tor_assert(new != NULL);
-
- if (smartlist_len(old->list) != smartlist_len(new->list))
- return 0;
-
- SMARTLIST_FOREACH(old->list, const char *, cp1, {
- const char *cp2 = smartlist_get(new->list, cp1_sl_idx);
- if (strcmp(cp1, cp2))
- return 0;
- });
-
- return 1;
-}
-
-/** Free all storage held in <b>routerset</b>. */
-void
-routerset_free(routerset_t *routerset)
-{
- if (!routerset)
- return;
-
- SMARTLIST_FOREACH(routerset->list, char *, cp, tor_free(cp));
- smartlist_free(routerset->list);
- SMARTLIST_FOREACH(routerset->policies, addr_policy_t *, p,
- addr_policy_free(p));
- smartlist_free(routerset->policies);
- SMARTLIST_FOREACH(routerset->country_names, char *, cp, tor_free(cp));
- smartlist_free(routerset->country_names);
-
- strmap_free(routerset->names, NULL);
- digestmap_free(routerset->digests, NULL);
- bitarray_free(routerset->countries);
- tor_free(routerset);
-}
-
-/** Refresh the country code of <b>ri</b>. This function MUST be called on
- * each router when the GeoIP database is reloaded, and on all new routers. */
-void
-node_set_country(node_t *node)
-{
- if (node->rs)
- node->country = geoip_get_country_by_ip(node->rs->addr);
- else if (node->ri)
- node->country = geoip_get_country_by_ip(node->ri->addr);
- else
- node->country = -1;
-}
-
-/** Set the country code of all routers in the routerlist. */
-void
-nodelist_refresh_countries(void) /* MOVE */
-{
- smartlist_t *nodes = nodelist_get_list();
- SMARTLIST_FOREACH(nodes, node_t *, node,
- node_set_country(node));
-}
-
/** Determine the routers that are responsible for <b>id</b> (binary) and
* add pointers to those routers' routerstatus_t to <b>responsible_dirs</b>.
* Return -1 if we're returning an empty smartlist, else return 0.
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index 8dcc6eb02..ce0f0f2e3 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,12 +8,25 @@
* \brief Header file for routerlist.c.
**/
-#ifndef _TOR_ROUTERLIST_H
-#define _TOR_ROUTERLIST_H
+#ifndef TOR_ROUTERLIST_H
+#define TOR_ROUTERLIST_H
int get_n_authorities(dirinfo_type_t type);
int trusted_dirs_reload_certs(void);
-int trusted_dirs_load_certs_from_string(const char *contents, int from_store,
+
+/*
+ * Pass one of these as source to trusted_dirs_load_certs_from_string()
+ * to indicate whence string originates; this controls error handling
+ * behavior such as marking downloads as failed.
+ */
+
+#define TRUSTED_DIRS_CERTS_SRC_SELF 0
+#define TRUSTED_DIRS_CERTS_SRC_FROM_STORE 1
+#define TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST 2
+#define TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST 3
+#define TRUSTED_DIRS_CERTS_SRC_FROM_VOTE 4
+
+int trusted_dirs_load_certs_from_string(const char *contents, int source,
int flush);
void trusted_dirs_flush_certs_to_disk(void);
authority_cert_t *authority_cert_get_newest_by_id(const char *id_digest);
@@ -21,40 +34,41 @@ authority_cert_t *authority_cert_get_by_sk_digest(const char *sk_digest);
authority_cert_t *authority_cert_get_by_digests(const char *id_digest,
const char *sk_digest);
void authority_cert_get_all(smartlist_t *certs_out);
-void authority_cert_dl_failed(const char *id_digest, int status);
+void authority_cert_dl_failed(const char *id_digest,
+ const char *signing_key_digest, int status);
void authority_certs_fetch_missing(networkstatus_t *status, time_t now);
int router_reload_router_list(void);
int authority_cert_dl_looks_uncertain(const char *id_digest);
-smartlist_t *router_get_trusted_dir_servers(void);
+const smartlist_t *router_get_trusted_dir_servers(void);
+const smartlist_t *router_get_fallback_dir_servers(void);
const routerstatus_t *router_pick_directory_server(dirinfo_type_t type,
int flags);
-trusted_dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
-trusted_dir_server_t *trusteddirserver_get_by_v3_auth_digest(const char *d);
+dir_server_t *router_get_trusteddirserver_by_digest(const char *d);
+dir_server_t *router_get_fallback_dirserver_by_digest(
+ const char *digest);
+dir_server_t *trusteddirserver_get_by_v3_auth_digest(const char *d);
const routerstatus_t *router_pick_trusteddirserver(dirinfo_type_t type,
int flags);
+const routerstatus_t *router_pick_fallback_dirserver(dirinfo_type_t type,
+ int flags);
int router_get_my_share_of_directory_requests(double *v2_share_out,
double *v3_share_out);
void router_reset_status_download_failures(void);
-int routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2);
-int router_nickname_is_in_list(const routerinfo_t *router, const char *list);
+int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
const routerinfo_t *routerlist_find_my_routerinfo(void);
-const node_t *router_find_exact_exit_enclave(const char *address,
- uint16_t port);
-int node_is_unreliable(const node_t *router, int need_uptime,
- int need_capacity, int need_guard);
uint32_t router_get_advertised_bandwidth(const routerinfo_t *router);
uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router);
-const node_t *node_sl_choose_by_bandwidth(smartlist_t *sl,
+const node_t *node_sl_choose_by_bandwidth(const smartlist_t *sl,
bandwidth_weight_rule_t rule);
+double frac_nodes_with_descriptors(const smartlist_t *sl,
+ bandwidth_weight_rule_t rule);
const node_t *router_choose_random_node(smartlist_t *excludedsmartlist,
struct routerset_t *excludedset,
router_crn_flags_t flags);
-const routerinfo_t *router_get_by_nickname(const char *nickname,
- int warn_if_unnamed);
int router_is_named(const routerinfo_t *router);
int router_digest_is_trusted_dir_type(const char *digest,
dirinfo_type_t type);
@@ -63,7 +77,6 @@ int router_digest_is_trusted_dir_type(const char *digest,
int router_addr_is_trusted_dir(uint32_t addr);
int hexdigest_to_digest(const char *hexdigest, char *digest);
-const routerinfo_t *router_get_by_hexdigest(const char *hexdigest);
const routerinfo_t *router_get_by_id_digest(const char *digest);
routerinfo_t *router_get_mutable_by_digest(const char *digest);
signed_descriptor_t *router_get_by_descriptor_digest(const char *digest);
@@ -80,7 +93,6 @@ void routerlist_remove(routerlist_t *rl, routerinfo_t *ri, int make_old,
time_t now);
void routerlist_free_all(void);
void routerlist_reset_warnings(void);
-void router_set_status(const char *digest, int up);
static int WRA_WAS_ADDED(was_router_added_t s);
static int WRA_WAS_OUTDATED(was_router_added_t s);
@@ -133,27 +145,25 @@ void router_load_extrainfo_from_string(const char *s, const char *eos,
int descriptor_digests);
void routerlist_retry_directory_downloads(time_t now);
-int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
- int need_uptime);
int router_exit_policy_rejects_all(const routerinfo_t *router);
-trusted_dir_server_t *add_trusted_dir_server(const char *nickname,
- const char *address,
- uint16_t dir_port, uint16_t or_port,
- const char *digest, const char *v3_auth_digest,
- dirinfo_type_t type);
+
+dir_server_t *trusted_dir_server_new(const char *nickname, const char *address,
+ uint16_t dir_port, uint16_t or_port,
+ const char *digest, const char *v3_auth_digest,
+ dirinfo_type_t type, double weight);
+dir_server_t *fallback_dir_server_new(const tor_addr_t *addr,
+ uint16_t dir_port, uint16_t or_port,
+ const char *id_digest, double weight);
+void dir_server_add(dir_server_t *ent);
+
void authority_cert_free(authority_cert_t *cert);
-void clear_trusted_dir_servers(void);
-int any_trusted_dir_is_v1_authority(void);
+void clear_dir_servers(void);
void update_consensus_router_descriptor_downloads(time_t now, int is_vote,
networkstatus_t *consensus);
void update_router_descriptor_downloads(time_t now);
void update_all_descriptor_downloads(time_t now);
void update_extrainfo_downloads(time_t now);
-int router_have_minimum_dir_info(void);
-void router_dir_info_changed(void);
-const char *get_dir_info_status_string(void);
-int count_loading_descriptors_progress(void);
void router_reset_descriptor_download_failures(void);
int router_differences_are_cosmetic(const routerinfo_t *r1,
const routerinfo_t *r2);
@@ -166,38 +176,6 @@ void routerlist_assert_ok(const routerlist_t *rl);
const char *esc_router_info(const routerinfo_t *router);
void routers_sort_by_identity(smartlist_t *routers);
-routerset_t *routerset_new(void);
-void routerset_refresh_countries(routerset_t *rs);
-int routerset_parse(routerset_t *target, const char *s,
- const char *description);
-void routerset_union(routerset_t *target, const routerset_t *source);
-int routerset_is_list(const routerset_t *set);
-int routerset_needs_geoip(const routerset_t *set);
-int routerset_is_empty(const routerset_t *set);
-int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
- country_t country);
-int routerset_contains_routerstatus(const routerset_t *set,
- const routerstatus_t *rs,
- country_t country);
-int routerset_contains_extendinfo(const routerset_t *set,
- const extend_info_t *ei);
-
-int routerset_contains_node(const routerset_t *set, const node_t *node);
-void routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
- const routerset_t *excludeset,
- int running_only);
-#if 0
-void routersets_get_node_disjunction(smartlist_t *target,
- const smartlist_t *source,
- const routerset_t *include,
- const routerset_t *exclude, int running_only);
-#endif
-void routerset_subtract_nodes(smartlist_t *out,
- const routerset_t *routerset);
-
-char *routerset_to_string(const routerset_t *routerset);
-int routerset_equal(const routerset_t *old, const routerset_t *new);
-void routerset_free(routerset_t *routerset);
void refresh_all_country_info(void);
int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
@@ -215,6 +193,23 @@ int hex_digest_nickname_decode(const char *hexdigest,
char *digest_out,
char *nickname_qualifier_out,
char *nickname_out);
+int hex_digest_nickname_matches(const char *hexdigest,
+ const char *identity_digest,
+ const char *nickname, int is_named);
+
+#ifdef ROUTERLIST_PRIVATE
+/** Helper type for choosing routers by bandwidth: contains a union of
+ * double and uint64_t. Before we call scale_array_elements_to_u64, it holds
+ * a double; after, it holds a uint64_t. */
+typedef union u64_dbl_t {
+ uint64_t u64;
+ double dbl;
+} u64_dbl_t;
+
+int choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries);
+void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
+ uint64_t *total_out);
+#endif
#endif
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 299d07d37..3aa4bdf8a 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,7 +11,7 @@
#include "or.h"
#include "config.h"
-#include "circuitbuild.h"
+#include "circuitstats.h"
#include "dirserv.h"
#include "dirvote.h"
#include "policies.h"
@@ -29,8 +29,8 @@
/****************************************************************************/
/** Enumeration of possible token types. The ones starting with K_ correspond
- * to directory 'keywords'. _ERR is an error in the tokenizing process, _EOF
- * is an end-of-file marker, and _NIL is used to encode not-a-token.
+ * to directory 'keywords'. ERR_ is an error in the tokenizing process, EOF_
+ * is an end-of-file marker, and NIL_ is used to encode not-a-token.
*/
typedef enum {
K_ACCEPT = 0,
@@ -43,6 +43,7 @@ typedef enum {
K_SIGNED_DIRECTORY,
K_SIGNING_KEY,
K_ONION_KEY,
+ K_ONION_KEY_NTOR,
K_ROUTER_SIGNATURE,
K_PUBLISHED,
K_RUNNING_ROUTERS,
@@ -66,7 +67,9 @@ typedef enum {
K_SERVER_VERSIONS,
K_OR_ADDRESS,
K_P,
+ K_P6,
K_R,
+ K_A,
K_S,
K_V,
K_W,
@@ -76,6 +79,7 @@ typedef enum {
K_CACHES_EXTRA_INFO,
K_HIDDEN_SERVICE_DIR,
K_ALLOW_SINGLE_HOP_EXITS,
+ K_IPV6_POLICY,
K_DIRREQ_END,
K_DIRREQ_V2_IPS,
@@ -130,7 +134,7 @@ typedef enum {
A_PURPOSE,
A_LAST_LISTED,
- _A_UNKNOWN,
+ A_UNKNOWN_,
R_RENDEZVOUS_SERVICE_DESCRIPTOR,
R_VERSION,
@@ -151,13 +155,13 @@ typedef enum {
C_DESCRIPTOR_COOKIE,
C_CLIENT_KEY,
- _ERR,
- _EOF,
- _NIL
+ ERR_,
+ EOF_,
+ NIL_
} directory_keyword;
#define MIN_ANNOTATION A_PURPOSE
-#define MAX_ANNOTATION _A_UNKNOWN
+#define MAX_ANNOTATION A_UNKNOWN_
/** Structure to hold a single directory token.
*
@@ -180,7 +184,7 @@ typedef struct directory_token_t {
crypto_pk_t *key; /**< For public keys only. Heap-allocated. */
- char *error; /**< For _ERR tokens only. */
+ char *error; /**< For ERR_ tokens only. */
} directory_token_t;
/* ********************************************************************** */
@@ -234,7 +238,7 @@ typedef struct token_rule_t {
*/
/** Appears to indicate the end of a table. */
-#define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
+#define END_OF_TABLE { NULL, NIL_, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
/** An item with no restrictions: used for obsolete document types */
#define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
/** An item with no restrictions on multiplicity or location. */
@@ -270,8 +274,10 @@ static token_rule_t routerdesc_token_table[] = {
T0N("reject6", K_REJECT6, ARGS, NO_OBJ ),
T0N("accept6", K_ACCEPT6, ARGS, NO_OBJ ),
T1_START( "router", K_ROUTER, GE(5), NO_OBJ ),
+ T01("ipv6-policy", K_IPV6_POLICY, CONCAT_ARGS, NO_OBJ),
T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
+ T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T01("uptime", K_UPTIME, GE(1), NO_OBJ ),
@@ -338,6 +344,7 @@ static token_rule_t extrainfo_token_table[] = {
static token_rule_t rtrstatus_token_table[] = {
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
T1( "r", K_R, GE(7), NO_OBJ ),
+ T0N("a", K_A, GE(1), NO_OBJ ),
T1( "s", K_S, ARGS, NO_OBJ ),
T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
T01("w", K_W, ARGS, NO_OBJ ),
@@ -371,25 +378,6 @@ static token_rule_t dir_footer_token_table[] = {
END_OF_TABLE
};
-/** List of tokens recognized in v1 directory headers/footers. */
-static token_rule_t dir_token_table[] = {
- /* don't enforce counts; this is obsolete. */
- T( "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ ),
- T( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ ),
- T( "recommended-software",K_RECOMMENDED_SOFTWARE,CONCAT_ARGS, NO_OBJ ),
- T( "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ ),
-
- T( "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ ),
- T( "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ ),
- T( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
- T( "opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
- T( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
- T( "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK ),
- T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
-
- END_OF_TABLE
-};
-
/** List of tokens common to V3 authority certificates and V3 consensuses. */
#define CERTIFICATE_MEMBERS \
T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
@@ -522,8 +510,11 @@ static token_rule_t networkstatus_detached_signature_token_table[] = {
/** List of tokens recognized in microdescriptors */
static token_rule_t microdesc_token_table[] = {
T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
+ T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
+ T0N("a", K_A, GE(1), NO_OBJ ),
T01("family", K_FAMILY, ARGS, NO_OBJ ),
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
+ T01("p6", K_P6, CONCAT_ARGS, NO_OBJ ),
A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
@@ -532,7 +523,8 @@ static token_rule_t microdesc_token_table[] = {
/* static function prototypes */
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
-static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
+static addr_policy_t *router_parse_addr_policy(directory_token_t *tok,
+ unsigned fmt_flags);
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
@@ -546,10 +538,10 @@ static int router_get_hashes_impl(const char *s, size_t s_len,
static void token_clear(directory_token_t *tok);
static smartlist_t *find_all_by_keyword(smartlist_t *s, directory_keyword k);
static smartlist_t *find_all_exitpolicy(smartlist_t *s);
-static directory_token_t *_find_by_keyword(smartlist_t *s,
+static directory_token_t *find_by_keyword_(smartlist_t *s,
directory_keyword keyword,
const char *keyword_str);
-#define find_by_keyword(s, keyword) _find_by_keyword((s), (keyword), #keyword)
+#define find_by_keyword(s, keyword) find_by_keyword_((s), (keyword), #keyword)
static directory_token_t *find_opt_by_keyword(smartlist_t *s,
directory_keyword keyword);
@@ -573,7 +565,6 @@ static int check_signature_token(const char *digest,
crypto_pk_t *pkey,
int flags,
const char *doctype);
-static crypto_pk_t *find_dir_signing_key(const char *str, const char *eos);
#undef DEBUG_AREA_ALLOC
@@ -671,18 +662,6 @@ router_get_networkstatus_v3_hashes(const char *s, digests_t *digests)
' ');
}
-/** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
- * string in <b>s</b>. Return 0 on success, -1 on failure. */
-int
-router_get_networkstatus_v3_hash(const char *s, char *digest,
- digest_algorithm_t alg)
-{
- return router_get_hash_impl(s, strlen(s), digest,
- "network-status-version",
- "\ndirectory-signature",
- ' ', alg);
-}
-
/** Set <b>digest</b> to the SHA-1 digest of the hash of the <b>s_len</b>-byte
* extrainfo string at <b>s</b>. Return 0 on success, -1 on failure. */
int
@@ -693,19 +672,23 @@ router_get_extrainfo_hash(const char *s, size_t s_len, char *digest)
}
/** Helper: used to generate signatures for routers, directories and
- * network-status objects. Given a digest in <b>digest</b> and a secret
- * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it,
- * surround it with -----BEGIN/END----- pairs, and write it to the
- * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on
- * failure.
+ * network-status objects. Given a <b>digest_len</b>-byte digest in
+ * <b>digest</b> and a secret <b>private_key</b>, generate an PKCS1-padded
+ * signature, BASE64-encode it, surround it with -----BEGIN/END----- pairs,
+ * and return the new signature on success or NULL on failure.
*/
-int
-router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
- size_t digest_len, crypto_pk_t *private_key)
+char *
+router_get_dirobj_signature(const char *digest,
+ size_t digest_len,
+ crypto_pk_t *private_key)
{
char *signature;
size_t i, keysize;
int siglen;
+ char *buf = NULL;
+ size_t buf_len;
+ /* overestimate of BEGIN/END lines total len. */
+#define BEGIN_END_OVERHEAD_LEN 64
keysize = crypto_pk_keysize(private_key);
signature = tor_malloc(keysize);
@@ -715,7 +698,12 @@ router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
log_warn(LD_BUG,"Couldn't sign digest.");
goto err;
}
- if (strlcat(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
+
+ /* The *2 here is a ridiculous overestimate of base-64 overhead. */
+ buf_len = (siglen * 2) + BEGIN_END_OVERHEAD_LEN;
+ buf = tor_malloc(buf_len);
+
+ if (strlcpy(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
goto truncated;
i = strlen(buf);
@@ -728,13 +716,42 @@ router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
goto truncated;
tor_free(signature);
- return 0;
+ return buf;
truncated:
log_warn(LD_BUG,"tried to exceed string length.");
err:
tor_free(signature);
- return -1;
+ tor_free(buf);
+ return NULL;
+}
+
+/** Helper: used to generate signatures for routers, directories and
+ * network-status objects. Given a digest in <b>digest</b> and a secret
+ * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it,
+ * surround it with -----BEGIN/END----- pairs, and write it to the
+ * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on
+ * failure.
+ */
+int
+router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
+ size_t digest_len, crypto_pk_t *private_key)
+{
+ size_t sig_len, s_len;
+ char *sig = router_get_dirobj_signature(digest, digest_len, private_key);
+ if (!sig) {
+ log_warn(LD_BUG, "No signature generated");
+ return -1;
+ }
+ sig_len = strlen(sig);
+ s_len = strlen(buf);
+ if (sig_len + s_len + 1 > buf_len) {
+ log_warn(LD_BUG, "Not enough room for signature");
+ tor_free(sig);
+ return -1;
+ }
+ memcpy(buf+s_len, sig, sig_len+1);
+ return 0;
}
/** Return VS_RECOMMENDED if <b>myversion</b> is contained in
@@ -816,218 +833,6 @@ tor_version_is_obsolete(const char *myversion, const char *versionlist)
return ret;
}
-/** Read a signed directory from <b>str</b>. If it's well-formed, return 0.
- * Otherwise, return -1. If we're a directory cache, cache it.
- */
-int
-router_parse_directory(const char *str)
-{
- directory_token_t *tok;
- char digest[DIGEST_LEN];
- time_t published_on;
- int r;
- const char *end, *cp, *str_dup = str;
- smartlist_t *tokens = NULL;
- crypto_pk_t *declared_key = NULL;
- memarea_t *area = memarea_new();
-
- /* XXXX This could be simplified a lot, but it will all go away
- * once pre-0.1.1.8 is obsolete, and for now it's better not to
- * touch it. */
-
- if (router_get_dir_hash(str, digest)) {
- log_warn(LD_DIR, "Unable to compute digest of directory");
- goto err;
- }
- log_debug(LD_DIR,"Received directory hashes to %s",hex_str(digest,4));
-
- /* Check signature first, before we try to tokenize. */
- cp = str;
- while (cp && (end = strstr(cp+1, "\ndirectory-signature")))
- cp = end;
- if (cp == str || !cp) {
- log_warn(LD_DIR, "No signature found on directory."); goto err;
- }
- ++cp;
- tokens = smartlist_new();
- if (tokenize_string(area,cp,strchr(cp,'\0'),tokens,dir_token_table,0)) {
- log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
- }
- if (smartlist_len(tokens) != 1) {
- log_warn(LD_DIR, "Unexpected number of tokens in signature"); goto err;
- }
- tok=smartlist_get(tokens,0);
- if (tok->tp != K_DIRECTORY_SIGNATURE) {
- log_warn(LD_DIR,"Expected a single directory signature"); goto err;
- }
- declared_key = find_dir_signing_key(str, str+strlen(str));
- note_crypto_pk_op(VERIFY_DIR);
- if (check_signature_token(digest, DIGEST_LEN, tok, declared_key,
- CST_CHECK_AUTHORITY, "directory")<0)
- goto err;
-
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_clear(tokens);
- memarea_clear(area);
-
- /* Now try to parse the first part of the directory. */
- if ((end = strstr(str,"\nrouter "))) {
- ++end;
- } else if ((end = strstr(str, "\ndirectory-signature"))) {
- ++end;
- } else {
- end = str + strlen(str);
- }
-
- if (tokenize_string(area,str,end,tokens,dir_token_table,0)) {
- log_warn(LD_DIR, "Error tokenizing directory"); goto err;
- }
-
- tok = find_by_keyword(tokens, K_PUBLISHED);
- tor_assert(tok->n_args == 1);
-
- if (parse_iso_time(tok->args[0], &published_on) < 0) {
- goto err;
- }
-
- /* Now that we know the signature is okay, and we have a
- * publication time, cache the directory. */
- if (directory_caches_v1_dir_info(get_options()) &&
- !authdir_mode_v1(get_options()))
- dirserv_set_cached_directory(str, published_on, 0);
-
- r = 0;
- goto done;
- err:
- dump_desc(str_dup, "v1 directory");
- r = -1;
- done:
- if (declared_key) crypto_pk_free(declared_key);
- if (tokens) {
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_free(tokens);
- }
- if (area) {
- DUMP_AREA(area, "v1 directory");
- memarea_drop_all(area);
- }
- return r;
-}
-
-/** Read a signed router status statement from <b>str</b>. If it's
- * well-formed, return 0. Otherwise, return -1. If we're a directory cache,
- * cache it.*/
-int
-router_parse_runningrouters(const char *str)
-{
- char digest[DIGEST_LEN];
- directory_token_t *tok;
- time_t published_on;
- int r = -1;
- crypto_pk_t *declared_key = NULL;
- smartlist_t *tokens = NULL;
- const char *eos = str + strlen(str), *str_dup = str;
- memarea_t *area = NULL;
-
- if (router_get_runningrouters_hash(str, digest)) {
- log_warn(LD_DIR, "Unable to compute digest of running-routers");
- goto err;
- }
- area = memarea_new();
- tokens = smartlist_new();
- if (tokenize_string(area,str,eos,tokens,dir_token_table,0)) {
- log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
- }
- tok = smartlist_get(tokens,0);
- if (tok->tp != K_NETWORK_STATUS) {
- log_warn(LD_DIR, "Network-status starts with wrong token");
- goto err;
- }
-
- tok = find_by_keyword(tokens, K_PUBLISHED);
- tor_assert(tok->n_args == 1);
- if (parse_iso_time(tok->args[0], &published_on) < 0) {
- goto err;
- }
- if (!(tok = find_opt_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
- log_warn(LD_DIR, "Missing signature on running-routers");
- goto err;
- }
- declared_key = find_dir_signing_key(str, eos);
- note_crypto_pk_op(VERIFY_DIR);
- if (check_signature_token(digest, DIGEST_LEN, tok, declared_key,
- CST_CHECK_AUTHORITY, "running-routers")
- < 0)
- goto err;
-
- /* Now that we know the signature is okay, and we have a
- * publication time, cache the list. */
- if (get_options()->DirPort_set && !authdir_mode_v1(get_options()))
- dirserv_set_cached_directory(str, published_on, 1);
-
- r = 0;
- err:
- dump_desc(str_dup, "v1 running-routers");
- if (declared_key) crypto_pk_free(declared_key);
- if (tokens) {
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_free(tokens);
- }
- if (area) {
- DUMP_AREA(area, "v1 running-routers");
- memarea_drop_all(area);
- }
- return r;
-}
-
-/** Given a directory or running-routers string in <b>str</b>, try to
- * find the its dir-signing-key token (if any). If this token is
- * present, extract and return the key. Return NULL on failure. */
-static crypto_pk_t *
-find_dir_signing_key(const char *str, const char *eos)
-{
- const char *cp;
- directory_token_t *tok;
- crypto_pk_t *key = NULL;
- memarea_t *area = NULL;
- tor_assert(str);
- tor_assert(eos);
-
- /* Is there a dir-signing-key in the directory? */
- cp = tor_memstr(str, eos-str, "\nopt dir-signing-key");
- if (!cp)
- cp = tor_memstr(str, eos-str, "\ndir-signing-key");
- if (!cp)
- return NULL;
- ++cp; /* Now cp points to the start of the token. */
-
- area = memarea_new();
- tok = get_next_token(area, &cp, eos, dir_token_table);
- if (!tok) {
- log_warn(LD_DIR, "Unparseable dir-signing-key token");
- goto done;
- }
- if (tok->tp != K_DIR_SIGNING_KEY) {
- log_warn(LD_DIR, "Dir-signing-key token did not parse as expected");
- goto done;
- }
-
- if (tok->key) {
- key = tok->key;
- tok->key = NULL; /* steal reference. */
- } else {
- log_warn(LD_DIR, "Dir-signing-key token contained no key");
- }
-
- done:
- if (tok) token_clear(tok);
- if (area) {
- DUMP_AREA(area, "dir-signing-key token");
- memarea_drop_all(area);
- }
- return key;
-}
-
/** Return true iff <b>key</b> is allowed to sign directories.
*/
static int
@@ -1250,13 +1055,50 @@ dump_distinct_digest_count(int severity)
#ifdef COUNT_DISTINCT_DIGESTS
if (!verified_digests)
verified_digests = digestmap_new();
- log(severity, LD_GENERAL, "%d *distinct* router digests verified",
+ tor_log(severity, LD_GENERAL, "%d *distinct* router digests verified",
digestmap_size(verified_digests));
#else
(void)severity; /* suppress "unused parameter" warning */
#endif
}
+/** Try to find an IPv6 OR port in <b>list</b> of directory_token_t's
+ * with at least one argument (use GE(1) in setup). If found, store
+ * address and port number to <b>addr_out</b> and
+ * <b>port_out</b>. Return number of OR ports found. */
+static int
+find_single_ipv6_orport(const smartlist_t *list,
+ tor_addr_t *addr_out,
+ uint16_t *port_out)
+{
+ int ret = 0;
+ tor_assert(list != NULL);
+ tor_assert(addr_out != NULL);
+ tor_assert(port_out != NULL);
+
+ SMARTLIST_FOREACH_BEGIN(list, directory_token_t *, t) {
+ tor_addr_t a;
+ maskbits_t bits;
+ uint16_t port_min, port_max;
+ tor_assert(t->n_args >= 1);
+ /* XXXX Prop186 the full spec allows much more than this. */
+ if (tor_addr_parse_mask_ports(t->args[0], 0,
+ &a, &bits, &port_min,
+ &port_max) == AF_INET6 &&
+ bits == 128 &&
+ port_min == port_max) {
+ /* Okay, this is one we can understand. Use it and ignore
+ any potential more addresses in list. */
+ tor_addr_copy(addr_out, &a);
+ *port_out = port_min;
+ ret = 1;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(t);
+
+ return ret;
+}
+
/** Helper function: reads a single router entry from *<b>s</b> ...
* *<b>end</b>. Mallocs a new router and returns it if all goes well, else
* returns NULL. If <b>cache_copy</b> is true, duplicate the contents of
@@ -1471,6 +1313,17 @@ router_parse_entry_from_string(const char *s, const char *end,
router->onion_pkey = tok->key;
tok->key = NULL; /* Prevent free */
+ if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) {
+ curve25519_public_key_t k;
+ tor_assert(tok->n_args >= 1);
+ if (curve25519_public_from_base64(&k, tok->args[0]) < 0) {
+ log_warn(LD_DIR, "Bogus ntor-onion-key in routerinfo");
+ goto err;
+ }
+ router->onion_curve25519_pkey =
+ tor_memdup(&k, sizeof(curve25519_public_key_t));
+ }
+
tok = find_by_keyword(tokens, K_SIGNING_KEY);
router->identity_pkey = tok->key;
tok->key = NULL; /* Prevent free */
@@ -1513,21 +1366,8 @@ router_parse_entry_from_string(const char *s, const char *end,
{
smartlist_t *or_addresses = find_all_by_keyword(tokens, K_OR_ADDRESS);
if (or_addresses) {
- SMARTLIST_FOREACH_BEGIN(or_addresses, directory_token_t *, t) {
- tor_addr_t a;
- maskbits_t bits;
- uint16_t port_min, port_max;
- /* XXXX Prop186 the full spec allows much more than this. */
- if (tor_addr_parse_mask_ports(t->args[0], &a, &bits, &port_min,
- &port_max) == AF_INET6 &&
- bits == 128 &&
- port_min == port_max) {
- /* Okay, this is one we can understand. */
- tor_addr_copy(&router->ipv6_addr, &a);
- router->ipv6_orport = port_min;
- break;
- }
- } SMARTLIST_FOREACH_END(t);
+ find_single_ipv6_orport(or_addresses, &router->ipv6_addr,
+ &router->ipv6_orport);
smartlist_free(or_addresses);
}
}
@@ -1542,7 +1382,18 @@ router_parse_entry_from_string(const char *s, const char *end,
goto err;
});
policy_expand_private(&router->exit_policy);
- if (policy_is_reject_star(router->exit_policy))
+
+ if ((tok = find_opt_by_keyword(tokens, K_IPV6_POLICY)) && tok->n_args) {
+ router->ipv6_exit_policy = parse_short_policy(tok->args[0]);
+ if (! router->ipv6_exit_policy) {
+ log_warn(LD_DIR , "Error in ipv6-policy %s", escaped(tok->args[0]));
+ goto err;
+ }
+ }
+
+ if (policy_is_reject_star(router->exit_policy, AF_INET) &&
+ (!router->ipv6_exit_policy ||
+ short_policy_is_reject_star(router->ipv6_exit_policy)))
router->policy_is_reject_star = 1;
if ((tok = find_opt_by_keyword(tokens, K_FAMILY)) && tok->n_args) {
@@ -1669,7 +1520,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
extrainfo = tor_malloc_zero(sizeof(extrainfo_t));
extrainfo->cache_info.is_extrainfo = 1;
if (cache_copy)
- extrainfo->cache_info.signed_descriptor_body = tor_strndup(s, end-s);
+ extrainfo->cache_info.signed_descriptor_body = tor_memdup_nulterm(s,end-s);
extrainfo->cache_info.signed_descriptor_len = end-s;
memcpy(extrainfo->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
@@ -2060,6 +1911,14 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->dir_port = (uint16_t) tor_parse_long(tok->args[7+offset],
10,0,65535,NULL,NULL);
+ {
+ smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
+ if (a_lines) {
+ find_single_ipv6_orport(a_lines, &rs->ipv6_addr, &rs->ipv6_orport);
+ smartlist_free(a_lines);
+ }
+ }
+
tok = find_opt_by_keyword(tokens, K_S);
if (tok && vote) {
int i;
@@ -2067,7 +1926,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
for (i=0; i < tok->n_args; ++i) {
int p = smartlist_string_pos(vote->known_flags, tok->args[i]);
if (p >= 0) {
- vote_rs->flags |= (1<<p);
+ vote_rs->flags |= (U64_LITERAL(1)<<p);
} else {
log_warn(LD_DIR, "Flags line had a flag %s not listed in known_flags.",
escaped(tok->args[i]));
@@ -2112,24 +1971,15 @@ routerstatus_parse_entry_from_string(memarea_t *area,
tor_assert(tok->n_args == 1);
rs->version_known = 1;
if (strcmpstart(tok->args[0], "Tor ")) {
- rs->version_supports_begindir = 1;
- rs->version_supports_extrainfo_upload = 1;
- rs->version_supports_conditional_consensus = 1;
rs->version_supports_microdesc_cache = 1;
rs->version_supports_optimistic_data = 1;
} else {
- rs->version_supports_begindir =
- tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha");
- rs->version_supports_extrainfo_upload =
- tor_version_as_new_as(tok->args[0], "0.2.0.0-alpha-dev (r10070)");
- rs->version_supports_v3_dir =
- tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha");
- rs->version_supports_conditional_consensus =
- tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha");
rs->version_supports_microdesc_cache =
tor_version_supports_microdescriptors(tok->args[0]);
rs->version_supports_optimistic_data =
tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha");
+ rs->version_supports_extend2_cells =
+ tor_version_as_new_as(tok->args[0], "0.2.4.8-alpha");
}
if (vote_rs) {
vote_rs->version = tor_strdup(tok->args[0]);
@@ -2142,17 +1992,18 @@ routerstatus_parse_entry_from_string(memarea_t *area,
for (i=0; i < tok->n_args; ++i) {
if (!strcmpstart(tok->args[i], "Bandwidth=")) {
int ok;
- rs->bandwidth = (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
- 10, 0, UINT32_MAX,
- &ok, NULL);
+ rs->bandwidth_kb =
+ (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
+ 10, 0, UINT32_MAX,
+ &ok, NULL);
if (!ok) {
log_warn(LD_DIR, "Invalid Bandwidth %s", escaped(tok->args[i]));
goto err;
}
rs->has_bandwidth = 1;
- } else if (!strcmpstart(tok->args[i], "Measured=")) {
+ } else if (!strcmpstart(tok->args[i], "Measured=") && vote_rs) {
int ok;
- rs->measured_bw =
+ vote_rs->measured_bw_kb =
(uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
10, 0, UINT32_MAX, &ok, NULL);
if (!ok) {
@@ -2160,7 +2011,10 @@ routerstatus_parse_entry_from_string(memarea_t *area,
escaped(tok->args[i]));
goto err;
}
- rs->has_measured_bw = 1;
+ vote_rs->has_measured_bw = 1;
+ vote->has_measured_bws = 1;
+ } else if (!strcmpstart(tok->args[i], "Unmeasured=1")) {
+ rs->bw_is_unmeasured = 1;
}
}
}
@@ -2203,7 +2057,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
}
} else {
log_info(LD_BUG, "Found an entry in networkstatus with no "
- "microdescriptor digest. (Router %s=%s at %s:%d.)",
+ "microdescriptor digest. (Router %s ($%s) at %s:%d.)",
rs->nickname, hex_str(rs->identity_digest, DIGEST_LEN),
fmt_addr32(rs->addr), rs->or_port);
}
@@ -2238,9 +2092,17 @@ compare_routerstatus_entries(const void **_a, const void **_b)
return fast_memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
}
+int
+compare_vote_routerstatus_entries(const void **_a, const void **_b)
+{
+ const vote_routerstatus_t *a = *_a, *b = *_b;
+ return fast_memcmp(a->status.identity_digest, b->status.identity_digest,
+ DIGEST_LEN);
+}
+
/** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */
static void
-_free_duplicate_routerstatus_entry(void *e)
+free_duplicate_routerstatus_entry_(void *e)
{
log_warn(LD_DIR,
"Network-status has two entries for the same router. "
@@ -2381,7 +2243,7 @@ networkstatus_v2_parse_from_string(const char *s)
}
smartlist_sort(ns->entries, compare_routerstatus_entries);
smartlist_uniq(ns->entries, compare_routerstatus_entries,
- _free_duplicate_routerstatus_entry);
+ free_duplicate_routerstatus_entry_);
if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) {
log_warn(LD_DIR, "Error tokenizing network-status footer.");
@@ -2422,7 +2284,7 @@ networkstatus_v2_parse_from_string(const char *s)
/** Verify the bandwidth weights of a network status document */
int
-networkstatus_verify_bw_weights(networkstatus_t *ns)
+networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method)
{
int64_t weight_scale;
int64_t G=0, M=0, E=0, D=0, T=0;
@@ -2431,7 +2293,7 @@ networkstatus_verify_bw_weights(networkstatus_t *ns)
const char *casename = NULL;
int valid = 1;
- weight_scale = circuit_build_times_get_bw_scale(ns);
+ weight_scale = networkstatus_get_weight_scale_param(ns);
Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1);
Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1);
Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1);
@@ -2508,24 +2370,31 @@ networkstatus_verify_bw_weights(networkstatus_t *ns)
// Then, gather G, M, E, D, T to determine case
SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
+ int is_exit = 0;
+ if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) {
+ /* Bug #2203: Don't count bad exits as exits for balancing */
+ is_exit = rs->is_exit && !rs->is_bad_exit;
+ } else {
+ is_exit = rs->is_exit;
+ }
if (rs->has_bandwidth) {
- T += rs->bandwidth;
- if (rs->is_exit && rs->is_possible_guard) {
- D += rs->bandwidth;
- Gtotal += Wgd*rs->bandwidth;
- Mtotal += Wmd*rs->bandwidth;
- Etotal += Wed*rs->bandwidth;
- } else if (rs->is_exit) {
- E += rs->bandwidth;
- Mtotal += Wme*rs->bandwidth;
- Etotal += Wee*rs->bandwidth;
+ T += rs->bandwidth_kb;
+ if (is_exit && rs->is_possible_guard) {
+ D += rs->bandwidth_kb;
+ Gtotal += Wgd*rs->bandwidth_kb;
+ Mtotal += Wmd*rs->bandwidth_kb;
+ Etotal += Wed*rs->bandwidth_kb;
+ } else if (is_exit) {
+ E += rs->bandwidth_kb;
+ Mtotal += Wme*rs->bandwidth_kb;
+ Etotal += Wee*rs->bandwidth_kb;
} else if (rs->is_possible_guard) {
- G += rs->bandwidth;
- Gtotal += Wgg*rs->bandwidth;
- Mtotal += Wmg*rs->bandwidth;
+ G += rs->bandwidth_kb;
+ Gtotal += Wgg*rs->bandwidth_kb;
+ Mtotal += Wmg*rs->bandwidth_kb;
} else {
- M += rs->bandwidth;
- Mtotal += Wmm*rs->bandwidth;
+ M += rs->bandwidth_kb;
+ Mtotal += Wmm*rs->bandwidth_kb;
}
} else {
log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
@@ -2981,6 +2850,16 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
log_warn(LD_DIR, "known-flags not in order");
goto err;
}
+ if (ns->type != NS_TYPE_CONSENSUS &&
+ smartlist_len(ns->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) {
+ /* If we allowed more than 64 flags in votes, then parsing them would make
+ * us invoke undefined behavior whenever we used 1<<flagnum to do a
+ * bit-shift. This is only for votes and opinions: consensus users don't
+ * care about flags they don't recognize, and so don't build a bitfield
+ * for them. */
+ log_warn(LD_DIR, "Too many known-flags in consensus vote or opinion");
+ goto err;
+ }
tok = find_opt_by_keyword(tokens, K_PARAMS);
if (tok) {
@@ -3599,6 +3478,10 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
/** Parse the addr policy in the string <b>s</b> and return it. If
* assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
* ADDR_POLICY_REJECT) for items that specify no action.
+ *
+ * The addr_policy_t returned by this function can have its address set to
+ * AF_UNSPEC for '*'. Use policy_expand_unspec() to turn this into a pair
+ * of AF_INET and AF_INET6 items.
*/
addr_policy_t *
router_parse_addr_policy_item_from_string(const char *s, int assume_action)
@@ -3628,7 +3511,7 @@ router_parse_addr_policy_item_from_string(const char *s, int assume_action)
eos = cp + strlen(cp);
area = memarea_new();
tok = get_next_token(area, &cp, eos, routerdesc_token_table);
- if (tok->tp == _ERR) {
+ if (tok->tp == ERR_) {
log_warn(LD_DIR, "Error reading address policy: %s", tok->error);
goto err;
}
@@ -3638,7 +3521,7 @@ router_parse_addr_policy_item_from_string(const char *s, int assume_action)
goto err;
}
- r = router_parse_addr_policy(tok);
+ r = router_parse_addr_policy(tok, TAPMP_EXTENDED_STAR);
goto done;
err:
r = NULL;
@@ -3657,7 +3540,7 @@ static int
router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
{
addr_policy_t *newe;
- newe = router_parse_addr_policy(tok);
+ newe = router_parse_addr_policy(tok, 0);
if (!newe)
return -1;
if (! router->exit_policy)
@@ -3682,7 +3565,7 @@ router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
/** Given a K_ACCEPT or K_REJECT token and a router, create and return
* a new exit_policy_t corresponding to the token. */
static addr_policy_t *
-router_parse_addr_policy(directory_token_t *tok)
+router_parse_addr_policy(directory_token_t *tok, unsigned fmt_flags)
{
addr_policy_t newe;
char *arg;
@@ -3704,7 +3587,7 @@ router_parse_addr_policy(directory_token_t *tok)
else
newe.policy_type = ADDR_POLICY_ACCEPT;
- if (tor_addr_parse_mask_ports(arg, &newe.addr, &newe.maskbits,
+ if (tor_addr_parse_mask_ports(arg, fmt_flags, &newe.addr, &newe.maskbits,
&newe.prt_min, &newe.prt_max) < 0) {
log_warn(LD_DIR,"Couldn't parse line %s. Dropping", escaped(arg));
return NULL;
@@ -3781,14 +3664,14 @@ token_clear(directory_token_t *tok)
STMT_BEGIN \
if (tok) token_clear(tok); \
tok = ALLOC_ZERO(sizeof(directory_token_t)); \
- tok->tp = _ERR; \
+ tok->tp = ERR_; \
tok->error = STRDUP(msg); \
goto done_tokenizing; \
STMT_END
/** Helper: make sure that the token <b>tok</b> with keyword <b>kwd</b> obeys
* the object syntax of <b>o_syn</b>. Allocate all storage in <b>area</b>.
- * Return <b>tok</b> on success, or a new _ERR token if the token didn't
+ * Return <b>tok</b> on success, or a new ERR_ token if the token didn't
* conform to the syntax we wanted.
**/
static INLINE directory_token_t *
@@ -3907,7 +3790,7 @@ get_next_token(memarea_t *area,
tor_assert(area);
tok = ALLOC_ZERO(sizeof(directory_token_t));
- tok->tp = _ERR;
+ tok->tp = ERR_;
/* Set *s to first token, eol to end-of-line, next to after first token */
*s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */
@@ -3964,10 +3847,10 @@ get_next_token(memarea_t *area,
}
}
- if (tok->tp == _ERR) {
+ if (tok->tp == ERR_) {
/* No keyword matched; call it an "K_opt" or "A_unrecognized" */
if (**s == '@')
- tok->tp = _A_UNKNOWN;
+ tok->tp = A_UNKNOWN_;
else
tok->tp = K_OPT;
tok->args = ALLOC(sizeof(char*));
@@ -4006,7 +3889,7 @@ get_next_token(memarea_t *area,
if ((size_t)(eol-next) != 9+obname_len+5 ||
strcmp_len(next+9, tok->object_type, obname_len) ||
strcmp_len(eol-5, "-----", 5)) {
- snprintf(ebuf, sizeof(ebuf), "Malformed object: mismatched end tag %s",
+ tor_snprintf(ebuf, sizeof(ebuf), "Malformed object: mismatched end tag %s",
tok->object_type);
ebuf[sizeof(ebuf)-1] = '\0';
RET_ERR(ebuf);
@@ -4057,23 +3940,30 @@ tokenize_string(memarea_t *area,
{
const char **s;
directory_token_t *tok = NULL;
- int counts[_NIL];
+ int counts[NIL_];
int i;
int first_nonannotation;
int prev_len = smartlist_len(out);
tor_assert(area);
s = &start;
- if (!end)
+ if (!end) {
end = start+strlen(start);
- for (i = 0; i < _NIL; ++i)
+ } else {
+ /* it's only meaningful to check for nuls if we got an end-of-string ptr */
+ if (memchr(start, '\0', end-start)) {
+ log_warn(LD_DIR, "parse error: internal NUL character.");
+ return -1;
+ }
+ }
+ for (i = 0; i < NIL_; ++i)
counts[i] = 0;
SMARTLIST_FOREACH(out, const directory_token_t *, t, ++counts[t->tp]);
- while (*s < end && (!tok || tok->tp != _EOF)) {
+ while (*s < end && (!tok || tok->tp != EOF_)) {
tok = get_next_token(area, s, end, table);
- if (tok->tp == _ERR) {
+ if (tok->tp == ERR_) {
log_warn(LD_DIR, "parse error: %s", tok->error);
token_clear(tok);
return -1;
@@ -4163,7 +4053,7 @@ find_opt_by_keyword(smartlist_t *s, directory_keyword keyword)
* with an assert if no such keyword is found.
*/
static directory_token_t *
-_find_by_keyword(smartlist_t *s, directory_keyword keyword,
+find_by_keyword_(smartlist_t *s, directory_keyword keyword,
const char *keyword_as_string)
{
directory_token_t *tok = find_opt_by_keyword(s, keyword);
@@ -4251,8 +4141,8 @@ router_get_hash_impl_helper(const char *s, size_t s_len,
/** Compute the digest of the substring of <b>s</b> taken from the first
* occurrence of <b>start_str</b> through the first instance of c after the
- * first subsequent occurrence of <b>end_str</b>; store the 20-byte result in
- * <b>digest</b>; return 0 on success.
+ * first subsequent occurrence of <b>end_str</b>; store the 20-byte or 32-byte
+ * result in <b>digest</b>; return 0 on success.
*
* If no such substring exists, return -1.
*/
@@ -4355,12 +4245,17 @@ find_start_of_next_microdesc(const char *s, const char *eos)
/** Parse as many microdescriptors as are found from the string starting at
* <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any
- * annotations we recognize and ignore ones we don't. If <b>copy_body</b> is
- * true, then strdup the bodies of the microdescriptors. Return all newly
+ * annotations we recognize and ignore ones we don't.
+ *
+ * If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each
+ * descriptor in the body field of each microdesc_t.
+ *
+ * Return all newly
* parsed microdescriptors in a newly allocated smartlist_t. */
smartlist_t *
microdescs_parse_from_string(const char *s, const char *eos,
- int allow_annotations, int copy_body)
+ int allow_annotations,
+ saved_location_t where)
{
smartlist_t *tokens;
smartlist_t *result;
@@ -4369,6 +4264,7 @@ microdescs_parse_from_string(const char *s, const char *eos,
const char *start = s;
const char *start_of_next_microdesc;
int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0;
+ const int copy_body = (where != SAVED_IN_CACHE);
directory_token_t *tok;
@@ -4398,8 +4294,9 @@ microdescs_parse_from_string(const char *s, const char *eos,
tor_assert(cp);
md->bodylen = start_of_next_microdesc - cp;
+ md->saved_location = where;
if (copy_body)
- md->body = tor_strndup(cp, md->bodylen);
+ md->body = tor_memdup_nulterm(cp, md->bodylen);
else
md->body = (char*)cp;
md->off = cp - start;
@@ -4421,6 +4318,25 @@ microdescs_parse_from_string(const char *s, const char *eos,
md->onion_pkey = tok->key;
tok->key = NULL;
+ if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) {
+ curve25519_public_key_t k;
+ tor_assert(tok->n_args >= 1);
+ if (curve25519_public_from_base64(&k, tok->args[0]) < 0) {
+ log_warn(LD_DIR, "Bogus ntor-onion-key in microdesc");
+ goto next;
+ }
+ md->onion_curve25519_pkey =
+ tor_memdup(&k, sizeof(curve25519_public_key_t));
+ }
+
+ {
+ smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
+ if (a_lines) {
+ find_single_ipv6_orport(a_lines, &md->ipv6_addr, &md->ipv6_orport);
+ smartlist_free(a_lines);
+ }
+ }
+
if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) {
int i;
md->family = smartlist_new();
@@ -4437,6 +4353,9 @@ microdescs_parse_from_string(const char *s, const char *eos,
if ((tok = find_opt_by_keyword(tokens, K_P))) {
md->exit_policy = parse_short_policy(tok->args[0]);
}
+ if ((tok = find_opt_by_keyword(tokens, K_P6))) {
+ md->ipv6_exit_policy = parse_short_policy(tok->args[0]);
+ }
crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
@@ -4654,7 +4573,7 @@ tor_version_same_series(tor_version_t *a, tor_version_t *b)
* if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent.
* Used to sort a list of versions. */
static int
-_compare_tor_version_str_ptr(const void **_a, const void **_b)
+compare_tor_version_str_ptr_(const void **_a, const void **_b)
{
const char *a = *_a, *b = *_b;
int ca, cb;
@@ -4678,10 +4597,10 @@ _compare_tor_version_str_ptr(const void **_a, const void **_b)
void
sort_version_list(smartlist_t *versions, int remove_duplicates)
{
- smartlist_sort(versions, _compare_tor_version_str_ptr);
+ smartlist_sort(versions, compare_tor_version_str_ptr_);
if (remove_duplicates)
- smartlist_uniq(versions, _compare_tor_version_str_ptr, _tor_free);
+ smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_);
}
/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
diff --git a/src/or/routerparse.h b/src/or/routerparse.h
index c6382a7f6..eb2e885cb 100644
--- a/src/or/routerparse.h
+++ b/src/or/routerparse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,18 +9,19 @@
* \brief Header file for routerparse.c.
**/
-#ifndef _TOR_ROUTERPARSE_H
-#define _TOR_ROUTERPARSE_H
+#ifndef TOR_ROUTERPARSE_H
+#define TOR_ROUTERPARSE_H
int router_get_router_hash(const char *s, size_t s_len, char *digest);
int router_get_dir_hash(const char *s, char *digest);
int router_get_runningrouters_hash(const char *s, char *digest);
int router_get_networkstatus_v2_hash(const char *s, char *digest);
-int router_get_networkstatus_v3_hash(const char *s, char *digest,
- digest_algorithm_t algorithm);
int router_get_networkstatus_v3_hashes(const char *s, digests_t *digests);
int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest);
#define DIROBJ_MAX_SIG_LEN 256
+char *router_get_dirobj_signature(const char *digest,
+ size_t digest_len,
+ crypto_pk_t *private_key);
int router_append_dirobj_signature(char *buf, size_t buf_len,
const char *digest,
size_t digest_len,
@@ -31,8 +32,6 @@ int router_parse_list_from_string(const char **s, const char *eos,
int is_extrainfo,
int allow_annotations,
const char *prepend_annotations);
-int router_parse_runningrouters(const char *str);
-int router_parse_directory(const char *str);
routerinfo_t *router_parse_entry_from_string(const char *s, const char *end,
int cache_copy,
@@ -54,8 +53,9 @@ void assert_addr_policy_ok(smartlist_t *t);
void dump_distinct_digest_count(int severity);
int compare_routerstatus_entries(const void **_a, const void **_b);
+int compare_vote_routerstatus_entries(const void **_a, const void **_b);
networkstatus_v2_t *networkstatus_v2_parse_from_string(const char *s);
-int networkstatus_verify_bw_weights(networkstatus_t *ns);
+int networkstatus_verify_bw_weights(networkstatus_t *ns, int);
networkstatus_t *networkstatus_parse_vote_from_string(const char *s,
const char **eos_out,
networkstatus_type_t ns_type);
@@ -64,7 +64,7 @@ ns_detached_signatures_t *networkstatus_parse_detached_signatures(
smartlist_t *microdescs_parse_from_string(const char *s, const char *eos,
int allow_annotations,
- int copy_body);
+ saved_location_t where);
authority_cert_t *authority_cert_parse_from_string(const char *s,
const char **end_of_string);
diff --git a/src/or/routerset.c b/src/or/routerset.c
new file mode 100644
index 000000000..2e41f7f6c
--- /dev/null
+++ b/src/or/routerset.c
@@ -0,0 +1,466 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "geoip.h"
+#include "nodelist.h"
+#include "policies.h"
+#include "router.h"
+#include "routerparse.h"
+#include "routerset.h"
+
+/** A routerset specifies constraints on a set of possible routerinfos, based
+ * on their names, identities, or addresses. It is optimized for determining
+ * whether a router is a member or not, in O(1+P) time, where P is the number
+ * of address policy constraints. */
+struct routerset_t {
+ /** A list of strings for the elements of the policy. Each string is either
+ * a nickname, a hexadecimal identity fingerprint, or an address policy. A
+ * router belongs to the set if its nickname OR its identity OR its address
+ * matches an entry here. */
+ smartlist_t *list;
+ /** A map from lowercase nicknames of routers in the set to (void*)1 */
+ strmap_t *names;
+ /** A map from identity digests routers in the set to (void*)1 */
+ digestmap_t *digests;
+ /** An address policy for routers in the set. For implementation reasons,
+ * a router belongs to the set if it is _rejected_ by this policy. */
+ smartlist_t *policies;
+
+ /** A human-readable description of what this routerset is for. Used in
+ * log messages. */
+ char *description;
+
+ /** A list of the country codes in this set. */
+ smartlist_t *country_names;
+ /** Total number of countries we knew about when we built <b>countries</b>.*/
+ int n_countries;
+ /** Bit array mapping the return value of geoip_get_country() to 1 iff the
+ * country is a member of this routerset. Note that we MUST call
+ * routerset_refresh_countries() whenever the geoip country list is
+ * reloaded. */
+ bitarray_t *countries;
+};
+
+/** Return a new empty routerset. */
+routerset_t *
+routerset_new(void)
+{
+ routerset_t *result = tor_malloc_zero(sizeof(routerset_t));
+ result->list = smartlist_new();
+ result->names = strmap_new();
+ result->digests = digestmap_new();
+ result->policies = smartlist_new();
+ result->country_names = smartlist_new();
+ return result;
+}
+
+/** If <b>c</b> is a country code in the form {cc}, return a newly allocated
+ * string holding the "cc" part. Else, return NULL. */
+static char *
+routerset_get_countryname(const char *c)
+{
+ char *country;
+
+ if (strlen(c) < 4 || c[0] !='{' || c[3] !='}')
+ return NULL;
+
+ country = tor_strndup(c+1, 2);
+ tor_strlower(country);
+ return country;
+}
+
+/** Update the routerset's <b>countries</b> bitarray_t. Called whenever
+ * the GeoIP IPv4 database is reloaded.
+ */
+void
+routerset_refresh_countries(routerset_t *target)
+{
+ int cc;
+ bitarray_free(target->countries);
+
+ if (!geoip_is_loaded(AF_INET)) {
+ target->countries = NULL;
+ target->n_countries = 0;
+ return;
+ }
+ target->n_countries = geoip_get_n_countries();
+ target->countries = bitarray_init_zero(target->n_countries);
+ SMARTLIST_FOREACH_BEGIN(target->country_names, const char *, country) {
+ cc = geoip_get_country(country);
+ if (cc >= 0) {
+ tor_assert(cc < target->n_countries);
+ bitarray_set(target->countries, cc);
+ } else {
+ log_warn(LD_CONFIG, "Country code '%s' is not recognized.",
+ country);
+ }
+ } SMARTLIST_FOREACH_END(country);
+}
+
+/** Parse the string <b>s</b> to create a set of routerset entries, and add
+ * them to <b>target</b>. In log messages, refer to the string as
+ * <b>description</b>. Return 0 on success, -1 on failure.
+ *
+ * Three kinds of elements are allowed in routersets: nicknames, IP address
+ * patterns, and fingerprints. They may be surrounded by optional space, and
+ * must be separated by commas.
+ */
+int
+routerset_parse(routerset_t *target, const char *s, const char *description)
+{
+ int r = 0;
+ int added_countries = 0;
+ char *countryname;
+ smartlist_t *list = smartlist_new();
+ smartlist_split_string(list, s, ",",
+ SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0);
+ SMARTLIST_FOREACH_BEGIN(list, char *, nick) {
+ addr_policy_t *p;
+ if (is_legal_hexdigest(nick)) {
+ char d[DIGEST_LEN];
+ if (*nick == '$')
+ ++nick;
+ log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description);
+ base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN);
+ digestmap_set(target->digests, d, (void*)1);
+ } else if (is_legal_nickname(nick)) {
+ log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description);
+ strmap_set_lc(target->names, nick, (void*)1);
+ } else if ((countryname = routerset_get_countryname(nick)) != NULL) {
+ log_debug(LD_CONFIG, "Adding country %s to %s", nick,
+ description);
+ smartlist_add(target->country_names, countryname);
+ added_countries = 1;
+ } else if ((strchr(nick,'.') || strchr(nick, '*')) &&
+ (p = router_parse_addr_policy_item_from_string(
+ nick, ADDR_POLICY_REJECT))) {
+ log_debug(LD_CONFIG, "Adding address %s to %s", nick, description);
+ smartlist_add(target->policies, p);
+ } else {
+ log_warn(LD_CONFIG, "Entry '%s' in %s is malformed.", nick,
+ description);
+ r = -1;
+ tor_free(nick);
+ SMARTLIST_DEL_CURRENT(list, nick);
+ }
+ } SMARTLIST_FOREACH_END(nick);
+ policy_expand_unspec(&target->policies);
+ smartlist_add_all(target->list, list);
+ smartlist_free(list);
+ if (added_countries)
+ routerset_refresh_countries(target);
+ return r;
+}
+
+/** Add all members of the set <b>source</b> to <b>target</b>. */
+void
+routerset_union(routerset_t *target, const routerset_t *source)
+{
+ char *s;
+ tor_assert(target);
+ if (!source || !source->list)
+ return;
+ s = routerset_to_string(source);
+ routerset_parse(target, s, "other routerset");
+ tor_free(s);
+}
+
+/** Return true iff <b>set</b> lists only nicknames and digests, and includes
+ * no IP ranges or countries. */
+int
+routerset_is_list(const routerset_t *set)
+{
+ return smartlist_len(set->country_names) == 0 &&
+ smartlist_len(set->policies) == 0;
+}
+
+/** Return true iff we need a GeoIP IP-to-country database to make sense of
+ * <b>set</b>. */
+int
+routerset_needs_geoip(const routerset_t *set)
+{
+ return set && smartlist_len(set->country_names);
+}
+
+/** Return true iff there are no entries in <b>set</b>. */
+int
+routerset_is_empty(const routerset_t *set)
+{
+ return !set || smartlist_len(set->list) == 0;
+}
+
+/** Helper. Return true iff <b>set</b> contains a router based on the other
+ * provided fields. Return higher values for more specific subentries: a
+ * single router is more specific than an address range of routers, which is
+ * more specific in turn than a country code.
+ *
+ * (If country is -1, then we take the country
+ * from addr.) */
+static int
+routerset_contains(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport,
+ const char *nickname, const char *id_digest,
+ country_t country)
+{
+ if (!set || !set->list)
+ return 0;
+ if (nickname && strmap_get_lc(set->names, nickname))
+ return 4;
+ if (id_digest && digestmap_get(set->digests, id_digest))
+ return 4;
+ if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies)
+ == ADDR_POLICY_REJECTED)
+ return 3;
+ if (set->countries) {
+ if (country < 0 && addr)
+ country = geoip_get_country_by_addr(addr);
+
+ if (country >= 0 && country < set->n_countries &&
+ bitarray_is_set(set->countries, country))
+ return 2;
+ }
+ return 0;
+}
+
+/** If *<b>setp</b> includes at least one country code, or if
+ * <b>only_some_cc_set</b> is 0, add the ?? and A1 country codes to
+ * *<b>setp</b>, creating it as needed. Return true iff *<b>setp</b> changed.
+ */
+int
+routerset_add_unknown_ccs(routerset_t **setp, int only_if_some_cc_set)
+{
+ routerset_t *set;
+ int add_unknown, add_a1;
+ if (only_if_some_cc_set) {
+ if (!*setp || smartlist_len((*setp)->country_names) == 0)
+ return 0;
+ }
+ if (!*setp)
+ *setp = routerset_new();
+
+ set = *setp;
+
+ add_unknown = ! smartlist_contains_string_case(set->country_names, "??") &&
+ geoip_get_country("??") >= 0;
+ add_a1 = ! smartlist_contains_string_case(set->country_names, "a1") &&
+ geoip_get_country("A1") >= 0;
+
+ if (add_unknown) {
+ smartlist_add(set->country_names, tor_strdup("??"));
+ smartlist_add(set->list, tor_strdup("{??}"));
+ }
+ if (add_a1) {
+ smartlist_add(set->country_names, tor_strdup("a1"));
+ smartlist_add(set->list, tor_strdup("{a1}"));
+ }
+
+ if (add_unknown || add_a1) {
+ routerset_refresh_countries(set);
+ return 1;
+ }
+ return 0;
+}
+
+/** Return true iff we can tell that <b>ei</b> is a member of <b>set</b>. */
+int
+routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei)
+{
+ return routerset_contains(set,
+ &ei->addr,
+ ei->port,
+ ei->nickname,
+ ei->identity_digest,
+ -1 /*country*/);
+}
+
+/** Return true iff <b>ri</b> is in <b>set</b>. If country is <b>-1</b>, we
+ * look up the country. */
+int
+routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
+ country_t country)
+{
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, ri->addr);
+ return routerset_contains(set,
+ &addr,
+ ri->or_port,
+ ri->nickname,
+ ri->cache_info.identity_digest,
+ country);
+}
+
+/** Return true iff <b>rs</b> is in <b>set</b>. If country is <b>-1</b>, we
+ * look up the country. */
+int
+routerset_contains_routerstatus(const routerset_t *set,
+ const routerstatus_t *rs,
+ country_t country)
+{
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, rs->addr);
+ return routerset_contains(set,
+ &addr,
+ rs->or_port,
+ rs->nickname,
+ rs->identity_digest,
+ country);
+}
+
+/** Return true iff <b>node</b> is in <b>set</b>. */
+int
+routerset_contains_node(const routerset_t *set, const node_t *node)
+{
+ if (node->rs)
+ return routerset_contains_routerstatus(set, node->rs, node->country);
+ else if (node->ri)
+ return routerset_contains_router(set, node->ri, node->country);
+ else
+ return 0;
+}
+
+/** Add every known node_t that is a member of <b>routerset</b> to
+ * <b>out</b>, but never add any that are part of <b>excludeset</b>.
+ * If <b>running_only</b>, only add the running ones. */
+void
+routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
+ const routerset_t *excludeset, int running_only)
+{
+ tor_assert(out);
+ if (!routerset || !routerset->list)
+ return;
+
+ if (routerset_is_list(routerset)) {
+ /* No routers are specified by type; all are given by name or digest.
+ * we can do a lookup in O(len(routerset)). */
+ SMARTLIST_FOREACH(routerset->list, const char *, name, {
+ const node_t *node = node_get_by_nickname(name, 1);
+ if (node) {
+ if (!running_only || node->is_running)
+ if (!routerset_contains_node(excludeset, node))
+ smartlist_add(out, (void*)node);
+ }
+ });
+ } else {
+ /* We need to iterate over the routerlist to get all the ones of the
+ * right kind. */
+ smartlist_t *nodes = nodelist_get_list();
+ SMARTLIST_FOREACH(nodes, const node_t *, node, {
+ if (running_only && !node->is_running)
+ continue;
+ if (routerset_contains_node(routerset, node) &&
+ !routerset_contains_node(excludeset, node))
+ smartlist_add(out, (void*)node);
+ });
+ }
+}
+
+#if 0
+/** Add to <b>target</b> every node_t from <b>source</b> except:
+ *
+ * 1) Don't add it if <b>include</b> is non-empty and the relay isn't in
+ * <b>include</b>; and
+ * 2) Don't add it if <b>exclude</b> is non-empty and the relay is
+ * excluded in a more specific fashion by <b>exclude</b>.
+ * 3) If <b>running_only</b>, don't add non-running routers.
+ */
+void
+routersets_get_node_disjunction(smartlist_t *target,
+ const smartlist_t *source,
+ const routerset_t *include,
+ const routerset_t *exclude, int running_only)
+{
+ SMARTLIST_FOREACH(source, const node_t *, node, {
+ int include_result;
+ if (running_only && !node->is_running)
+ continue;
+ if (!routerset_is_empty(include))
+ include_result = routerset_contains_node(include, node);
+ else
+ include_result = 1;
+
+ if (include_result) {
+ int exclude_result = routerset_contains_node(exclude, node);
+ if (include_result >= exclude_result)
+ smartlist_add(target, (void*)node);
+ }
+ });
+}
+#endif
+
+/** Remove every node_t from <b>lst</b> that is in <b>routerset</b>. */
+void
+routerset_subtract_nodes(smartlist_t *lst, const routerset_t *routerset)
+{
+ tor_assert(lst);
+ if (!routerset)
+ return;
+ SMARTLIST_FOREACH(lst, const node_t *, node, {
+ if (routerset_contains_node(routerset, node)) {
+ //log_debug(LD_DIR, "Subtracting %s",r->nickname);
+ SMARTLIST_DEL_CURRENT(lst, node);
+ }
+ });
+}
+
+/** Return a new string that when parsed by routerset_parse_string() will
+ * yield <b>set</b>. */
+char *
+routerset_to_string(const routerset_t *set)
+{
+ if (!set || !set->list)
+ return tor_strdup("");
+ return smartlist_join_strings(set->list, ",", 0, NULL);
+}
+
+/** Helper: return true iff old and new are both NULL, or both non-NULL
+ * equal routersets. */
+int
+routerset_equal(const routerset_t *old, const routerset_t *new)
+{
+ if (routerset_is_empty(old) && routerset_is_empty(new)) {
+ /* Two empty sets are equal */
+ return 1;
+ } else if (routerset_is_empty(old) || routerset_is_empty(new)) {
+ /* An empty set is equal to nothing else. */
+ return 0;
+ }
+ tor_assert(old != NULL);
+ tor_assert(new != NULL);
+
+ if (smartlist_len(old->list) != smartlist_len(new->list))
+ return 0;
+
+ SMARTLIST_FOREACH(old->list, const char *, cp1, {
+ const char *cp2 = smartlist_get(new->list, cp1_sl_idx);
+ if (strcmp(cp1, cp2))
+ return 0;
+ });
+
+ return 1;
+}
+
+/** Free all storage held in <b>routerset</b>. */
+void
+routerset_free(routerset_t *routerset)
+{
+ if (!routerset)
+ return;
+
+ SMARTLIST_FOREACH(routerset->list, char *, cp, tor_free(cp));
+ smartlist_free(routerset->list);
+ SMARTLIST_FOREACH(routerset->policies, addr_policy_t *, p,
+ addr_policy_free(p));
+ smartlist_free(routerset->policies);
+ SMARTLIST_FOREACH(routerset->country_names, char *, cp, tor_free(cp));
+ smartlist_free(routerset->country_names);
+
+ strmap_free(routerset->names, NULL);
+ digestmap_free(routerset->digests, NULL);
+ bitarray_free(routerset->countries);
+ tor_free(routerset);
+}
+
diff --git a/src/or/routerset.h b/src/or/routerset.h
new file mode 100644
index 000000000..bfa0c59ac
--- /dev/null
+++ b/src/or/routerset.h
@@ -0,0 +1,49 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file routerlist.h
+ * \brief Header file for routerset.c
+ **/
+
+#ifndef TOR_ROUTERSET_H
+#define TOR_ROUTERSET_H
+
+routerset_t *routerset_new(void);
+void routerset_refresh_countries(routerset_t *rs);
+int routerset_parse(routerset_t *target, const char *s,
+ const char *description);
+void routerset_union(routerset_t *target, const routerset_t *source);
+int routerset_is_list(const routerset_t *set);
+int routerset_needs_geoip(const routerset_t *set);
+int routerset_is_empty(const routerset_t *set);
+int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
+ country_t country);
+int routerset_contains_routerstatus(const routerset_t *set,
+ const routerstatus_t *rs,
+ country_t country);
+int routerset_contains_extendinfo(const routerset_t *set,
+ const extend_info_t *ei);
+
+int routerset_contains_node(const routerset_t *set, const node_t *node);
+void routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
+ const routerset_t *excludeset,
+ int running_only);
+int routerset_add_unknown_ccs(routerset_t **setp, int only_if_some_cc_set);
+#if 0
+void routersets_get_node_disjunction(smartlist_t *target,
+ const smartlist_t *source,
+ const routerset_t *include,
+ const routerset_t *exclude, int running_only);
+#endif
+void routerset_subtract_nodes(smartlist_t *out,
+ const routerset_t *routerset);
+
+char *routerset_to_string(const routerset_t *routerset);
+int routerset_equal(const routerset_t *old, const routerset_t *new);
+void routerset_free(routerset_t *routerset);
+
+#endif
+
diff --git a/src/or/statefile.c b/src/or/statefile.c
new file mode 100644
index 000000000..bcb7b0741
--- /dev/null
+++ b/src/or/statefile.c
@@ -0,0 +1,616 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "circuitstats.h"
+#include "config.h"
+#include "confparse.h"
+#include "entrynodes.h"
+#include "hibernate.h"
+#include "rephist.h"
+#include "router.h"
+#include "statefile.h"
+
+/** A list of state-file "abbreviations," for compatibility. */
+static config_abbrev_t state_abbrevs_[] = {
+ { "AccountingBytesReadInterval", "AccountingBytesReadInInterval", 0, 0 },
+ { "HelperNode", "EntryGuard", 0, 0 },
+ { "HelperNodeDownSince", "EntryGuardDownSince", 0, 0 },
+ { "HelperNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
+ { "EntryNode", "EntryGuard", 0, 0 },
+ { "EntryNodeDownSince", "EntryGuardDownSince", 0, 0 },
+ { "EntryNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 },
+ { NULL, NULL, 0, 0},
+};
+
+/*XXXX these next two are duplicates or near-duplicates from config.c */
+#define VAR(name,conftype,member,initvalue) \
+ { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_state_t, member), \
+ initvalue }
+/** As VAR, but the option name and member name are the same. */
+#define V(member,conftype,initvalue) \
+ VAR(#member, conftype, member, initvalue)
+
+/** Array of "state" variables saved to the ~/.tor/state file. */
+static config_var_t state_vars_[] = {
+ /* Remember to document these in state-contents.txt ! */
+
+ V(AccountingBytesReadInInterval, MEMUNIT, NULL),
+ V(AccountingBytesWrittenInInterval, MEMUNIT, NULL),
+ V(AccountingExpectedUsage, MEMUNIT, NULL),
+ V(AccountingIntervalStart, ISOTIME, NULL),
+ V(AccountingSecondsActive, INTERVAL, NULL),
+ V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL),
+ V(AccountingSoftLimitHitAt, ISOTIME, NULL),
+ V(AccountingBytesAtSoftLimit, MEMUNIT, NULL),
+
+ VAR("EntryGuard", LINELIST_S, EntryGuards, NULL),
+ VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL),
+ VAR("EntryGuardUnlistedSince", LINELIST_S, EntryGuards, NULL),
+ VAR("EntryGuardAddedBy", LINELIST_S, EntryGuards, NULL),
+ VAR("EntryGuardPathBias", LINELIST_S, EntryGuards, NULL),
+ VAR("EntryGuardPathUseBias", LINELIST_S, EntryGuards, NULL),
+ V(EntryGuards, LINELIST_V, NULL),
+
+ VAR("TransportProxy", LINELIST_S, TransportProxies, NULL),
+ V(TransportProxies, LINELIST_V, NULL),
+
+ V(BWHistoryReadEnds, ISOTIME, NULL),
+ V(BWHistoryReadInterval, UINT, "900"),
+ V(BWHistoryReadValues, CSV, ""),
+ V(BWHistoryReadMaxima, CSV, ""),
+ V(BWHistoryWriteEnds, ISOTIME, NULL),
+ V(BWHistoryWriteInterval, UINT, "900"),
+ V(BWHistoryWriteValues, CSV, ""),
+ V(BWHistoryWriteMaxima, CSV, ""),
+ V(BWHistoryDirReadEnds, ISOTIME, NULL),
+ V(BWHistoryDirReadInterval, UINT, "900"),
+ V(BWHistoryDirReadValues, CSV, ""),
+ V(BWHistoryDirReadMaxima, CSV, ""),
+ V(BWHistoryDirWriteEnds, ISOTIME, NULL),
+ V(BWHistoryDirWriteInterval, UINT, "900"),
+ V(BWHistoryDirWriteValues, CSV, ""),
+ V(BWHistoryDirWriteMaxima, CSV, ""),
+
+ V(TorVersion, STRING, NULL),
+
+ V(LastRotatedOnionKey, ISOTIME, NULL),
+ V(LastWritten, ISOTIME, NULL),
+
+ V(TotalBuildTimes, UINT, NULL),
+ V(CircuitBuildAbandonedCount, UINT, "0"),
+ VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL),
+ VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL),
+ { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
+};
+
+#undef VAR
+#undef V
+
+static int or_state_validate(or_state_t *old_options, or_state_t *options,
+ int from_setconf, char **msg);
+
+/** Magic value for or_state_t. */
+#define OR_STATE_MAGIC 0x57A73f57
+
+/** "Extra" variable in the state that receives lines we can't parse. This
+ * lets us preserve options from versions of Tor newer than us. */
+static config_var_t state_extra_var = {
+ "__extra", CONFIG_TYPE_LINELIST, STRUCT_OFFSET(or_state_t, ExtraLines), NULL
+};
+
+/** Configuration format for or_state_t. */
+static const config_format_t state_format = {
+ sizeof(or_state_t),
+ OR_STATE_MAGIC,
+ STRUCT_OFFSET(or_state_t, magic_),
+ state_abbrevs_,
+ state_vars_,
+ (validate_fn_t)or_state_validate,
+ &state_extra_var,
+};
+
+/** Persistent serialized state. */
+static or_state_t *global_state = NULL;
+
+/** Return the persistent state struct for this Tor. */
+or_state_t *
+get_or_state(void)
+{
+ tor_assert(global_state);
+ return global_state;
+}
+
+/** Return true iff we have loaded the global state for this Tor */
+int
+or_state_loaded(void)
+{
+ return global_state != NULL;
+}
+
+/** Return true if <b>line</b> is a valid state TransportProxy line.
+ * Return false otherwise. */
+static int
+state_transport_line_is_valid(const char *line)
+{
+ smartlist_t *items = NULL;
+ char *addrport=NULL;
+ tor_addr_t addr;
+ uint16_t port = 0;
+ int r;
+
+ items = smartlist_new();
+ smartlist_split_string(items, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(items) != 2) {
+ log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line.");
+ goto err;
+ }
+
+ addrport = smartlist_get(items, 1);
+ if (tor_addr_port_lookup(addrport, &addr, &port) < 0) {
+ log_warn(LD_CONFIG, "state: Could not parse addrport.");
+ goto err;
+ }
+
+ if (!port) {
+ log_warn(LD_CONFIG, "state: Transport line did not contain port.");
+ goto err;
+ }
+
+ r = 1;
+ goto done;
+
+ err:
+ r = 0;
+
+ done:
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+ return r;
+}
+
+/** Return 0 if all TransportProxy lines in <b>state</b> are well
+ * formed. Otherwise, return -1. */
+static int
+validate_transports_in_state(or_state_t *state)
+{
+ int broken = 0;
+ config_line_t *line;
+
+ for (line = state->TransportProxies ; line ; line = line->next) {
+ tor_assert(!strcmp(line->key, "TransportProxy"));
+ if (!state_transport_line_is_valid(line->value))
+ broken = 1;
+ }
+
+ if (broken)
+ log_warn(LD_CONFIG, "state: State file seems to be broken.");
+
+ return 0;
+}
+
+/** Return 0 if every setting in <b>state</b> is reasonable, and a
+ * permissible transition from <b>old_state</b>. Else warn and return -1.
+ * Should have no side effects, except for normalizing the contents of
+ * <b>state</b>.
+ */
+/* XXX from_setconf is here because of bug 238 */
+static int
+or_state_validate(or_state_t *old_state, or_state_t *state,
+ int from_setconf, char **msg)
+{
+ /* We don't use these; only options do. Still, we need to match that
+ * signature. */
+ (void) from_setconf;
+ (void) old_state;
+
+ if (entry_guards_parse_state(state, 0, msg)<0)
+ return -1;
+
+ if (validate_transports_in_state(state)<0)
+ return -1;
+
+ return 0;
+}
+
+/** Replace the current persistent state with <b>new_state</b> */
+static int
+or_state_set(or_state_t *new_state)
+{
+ char *err = NULL;
+ int ret = 0;
+ tor_assert(new_state);
+ config_free(&state_format, global_state);
+ global_state = new_state;
+ if (entry_guards_parse_state(global_state, 1, &err)<0) {
+ log_warn(LD_GENERAL,"%s",err);
+ tor_free(err);
+ ret = -1;
+ }
+ if (rep_hist_load_state(global_state, &err)<0) {
+ log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
+ tor_free(err);
+ ret = -1;
+ }
+ if (circuit_build_times_parse_state(&circ_times, global_state) < 0) {
+ ret = -1;
+ }
+ return ret;
+}
+
+/**
+ * Save a broken state file to a backup location.
+ */
+static void
+or_state_save_broken(char *fname)
+{
+ int i;
+ file_status_t status;
+ char *fname2 = NULL;
+ for (i = 0; i < 100; ++i) {
+ tor_asprintf(&fname2, "%s.%d", fname, i);
+ status = file_status(fname2);
+ if (status == FN_NOENT)
+ break;
+ tor_free(fname2);
+ }
+ if (i == 100) {
+ log_warn(LD_BUG, "Unable to parse state in \"%s\"; too many saved bad "
+ "state files to move aside. Discarding the old state file.",
+ fname);
+ unlink(fname);
+ } else {
+ log_warn(LD_BUG, "Unable to parse state in \"%s\". Moving it aside "
+ "to \"%s\". This could be a bug in Tor; please tell "
+ "the developers.", fname, fname2);
+ if (rename(fname, fname2) < 0) {
+ log_warn(LD_BUG, "Weirdly, I couldn't even move the state aside. The "
+ "OS gave an error of %s", strerror(errno));
+ }
+ }
+ tor_free(fname2);
+}
+
+/** Reload the persistent state from disk, generating a new state as needed.
+ * Return 0 on success, less than 0 on failure.
+ */
+int
+or_state_load(void)
+{
+ or_state_t *new_state = NULL;
+ char *contents = NULL, *fname;
+ char *errmsg = NULL;
+ int r = -1, badstate = 0;
+
+ fname = get_datadir_fname("state");
+ switch (file_status(fname)) {
+ case FN_FILE:
+ if (!(contents = read_file_to_str(fname, 0, NULL))) {
+ log_warn(LD_FS, "Unable to read state file \"%s\"", fname);
+ goto done;
+ }
+ break;
+ case FN_NOENT:
+ break;
+ case FN_ERROR:
+ case FN_DIR:
+ default:
+ log_warn(LD_GENERAL,"State file \"%s\" is not a file? Failing.", fname);
+ goto done;
+ }
+ new_state = tor_malloc_zero(sizeof(or_state_t));
+ new_state->magic_ = OR_STATE_MAGIC;
+ config_init(&state_format, new_state);
+ if (contents) {
+ config_line_t *lines=NULL;
+ int assign_retval;
+ if (config_get_lines(contents, &lines, 0)<0)
+ goto done;
+ assign_retval = config_assign(&state_format, new_state,
+ lines, 0, 0, &errmsg);
+ config_free_lines(lines);
+ if (assign_retval<0)
+ badstate = 1;
+ if (errmsg) {
+ log_warn(LD_GENERAL, "%s", errmsg);
+ tor_free(errmsg);
+ }
+ }
+
+ if (!badstate && or_state_validate(NULL, new_state, 1, &errmsg) < 0)
+ badstate = 1;
+
+ if (errmsg) {
+ log_warn(LD_GENERAL, "%s", errmsg);
+ tor_free(errmsg);
+ }
+
+ if (badstate && !contents) {
+ log_warn(LD_BUG, "Uh oh. We couldn't even validate our own default state."
+ " This is a bug in Tor.");
+ goto done;
+ } else if (badstate && contents) {
+ or_state_save_broken(fname);
+
+ tor_free(contents);
+ config_free(&state_format, new_state);
+
+ new_state = tor_malloc_zero(sizeof(or_state_t));
+ new_state->magic_ = OR_STATE_MAGIC;
+ config_init(&state_format, new_state);
+ } else if (contents) {
+ log_info(LD_GENERAL, "Loaded state from \"%s\"", fname);
+ } else {
+ log_info(LD_GENERAL, "Initialized state");
+ }
+ if (or_state_set(new_state) == -1) {
+ or_state_save_broken(fname);
+ }
+ new_state = NULL;
+ if (!contents) {
+ global_state->next_write = 0;
+ or_state_save(time(NULL));
+ }
+ r = 0;
+
+ done:
+ tor_free(fname);
+ tor_free(contents);
+ if (new_state)
+ config_free(&state_format, new_state);
+
+ return r;
+}
+
+/** Did the last time we tried to write the state file fail? If so, we
+ * should consider disabling such features as preemptive circuit generation
+ * to compute circuit-build-time. */
+static int last_state_file_write_failed = 0;
+
+/** Return whether the state file failed to write last time we tried. */
+int
+did_last_state_file_write_fail(void)
+{
+ return last_state_file_write_failed;
+}
+
+/** If writing the state to disk fails, try again after this many seconds. */
+#define STATE_WRITE_RETRY_INTERVAL 3600
+
+/** If we're a relay, how often should we checkpoint our state file even
+ * if nothing else dirties it? This will checkpoint ongoing stats like
+ * bandwidth used, per-country user stats, etc. */
+#define STATE_RELAY_CHECKPOINT_INTERVAL (12*60*60)
+
+/** Write the persistent state to disk. Return 0 for success, <0 on failure. */
+int
+or_state_save(time_t now)
+{
+ char *state, *contents;
+ char tbuf[ISO_TIME_LEN+1];
+ char *fname;
+
+ tor_assert(global_state);
+
+ if (global_state->next_write > now)
+ return 0;
+
+ /* Call everything else that might dirty the state even more, in order
+ * to avoid redundant writes. */
+ entry_guards_update_state(global_state);
+ rep_hist_update_state(global_state);
+ circuit_build_times_update_state(&circ_times, global_state);
+ if (accounting_is_enabled(get_options()))
+ accounting_run_housekeeping(now);
+
+ global_state->LastWritten = now;
+
+ tor_free(global_state->TorVersion);
+ tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
+
+ state = config_dump(&state_format, NULL, global_state, 1, 0);
+ format_local_iso_time(tbuf, now);
+ tor_asprintf(&contents,
+ "# Tor state file last generated on %s local time\n"
+ "# Other times below are in UTC\n"
+ "# You *do not* need to edit this file.\n\n%s",
+ tbuf, state);
+ tor_free(state);
+ fname = get_datadir_fname("state");
+ if (write_str_to_file(fname, contents, 0)<0) {
+ log_warn(LD_FS, "Unable to write state to file \"%s\"; "
+ "will try again later", fname);
+ last_state_file_write_failed = 1;
+ tor_free(fname);
+ tor_free(contents);
+ /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state
+ * changes sooner). */
+ global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL;
+ return -1;
+ }
+
+ last_state_file_write_failed = 0;
+ log_info(LD_GENERAL, "Saved state to \"%s\"", fname);
+ tor_free(fname);
+ tor_free(contents);
+
+ if (server_mode(get_options()))
+ global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL;
+ else
+ global_state->next_write = TIME_MAX;
+
+ return 0;
+}
+
+/** Return the config line for transport <b>transport</b> in the current state.
+ * Return NULL if there is no config line for <b>transport</b>. */
+static config_line_t *
+get_transport_in_state_by_name(const char *transport)
+{
+ or_state_t *or_state = get_or_state();
+ config_line_t *line;
+ config_line_t *ret = NULL;
+ smartlist_t *items = NULL;
+
+ for (line = or_state->TransportProxies ; line ; line = line->next) {
+ tor_assert(!strcmp(line->key, "TransportProxy"));
+
+ items = smartlist_new();
+ smartlist_split_string(items, line->value, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+ if (smartlist_len(items) != 2) /* broken state */
+ goto done;
+
+ if (!strcmp(smartlist_get(items, 0), transport)) {
+ ret = line;
+ goto done;
+ }
+
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+ items = NULL;
+ }
+
+ done:
+ if (items) {
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+ }
+ return ret;
+}
+
+/** Return string containing the address:port part of the
+ * TransportProxy <b>line</b> for transport <b>transport</b>.
+ * If the line is corrupted, return NULL. */
+static const char *
+get_transport_bindaddr(const char *line, const char *transport)
+{
+ char *line_tmp = NULL;
+
+ if (strlen(line) < strlen(transport) + 2) {
+ goto broken_state;
+ } else {
+ /* line should start with the name of the transport and a space.
+ (for example, "obfs2 127.0.0.1:47245") */
+ tor_asprintf(&line_tmp, "%s ", transport);
+ if (strcmpstart(line, line_tmp))
+ goto broken_state;
+
+ tor_free(line_tmp);
+ return (line+strlen(transport)+1);
+ }
+
+ broken_state:
+ tor_free(line_tmp);
+ return NULL;
+}
+
+/** Return a string containing the address:port that a proxy transport
+ * should bind on. The string is stored on the heap and must be freed
+ * by the caller of this function. */
+char *
+get_stored_bindaddr_for_server_transport(const char *transport)
+{
+ char *default_addrport = NULL;
+ const char *stored_bindaddr = NULL;
+ config_line_t *line = NULL;
+
+ {
+ /* See if the user explicitly asked for a specific listening
+ address for this transport. */
+ char *conf_bindaddr = get_transport_bindaddr_from_config(transport);
+ if (conf_bindaddr)
+ return conf_bindaddr;
+ }
+
+ line = get_transport_in_state_by_name(transport);
+ if (!line) /* Found no references in state for this transport. */
+ goto no_bindaddr_found;
+
+ stored_bindaddr = get_transport_bindaddr(line->value, transport);
+ if (stored_bindaddr) /* found stored bindaddr in state file. */
+ return tor_strdup(stored_bindaddr);
+
+ no_bindaddr_found:
+ /** If we didn't find references for this pluggable transport in the
+ state file, we should instruct the pluggable transport proxy to
+ listen on INADDR_ANY on a random ephemeral port. */
+ tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0");
+ return default_addrport;
+}
+
+/** Save <b>transport</b> listening on <b>addr</b>:<b>port</b> to
+ state */
+void
+save_transport_to_state(const char *transport,
+ const tor_addr_t *addr, uint16_t port)
+{
+ or_state_t *state = get_or_state();
+
+ char *transport_addrport=NULL;
+
+ /** find where to write on the state */
+ config_line_t **next, *line;
+
+ /* see if this transport is already stored in state */
+ config_line_t *transport_line =
+ get_transport_in_state_by_name(transport);
+
+ if (transport_line) { /* if transport already exists in state... */
+ const char *prev_bindaddr = /* get its addrport... */
+ get_transport_bindaddr(transport_line->value, transport);
+ transport_addrport = tor_strdup(fmt_addrport(addr, port));
+
+ /* if transport in state has the same address as this one, life is good */
+ if (!strcmp(prev_bindaddr, transport_addrport)) {
+ log_info(LD_CONFIG, "Transport seems to have spawned on its usual "
+ "address:port.");
+ goto done;
+ } else { /* if addrport in state is different than the one we got */
+ log_info(LD_CONFIG, "Transport seems to have spawned on different "
+ "address:port. Let's update the state file with the new "
+ "address:port");
+ tor_free(transport_line->value); /* free the old line */
+ /* replace old addrport line with new line */
+ tor_asprintf(&transport_line->value, "%s %s", transport,
+ fmt_addrport(addr, port));
+ }
+ } else { /* never seen this one before; save it in state for next time */
+ log_info(LD_CONFIG, "It's the first time we see this transport. "
+ "Let's save its address:port");
+ next = &state->TransportProxies;
+ /* find the last TransportProxy line in the state and point 'next'
+ right after it */
+ line = state->TransportProxies;
+ while (line) {
+ next = &(line->next);
+ line = line->next;
+ }
+
+ /* allocate space for the new line and fill it in */
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("TransportProxy");
+ tor_asprintf(&line->value, "%s %s", transport, fmt_addrport(addr, port));
+
+ next = &(line->next);
+ }
+
+ if (!get_options()->AvoidDiskWrites)
+ or_state_mark_dirty(state, 0);
+
+ done:
+ tor_free(transport_addrport);
+}
+
+void
+or_state_free_all(void)
+{
+ config_free(&state_format, global_state);
+ global_state = NULL;
+}
+
diff --git a/src/or/statefile.h b/src/or/statefile.h
new file mode 100644
index 000000000..dcdee6c60
--- /dev/null
+++ b/src/or/statefile.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_STATEFILE_H
+#define TOR_STATEFILE_H
+
+or_state_t *get_or_state(void);
+int did_last_state_file_write_fail(void);
+int or_state_save(time_t now);
+
+void save_transport_to_state(const char *transport_name,
+ const tor_addr_t *addr, uint16_t port);
+char *get_stored_bindaddr_for_server_transport(const char *transport);
+int or_state_load(void);
+int or_state_loaded(void);
+void or_state_free_all(void);
+
+#endif
+
diff --git a/src/or/status.c b/src/or/status.c
index 04cd96eed..69f92ed09 100644
--- a/src/or/status.c
+++ b/src/or/status.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Tor Project, Inc. */
+/* Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,9 +10,12 @@
#include "config.h"
#include "status.h"
#include "nodelist.h"
+#include "relay.h"
#include "router.h"
#include "circuitlist.h"
#include "main.h"
+#include "hibernate.h"
+#include "rephist.h"
/** Return the total number of circuits. */
static int
@@ -21,7 +24,7 @@ count_circuits(void)
circuit_t *circ;
int nr=0;
- for (circ = _circuit_get_global_list(); circ; circ = circ->next)
+ for (circ = circuit_get_global_list_(); circ; circ = circ->next)
nr++;
return nr;
@@ -84,11 +87,13 @@ log_heartbeat(time_t now)
char *bw_rcvd = NULL;
char *uptime = NULL;
const routerinfo_t *me;
+ double r = tls_get_write_overhead_ratio();
+ const int hibernating = we_are_hibernating();
const or_options_t *options = get_options();
(void)now;
- if (public_server_mode(options)) {
+ if (public_server_mode(options) && !hibernating) {
/* Let's check if we are in the current cached consensus. */
if (!(me = router_get_my_routerinfo()))
return -1; /* Something stinks, we won't even attempt this. */
@@ -103,8 +108,22 @@ log_heartbeat(time_t now)
bw_sent = bytes_to_usage(get_bytes_written());
log_fn(LOG_NOTICE, LD_HEARTBEAT, "Heartbeat: Tor's uptime is %s, with %d "
- "circuits open. I've sent %s and received %s.",
- uptime, count_circuits(),bw_sent,bw_rcvd);
+ "circuits open. I've sent %s and received %s.%s",
+ uptime, count_circuits(),bw_sent,bw_rcvd,
+ hibernating?" We are currently hibernating.":"");
+
+ if (stats_n_data_cells_packaged && !hibernating)
+ log_notice(LD_HEARTBEAT, "Average packaged cell fullness: %2.3f%%",
+ 100*(U64_TO_DBL(stats_n_data_bytes_packaged) /
+ U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) );
+
+ if (r > 1.0) {
+ double overhead = ( r - 1.0 ) * 100.0;
+ log_notice(LD_HEARTBEAT, "TLS write overhead: %.f%%", overhead);
+ }
+
+ if (public_server_mode(options))
+ rep_hist_log_circuit_handshake_stats(now);
tor_free(uptime);
tor_free(bw_sent);
diff --git a/src/or/status.h b/src/or/status.h
index 189ac789e..7c3b969c8 100644
--- a/src/or/status.h
+++ b/src/or/status.h
@@ -1,8 +1,8 @@
-/* Copyright (c) 2010-2012, The Tor Project, Inc. */
+/* Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_STATUS_H
-#define _TOR_STATUS_H
+#ifndef TOR_STATUS_H
+#define TOR_STATUS_H
int log_heartbeat(time_t now);
diff --git a/src/or/tor_main.c b/src/or/tor_main.c
index 2f4922317..05dc0bf0b 100644
--- a/src/or/tor_main.c
+++ b/src/or/tor_main.c
@@ -1,11 +1,11 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-/** String describing which Tor subversion repository version the source was
- * built from. This string is generated by a bit of shell kludging int
- * src/or/Makefile.am, and is usually right.
+/** String describing which Tor Git repository version the source was
+ * built from. This string is generated by a bit of shell kludging in
+ * src/or/include.am, and is usually right.
*/
const char tor_git_revision[] =
#ifndef _MSC_VER
diff --git a/src/or/transports.c b/src/or/transports.c
index 4ba239562..3749d6bb2 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* Copyright (c) 2011-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -39,13 +39,17 @@
* transport_t structs.
*
* When the managed proxy stops spitting METHOD lines (signified by a
- * '{S,C}METHODS DONE' message) we register all the transports
- * collected to the circuitbuild.c subsystem. At this point, the
- * pointers to transport_t can be transformed into dangling pointers
- * at any point by the circuitbuild.c subsystem, and so we replace all
- * transport_t pointers with strings describing the transport names.
- * We can still go from a transport name to a transport_t using the
- * fact that each transport name uniquely identifies a transport_t.
+ * '{S,C}METHODS DONE' message) we pass copies of its transports to
+ * the bridge subsystem. We keep copies of the 'transport_t's on the
+ * managed proxy to be able to associate the proxy with its
+ * transports, and we pass copies to the bridge subsystem so that
+ * transports can be associated with bridges.
+ * [ XXX We should try see whether the two copies are really needed
+ * and maybe cut it into a single copy of the 'transport_t' shared
+ * between the managed proxy and the bridge subsystem. Preliminary
+ * analysis shows that both copies are needed with the current code
+ * logic, because of race conditions that can cause dangling
+ * pointers. ]
*
* <b>In even more detail, this is what happens when a SIGHUP
* occurs:</b>
@@ -90,6 +94,7 @@
#include "transports.h"
#include "util.h"
#include "router.h"
+#include "statefile.h"
static process_environment_t *
create_managed_proxy_environment(const managed_proxy_t *mp);
@@ -100,7 +105,7 @@ static void managed_proxy_destroy(managed_proxy_t *mp,
int also_terminate_process);
static void handle_finished_proxy(managed_proxy_t *mp);
-static void configure_proxy(managed_proxy_t *mp);
+static int configure_proxy(managed_proxy_t *mp);
static void parse_method_error(const char *line, int is_server_method);
#define parse_server_method_error(l) parse_method_error(l, 1)
@@ -119,14 +124,228 @@ static INLINE void free_execve_args(char **arg);
#define PROTO_CMETHODS_DONE "CMETHODS DONE"
#define PROTO_SMETHODS_DONE "SMETHODS DONE"
-/** Number of environment variables for managed proxy clients/servers. */
-#define ENVIRON_SIZE_CLIENT 3
-#define ENVIRON_SIZE_SERVER 7 /* XXX known to be too high, but that's ok */
-
/** The first and only supported - at the moment - configuration
protocol version. */
#define PROTO_VERSION_ONE 1
+/** A list of pluggable transports found in torrc. */
+static smartlist_t *transport_list = NULL;
+
+/** Returns a transport_t struct for a transport proxy supporting the
+ protocol <b>name</b> listening at <b>addr</b>:<b>port</b> using
+ SOCKS version <b>socks_ver</b>. */
+static transport_t *
+transport_new(const tor_addr_t *addr, uint16_t port,
+ const char *name, int socks_ver)
+{
+ transport_t *t = tor_malloc_zero(sizeof(transport_t));
+
+ tor_addr_copy(&t->addr, addr);
+ t->port = port;
+ t->name = tor_strdup(name);
+ t->socks_version = socks_ver;
+
+ return t;
+}
+
+/** Free the pluggable transport struct <b>transport</b>. */
+void
+transport_free(transport_t *transport)
+{
+ if (!transport)
+ return;
+
+ tor_free(transport->name);
+ tor_free(transport);
+}
+
+/** Mark every entry of the transport list to be removed on our next call to
+ * sweep_transport_list unless it has first been un-marked. */
+void
+mark_transport_list(void)
+{
+ if (!transport_list)
+ transport_list = smartlist_new();
+ SMARTLIST_FOREACH(transport_list, transport_t *, t,
+ t->marked_for_removal = 1);
+}
+
+/** Remove every entry of the transport list that was marked with
+ * mark_transport_list if it has not subsequently been un-marked. */
+void
+sweep_transport_list(void)
+{
+ if (!transport_list)
+ transport_list = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, t) {
+ if (t->marked_for_removal) {
+ SMARTLIST_DEL_CURRENT(transport_list, t);
+ transport_free(t);
+ }
+ } SMARTLIST_FOREACH_END(t);
+}
+
+/** Initialize the pluggable transports list to empty, creating it if
+ * needed. */
+static void
+clear_transport_list(void)
+{
+ if (!transport_list)
+ transport_list = smartlist_new();
+ SMARTLIST_FOREACH(transport_list, transport_t *, t, transport_free(t));
+ smartlist_clear(transport_list);
+}
+
+/** Return a deep copy of <b>transport</b>. */
+static transport_t *
+transport_copy(const transport_t *transport)
+{
+ transport_t *new_transport = NULL;
+
+ tor_assert(transport);
+
+ new_transport = tor_malloc_zero(sizeof(transport_t));
+
+ new_transport->socks_version = transport->socks_version;
+ new_transport->name = tor_strdup(transport->name);
+ tor_addr_copy(&new_transport->addr, &transport->addr);
+ new_transport->port = transport->port;
+ new_transport->marked_for_removal = transport->marked_for_removal;
+
+ return new_transport;
+}
+
+/** Returns the transport in our transport list that has the name <b>name</b>.
+ * Else returns NULL. */
+transport_t *
+transport_get_by_name(const char *name)
+{
+ tor_assert(name);
+
+ if (!transport_list)
+ return NULL;
+
+ SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, transport) {
+ if (!strcmp(transport->name, name))
+ return transport;
+ } SMARTLIST_FOREACH_END(transport);
+
+ return NULL;
+}
+
+/** Resolve any conflicts that the insertion of transport <b>t</b>
+ * might cause.
+ * Return 0 if <b>t</b> is OK and should be registered, 1 if there is
+ * a transport identical to <b>t</b> already registered and -1 if
+ * <b>t</b> cannot be added due to conflicts. */
+static int
+transport_resolve_conflicts(const transport_t *t)
+{
+ /* This is how we resolve transport conflicts:
+
+ If there is already a transport with the same name and addrport,
+ we either have duplicate torrc lines OR we are here post-HUP and
+ this transport was here pre-HUP as well. In any case, mark the
+ old transport so that it doesn't get removed and ignore the new
+ one. Our caller has to free the new transport so we return '1' to
+ signify this.
+
+ If there is already a transport with the same name but different
+ addrport:
+ * if it's marked for removal, it means that it either has a lower
+ priority than 't' in torrc (otherwise the mark would have been
+ cleared by the paragraph above), or it doesn't exist at all in
+ the post-HUP torrc. We destroy the old transport and register 't'.
+ * if it's *not* marked for removal, it means that it was newly
+ added in the post-HUP torrc or that it's of higher priority, in
+ this case we ignore 't'. */
+ transport_t *t_tmp = transport_get_by_name(t->name);
+ if (t_tmp) { /* same name */
+ if (tor_addr_eq(&t->addr, &t_tmp->addr) && (t->port == t_tmp->port)) {
+ /* same name *and* addrport */
+ t_tmp->marked_for_removal = 0;
+ return 1;
+ } else { /* same name but different addrport */
+ char *new_transport_addrport =
+ tor_strdup(fmt_addrport(&t->addr, t->port));
+ if (t_tmp->marked_for_removal) { /* marked for removal */
+ log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s' "
+ "but there was already a transport marked for deletion at "
+ "'%s'. We deleted the old transport and registered the "
+ "new one.", t->name, new_transport_addrport,
+ fmt_addrport(&t_tmp->addr, t_tmp->port));
+ smartlist_remove(transport_list, t_tmp);
+ transport_free(t_tmp);
+ tor_free(new_transport_addrport);
+ } else { /* *not* marked for removal */
+ log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s' "
+ "but the same transport already exists at '%s'. "
+ "Skipping.", t->name, new_transport_addrport,
+ fmt_addrport(&t_tmp->addr, t_tmp->port));
+ tor_free(new_transport_addrport);
+ return -1;
+ }
+ tor_free(new_transport_addrport);
+ }
+ }
+
+ return 0;
+}
+
+/** Add transport <b>t</b> to the internal list of pluggable
+ * transports.
+ * Returns 0 if the transport was added correctly, 1 if the same
+ * transport was already registered (in this case the caller must
+ * free the transport) and -1 if there was an error. */
+static int
+transport_add(transport_t *t)
+{
+ int r;
+ tor_assert(t);
+
+ r = transport_resolve_conflicts(t);
+
+ switch (r) {
+ case 0: /* should register transport */
+ if (!transport_list)
+ transport_list = smartlist_new();
+ smartlist_add(transport_list, t);
+ return 0;
+ default: /* let our caller know the return code */
+ return r;
+ }
+}
+
+/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>.
+ * <b>name</b> is set to the name of the protocol this proxy uses.
+ * <b>socks_ver</b> is set to the SOCKS version of the proxy. */
+int
+transport_add_from_config(const tor_addr_t *addr, uint16_t port,
+ const char *name, int socks_ver)
+{
+ transport_t *t = transport_new(addr, port, name, socks_ver);
+
+ int r = transport_add(t);
+
+ switch (r) {
+ case -1:
+ default:
+ log_notice(LD_GENERAL, "Could not add transport %s at %s. Skipping.",
+ t->name, fmt_addrport(&t->addr, t->port));
+ transport_free(t);
+ return -1;
+ case 1:
+ log_info(LD_GENERAL, "Successfully registered transport %s at %s.",
+ t->name, fmt_addrport(&t->addr, t->port));
+ transport_free(t); /* falling */
+ return 0;
+ case 0:
+ log_info(LD_GENERAL, "Successfully registered transport %s at %s.",
+ t->name, fmt_addrport(&t->addr, t->port));
+ return 0;
+ }
+}
+
/** List of unconfigured managed proxies. */
static smartlist_t *managed_proxy_list = NULL;
/** Number of still unconfigured proxies. */
@@ -205,7 +424,7 @@ static void
add_transport_to_proxy(const char *transport, managed_proxy_t *mp)
{
tor_assert(mp->transports_to_launch);
- if (!smartlist_string_isin(mp->transports_to_launch, transport))
+ if (!smartlist_contains_string(mp->transports_to_launch, transport))
smartlist_add(mp->transports_to_launch, tor_strdup(transport));
}
@@ -217,11 +436,11 @@ proxy_needs_restart(const managed_proxy_t *mp)
{
/* mp->transport_to_launch is populated with the names of the
transports that must be launched *after* the SIGHUP.
- mp->transports is populated with the names of the transports that
- were launched *before* the SIGHUP.
+ mp->transports is populated with the transports that were
+ launched *before* the SIGHUP.
- If the two lists contain the same strings, we don't need to
- restart the proxy, since it already does what we want. */
+ Check if all the transports that need to be launched are already
+ launched: */
tor_assert(smartlist_len(mp->transports_to_launch) > 0);
tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
@@ -229,11 +448,11 @@ proxy_needs_restart(const managed_proxy_t *mp)
if (smartlist_len(mp->transports_to_launch) != smartlist_len(mp->transports))
goto needs_restart;
- SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t_t_l) {
- if (!smartlist_string_isin(mp->transports, t_t_l))
+ SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
+ if (!smartlist_contains_string(mp->transports_to_launch, t->name))
goto needs_restart;
- } SMARTLIST_FOREACH_END(t_t_l);
+ } SMARTLIST_FOREACH_END(t);
return 0;
@@ -245,6 +464,7 @@ proxy_needs_restart(const managed_proxy_t *mp)
* preparations and then flag its state so that it will be relaunched
* in the next tick. */
static void
+
proxy_prepare_for_restart(managed_proxy_t *mp)
{
transport_t *t_tmp = NULL;
@@ -255,16 +475,17 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
tor_process_handle_destroy(mp->process_handle, 1);
mp->process_handle = NULL;
- /* destroy all its old transports. we no longer use them. */
- SMARTLIST_FOREACH_BEGIN(mp->transports, const char *, t_name) {
- t_tmp = transport_get_by_name(t_name);
+ /* destroy all its registered transports, since we will no longer
+ use them. */
+ SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
+ t_tmp = transport_get_by_name(t->name);
if (t_tmp)
t_tmp->marked_for_removal = 1;
- } SMARTLIST_FOREACH_END(t_name);
+ } SMARTLIST_FOREACH_END(t);
sweep_transport_list();
- /* free the transport names in mp->transports */
- SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name));
+ /* free the transport in mp->transports */
+ SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
smartlist_clear(mp->transports);
/* flag it as an infant proxy so that it gets launched on next tick */
@@ -315,6 +536,7 @@ launch_managed_proxy(managed_proxy_t *mp)
void
pt_configure_remaining_proxies(void)
{
+ int at_least_a_proxy_config_finished = 0;
smartlist_t *tmp = smartlist_new();
log_debug(LD_CONFIG, "Configuring remaining managed proxies (%d)!",
@@ -350,24 +572,29 @@ pt_configure_remaining_proxies(void)
/* If the proxy is not fully configured, try to configure it
futher. */
if (!proxy_configuration_finished(mp))
- configure_proxy(mp);
+ if (configure_proxy(mp) == 1)
+ at_least_a_proxy_config_finished = 1;
} SMARTLIST_FOREACH_END(mp);
smartlist_free(tmp);
check_if_restarts_needed = 0;
assert_unconfigured_count_ok();
-}
-#ifdef _WIN32
+ if (at_least_a_proxy_config_finished)
+ mark_my_descriptor_dirty("configured managed proxies");
+}
-/** Attempt to continue configuring managed proxy <b>mp</b>. */
-static void
+/** Attempt to continue configuring managed proxy <b>mp</b>.
+ * Return 1 if the transport configuration finished, and return 0
+ * otherwise (if we still have more configuring to do for this
+ * proxy). */
+static int
configure_proxy(managed_proxy_t *mp)
{
- int pos;
- char stdout_buf[200];
- smartlist_t *lines = NULL;
+ int configuration_finished = 0;
+ smartlist_t *proxy_output = NULL;
+ enum stream_status stream_status = 0;
/* if we haven't launched the proxy yet, do it now */
if (mp->conf_state == PT_PROTO_INFANT) {
@@ -375,34 +602,31 @@ configure_proxy(managed_proxy_t *mp)
mp->conf_state = PT_PROTO_FAILED_LAUNCH;
handle_finished_proxy(mp);
}
- return;
+ return 0;
}
tor_assert(mp->conf_state != PT_PROTO_INFANT);
tor_assert(mp->process_handle);
- pos = tor_read_all_handle(tor_process_get_stdout_pipe(mp->process_handle),
- stdout_buf, sizeof(stdout_buf) - 1, NULL);
- if (pos < 0) {
- log_notice(LD_GENERAL, "Failed to read data from managed proxy '%s'.",
- mp->argv[0]);
- mp->conf_state = PT_PROTO_BROKEN;
+ proxy_output =
+ tor_get_lines_from_handle(tor_process_get_stdout_pipe(mp->process_handle),
+ &stream_status);
+ if (!proxy_output) { /* failed to get input from proxy */
+ if (stream_status != IO_STREAM_EAGAIN) { /* bad stream status! */
+ mp->conf_state = PT_PROTO_BROKEN;
+ log_warn(LD_GENERAL, "The communication stream of managed proxy '%s' "
+ "is '%s'. Most probably the managed proxy stopped running. "
+ "This might be a bug of the managed proxy, a bug of Tor, or "
+ "a misconfiguration. Please enable logging on your managed "
+ "proxy and check the logs for errors.",
+ mp->argv[0], stream_status_to_string(stream_status));
+ }
+
goto done;
}
- if (pos == 0) /* proxy has nothing interesting to say. */
- return;
-
- /* End with a null even if there isn't a \r\n at the end */
- /* TODO: What if this is a partial line? */
- stdout_buf[pos] = '\0';
-
- /* Split up the buffer */
- lines = smartlist_new();
- tor_split_lines(lines, stdout_buf, pos);
-
/* Handle lines. */
- SMARTLIST_FOREACH_BEGIN(lines, const char *, line) {
+ SMARTLIST_FOREACH_BEGIN(proxy_output, const char *, line) {
handle_proxy_line(line, mp);
if (proxy_configuration_finished(mp))
goto done;
@@ -410,126 +634,63 @@ configure_proxy(managed_proxy_t *mp)
done:
/* if the proxy finished configuring, exit the loop. */
- if (proxy_configuration_finished(mp))
+ if (proxy_configuration_finished(mp)) {
handle_finished_proxy(mp);
-
- if (lines)
- smartlist_free(lines);
-}
-
-#else /* _WIN32 */
-
-/** Attempt to continue configuring managed proxy <b>mp</b>. */
-static void
-configure_proxy(managed_proxy_t *mp)
-{
- enum stream_status r;
- char stdout_buf[200];
-
- /* if we haven't launched the proxy yet, do it now */
- if (mp->conf_state == PT_PROTO_INFANT) {
- if (launch_managed_proxy(mp) < 0) { /* launch fail */
- mp->conf_state = PT_PROTO_FAILED_LAUNCH;
- handle_finished_proxy(mp);
- }
- return;
+ configuration_finished = 1;
}
- tor_assert(mp->conf_state != PT_PROTO_INFANT);
- tor_assert(mp->process_handle);
-
- while (1) {
- r = get_string_from_pipe(tor_process_get_stdout_pipe(mp->process_handle),
- stdout_buf, sizeof(stdout_buf) - 1);
-
- if (r == IO_STREAM_OKAY) { /* got a line; handle it! */
- handle_proxy_line((const char *)stdout_buf, mp);
- } else if (r == IO_STREAM_EAGAIN) { /* check back later */
- return;
- } else if (r == IO_STREAM_CLOSED || r == IO_STREAM_TERM) { /* snap! */
- log_warn(LD_GENERAL, "Our communication channel with the managed proxy "
- "'%s' closed. Most probably application stopped running.",
- mp->argv[0]);
- mp->conf_state = PT_PROTO_BROKEN;
- } else { /* unknown stream status */
- log_warn(LD_BUG, "Unknown stream status '%d' while configuring managed "
- "proxy '%s'.", (int)r, mp->argv[0]);
- }
-
- /* if the proxy finished configuring, exit the loop. */
- if (proxy_configuration_finished(mp)) {
- handle_finished_proxy(mp);
- return;
- }
+ if (proxy_output) {
+ SMARTLIST_FOREACH(proxy_output, char *, cp, tor_free(cp));
+ smartlist_free(proxy_output);
}
-}
-#endif /* _WIN32 */
+ return configuration_finished;
+}
/** Register server managed proxy <b>mp</b> transports to state */
static void
-register_server_proxy(managed_proxy_t *mp)
+register_server_proxy(const managed_proxy_t *mp)
{
- /* After we register this proxy's transports, we switch its
- mp->transports to a list containing strings of its transport
- names. (See transports.h) */
- smartlist_t *sm_tmp = smartlist_new();
-
tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
+
SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
save_transport_to_state(t->name, &t->addr, t->port);
- log_notice(LD_GENERAL, "Registered server transport '%s' at '%s:%d'",
- t->name, fmt_addr(&t->addr), (int)t->port);
- smartlist_add(sm_tmp, tor_strdup(t->name));
+ log_notice(LD_GENERAL, "Registered server transport '%s' at '%s'",
+ t->name, fmt_addrport(&t->addr, t->port));
} SMARTLIST_FOREACH_END(t);
-
- /* Since server proxies don't register their transports in the
- circuitbuild.c subsystem, it's our duty to free them when we
- switch mp->transports to strings. */
- SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
- smartlist_free(mp->transports);
-
- mp->transports = sm_tmp;
}
/** Register all the transports supported by client managed proxy
* <b>mp</b> to the bridge subsystem. */
static void
-register_client_proxy(managed_proxy_t *mp)
+register_client_proxy(const managed_proxy_t *mp)
{
int r;
- /* After we register this proxy's transports, we switch its
- mp->transports to a list containing strings of its transport
- names. (See transports.h) */
- smartlist_t *sm_tmp = smartlist_new();
tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
+
SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
- r = transport_add(t);
+ transport_t *transport_tmp = transport_copy(t);
+ r = transport_add(transport_tmp);
switch (r) {
case -1:
log_notice(LD_GENERAL, "Could not add transport %s. Skipping.", t->name);
- transport_free(t);
+ transport_free(transport_tmp);
break;
case 0:
- log_info(LD_GENERAL, "Succesfully registered transport %s", t->name);
- smartlist_add(sm_tmp, tor_strdup(t->name));
+ log_info(LD_GENERAL, "Successfully registered transport %s", t->name);
break;
case 1:
- log_info(LD_GENERAL, "Succesfully registered transport %s", t->name);
- smartlist_add(sm_tmp, tor_strdup(t->name));
- transport_free(t);
+ log_info(LD_GENERAL, "Successfully registered transport %s", t->name);
+ transport_free(transport_tmp);
break;
}
} SMARTLIST_FOREACH_END(t);
-
- smartlist_free(mp->transports);
- mp->transports = sm_tmp;
}
/** Register the transports of managed proxy <b>mp</b>. */
static INLINE void
-register_proxy(managed_proxy_t *mp)
+register_proxy(const managed_proxy_t *mp)
{
if (mp->is_server)
register_server_proxy(mp);
@@ -542,10 +703,7 @@ static void
managed_proxy_destroy(managed_proxy_t *mp,
int also_terminate_process)
{
- if (mp->conf_state != PT_PROTO_COMPLETED)
- SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
- else
- SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name));
+ SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
/* free the transports smartlist */
smartlist_free(mp->transports);
@@ -815,7 +973,7 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
}
addrport = smartlist_get(items, 2);
- if (tor_addr_port_split(LOG_PROTOCOL_WARN, addrport, &address, &port)<0) {
+ if (tor_addr_port_split(LOG_WARN, addrport, &address, &port)<0) {
log_warn(LD_CONFIG, "Error parsing transport "
"address '%s'", addrport);
goto err;
@@ -907,7 +1065,7 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp)
}
addrport = smartlist_get(items, 3);
- if (tor_addr_port_split(LOG_PROTOCOL_WARN, addrport, &address, &port)<0) {
+ if (tor_addr_port_split(LOG_WARN, addrport, &address, &port)<0) {
log_warn(LD_CONFIG, "Error parsing transport "
"address '%s'", addrport);
goto err;
@@ -1039,7 +1197,7 @@ create_managed_proxy_environment(const managed_proxy_t *mp)
SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) {
set_environment_variable_in_smartlist(merged_env_vars, env_var,
- _tor_free, 1);
+ tor_free_, 1);
} SMARTLIST_FOREACH_END(env_var);
env = process_environment_make(merged_env_vars);
@@ -1143,7 +1301,7 @@ free_execve_args(char **arg)
char **tmp = arg;
while (*tmp) /* use the fact that the last element of the array is a
NULL pointer to know when to stop freeing */
- _tor_free(*tmp++);
+ tor_free_(*tmp++);
tor_free(arg);
}
@@ -1181,6 +1339,93 @@ pt_prepare_proxy_list_for_config_read(void)
tor_assert(unconfigured_proxies_n == 0);
}
+/** Return a smartlist containing the ports where our pluggable
+ * transports are listening. */
+smartlist_t *
+get_transport_proxy_ports(void)
+{
+ smartlist_t *sl = NULL;
+
+ if (!managed_proxy_list)
+ return NULL;
+
+ /** XXX assume that external proxy ports have been forwarded
+ manually */
+ SMARTLIST_FOREACH_BEGIN(managed_proxy_list, const managed_proxy_t *, mp) {
+ if (!mp->is_server || mp->conf_state != PT_PROTO_COMPLETED)
+ continue;
+
+ if (!sl) sl = smartlist_new();
+
+ tor_assert(mp->transports);
+ SMARTLIST_FOREACH(mp->transports, const transport_t *, t,
+ smartlist_add_asprintf(sl, "%u:%u", t->port, t->port));
+
+ } SMARTLIST_FOREACH_END(mp);
+
+ return sl;
+}
+
+/** Return the pluggable transport string that we should display in
+ * our extra-info descriptor. If we shouldn't display such a string,
+ * or we have nothing to display, return NULL. The string is
+ * allocated on the heap and it's the responsibility of the caller to
+ * free it. */
+char *
+pt_get_extra_info_descriptor_string(void)
+{
+ char *the_string = NULL;
+ smartlist_t *string_chunks = NULL;
+
+ if (!managed_proxy_list)
+ return NULL;
+
+ string_chunks = smartlist_new();
+
+ /* For each managed proxy, add its transports to the chunks list. */
+ SMARTLIST_FOREACH_BEGIN(managed_proxy_list, const managed_proxy_t *, mp) {
+ if ((!mp->is_server) || (mp->conf_state != PT_PROTO_COMPLETED))
+ continue;
+
+ tor_assert(mp->transports);
+
+ SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
+ /* If the transport proxy returned "0.0.0.0" as its address, and
+ * we know our external IP address, use it. Otherwise, use the
+ * returned address. */
+ const char *addrport = NULL;
+ uint32_t external_ip_address = 0;
+ if (tor_addr_is_null(&t->addr) &&
+ router_pick_published_address(get_options(),
+ &external_ip_address) >= 0) {
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, external_ip_address);
+ addrport = fmt_addrport(&addr, t->port);
+ } else {
+ addrport = fmt_addrport(&t->addr, t->port);
+ }
+
+ smartlist_add_asprintf(string_chunks,
+ "transport %s %s",
+ t->name, addrport);
+ } SMARTLIST_FOREACH_END(t);
+
+ } SMARTLIST_FOREACH_END(mp);
+
+ if (smartlist_len(string_chunks) == 0) {
+ smartlist_free(string_chunks);
+ return NULL;
+ }
+
+ /* Join all the chunks into the final string. */
+ the_string = smartlist_join_strings(string_chunks, "\n", 1, NULL);
+
+ SMARTLIST_FOREACH(string_chunks, char *, s, tor_free(s));
+ smartlist_free(string_chunks);
+
+ return the_string;
+}
+
/** The tor config was read.
* Destroy all managed proxies that were marked by a previous call to
* prepare_proxy_list_for_config_read() and are not used by the new
@@ -1204,6 +1449,12 @@ sweep_proxy_list(void)
void
pt_free_all(void)
{
+ if (transport_list) {
+ clear_transport_list();
+ smartlist_free(transport_list);
+ transport_list = NULL;
+ }
+
if (managed_proxy_list) {
/* If the proxy is in PT_PROTO_COMPLETED, it has registered its
transports and it's the duty of the circuitbuild.c subsystem to
diff --git a/src/or/transports.h b/src/or/transports.h
index 02f159a5d..6ee82f455 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,6 +11,30 @@
#ifndef TOR_TRANSPORTS_H
#define TOR_TRANSPORTS_H
+/** Represents a pluggable transport used by a bridge. */
+typedef struct transport_t {
+ /** SOCKS version: One of PROXY_SOCKS4, PROXY_SOCKS5. */
+ int socks_version;
+ /** Name of pluggable transport protocol */
+ char *name;
+ /** The IP address where the transport bound and is waiting for
+ * connections. */
+ tor_addr_t addr;
+ /** Port of proxy */
+ uint16_t port;
+ /** Boolean: We are re-parsing our transport list, and we are going to remove
+ * this one if we don't find it in the list of configured transports. */
+ unsigned marked_for_removal : 1;
+} transport_t;
+
+void mark_transport_list(void);
+void sweep_transport_list(void);
+int transport_add_from_config(const tor_addr_t *addr, uint16_t port,
+ const char *name, int socks_ver);
+void transport_free(transport_t *transport);
+
+transport_t *transport_get_by_name(const char *name);
+
void pt_kickstart_proxy(const smartlist_t *transport_list, char **proxy_argv,
int is_server);
@@ -23,11 +47,15 @@ void pt_configure_remaining_proxies(void);
int pt_proxies_configuration_pending(void);
+char *pt_get_extra_info_descriptor_string(void);
+
void pt_free_all(void);
void pt_prepare_proxy_list_for_config_read(void);
void sweep_proxy_list(void);
+smartlist_t *get_transport_proxy_ports(void);
+
#ifdef PT_PRIVATE
/** State of the managed proxy configuration protocol. */
enum pt_proto_state {
@@ -68,28 +96,7 @@ typedef struct {
smartlist_t *transports_to_launch;
/* The 'transports' list contains all the transports this proxy has
- launched.
-
- Before a managed_proxy_t reaches the PT_PROTO_COMPLETED phase,
- this smartlist contains a 'transport_t' for every transport it
- has launched.
-
- When the managed_proxy_t reaches the PT_PROTO_COMPLETED phase, it
- registers all its transports to the circuitbuild.c subsystem. At
- that point the 'transport_t's are owned by the circuitbuild.c
- subsystem.
-
- To avoid carrying dangling 'transport_t's in this smartlist,
- right before the managed_proxy_t reaches the PT_PROTO_COMPLETED
- phase we replace all 'transport_t's with strings of their
- transport names.
-
- So, tl;dr:
- When (conf_state != PT_PROTO_COMPLETED) this list carries
- (transport_t *).
- When (conf_state == PT_PROTO_COMPLETED) this list carries
- (char *).
- */
+ launched. */
smartlist_t *transports;
} managed_proxy_t;
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
deleted file mode 100644
index 31a464ee7..000000000
--- a/src/test/Makefile.am
+++ /dev/null
@@ -1,49 +0,0 @@
-TESTS = test
-
-noinst_PROGRAMS = test test-child bench
-
-AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
- -DLOCALSTATEDIR="\"$(localstatedir)\"" \
- -DBINDIR="\"$(bindir)\"" \
- -I"$(top_srcdir)/src/or"
-
-# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
-# This seems to matter nowhere but on Windows, but I assure you that it
-# matters a lot there, and is quite hard to debug if you forget to do it.
-
-test_SOURCES = \
- test.c \
- test_addr.c \
- test_containers.c \
- test_crypto.c \
- test_data.c \
- test_dir.c \
- test_microdesc.c \
- test_pt.c \
- test_util.c \
- test_config.c \
- tinytest.c
-
-bench_SOURCES = \
- bench.c
-
-test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
- @TOR_LDFLAGS_libevent@
-test_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \
- ../common/libor-event.a \
- @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
- @TOR_LDFLAGS_libevent@
-bench_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \
- ../common/libor-event.a \
- @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-noinst_HEADERS = \
- tinytest.h \
- tinytest_macros.h \
- test.h
-
-
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
index aec477cf9..562c8df8b 100644
--- a/src/test/Makefile.nmake
+++ b/src/test/Makefile.nmake
@@ -1,20 +1,32 @@
-all: test.exe
+all: test.exe test-child.exe bench.exe
-CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common /I ..\or
+CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common /I ..\or \
+ /I ..\ext
LIBS = ..\..\..\build-alpha\lib\libevent.lib \
..\..\..\build-alpha\lib\libcrypto.lib \
..\..\..\build-alpha\lib\libssl.lib \
..\..\..\build-alpha\lib\libz.lib \
..\or\libtor.lib \
- ws2_32.lib advapi32.lib shell32.lib
+ ws2_32.lib advapi32.lib shell32.lib \
+ crypt32.lib gdi32.lib user32.lib
TEST_OBJECTS = test.obj test_addr.obj test_containers.obj \
test_crypto.obj test_data.obj test_dir.obj test_microdesc.obj \
- test_pt.obj test_util.obj test_config.obj tinytest.obj
+ test_pt.obj test_util.obj test_config.obj test_cell_formats.obj \
+ test_replay.obj test_introduce.obj tinytest.obj
+
+tinytest.obj: ..\ext\tinytest.c
+ $(CC) $(CFLAGS) /D snprintf=_snprintf /c ..\ext\tinytest.c
test.exe: $(TEST_OBJECTS)
- $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib $(TEST_OBJECTS)
+ $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib $(TEST_OBJECTS) /Fe$@
+
+bench.exe: bench.obj
+ $(CC) $(CFLAGS) bench.obj $(LIBS) ..\common\*.lib /Fe$@
+
+test-child.exe: test-child.obj
+ $(CC) $(CFLAGS) test-child.obj /Fe$@
clean:
- del $(TEST_OBJECTS) *.lib test.exe
+ del *.obj *.lib test.exe bench.exe test-child.exe
diff --git a/src/test/bench.c b/src/test/bench.c
index 3eae532d3..706b8bc7f 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Ordinarily defined in tor_main.c; this bit is just here to provide one
@@ -15,9 +15,24 @@ const char tor_git_revision[] = "";
#include "orconfig.h"
#define RELAY_PRIVATE
+#define CONFIG_PRIVATE
#include "or.h"
+#include "onion_tap.h"
#include "relay.h"
+#include <openssl/opensslv.h>
+#include <openssl/evp.h>
+#ifndef OPENSSL_NO_EC
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/obj_mac.h>
+#endif
+
+#include "config.h"
+#ifdef CURVE25519_ENABLED
+#include "crypto_curve25519.h"
+#include "onion_ntor.h"
+#endif
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
static uint64_t nanostart;
@@ -97,6 +112,131 @@ bench_aes(void)
}
static void
+bench_onion_TAP(void)
+{
+ const int iters = 1<<9;
+ int i;
+ crypto_pk_t *key, *key2;
+ uint64_t start, end;
+ char os[TAP_ONIONSKIN_CHALLENGE_LEN];
+ char or[TAP_ONIONSKIN_REPLY_LEN];
+ crypto_dh_t *dh_out;
+
+ key = crypto_pk_new();
+ key2 = crypto_pk_new();
+ if (crypto_pk_generate_key_with_bits(key, 1024) < 0)
+ goto done;
+ if (crypto_pk_generate_key_with_bits(key2, 1024) < 0)
+ goto done;
+
+ reset_perftime();
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ onion_skin_TAP_create(key, &dh_out, os);
+ crypto_dh_free(dh_out);
+ }
+ end = perftime();
+ printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
+
+ onion_skin_TAP_create(key, &dh_out, os);
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ char key_out[CPATH_KEY_MATERIAL_LEN];
+ onion_skin_TAP_server_handshake(os, key, NULL, or,
+ key_out, sizeof(key_out));
+ }
+ end = perftime();
+ printf("Server-side, key guessed right: %f usec\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ char key_out[CPATH_KEY_MATERIAL_LEN];
+ onion_skin_TAP_server_handshake(os, key2, key, or,
+ key_out, sizeof(key_out));
+ }
+ end = perftime();
+ printf("Server-side, key guessed wrong: %f usec.\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ crypto_dh_t *dh;
+ char key_out[CPATH_KEY_MATERIAL_LEN];
+ int s;
+ dh = crypto_dh_dup(dh_out);
+ s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out));
+ crypto_dh_free(dh);
+ tor_assert(s == 0);
+ }
+ end = perftime();
+ printf("Client-side, part 2: %f usec.\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ done:
+ crypto_pk_free(key);
+ crypto_pk_free(key2);
+}
+
+#ifdef CURVE25519_ENABLED
+static void
+bench_onion_ntor(void)
+{
+ const int iters = 1<<10;
+ int i;
+ curve25519_keypair_t keypair1, keypair2;
+ uint64_t start, end;
+ uint8_t os[NTOR_ONIONSKIN_LEN];
+ uint8_t or[NTOR_REPLY_LEN];
+ ntor_handshake_state_t *state = NULL;
+ uint8_t nodeid[DIGEST_LEN];
+ di_digest256_map_t *keymap = NULL;
+
+ curve25519_secret_key_generate(&keypair1.seckey, 0);
+ curve25519_public_key_generate(&keypair1.pubkey, &keypair1.seckey);
+ curve25519_secret_key_generate(&keypair2.seckey, 0);
+ curve25519_public_key_generate(&keypair2.pubkey, &keypair2.seckey);
+ dimap_add_entry(&keymap, keypair1.pubkey.public_key, &keypair1);
+ dimap_add_entry(&keymap, keypair2.pubkey.public_key, &keypair2);
+
+ reset_perftime();
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
+ ntor_handshake_state_free(state);
+ }
+ end = perftime();
+ printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
+
+ state = NULL;
+ onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
+ onion_skin_ntor_server_handshake(os, keymap, NULL, nodeid, or,
+ key_out, sizeof(key_out));
+ }
+ end = perftime();
+ printf("Server-side: %f usec\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
+ int s;
+ s = onion_skin_ntor_client_handshake(state, or, key_out, sizeof(key_out));
+ tor_assert(s == 0);
+ }
+ end = perftime();
+ printf("Client-side, part 2: %f usec.\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ ntor_handshake_state_free(state);
+ dimap_free(keymap, NULL);
+}
+#endif
+
+static void
bench_cell_aes(void)
{
uint64_t start, end;
@@ -175,18 +315,18 @@ bench_dmap(void)
NANOCOUNT(pt3, pt4, iters*elts));
for (i = 0; i < iters; ++i) {
- SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_isin(ds, cp));
- SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_isin(ds, cp));
+ SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_contains(ds, cp));
+ SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_contains(ds, cp));
}
end = perftime();
- printf("digestset_isin: %.2f ns per element.\n",
+ printf("digestset_contains: %.2f ns per element.\n",
NANOCOUNT(pt4, end, iters*elts*2));
/* We need to use this, or else the whole loop gets optimized out. */
printf("Hits == %d\n", n);
for (i = 0; i < fpostests; ++i) {
crypto_rand(d, 20);
- if (digestset_isin(ds, d)) ++fp;
+ if (digestset_contains(ds, d)) ++fp;
}
printf("False positive rate on digestset: %.2f%%\n",
(fp/(double)fpostests)*100);
@@ -214,8 +354,8 @@ bench_cell_ops(void)
crypto_rand((char*)cell->payload, sizeof(cell->payload));
/* Mock-up or_circuit_t */
- or_circ->_base.magic = OR_CIRCUIT_MAGIC;
- or_circ->_base.purpose = CIRCUIT_PURPOSE_OR;
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->base_.purpose = CIRCUIT_PURPOSE_OR;
/* Initialize crypto */
or_circ->p_crypto = crypto_cipher_new(NULL);
@@ -248,6 +388,95 @@ bench_cell_ops(void)
tor_free(cell);
}
+static void
+bench_dh(void)
+{
+ const int iters = 1<<10;
+ int i;
+ uint64_t start, end;
+
+ reset_perftime();
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ char dh_pubkey_a[DH_BYTES], dh_pubkey_b[DH_BYTES];
+ char secret_a[DH_BYTES], secret_b[DH_BYTES];
+ ssize_t slen_a, slen_b;
+ crypto_dh_t *dh_a = crypto_dh_new(DH_TYPE_TLS);
+ crypto_dh_t *dh_b = crypto_dh_new(DH_TYPE_TLS);
+ crypto_dh_generate_public(dh_a);
+ crypto_dh_generate_public(dh_b);
+ crypto_dh_get_public(dh_a, dh_pubkey_a, sizeof(dh_pubkey_a));
+ crypto_dh_get_public(dh_b, dh_pubkey_b, sizeof(dh_pubkey_b));
+ slen_a = crypto_dh_compute_secret(LOG_NOTICE,
+ dh_a, dh_pubkey_b, sizeof(dh_pubkey_b),
+ secret_a, sizeof(secret_a));
+ slen_b = crypto_dh_compute_secret(LOG_NOTICE,
+ dh_b, dh_pubkey_a, sizeof(dh_pubkey_a),
+ secret_b, sizeof(secret_b));
+ tor_assert(slen_a == slen_b);
+ tor_assert(!memcmp(secret_a, secret_b, slen_a));
+ crypto_dh_free(dh_a);
+ crypto_dh_free(dh_b);
+ }
+ end = perftime();
+ printf("Complete DH handshakes (1024 bit, public and private ops):\n"
+ " %f millisec each.\n", NANOCOUNT(start, end, iters)/1e6);
+}
+
+#if (!defined(OPENSSL_NO_EC) \
+ && OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0))
+#define HAVE_EC_BENCHMARKS
+static void
+bench_ecdh_impl(int nid, const char *name)
+{
+ const int iters = 1<<10;
+ int i;
+ uint64_t start, end;
+
+ reset_perftime();
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ char secret_a[DH_BYTES], secret_b[DH_BYTES];
+ ssize_t slen_a, slen_b;
+ EC_KEY *dh_a = EC_KEY_new_by_curve_name(nid);
+ EC_KEY *dh_b = EC_KEY_new_by_curve_name(nid);
+ if (!dh_a || !dh_b) {
+ puts("Skipping. (No implementation?)");
+ return;
+ }
+
+ EC_KEY_generate_key(dh_a);
+ EC_KEY_generate_key(dh_b);
+ slen_a = ECDH_compute_key(secret_a, DH_BYTES,
+ EC_KEY_get0_public_key(dh_b), dh_a,
+ NULL);
+ slen_b = ECDH_compute_key(secret_b, DH_BYTES,
+ EC_KEY_get0_public_key(dh_a), dh_b,
+ NULL);
+
+ tor_assert(slen_a == slen_b);
+ tor_assert(!memcmp(secret_a, secret_b, slen_a));
+ EC_KEY_free(dh_a);
+ EC_KEY_free(dh_b);
+ }
+ end = perftime();
+ printf("Complete ECDH %s handshakes (2 public and 2 private ops):\n"
+ " %f millisec each.\n", name, NANOCOUNT(start, end, iters)/1e6);
+}
+
+static void
+bench_ecdh_p256(void)
+{
+ bench_ecdh_impl(NID_X9_62_prime256v1, "P-256");
+}
+
+static void
+bench_ecdh_p224(void)
+{
+ bench_ecdh_impl(NID_secp224r1, "P-224");
+}
+#endif
+
typedef void (*bench_fn)(void);
typedef struct benchmark_t {
@@ -261,8 +490,17 @@ typedef struct benchmark_t {
static struct benchmark_t benchmarks[] = {
ENT(dmap),
ENT(aes),
+ ENT(onion_TAP),
+#ifdef CURVE25519_ENABLED
+ ENT(onion_ntor),
+#endif
ENT(cell_aes),
ENT(cell_ops),
+ ENT(dh),
+#ifdef HAVE_EC_BENCHMARKS
+ ENT(ecdh_p256),
+ ENT(ecdh_p224),
+#endif
{NULL,NULL,0}
};
@@ -286,6 +524,8 @@ main(int argc, const char **argv)
int i;
int list=0, n_enabled=0;
benchmark_t *b;
+ char *errmsg;
+ or_options_t *options;
tor_threads_init();
@@ -306,6 +546,16 @@ main(int argc, const char **argv)
reset_perftime();
crypto_seed_rng(1);
+ options = options_new();
+ init_logging();
+ options->command = CMD_RUN_UNITTESTS;
+ options->DataDirectory = tor_strdup("");
+ options_init(options);
+ if (set_options(options, &errmsg) < 0) {
+ printf("Failed to set initial options: %s\n", errmsg);
+ tor_free(errmsg);
+ return 1;
+ }
for (b = benchmarks; b->name; ++b) {
if (b->enabled || n_enabled == 0) {
diff --git a/src/test/include.am b/src/test/include.am
new file mode 100644
index 000000000..112d1a79d
--- /dev/null
+++ b/src/test/include.am
@@ -0,0 +1,68 @@
+TESTS+= src/test/test
+
+noinst_PROGRAMS+= src/test/test src/test/test-child src/test/bench
+
+src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
+ -DLOCALSTATEDIR="\"$(localstatedir)\"" \
+ -DBINDIR="\"$(bindir)\"" \
+ -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext"
+
+# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
+# This seems to matter nowhere but on Windows, but I assure you that it
+# matters a lot there, and is quite hard to debug if you forget to do it.
+
+src_test_test_SOURCES = \
+ src/test/test.c \
+ src/test/test_addr.c \
+ src/test/test_cell_formats.c \
+ src/test/test_containers.c \
+ src/test/test_crypto.c \
+ src/test/test_data.c \
+ src/test/test_dir.c \
+ src/test/test_introduce.c \
+ src/test/test_microdesc.c \
+ src/test/test_pt.c \
+ src/test/test_replay.c \
+ src/test/test_util.c \
+ src/test/test_config.c \
+ src/ext/tinytest.c
+
+src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS)
+
+src_test_bench_SOURCES = \
+ src/test/bench.c
+
+src_test_bench_CPPFLAGS= $(src_test_AM_CPPFLAGS)
+
+src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
+ @TOR_LDFLAGS_libevent@
+src_test_test_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-crypto.a $(LIBDONNA) \
+ src/common/libor-event.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+
+src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
+ @TOR_LDFLAGS_libevent@
+src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-crypto.a $(LIBDONNA) \
+ src/common/libor-event.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+
+noinst_HEADERS+= \
+ src/test/test.h
+
+if CURVE25519_ENABLED
+noinst_PROGRAMS+= src/test/test-ntor-cl
+src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c
+src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
+src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-crypto.a $(LIBDONNA) \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+src_test_test_ntor_cl_AM_CPPFLAGS = \
+ -I"$(top_srcdir)/src/or"
+
+endif
+
diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py
new file mode 100644
index 000000000..ade468da7
--- /dev/null
+++ b/src/test/ntor_ref.py
@@ -0,0 +1,387 @@
+# Copyright 2012-2013, The Tor Project, Inc
+# See LICENSE for licensing information
+
+"""
+ntor_ref.py
+
+
+This module is a reference implementation for the "ntor" protocol
+s proposed by Goldberg, Stebila, and Ustaoglu and as instantiated in
+Tor Proposal 216.
+
+It's meant to be used to validate Tor's ntor implementation. It
+requirs the curve25519 python module from the curve25519-donna
+package.
+
+ *** DO NOT USE THIS IN PRODUCTION. ***
+
+commands:
+
+ gen_kdf_vectors: Print out some test vectors for the RFC5869 KDF.
+ timing: Print a little timing information about this implementation's
+ handshake.
+ self-test: Try handshaking with ourself; make sure we can.
+ test-tor: Handshake with tor's ntor implementation via the program
+ src/test/test-ntor-cl; make sure we can.
+
+"""
+
+import binascii
+import curve25519
+import hashlib
+import hmac
+import subprocess
+
+# **********************************************************************
+# Helpers and constants
+
+def HMAC(key,msg):
+ "Return the HMAC-SHA256 of 'msg' using the key 'key'."
+ H = hmac.new(key, "", hashlib.sha256)
+ H.update(msg)
+ return H.digest()
+
+def H(msg,tweak):
+ """Return the hash of 'msg' using tweak 'tweak'. (In this version of ntor,
+ the tweaked hash is just HMAC with the tweak as the key.)"""
+ return HMAC(key=tweak,
+ msg=msg)
+
+def keyid(k):
+ """Return the 32-byte key ID of a public key 'k'. (Since we're
+ using curve25519, we let k be its own keyid.)
+ """
+ return k.serialize()
+
+NODE_ID_LENGTH = 20
+KEYID_LENGTH = 32
+G_LENGTH = 32
+H_LENGTH = 32
+
+PROTOID = b"ntor-curve25519-sha256-1"
+M_EXPAND = PROTOID + ":key_expand"
+T_MAC = PROTOID + ":mac"
+T_KEY = PROTOID + ":key_extract"
+T_VERIFY = PROTOID + ":verify"
+
+def H_mac(msg): return H(msg, tweak=T_MAC)
+def H_verify(msg): return H(msg, tweak=T_VERIFY)
+
+class PrivateKey(curve25519.keys.Private):
+ """As curve25519.keys.Private, but doesn't regenerate its public key
+ every time you ask for it.
+ """
+ def __init__(self):
+ curve25519.keys.Private.__init__(self)
+ self._memo_public = None
+
+ def get_public(self):
+ if self._memo_public is None:
+ self._memo_public = curve25519.keys.Private.get_public(self)
+
+ return self._memo_public
+
+# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+def kdf_rfc5869(key, salt, info, n):
+
+ prk = HMAC(key=salt, msg=key)
+
+ out = b""
+ last = b""
+ i = 1
+ while len(out) < n:
+ m = last + info + chr(i)
+ last = h = HMAC(key=prk, msg=m)
+ out += h
+ i = i + 1
+ return out[:n]
+
+def kdf_ntor(key, n):
+ return kdf_rfc5869(key, T_KEY, M_EXPAND, n)
+
+# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+def client_part1(node_id, pubkey_B):
+ """Initial handshake, client side.
+
+ From the specification:
+
+ <<To send a create cell, the client generates a keypair x,X =
+ KEYGEN(), and sends a CREATE cell with contents:
+
+ NODEID: ID -- ID_LENGTH bytes
+ KEYID: KEYID(B) -- H_LENGTH bytes
+ CLIENT_PK: X -- G_LENGTH bytes
+ >>
+
+ Takes node_id -- a digest of the server's identity key,
+ pubkey_B -- a public key for the server.
+ Returns a tuple of (client secret key x, client->server message)"""
+
+ assert len(node_id) == NODE_ID_LENGTH
+
+ key_id = keyid(pubkey_B)
+ seckey_x = PrivateKey()
+ pubkey_X = seckey_x.get_public().serialize()
+
+ message = node_id + key_id + pubkey_X
+
+ assert len(message) == NODE_ID_LENGTH + H_LENGTH + H_LENGTH
+ return seckey_x , message
+
+def hash_nil(x):
+ """Identity function: if we don't pass a hash function that does nothing,
+ the curve25519 python lib will try to sha256 it for us."""
+ return x
+
+def bad_result(r):
+ """Helper: given a result of multiplying a public key by a private key,
+ return True iff one of the inputs was broken"""
+ assert len(r) == 32
+ return r == '\x00'*32
+
+def server(seckey_b, my_node_id, message, keyBytes=72):
+ """Handshake step 2, server side.
+
+ From the spec:
+
+ <<
+ The server generates a keypair of y,Y = KEYGEN(), and computes
+
+ secret_input = EXP(X,y) | EXP(X,b) | ID | B | X | Y | PROTOID
+ KEY_SEED = H(secret_input, t_key)
+ verify = H(secret_input, t_verify)
+ auth_input = verify | ID | B | Y | X | PROTOID | "Server"
+
+ The server sends a CREATED cell containing:
+
+ SERVER_PK: Y -- G_LENGTH bytes
+ AUTH: H(auth_input, t_mac) -- H_LENGTH byets
+ >>
+
+ Takes seckey_b -- the server's secret key
+ my_node_id -- the servers's public key digest,
+ message -- a message from a client
+ keybytes -- amount of key material to generate
+
+ Returns a tuple of (key material, sever->client reply), or None on
+ error.
+ """
+
+ assert len(message) == NODE_ID_LENGTH + H_LENGTH + H_LENGTH
+
+ if my_node_id != message[:NODE_ID_LENGTH]:
+ return None
+
+ badness = (keyid(seckey_b.get_public()) !=
+ message[NODE_ID_LENGTH:NODE_ID_LENGTH+H_LENGTH])
+
+ pubkey_X = curve25519.keys.Public(message[NODE_ID_LENGTH+H_LENGTH:])
+ seckey_y = PrivateKey()
+ pubkey_Y = seckey_y.get_public()
+ pubkey_B = seckey_b.get_public()
+ xy = seckey_y.get_shared_key(pubkey_X, hash_nil)
+ xb = seckey_b.get_shared_key(pubkey_X, hash_nil)
+
+ # secret_input = EXP(X,y) | EXP(X,b) | ID | B | X | Y | PROTOID
+ secret_input = (xy + xb + my_node_id +
+ pubkey_B.serialize() +
+ pubkey_X.serialize() +
+ pubkey_Y.serialize() +
+ PROTOID)
+
+ verify = H_verify(secret_input)
+
+ # auth_input = verify | ID | B | Y | X | PROTOID | "Server"
+ auth_input = (verify +
+ my_node_id +
+ pubkey_B.serialize() +
+ pubkey_Y.serialize() +
+ pubkey_X.serialize() +
+ PROTOID +
+ "Server")
+
+ msg = pubkey_Y.serialize() + H_mac(auth_input)
+
+ badness += bad_result(xb)
+ badness += bad_result(xy)
+
+ if badness:
+ return None
+
+ keys = kdf_ntor(secret_input, keyBytes)
+
+ return keys, msg
+
+def client_part2(seckey_x, msg, node_id, pubkey_B, keyBytes=72):
+ """Handshake step 3: client side again.
+
+ From the spec:
+
+ <<
+ The client then checks Y is in G^* [see NOTE below], and computes
+
+ secret_input = EXP(Y,x) | EXP(B,x) | ID | B | X | Y | PROTOID
+ KEY_SEED = H(secret_input, t_key)
+ verify = H(secret_input, t_verify)
+ auth_input = verify | ID | B | Y | X | PROTOID | "Server"
+
+ The client verifies that AUTH == H(auth_input, t_mac).
+ >>
+
+ Takes seckey_x -- the secret key we generated in step 1.
+ msg -- the message from the server.
+ node_id -- the node_id we used in step 1.
+ server_key -- the same public key we used in step 1.
+ keyBytes -- the number of bytes we want to generate
+ Returns key material, or None on error
+
+ """
+ assert len(msg) == G_LENGTH + H_LENGTH
+
+ pubkey_Y = curve25519.keys.Public(msg[:G_LENGTH])
+ their_auth = msg[G_LENGTH:]
+
+ pubkey_X = seckey_x.get_public()
+
+ yx = seckey_x.get_shared_key(pubkey_Y, hash_nil)
+ bx = seckey_x.get_shared_key(pubkey_B, hash_nil)
+
+
+ # secret_input = EXP(Y,x) | EXP(B,x) | ID | B | X | Y | PROTOID
+ secret_input = (yx + bx + node_id +
+ pubkey_B.serialize() +
+ pubkey_X.serialize() +
+ pubkey_Y.serialize() + PROTOID)
+
+ verify = H_verify(secret_input)
+
+ # auth_input = verify | ID | B | Y | X | PROTOID | "Server"
+ auth_input = (verify + node_id +
+ pubkey_B.serialize() +
+ pubkey_Y.serialize() +
+ pubkey_X.serialize() + PROTOID +
+ "Server")
+
+ my_auth = H_mac(auth_input)
+
+ badness = my_auth != their_auth
+ badness = bad_result(yx) + bad_result(bx)
+
+ if badness:
+ return None
+
+ return kdf_ntor(secret_input, keyBytes)
+
+# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+def demo(node_id="iToldYouAboutStairs.", server_key=PrivateKey()):
+ """
+ Try to handshake with ourself.
+ """
+ x, create = client_part1(node_id, server_key.get_public())
+ skeys, created = server(server_key, node_id, create)
+ ckeys = client_part2(x, created, node_id, server_key.get_public())
+ assert len(skeys) == 72
+ assert len(ckeys) == 72
+ assert skeys == ckeys
+
+# ======================================================================
+def timing():
+ """
+ Use Python's timeit module to see how fast this nonsense is
+ """
+ import timeit
+ t = timeit.Timer(stmt="ntor_ref.demo(N,SK)",
+ setup="import ntor_ref,curve25519;N='ABCD'*5;SK=ntor_ref.PrivateKey()")
+ print t.timeit(number=1000)
+
+# ======================================================================
+
+def kdf_vectors():
+ """
+ Generate some vectors to check our KDF.
+ """
+ import binascii
+ def kdf_vec(inp):
+ k = kdf(inp, T_KEY, M_EXPAND, 100)
+ print repr(inp), "\n\""+ binascii.b2a_hex(k)+ "\""
+ kdf_vec("")
+ kdf_vec("Tor")
+ kdf_vec("AN ALARMING ITEM TO FIND ON YOUR CREDIT-RATING STATEMENT")
+
+# ======================================================================
+
+
+def test_tor():
+ """
+ Call the test-ntor-cl command-line program to make sure we can
+ interoperate with Tor's ntor program
+ """
+ enhex=binascii.b2a_hex
+ dehex=lambda s: binascii.a2b_hex(s.strip())
+
+ PROG = "./src/test/test-ntor-cl"
+ def tor_client1(node_id, pubkey_B):
+ " returns (msg, state) "
+ p = subprocess.Popen([PROG, "client1", enhex(node_id),
+ enhex(pubkey_B.serialize())],
+ stdout=subprocess.PIPE)
+ return map(dehex, p.stdout.readlines())
+ def tor_server1(seckey_b, node_id, msg, n):
+ " returns (msg, keys) "
+ p = subprocess.Popen([PROG, "server1", enhex(seckey_b.serialize()),
+ enhex(node_id), enhex(msg), str(n)],
+ stdout=subprocess.PIPE)
+ return map(dehex, p.stdout.readlines())
+ def tor_client2(state, msg, n):
+ " returns (keys,) "
+ p = subprocess.Popen([PROG, "client2", enhex(state),
+ enhex(msg), str(n)],
+ stdout=subprocess.PIPE)
+ return map(dehex, p.stdout.readlines())
+
+
+ node_id = "thisisatornodeid$#%^"
+ seckey_b = PrivateKey()
+ pubkey_B = seckey_b.get_public()
+
+ # Do a pure-Tor handshake
+ c2s_msg, c_state = tor_client1(node_id, pubkey_B)
+ s2c_msg, s_keys = tor_server1(seckey_b, node_id, c2s_msg, 90)
+ c_keys, = tor_client2(c_state, s2c_msg, 90)
+ assert c_keys == s_keys
+ assert len(c_keys) == 90
+
+ # Try a mixed handshake with Tor as the client
+ c2s_msg, c_state = tor_client1(node_id, pubkey_B)
+ s_keys, s2c_msg = server(seckey_b, node_id, c2s_msg, 90)
+ c_keys, = tor_client2(c_state, s2c_msg, 90)
+ assert c_keys == s_keys
+ assert len(c_keys) == 90
+
+ # Now do a mixed handshake with Tor as the server
+ c_x, c2s_msg = client_part1(node_id, pubkey_B)
+ s2c_msg, s_keys = tor_server1(seckey_b, node_id, c2s_msg, 90)
+ c_keys = client_part2(c_x, s2c_msg, node_id, pubkey_B, 90)
+ assert c_keys == s_keys
+ assert len(c_keys) == 90
+
+ print "We just interoperated."
+
+# ======================================================================
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1] == 'gen_kdf_vectors':
+ kdf_vectors()
+ elif sys.argv[1] == 'timing':
+ timing()
+ elif sys.argv[1] == 'self-test':
+ demo()
+ elif sys.argv[1] == 'test-tor':
+ test_tor()
+
+ else:
+ print __doc__
diff --git a/src/test/test-child.c b/src/test/test-child.c
index c5725f1c5..ef10fbb92 100644
--- a/src/test/test-child.c
+++ b/src/test/test-child.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* Copyright (c) 2011-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include <stdio.h>
diff --git a/src/test/test.c b/src/test/test.c
index ae423948e..4ec879234 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Ordinarily defined in tor_main.c; this bit is just here to provide one
@@ -32,7 +32,7 @@ const char tor_git_revision[] = "";
#define CONFIG_PRIVATE
#define GEOIP_PRIVATE
#define ROUTER_PRIVATE
-#define CIRCUIT_PRIVATE
+#define CIRCUITSTATS_PRIVATE
/*
* Linux doesn't provide lround in math.h by default, but mac os does...
@@ -44,7 +44,8 @@ double fabs(double x);
#include "or.h"
#include "buffers.h"
-#include "circuitbuild.h"
+#include "circuitlist.h"
+#include "circuitstats.h"
#include "config.h"
#include "connection_edge.h"
#include "geoip.h"
@@ -54,9 +55,14 @@ double fabs(double x);
#include "mempool.h"
#include "memarea.h"
#include "onion.h"
+#include "onion_tap.h"
#include "policies.h"
#include "rephist.h"
#include "routerparse.h"
+#ifdef CURVE25519_ENABLED
+#include "crypto_curve25519.h"
+#include "onion_ntor.h"
+#endif
#ifdef USE_DMALLOC
#include <dmalloc.h>
@@ -84,8 +90,14 @@ setup_directory(void)
{
static int is_setup = 0;
int r;
+ char rnd[256], rnd32[256];
if (is_setup) return;
+/* Due to base32 limitation needs to be a multiple of 5. */
+#define RAND_PATH_BYTES 5
+ crypto_rand(rnd, RAND_PATH_BYTES);
+ base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
+
#ifdef _WIN32
{
char buf[MAX_PATH];
@@ -94,11 +106,12 @@ setup_directory(void)
if (!GetTempPathA(sizeof(buf),buf))
tmp = "c:\\windows\\temp";
tor_snprintf(temp_dir, sizeof(temp_dir),
- "%s\\tor_test_%d", tmp, (int)getpid());
+ "%s\\tor_test_%d_%s", tmp, (int)getpid(), rnd32);
r = mkdir(temp_dir);
}
#else
- tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d", (int) getpid());
+ tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
+ (int) getpid(), rnd32);
r = mkdir(temp_dir, 0700);
#endif
if (r) {
@@ -352,7 +365,7 @@ test_socks_5_unsupported_commands(void *ptr)
test_eq(5, socks->socks_version);
test_eq(2, socks->replylen);
test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
+ test_eq(2, socks->reply[1]);
ADD_DATA(buf, "\x05\x03\x00\x01\x02\x02\x02\x01\x01\x01");
test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
get_options()->SafeSocks), -1);
@@ -457,7 +470,7 @@ test_socks_5_no_authenticate(void *ptr)
get_options()->SafeSocks));
test_eq(5, socks->socks_version);
test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
+ test_eq(1, socks->reply[0]);
test_eq(0, socks->reply[1]);
test_eq(2, socks->usernamelen);
@@ -496,7 +509,7 @@ test_socks_5_authenticate(void *ptr)
get_options()->SafeSocks));
test_eq(5, socks->socks_version);
test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
+ test_eq(1, socks->reply[0]);
test_eq(0, socks->reply[1]);
test_eq(2, socks->usernamelen);
@@ -536,7 +549,7 @@ test_socks_5_authenticate_with_data(void *ptr)
get_options()->SafeSocks) == 1);
test_eq(5, socks->socks_version);
test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
+ test_eq(1, socks->reply[0]);
test_eq(0, socks->reply[1]);
test_streq("2.2.2.2", socks->address);
@@ -827,11 +840,11 @@ test_onion_handshake(void)
{
/* client-side */
crypto_dh_t *c_dh = NULL;
- char c_buf[ONIONSKIN_CHALLENGE_LEN];
+ char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
char c_keys[40];
/* server-side */
- char s_buf[ONIONSKIN_REPLY_LEN];
+ char s_buf[TAP_ONIONSKIN_REPLY_LEN];
char s_keys[40];
/* shared */
@@ -840,18 +853,18 @@ test_onion_handshake(void)
pk = pk_generate(0);
/* client handshake 1. */
- memset(c_buf, 0, ONIONSKIN_CHALLENGE_LEN);
- test_assert(! onion_skin_create(pk, &c_dh, c_buf));
+ memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
+ test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
/* server handshake */
- memset(s_buf, 0, ONIONSKIN_REPLY_LEN);
+ memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN);
memset(s_keys, 0, 40);
- test_assert(! onion_skin_server_handshake(c_buf, pk, NULL,
+ test_assert(! onion_skin_TAP_server_handshake(c_buf, pk, NULL,
s_buf, s_keys, 40));
/* client handshake 2 */
memset(c_keys, 0, 40);
- test_assert(! onion_skin_client_handshake(c_dh, s_buf, c_keys, 40));
+ test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
if (memcmp(c_keys, s_keys, 40)) {
puts("Aiiiie");
@@ -868,6 +881,103 @@ test_onion_handshake(void)
crypto_pk_free(pk);
}
+#ifdef CURVE25519_ENABLED
+static void
+test_ntor_handshake(void *arg)
+{
+ /* client-side */
+ ntor_handshake_state_t *c_state = NULL;
+ uint8_t c_buf[NTOR_ONIONSKIN_LEN];
+ uint8_t c_keys[400];
+
+ /* server-side */
+ di_digest256_map_t *s_keymap=NULL;
+ curve25519_keypair_t s_keypair;
+ uint8_t s_buf[NTOR_REPLY_LEN];
+ uint8_t s_keys[400];
+
+ /* shared */
+ const curve25519_public_key_t *server_pubkey;
+ uint8_t node_id[20] = "abcdefghijklmnopqrst";
+
+ (void) arg;
+
+ /* Make the server some keys */
+ curve25519_secret_key_generate(&s_keypair.seckey, 0);
+ curve25519_public_key_generate(&s_keypair.pubkey, &s_keypair.seckey);
+ dimap_add_entry(&s_keymap, s_keypair.pubkey.public_key, &s_keypair);
+ server_pubkey = &s_keypair.pubkey;
+
+ /* client handshake 1. */
+ memset(c_buf, 0, NTOR_ONIONSKIN_LEN);
+ tt_int_op(0, ==, onion_skin_ntor_create(node_id, server_pubkey,
+ &c_state, c_buf));
+
+ /* server handshake */
+ memset(s_buf, 0, NTOR_REPLY_LEN);
+ memset(s_keys, 0, 40);
+ tt_int_op(0, ==, onion_skin_ntor_server_handshake(c_buf, s_keymap, NULL,
+ node_id,
+ s_buf, s_keys, 400));
+
+ /* client handshake 2 */
+ memset(c_keys, 0, 40);
+ tt_int_op(0, ==, onion_skin_ntor_client_handshake(c_state, s_buf,
+ c_keys, 400));
+
+ test_memeq(c_keys, s_keys, 400);
+ memset(s_buf, 0, 40);
+ test_memneq(c_keys, s_buf, 40);
+
+ done:
+ ntor_handshake_state_free(c_state);
+ dimap_free(s_keymap, NULL);
+}
+#endif
+
+/** Run unit tests for the onion queues. */
+static void
+test_onion_queues(void)
+{
+ uint8_t buf1[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
+ uint8_t buf2[NTOR_ONIONSKIN_LEN] = {0};
+
+ or_circuit_t *circ1 = or_circuit_new(0, NULL);
+ or_circuit_t *circ2 = or_circuit_new(0, NULL);
+
+ create_cell_t *onionskin = NULL;
+ create_cell_t *create1 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t));
+
+ create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
+ TAP_ONIONSKIN_CHALLENGE_LEN, buf1);
+ create_cell_init(create2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
+ NTOR_ONIONSKIN_LEN, buf2);
+
+ test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ test_eq(0, onion_pending_add(circ1, create1));
+ test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+
+ test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ test_eq(0, onion_pending_add(circ2, create2));
+ test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+
+ test_eq_ptr(circ2, onion_next_task(&onionskin));
+ test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+
+ clear_pending_onions();
+ test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+
+ done:
+ ;
+// circuit_free(circ1);
+// circuit_free(circ2);
+ /* and free create1 and create2 */
+ /* XXX leaks everything here */
+}
+
static void
test_circuit_timeout(void)
{
@@ -1056,9 +1166,9 @@ test_policy_summary_helper(const char *policy_str,
line.value = (char *)policy_str;
line.next = NULL;
- r = policies_parse_exit_policy(&line, &policy, 0, NULL, 1);
+ r = policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1);
test_eq(r, 0);
- summary = policy_summarize(policy);
+ summary = policy_summarize(policy, AF_INET);
test_assert(summary != NULL);
test_streq(summary, expected_summary);
@@ -1113,7 +1223,7 @@ test_policies(void)
test_assert(ADDR_POLICY_REJECTED ==
compare_tor_addr_to_addr_policy(&tar, 2, policy));
- test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, NULL, 1));
+ test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, NULL, 1));
test_assert(policy2);
policy3 = smartlist_new();
@@ -1188,9 +1298,9 @@ test_policies(void)
test_assert(!cmp_addr_policies(policy2, policy2));
test_assert(!cmp_addr_policies(NULL, NULL));
- test_assert(!policy_is_reject_star(policy2));
- test_assert(policy_is_reject_star(policy));
- test_assert(policy_is_reject_star(NULL));
+ test_assert(!policy_is_reject_star(policy2, AF_INET));
+ test_assert(policy_is_reject_star(policy, AF_INET));
+ test_assert(policy_is_reject_star(NULL, AF_INET));
addr_policy_list_free(policy);
policy = NULL;
@@ -1200,11 +1310,11 @@ test_policies(void)
line.key = (char*)"foo";
line.value = (char*)"accept *:80,reject private:*,reject *:*";
line.next = NULL;
- test_assert(0 == policies_parse_exit_policy(&line, &policy, 0, NULL, 1));
+ test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1));
test_assert(policy);
//test_streq(policy->string, "accept *:80");
//test_streq(policy->next->string, "reject *:*");
- test_eq(smartlist_len(policy), 2);
+ test_eq(smartlist_len(policy), 4);
/* test policy summaries */
/* check if we properly ignore private IP addresses */
@@ -1366,11 +1476,20 @@ test_rend_fns(void)
char address2[] = "aaaaaaaaaaaaaaaa.onion";
char address3[] = "fooaddress.exit";
char address4[] = "www.torproject.org";
+ char address5[] = "foo.abcdefghijklmnop.onion";
+ char address6[] = "foo.bar.abcdefghijklmnop.onion";
+ char address7[] = ".abcdefghijklmnop.onion";
test_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
test_assert(ONION_HOSTNAME == parse_extended_hostname(address2));
+ test_streq(address2, "aaaaaaaaaaaaaaaa");
test_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
test_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
+ test_assert(ONION_HOSTNAME == parse_extended_hostname(address5));
+ test_streq(address5, "abcdefghijklmnop");
+ test_assert(ONION_HOSTNAME == parse_extended_hostname(address6));
+ test_streq(address6, "abcdefghijklmnop");
+ test_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
pk1 = pk_generate(0);
pk2 = pk_generate(1);
@@ -1466,66 +1585,43 @@ test_geoip(void)
{
int i, j;
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- char *s = NULL;
+ char *s = NULL, *v = NULL;
const char *bridge_stats_1 =
"bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n"
- "bridge-ips zz=24,xy=8\n",
+ "bridge-ips zz=24,xy=8\n"
+ "bridge-ip-versions v4=16,v6=16\n",
*dirreq_stats_1 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips ab=8\n"
- "dirreq-v2-ips \n"
"dirreq-v3-reqs ab=8\n"
- "dirreq-v2-reqs \n"
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
- "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
- "busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_2 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
- "dirreq-v2-ips \n"
"dirreq-v3-reqs \n"
- "dirreq-v2-reqs \n"
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
- "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
- "busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_3 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
- "dirreq-v2-ips \n"
"dirreq-v3-reqs \n"
- "dirreq-v2-reqs \n"
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
- "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
- "busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_4 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
- "dirreq-v2-ips \n"
"dirreq-v3-reqs \n"
- "dirreq-v2-reqs \n"
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
- "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
- "busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n"
- "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n",
*entry_stats_1 =
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"entry-ips ab=8\n",
@@ -1533,61 +1629,109 @@ test_geoip(void)
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"entry-ips \n";
tor_addr_t addr;
+ struct in6_addr in6;
/* Populate the DB a bit. Add these in order, since we can't do the final
* 'sort' step. These aren't very good IP addresses, but they're perfectly
* fine uint32_t values. */
- test_eq(0, geoip_parse_entry("10,50,AB"));
- test_eq(0, geoip_parse_entry("52,90,XY"));
- test_eq(0, geoip_parse_entry("95,100,AB"));
- test_eq(0, geoip_parse_entry("\"105\",\"140\",\"ZZ\""));
- test_eq(0, geoip_parse_entry("\"150\",\"190\",\"XY\""));
- test_eq(0, geoip_parse_entry("\"200\",\"250\",\"AB\""));
+ test_eq(0, geoip_parse_entry("10,50,AB", AF_INET));
+ test_eq(0, geoip_parse_entry("52,90,XY", AF_INET));
+ test_eq(0, geoip_parse_entry("95,100,AB", AF_INET));
+ test_eq(0, geoip_parse_entry("\"105\",\"140\",\"ZZ\"", AF_INET));
+ test_eq(0, geoip_parse_entry("\"150\",\"190\",\"XY\"", AF_INET));
+ test_eq(0, geoip_parse_entry("\"200\",\"250\",\"AB\"", AF_INET));
+
+ /* Populate the IPv6 DB equivalently with fake IPs in the same range */
+ test_eq(0, geoip_parse_entry("::a,::32,AB", AF_INET6));
+ test_eq(0, geoip_parse_entry("::34,::5a,XY", AF_INET6));
+ test_eq(0, geoip_parse_entry("::5f,::64,AB", AF_INET6));
+ test_eq(0, geoip_parse_entry("::69,::8c,ZZ", AF_INET6));
+ test_eq(0, geoip_parse_entry("::96,::be,XY", AF_INET6));
+ test_eq(0, geoip_parse_entry("::c8,::fa,AB", AF_INET6));
/* We should have 4 countries: ??, ab, xy, zz. */
test_eq(4, geoip_get_n_countries());
+ memset(&in6, 0, sizeof(in6));
+
/* Make sure that country ID actually works. */
-#define NAMEFOR(x) geoip_get_country_name(geoip_get_country_by_ip(x))
- test_streq("??", NAMEFOR(3));
- test_eq(0, geoip_get_country_by_ip(3));
- test_streq("ab", NAMEFOR(32));
- test_streq("??", NAMEFOR(5));
- test_streq("??", NAMEFOR(51));
- test_streq("xy", NAMEFOR(150));
- test_streq("xy", NAMEFOR(190));
- test_streq("??", NAMEFOR(2000));
-#undef NAMEFOR
+#define SET_TEST_IPV6(i) \
+ do { \
+ set_uint32(in6.s6_addr + 12, htonl((uint32_t) (i))); \
+ } while (0)
+#define CHECK_COUNTRY(country, val) do { \
+ /* test ipv4 country lookup */ \
+ test_streq(country, \
+ geoip_get_country_name(geoip_get_country_by_ipv4(val))); \
+ /* test ipv6 country lookup */ \
+ SET_TEST_IPV6(val); \
+ test_streq(country, \
+ geoip_get_country_name(geoip_get_country_by_ipv6(&in6))); \
+ } while (0)
+
+ CHECK_COUNTRY("??", 3);
+ CHECK_COUNTRY("ab", 32);
+ CHECK_COUNTRY("??", 5);
+ CHECK_COUNTRY("??", 51);
+ CHECK_COUNTRY("xy", 150);
+ CHECK_COUNTRY("xy", 190);
+ CHECK_COUNTRY("??", 2000);
+
+ test_eq(0, geoip_get_country_by_ipv4(3));
+ SET_TEST_IPV6(3);
+ test_eq(0, geoip_get_country_by_ipv6(&in6));
+
+#undef CHECK_COUNTRY
+
+ /* Record odd numbered fake-IPs using ipv6, even numbered fake-IPs
+ * using ipv4. Since our fake geoip database is the same between
+ * ipv4 and ipv6, we should get the same result no matter which
+ * address family we pick for each IP. */
+#define SET_TEST_ADDRESS(i) do { \
+ if ((i) & 1) { \
+ SET_TEST_IPV6(i); \
+ tor_addr_from_in6(&addr, &in6); \
+ } else { \
+ tor_addr_from_ipv4h(&addr, (uint32_t) i); \
+ } \
+ } while (0)
get_options_mutable()->BridgeRelay = 1;
get_options_mutable()->BridgeRecordUsageByCountry = 1;
/* Put 9 observations in AB... */
for (i=32; i < 40; ++i) {
- tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
}
- tor_addr_from_ipv4h(&addr, (uint32_t) 225);
+ SET_TEST_ADDRESS(225);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
/* and 3 observations in XY, several times. */
for (j=0; j < 10; ++j)
for (i=52; i < 55; ++i) {
- tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-3600);
}
/* and 17 observations in ZZ... */
for (i=110; i < 127; ++i) {
- tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
}
- s = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
test_assert(s);
+ test_assert(v);
test_streq("zz=24,ab=16,xy=8", s);
+ test_streq("v4=16,v6=16", v);
tor_free(s);
+ tor_free(v);
/* Now clear out all the AB observations. */
geoip_remove_old_clients(now-6000);
- s = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
test_assert(s);
+ test_assert(v);
test_streq("zz=24,xy=8", s);
+ test_streq("v4=16,v6=16", v);
+ tor_free(s);
+ tor_free(v);
/* Start testing bridge statistics by making sure that we don't output
* bridge stats without initializing them. */
@@ -1598,6 +1742,7 @@ test_geoip(void)
* the connecting clients added above. */
geoip_bridge_stats_init(now);
s = geoip_format_bridge_stats(now + 86400);
+ test_assert(s);
test_streq(bridge_stats_1, s);
tor_free(s);
@@ -1616,7 +1761,7 @@ test_geoip(void)
/* Start testing dirreq statistics by making sure that we don't collect
* dirreq stats without initializing them. */
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
@@ -1624,7 +1769,7 @@ test_geoip(void)
/* Initialize stats, note one connecting client, and generate the
* dirreq-stats history string. */
geoip_dirreq_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_1, s);
@@ -1633,7 +1778,7 @@ test_geoip(void)
/* Stop collecting stats, add another connecting client, and ensure we
* don't generate a history string. */
geoip_dirreq_stats_term();
- tor_addr_from_ipv4h(&addr, (uint32_t) 101);
+ SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
@@ -1641,7 +1786,7 @@ test_geoip(void)
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
geoip_dirreq_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
geoip_reset_dirreq_stats(now);
s = geoip_format_dirreq_stats(now + 86400);
@@ -1650,14 +1795,13 @@ test_geoip(void)
/* Note a successful network status response and make sure that it
* appears in the history string. */
- geoip_note_ns_response(GEOIP_CLIENT_NETWORKSTATUS, GEOIP_SUCCESS);
+ geoip_note_ns_response(GEOIP_SUCCESS);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_3, s);
tor_free(s);
/* Start a tunneled directory request. */
- geoip_start_dirreq((uint64_t) 1, 1024, GEOIP_CLIENT_NETWORKSTATUS,
- DIRREQ_TUNNELED);
+ geoip_start_dirreq((uint64_t) 1, 1024, DIRREQ_TUNNELED);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_4, s);
@@ -1669,7 +1813,7 @@ test_geoip(void)
/* Start testing entry statistics by making sure that we don't collect
* anything without initializing entry stats. */
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
@@ -1677,7 +1821,7 @@ test_geoip(void)
/* Initialize stats, note one connecting client, and generate the
* entry-stats history string. */
geoip_entry_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
s = geoip_format_entry_stats(now + 86400);
test_streq(entry_stats_1, s);
@@ -1686,7 +1830,7 @@ test_geoip(void)
/* Stop collecting stats, add another connecting client, and ensure we
* don't generate a history string. */
geoip_entry_stats_term();
- tor_addr_from_ipv4h(&addr, (uint32_t) 101);
+ SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
@@ -1694,19 +1838,23 @@ test_geoip(void)
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
geoip_entry_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
geoip_reset_entry_stats(now);
s = geoip_format_entry_stats(now + 86400);
test_streq(entry_stats_2, s);
tor_free(s);
+#undef SET_TEST_ADDRESS
+#undef SET_TEST_IPV6
+
/* Stop collecting entry statistics. */
geoip_entry_stats_term();
get_options_mutable()->EntryStatistics = 0;
done:
tor_free(s);
+ tor_free(v);
}
/** Run unit tests for stats code. */
@@ -1895,11 +2043,6 @@ const struct testcase_setup_t legacy_setup = {
#define ENT(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_ ## name }
-#define SUBENT(group, name) \
- { #group "_" #name, legacy_test_helper, 0, &legacy_setup, \
- test_ ## group ## _ ## name }
-#define DISABLED(name) \
- { #name, legacy_test_helper, TT_SKIP, &legacy_setup, test_ ## name }
#define FORK(name) \
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_ ## name }
@@ -1907,6 +2050,10 @@ static struct testcase_t test_array[] = {
ENT(buffers),
{ "buffer_copy", test_buffer_copy, 0, NULL, NULL },
ENT(onion_handshake),
+ ENT(onion_queues),
+#ifdef CURVE25519_ENABLED
+ { "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
+#endif
ENT(circuit_timeout),
ENT(policies),
ENT(rend_fns),
@@ -1941,6 +2088,9 @@ extern struct testcase_t dir_tests[];
extern struct testcase_t microdesc_tests[];
extern struct testcase_t pt_tests[];
extern struct testcase_t config_tests[];
+extern struct testcase_t introduce_tests[];
+extern struct testcase_t replaycache_tests[];
+extern struct testcase_t cell_format_tests[];
static struct testgroup_t testgroups[] = {
{ "", test_array },
@@ -1949,10 +2099,13 @@ static struct testgroup_t testgroups[] = {
{ "crypto/", crypto_tests },
{ "container/", container_tests },
{ "util/", util_tests },
+ { "cellfmt/", cell_format_tests },
{ "dir/", dir_tests },
{ "dir/md/", microdesc_tests },
{ "pt/", pt_tests },
{ "config/", config_tests },
+ { "replaycache/", replaycache_tests },
+ { "introduce/", introduce_tests },
END_OF_GROUPS
};
@@ -1968,7 +2121,7 @@ main(int c, const char **v)
#ifdef USE_DMALLOC
{
- int r = CRYPTO_set_mem_ex_functions(_tor_malloc, _tor_realloc, _tor_free);
+ int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
tor_assert(r);
}
#endif
@@ -2006,6 +2159,7 @@ main(int c, const char **v)
return 1;
}
crypto_set_tls_dh_prime(NULL);
+ crypto_seed_rng(1);
rep_hist_init();
network_init();
setup_directory();
@@ -2018,8 +2172,6 @@ main(int c, const char **v)
return 1;
}
- crypto_seed_rng(1);
-
atexit(remove_directory);
have_failed = (tinytest_main(c, v, testgroups) != 0);
diff --git a/src/test/test.h b/src/test/test.h
index 0b6e6c60c..a89b558e5 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -1,10 +1,10 @@
/* Copyright (c) 2001-2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_TEST_H
-#define _TOR_TEST_H
+#ifndef TOR_TEST_H
+#define TOR_TEST_H
/**
* \file test.h
@@ -65,6 +65,10 @@
#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, ==, hex)
+#define tt_double_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%f", \
+ TT_EXIT_TEST_FUNCTION)
+
const char *get_fname(const char *name);
crypto_pk_t *pk_generate(int idx);
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index e3f38073e..fec85a469 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -1,11 +1,13 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#define ADDRESSMAP_PRIVATE
#include "orconfig.h"
#include "or.h"
#include "test.h"
+#include "addressmap.h"
static void
test_addr_basic(void)
@@ -38,7 +40,7 @@ test_addr_basic(void)
tor_free(cp);
u32 = 3;
test_assert(!addr_port_lookup(LOG_WARN, "localhost", NULL, &u32, &u16));
- test_eq(cp, NULL);
+ test_eq_ptr(cp, NULL);
test_eq(u32, 0x7f000001u);
test_eq(u16, 0);
tor_free(cp);
@@ -70,7 +72,7 @@ test_addr_basic(void)
;
}
-#define _test_op_ip6(a,op,b,e1,e2) \
+#define test_op_ip6_(a,op,b,e1,e2) \
STMT_BEGIN \
tt_assert_test_fmt_type(a,b,e1" "#op" "e2,struct in6_addr*, \
(memcmp(val1_->s6_addr, val2_->s6_addr, 16) op 0), \
@@ -93,7 +95,7 @@ test_addr_basic(void)
#define test_pton6_same(a,b) STMT_BEGIN \
test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
- _test_op_ip6(&a1,==,&a2,#a,#b); \
+ test_op_ip6_(&a1,==,&a2,#a,#b); \
STMT_END
/** Helper: Assert that <b>a</b> is recognized as a bad IPv6 address by
@@ -108,7 +110,7 @@ test_addr_basic(void)
test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
test_streq(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), b); \
test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
- _test_op_ip6(&a1, ==, &a2, a, b); \
+ test_op_ip6_(&a1, ==, &a2, a, b); \
STMT_END
/** Helper: assert that <b>a</b> parses by tor_inet_pton() into a address that
@@ -159,7 +161,8 @@ test_addr_basic(void)
* as <b>pt1..pt2</b>. */
#define test_addr_mask_ports_parse(xx, f, ip1, ip2, ip3, ip4, mm, pt1, pt2) \
STMT_BEGIN \
- test_eq(tor_addr_parse_mask_ports(xx, &t1, &mask, &port1, &port2), f); \
+ test_eq(tor_addr_parse_mask_ports(xx, 0, &t1, &mask, &port1, &port2), \
+ f); \
p1=tor_inet_ntop(AF_INET6, &t1.addr.in6_addr, bug, sizeof(bug)); \
test_eq(htonl(ip1), tor_addr_to_in6_addr32(&t1)[0]); \
test_eq(htonl(ip2), tor_addr_to_in6_addr32(&t1)[1]); \
@@ -401,11 +404,11 @@ test_addr_ip6_helpers(void)
test_addr_compare("0::2:2:1", <, "0::ffff:0.3.2.1");
test_addr_compare("0::ffff:0.3.2.1", >, "0::0:0:0");
test_addr_compare("0::ffff:5.2.2.1", <, "::ffff:6.0.0.0"); /* XXXX wrong. */
- tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", &t1, NULL, NULL, NULL);
- tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", 0, &t1, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) == 0);
- tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", &t1, NULL, NULL, NULL);
- tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", 0, &t1, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) < 0);
/* test compare_masked */
@@ -568,6 +571,7 @@ test_addr_ip6_helpers(void)
test_streq(rbuf, addr_PTR);
}
+ /* XXXX turn this into a separate function; it's not all IPv6. */
/* test tor_addr_parse_mask_ports */
test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6,
0, 0, 0, 0x0000000f, 17, 47, 95);
@@ -581,27 +585,123 @@ test_addr_ip6_helpers(void)
0xabcd0002, 0, 0, 0x044a0000, 128, 2, 65000);
test_streq(p1, "abcd:2::44a:0");
- r=tor_addr_parse_mask_ports("[fefef::]/112", &t1, NULL, NULL, NULL);
+ /* Try some long addresses. */
+ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == AF_INET6);
+ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:11111]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111:1]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports(
+ "[ffff:1111:1111:1111:1111:1111:1111:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ /* Try some failing cases. */
+ r=tor_addr_parse_mask_ports("[fefef::]/112", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[fefe::/112", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[fefe::", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[fefe::X]", 0, &t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("efef::/112", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("efef::/112", 0, &t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]",0,&t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/fred",0,&t1,&mask, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/255.255.0.0",
+ 0,&t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ /* This one will get rejected because it isn't a pure prefix. */
+ r=tor_addr_parse_mask_ports("1.1.2.3/255.255.64.0",0,&t1, &mask,NULL,NULL);
test_assert(r == -1);
/* Test for V4-mapped address with mask < 96. (arguably not valid) */
- r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]", &t1, &mask, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("1.1.2.2/33",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ /* Try extended wildcard addresses with out TAPMP_EXTENDED_STAR*/
+ r=tor_addr_parse_mask_ports("*4",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("*6",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+#if 0
+ /* Try a mask with a wildcard. */
+ r=tor_addr_parse_mask_ports("*/16",0,&t1, &mask, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("1.1.2.2/33", &t1, &mask, NULL, NULL);
+ r=tor_addr_parse_mask_ports("*4/16",TAPMP_EXTENDED_STAR,
+ &t1, &mask, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("1.1.2.2/31", &t1, &mask, NULL, NULL);
+ r=tor_addr_parse_mask_ports("*6/30",TAPMP_EXTENDED_STAR,
+ &t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+#endif
+ /* Basic mask tests*/
+ r=tor_addr_parse_mask_ports("1.1.2.2/31",0,&t1, &mask, NULL, NULL);
+ test_assert(r == AF_INET);
+ tt_int_op(mask,==,31);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010202);
+ r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2);
+ test_assert(r == AF_INET);
+ tt_int_op(mask,==,32);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0x03041020);
+ test_assert(port1 == 1);
+ test_assert(port2 == 2);
+ r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL);
test_assert(r == AF_INET);
- r=tor_addr_parse_mask_ports("[efef::]/112", &t1, &mask, &port1, &port2);
+ tt_int_op(mask,==,17);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010203);
+ r=tor_addr_parse_mask_ports("[efef::]/112",0,&t1, &mask, &port1, &port2);
test_assert(r == AF_INET6);
test_assert(port1 == 1);
test_assert(port2 == 65535);
+ /* Try regular wildcard behavior without TAPMP_EXTENDED_STAR */
+ r=tor_addr_parse_mask_ports("*:80-443",0,&t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_INET); /* Old users of this always get inet */
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0);
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,80);
+ tt_int_op(port2,==,443);
+ /* Now try wildcards *with* TAPMP_EXTENDED_STAR */
+ r=tor_addr_parse_mask_ports("*:8000-9000",TAPMP_EXTENDED_STAR,
+ &t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_UNSPEC);
+ tt_int_op(tor_addr_family(&t1),==,AF_UNSPEC);
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,8000);
+ tt_int_op(port2,==,9000);
+ r=tor_addr_parse_mask_ports("*4:6667",TAPMP_EXTENDED_STAR,
+ &t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_INET);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0);
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,6667);
+ tt_int_op(port2,==,6667);
+ r=tor_addr_parse_mask_ports("*6",TAPMP_EXTENDED_STAR,
+ &t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_INET6);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET6);
+ tt_assert(tor_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16));
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,1);
+ tt_int_op(port2,==,65535);
/* make sure inet address lengths >= max */
test_assert(INET_NTOA_BUF_LEN >= sizeof("255.255.255.255"));
@@ -623,6 +723,126 @@ test_addr_ip6_helpers(void)
;
}
+/** Test tor_addr_port_parse(). */
+static void
+test_addr_parse(void)
+{
+ int r;
+ tor_addr_t addr;
+ char buf[TOR_ADDR_BUF_LEN];
+ uint16_t port = 0;
+
+ /* Correct call. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.1:1234",
+ &addr, &port);
+ test_assert(r == 0);
+ tor_addr_to_str(buf, &addr, sizeof(buf), 0);
+ test_streq(buf, "192.0.2.1");
+ test_eq(port, 1234);
+
+ /* Domain name. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "torproject.org:1234",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Only IP. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.2",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Bad port. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.2:66666",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Only domain name */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "torproject.org",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Bad IP address */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2:1234",
+ &addr, &port);
+ test_assert(r == -1);
+
+ done:
+ ;
+}
+
+static void
+update_difference(int ipv6, uint8_t *d,
+ const tor_addr_t *a, const tor_addr_t *b)
+{
+ const int n_bytes = ipv6 ? 16 : 4;
+ uint8_t a_tmp[4], b_tmp[4];
+ const uint8_t *ba, *bb;
+ int i;
+
+ if (ipv6) {
+ ba = tor_addr_to_in6_addr8(a);
+ bb = tor_addr_to_in6_addr8(b);
+ } else {
+ set_uint32(a_tmp, tor_addr_to_ipv4n(a));
+ set_uint32(b_tmp, tor_addr_to_ipv4n(b));
+ ba = a_tmp; bb = b_tmp;
+ }
+
+ for (i = 0; i < n_bytes; ++i) {
+ d[i] |= ba[i] ^ bb[i];
+ }
+}
+
+static void
+test_virtaddrmap(void *data)
+{
+ /* Let's start with a bunch of random addresses. */
+ int ipv6, bits, iter, b;
+ virtual_addr_conf_t cfg[2];
+ uint8_t bytes[16];
+
+ (void)data;
+
+ tor_addr_parse(&cfg[0].addr, "64.65.0.0");
+ tor_addr_parse(&cfg[1].addr, "3491:c0c0::");
+
+ for (ipv6 = 0; ipv6 <= 1; ++ipv6) {
+ for (bits = 0; bits < 18; ++bits) {
+ tor_addr_t last_a;
+ cfg[ipv6].bits = bits;
+ memset(bytes, 0, sizeof(bytes));
+ tor_addr_copy(&last_a, &cfg[ipv6].addr);
+ /* Generate 128 addresses with each addr/bits combination. */
+ for (iter = 0; iter < 128; ++iter) {
+ tor_addr_t a;
+
+ get_random_virtual_addr(&cfg[ipv6], &a);
+ //printf("%s\n", fmt_addr(&a));
+ /* Make sure that the first b bits match the configured network */
+ tt_int_op(0, ==, tor_addr_compare_masked(&a, &cfg[ipv6].addr,
+ bits, CMP_EXACT));
+
+ /* And track which bits have been different between pairs of
+ * addresses */
+ update_difference(ipv6, bytes, &last_a, &a);
+ }
+
+ /* Now make sure all but the first 'bits' bits of bytes are true */
+ for (b = bits+1; b < (ipv6?128:32); ++b) {
+ tt_assert(1 & (bytes[b/8] >> (7-(b&7))));
+ }
+ }
+ }
+
+ done:
+ ;
+}
+
static void
test_addr_is_loopback(void *data)
{
@@ -664,6 +884,8 @@ test_addr_is_loopback(void *data)
struct testcase_t addr_tests[] = {
ADDR_LEGACY(basic),
ADDR_LEGACY(ip6_helpers),
+ ADDR_LEGACY(parse),
+ { "virtaddr", test_virtaddrmap, 0, NULL, NULL },
{ "is_loopback", test_addr_is_loopback, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
new file mode 100644
index 000000000..55d8d0f00
--- /dev/null
+++ b/src/test/test_cell_formats.c
@@ -0,0 +1,888 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define CONNECTION_EDGE_PRIVATE
+#define RELAY_PRIVATE
+#include "or.h"
+#include "connection_edge.h"
+#include "onion.h"
+#include "onion_tap.h"
+#include "onion_fast.h"
+#include "onion_ntor.h"
+#include "relay.h"
+#include "test.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static void
+test_cfmt_relay_header(void *arg)
+{
+ relay_header_t rh;
+ const uint8_t hdr_1[RELAY_HEADER_SIZE] =
+ "\x03" "\x00\x00" "\x21\x22" "ABCD" "\x01\x03";
+ uint8_t hdr_out[RELAY_HEADER_SIZE];
+ (void)arg;
+
+ tt_int_op(sizeof(hdr_1), ==, RELAY_HEADER_SIZE);
+ relay_header_unpack(&rh, hdr_1);
+ tt_int_op(rh.command, ==, 3);
+ tt_int_op(rh.recognized, ==, 0);
+ tt_int_op(rh.stream_id, ==, 0x2122);
+ test_mem_op(rh.integrity, ==, "ABCD", 4);
+ tt_int_op(rh.length, ==, 0x103);
+
+ relay_header_pack(hdr_out, &rh);
+ test_mem_op(hdr_out, ==, hdr_1, RELAY_HEADER_SIZE);
+
+ done:
+ ;
+}
+
+static void
+make_relay_cell(cell_t *out, uint8_t command,
+ const void *body, size_t bodylen)
+{
+ relay_header_t rh;
+
+ memset(&rh, 0, sizeof(rh));
+ rh.stream_id = 5;
+ rh.command = command;
+ rh.length = bodylen;
+
+ out->command = CELL_RELAY;
+ out->circ_id = 10;
+ relay_header_pack(out->payload, &rh);
+
+ memcpy(out->payload + RELAY_HEADER_SIZE, body, bodylen);
+}
+
+static void
+test_cfmt_begin_cells(void *arg)
+{
+ cell_t cell;
+ begin_cell_t bcell;
+ uint8_t end_reason;
+ (void)arg;
+
+ /* Try begindir. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "", 0);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_ptr_op(NULL, ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(0, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(1, ==, bcell.is_begindir);
+
+ /* A Begindir with extra stuff. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "12345", 5);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_ptr_op(NULL, ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(0, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(1, ==, bcell.is_begindir);
+
+ /* A short but valid begin cell */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:9", 6);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("a.b", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(9, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* A significantly loner begin cell */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "here-is-a-nice-long.hostname.com:65535";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, strlen(c)+1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("here-is-a-nice-long.hostname.com", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(65535, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* An IPv4 begin cell. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("18.9.22.169", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(80, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* An IPv6 begin cell. Let's make sure we handle colons*/
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN,
+ "[2620::6b0:b:1a1a:0:26e5:480e]:80", 34);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("[2620::6b0:b:1a1a:0:26e5:480e]", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(80, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* a begin cell with extra junk but not enough for flags. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "another.example.com:80\x00\x01\x02";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("another.example.com", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(80, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* a begin cell with flags. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "another.example.com:443\x00\x01\x02\x03\x04";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("another.example.com", ==, bcell.address);
+ tt_int_op(0x1020304, ==, bcell.flags);
+ tt_int_op(443, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* a begin cell with flags and even more cruft after that. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "a-further.example.com:22\x00\xee\xaa\x00\xffHi mom";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("a-further.example.com", ==, bcell.address);
+ tt_int_op(0xeeaa00ff, ==, bcell.flags);
+ tt_int_op(22, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* bad begin cell: impossible length. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 7);
+ cell.payload[9] = 0x01; /* Set length to 510 */
+ cell.payload[10] = 0xfe;
+ {
+ relay_header_t rh;
+ relay_header_unpack(&rh, cell.payload);
+ tt_int_op(rh.length, ==, 510);
+ }
+ tt_int_op(-2, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* Bad begin cell: no body. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no body. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no colon */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b", 4);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no ports */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:", 5);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: bad port */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:xyz", 8);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:100000", 11);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no nul */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 6);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ done:
+ tor_free(bcell.address);
+}
+
+static void
+test_cfmt_connected_cells(void *arg)
+{
+ relay_header_t rh;
+ cell_t cell;
+ tor_addr_t addr;
+ int ttl, r;
+ char *mem_op_hex_tmp = NULL;
+ (void)arg;
+
+ /* Let's try an oldschool one with nothing in it. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "", 0);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_UNSPEC);
+ tt_int_op(ttl, ==, -1);
+
+ /* A slightly less oldschool one: only an IPv4 address */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "32.48.64.80");
+ tt_int_op(ttl, ==, -1);
+
+ /* Bogus but understandable: truncated TTL */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "17.18.19.20");
+ tt_int_op(ttl, ==, -1);
+
+ /* Regular IPv4 one: address and TTL */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x02\x03\x04\x05\x00\x00\x0e\x10", 8);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "2.3.4.5");
+ tt_int_op(ttl, ==, 3600);
+
+ /* IPv4 with too-big TTL */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x02\x03\x04\x05\xf0\x00\x00\x00", 8);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "2.3.4.5");
+ tt_int_op(ttl, ==, -1);
+
+ /* IPv6 (ttl is mandatory) */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x06"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x00\x00\x02\x58", 25);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+ tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68");
+ tt_int_op(ttl, ==, 600);
+
+ /* IPv6 (ttl too big) */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x06"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x90\x00\x02\x58", 25);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+ tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68");
+ tt_int_op(ttl, ==, -1);
+
+ /* Bogus size: 3. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x01\x02", 3);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, -1);
+
+ /* Bogus family: 7. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x07"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x90\x00\x02\x58", 25);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, -1);
+
+ /* Truncated IPv6. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x06"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x00\x00\x02", 24);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, -1);
+
+ /* Now make sure we can generate connected cells correctly. */
+ /* Try an IPv4 address */
+ memset(&rh, 0, sizeof(rh));
+ memset(&cell, 0, sizeof(cell));
+ tor_addr_parse(&addr, "30.40.50.60");
+ rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
+ &addr, 128);
+ tt_int_op(rh.length, ==, 8);
+ test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000080");
+
+ /* Try parsing it. */
+ tor_addr_make_unspec(&addr);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "30.40.50.60");
+ tt_int_op(ttl, ==, 128);
+
+ /* Try an IPv6 address */
+ memset(&rh, 0, sizeof(rh));
+ memset(&cell, 0, sizeof(cell));
+ tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e");
+ rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
+ &addr, 3600);
+ tt_int_op(rh.length, ==, 25);
+ test_memeq_hex(cell.payload + RELAY_HEADER_SIZE,
+ "00000000" "06"
+ "2620000006b0000b1a1a000026e5480e" "00000e10");
+
+ /* Try parsing it. */
+ tor_addr_make_unspec(&addr);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+ tt_str_op(fmt_addr(&addr), ==, "2620:0:6b0:b:1a1a:0:26e5:480e");
+ tt_int_op(ttl, ==, 3600);
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_cfmt_create_cells(void *arg)
+{
+ uint8_t b[MAX_ONIONSKIN_CHALLENGE_LEN];
+ create_cell_t cc;
+ cell_t cell;
+ cell_t cell2;
+
+ (void)arg;
+
+ /* === Let's try parsing some good cells! */
+
+ /* A valid create cell. */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ cell.command = CELL_CREATE;
+ memcpy(cell.payload, b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type);
+ tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A valid create_fast cell. */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, CREATE_FAST_LEN);
+ cell.command = CELL_CREATE_FAST;
+ memcpy(cell.payload, b, CREATE_FAST_LEN);
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE_FAST, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_FAST, ==, cc.handshake_type);
+ tt_int_op(CREATE_FAST_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, CREATE_FAST_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A valid create2 cell with a TAP payload */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ cell.command = CELL_CREATE2;
+ memcpy(cell.payload, "\x00\x00\x00\xBA", 4); /* TAP, 186 bytes long */
+ memcpy(cell.payload+4, b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE2, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type);
+ tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A valid create2 cell with an ntor payload */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+ cell.command = CELL_CREATE2;
+ memcpy(cell.payload, "\x00\x02\x00\x54", 4); /* ntor, 84 bytes long */
+ memcpy(cell.payload+4, b, NTOR_ONIONSKIN_LEN);
+#ifdef CURVE25519_ENABLED
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE2, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type);
+ tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+#else
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+#endif
+
+ /* A valid create cell with an ntor payload, in legacy format. */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+ cell.command = CELL_CREATE;
+ memcpy(cell.payload, "ntorNTORntorNTOR", 16);
+ memcpy(cell.payload+16, b, NTOR_ONIONSKIN_LEN);
+#ifdef CURVE25519_ENABLED
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type);
+ tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+#else
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+#endif
+
+ /* == Okay, now let's try to parse some impossible stuff. */
+
+ /* It has to be some kind of a create cell! */
+ cell.command = CELL_CREATED;
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+
+ /* You can't acutally make an unparseable CREATE or CREATE_FAST cell. */
+
+ /* Try some CREATE2 cells. First with a bad type. */
+ cell.command = CELL_CREATE2;
+ memcpy(cell.payload, "\x00\x50\x00\x99", 4); /* Type 0x50???? */
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+ /* Now a good type with an incorrect length. */
+ memcpy(cell.payload, "\x00\x00\x00\xBC", 4); /* TAP, 187 bytes.*/
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+ /* Now a good type with a ridiculous length. */
+ memcpy(cell.payload, "\x00\x00\x02\x00", 4); /* TAP, 512 bytes.*/
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+
+ /* == Time to try formatting bad cells. The important thing is that
+ we reject big lengths, so just check that for now. */
+ cc.handshake_len = 512;
+ tt_int_op(-1, ==, create_cell_format(&cell2, &cc));
+
+ /* == Try formatting a create2 cell we don't understand. XXXX */
+
+ done:
+ ;
+}
+
+static void
+test_cfmt_created_cells(void *arg)
+{
+ uint8_t b[512];
+ created_cell_t cc;
+ cell_t cell;
+ cell_t cell2;
+
+ (void)arg;
+
+ /* A good CREATED cell */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
+ cell.command = CELL_CREATED;
+ memcpy(cell.payload, b, TAP_ONIONSKIN_REPLY_LEN);
+ tt_int_op(0, ==, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED, ==, cc.cell_type);
+ tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, cc.handshake_len);
+ test_memeq(cc.reply, b, TAP_ONIONSKIN_REPLY_LEN + 10);
+ tt_int_op(0, ==, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A good CREATED_FAST cell */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, CREATED_FAST_LEN);
+ cell.command = CELL_CREATED_FAST;
+ memcpy(cell.payload, b, CREATED_FAST_LEN);
+ tt_int_op(0, ==, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED_FAST, ==, cc.cell_type);
+ tt_int_op(CREATED_FAST_LEN, ==, cc.handshake_len);
+ test_memeq(cc.reply, b, CREATED_FAST_LEN + 10);
+ tt_int_op(0, ==, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A good CREATED2 cell with short reply */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 64);
+ cell.command = CELL_CREATED2;
+ memcpy(cell.payload, "\x00\x40", 2);
+ memcpy(cell.payload+2, b, 64);
+ tt_int_op(0, ==, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED2, ==, cc.cell_type);
+ tt_int_op(64, ==, cc.handshake_len);
+ test_memeq(cc.reply, b, 80);
+ tt_int_op(0, ==, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A good CREATED2 cell with maximal reply */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 496);
+ cell.command = CELL_CREATED2;
+ memcpy(cell.payload, "\x01\xF0", 2);
+ memcpy(cell.payload+2, b, 496);
+ tt_int_op(0, ==, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED2, ==, cc.cell_type);
+ tt_int_op(496, ==, cc.handshake_len);
+ test_memeq(cc.reply, b, 496);
+ tt_int_op(0, ==, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* Bogus CREATED2 cell: too long! */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 496);
+ cell.command = CELL_CREATED2;
+ memcpy(cell.payload, "\x01\xF1", 2);
+ tt_int_op(-1, ==, created_cell_parse(&cc, &cell));
+
+ /* Unformattable CREATED2 cell: too long! */
+ cc.handshake_len = 497;
+ tt_int_op(-1, ==, created_cell_format(&cell2, &cc));
+
+ done:
+ ;
+}
+
+static void
+test_cfmt_extend_cells(void *arg)
+{
+ cell_t cell;
+ uint8_t b[512];
+ extend_cell_t ec;
+ create_cell_t *cc = &ec.create_cell;
+ uint8_t p[RELAY_PAYLOAD_SIZE];
+ uint8_t p2[RELAY_PAYLOAD_SIZE];
+ uint8_t p2_cmd;
+ uint16_t p2_len;
+ char *mem_op_hex_tmp = NULL;
+
+ (void) arg;
+
+ /* Let's start with a simple EXTEND cell. */
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
+ memcpy(p+6,b,TAP_ONIONSKIN_CHALLENGE_LEN);
+ memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
+ tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
+ p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
+ tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type);
+ tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(258, ==, ec.orport_ipv4.port);
+ tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
+ test_memeq(ec.node_id, "electroencephalogram", 20);
+ tt_int_op(cc->cell_type, ==, CELL_CREATE);
+ tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_TAP);
+ tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_CHALLENGE_LEN);
+ test_memeq(cc->onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN+20);
+ tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND);
+ tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
+ test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
+
+ /* Let's do an ntor stuffed in a legacy EXTEND cell */
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+ memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
+ memcpy(p+6,"ntorNTORntorNTOR", 16);
+ memcpy(p+22, b, NTOR_ONIONSKIN_LEN);
+ memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
+ tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
+ p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
+ tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type);
+ tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(258, ==, ec.orport_ipv4.port);
+ tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
+ test_memeq(ec.node_id, "electroencephalogram", 20);
+ tt_int_op(cc->cell_type, ==, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR);
+ tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN);
+ test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20);
+ tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND);
+ tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
+ test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
+ tt_int_op(0, ==, create_cell_format_relayed(&cell, cc));
+
+ /* Now let's do a minimal ntor EXTEND2 cell. */
+ memset(&ec, 0xff, sizeof(ec));
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+ /* 2 items; one 18.244.0.1:61681 */
+ memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ /* The other is a digest. */
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ /* Prep for the handshake: type and length */
+ memcpy(p+31, "\x00\x02\x00\x54", 4);
+ memcpy(p+35, b, NTOR_ONIONSKIN_LEN);
+ tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, 35+NTOR_ONIONSKIN_LEN));
+ tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type);
+ tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(61681, ==, ec.orport_ipv4.port);
+ tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
+ test_memeq(ec.node_id, "anarchoindividualist", 20);
+ tt_int_op(cc->cell_type, ==, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR);
+ tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN);
+ test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20);
+ tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2);
+ tt_int_op(p2_len, ==, 35+NTOR_ONIONSKIN_LEN);
+ test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
+
+ /* Now let's do a fanciful EXTEND2 cell. */
+ memset(&ec, 0xff, sizeof(ec));
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 99);
+ /* 4 items; one 18 244 0 1 61681 */
+ memcpy(p, "\x04\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ /* One is a digest. */
+ memcpy(p+9, "\x02\x14" "anthropomorphization", 22);
+ /* One is an ipv6 address */
+ memcpy(p+31, "\x01\x12\x20\x02\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\xf0\xc5\x1e\x11\x12", 20);
+ /* One is the Konami code. */
+ memcpy(p+51, "\xf0\x20upupdowndownleftrightleftrightba", 34);
+ /* Prep for the handshake: weird type and length */
+ memcpy(p+85, "\x01\x05\x00\x63", 4);
+ memcpy(p+89, b, 99);
+ tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, 89+99));
+ tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type);
+ tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(61681, ==, ec.orport_ipv4.port);
+ tt_str_op("2002::f0:c51e", ==, fmt_addr(&ec.orport_ipv6.addr));
+ tt_int_op(4370, ==, ec.orport_ipv6.port);
+ test_memeq(ec.node_id, "anthropomorphization", 20);
+ tt_int_op(cc->cell_type, ==, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, ==, 0x105);
+ tt_int_op(cc->handshake_len, ==, 99);
+ test_memeq(cc->onionskin, b, 99+20);
+ tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2);
+ /* We'll generate it minus the IPv6 address and minus the konami code */
+ tt_int_op(p2_len, ==, 89+99-34-20);
+ test_memeq_hex(p2,
+ /* Two items: one that same darn IP address. */
+ "02000612F40001F0F1"
+ /* The next is a digest : anthropomorphization */
+ "0214616e7468726f706f6d6f727068697a6174696f6e"
+ /* Now the handshake prologue */
+ "01050063");
+ test_memeq(p2+1+8+22+4, b, 99+20);
+ tt_int_op(0, ==, create_cell_format_relayed(&cell, cc));
+
+ /* == Now try parsing some junk */
+
+ /* Try a too-long handshake */
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+31, "\xff\xff\x01\xd0", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* Try two identities. */
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+31, "\x02\x14" "autodepolymerization", 22);
+ memcpy(p+53, "\xff\xff\x00\x10", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* No identities. */
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x01\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+53, "\xff\xff\x00\x10", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* Try a bad IPv4 address (too long, too short)*/
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02\x00\x07\x12\xf4\x00\x01\xf0\xf1\xff", 10);
+ memcpy(p+10, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+32, "\xff\xff\x00\x10", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02\x00\x05\x12\xf4\x00\x01\xf0", 8);
+ memcpy(p+8, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+30, "\xff\xff\x00\x10", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* IPv6 address (too long, too short, no IPv4)*/
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+31, "\x01\x13" "xxxxxxxxxxxxxxxxYYZ", 19);
+ memcpy(p+50, "\xff\xff\x00\x20", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+31, "\x01\x11" "xxxxxxxxxxxxxxxxY", 17);
+ memcpy(p+48, "\xff\xff\x00\x20", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02", 1);
+ memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
+ memcpy(p+41, "\xff\xff\x00\x20", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* Running out of space in specifiers */
+ memset(p,0,sizeof(p));
+ memcpy(p, "\x05\x0a\xff", 3);
+ memcpy(p+3+255, "\x0a\xff", 2);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* Fuzz, because why not. */
+ memset(&ec, 0xff, sizeof(ec));
+ {
+ int i;
+ memset(p, 0, sizeof(p));
+ for (i = 0; i < 10000; ++i) {
+ int n = crypto_rand_int(sizeof(p));
+ crypto_rand((char *)p, n);
+ extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, n);
+ }
+ }
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_cfmt_extended_cells(void *arg)
+{
+ uint8_t b[512];
+ extended_cell_t ec;
+ created_cell_t *cc = &ec.created_cell;
+ uint8_t p[RELAY_PAYLOAD_SIZE];
+ uint8_t p2[RELAY_PAYLOAD_SIZE];
+ uint8_t p2_cmd;
+ uint16_t p2_len;
+ char *mem_op_hex_tmp = NULL;
+
+ (void) arg;
+
+ /* Try a regular EXTENDED cell. */
+ memset(&ec, 0xff, sizeof(ec));
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
+ memcpy(p,b,TAP_ONIONSKIN_REPLY_LEN);
+ tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED, p,
+ TAP_ONIONSKIN_REPLY_LEN));
+ tt_int_op(RELAY_COMMAND_EXTENDED, ==, ec.cell_type);
+ tt_int_op(cc->cell_type, ==, CELL_CREATED);
+ tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_REPLY_LEN);
+ test_memeq(cc->reply, b, TAP_ONIONSKIN_REPLY_LEN);
+ tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(RELAY_COMMAND_EXTENDED, ==, p2_cmd);
+ tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, p2_len);
+ test_memeq(p2, p, sizeof(p2));
+
+ /* Try an EXTENDED2 cell */
+ memset(&ec, 0xff, sizeof(ec));
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 42);
+ memcpy(p,"\x00\x2a",2);
+ memcpy(p+2,b,42);
+ tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, 2+42));
+ tt_int_op(RELAY_COMMAND_EXTENDED2, ==, ec.cell_type);
+ tt_int_op(cc->cell_type, ==, CELL_CREATED2);
+ tt_int_op(cc->handshake_len, ==, 42);
+ test_memeq(cc->reply, b, 42+10);
+ tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(RELAY_COMMAND_EXTENDED2, ==, p2_cmd);
+ tt_int_op(2+42, ==, p2_len);
+ test_memeq(p2, p, sizeof(p2));
+
+ /* Try an almost-too-long EXTENDED2 cell */
+ memcpy(p, "\x01\xf0", 2);
+ tt_int_op(0, ==,
+ extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p)));
+
+ /* Now try a too-long extended2 cell. That's the only misparse I can think
+ * of. */
+ memcpy(p, "\x01\xf1", 2);
+ tt_int_op(-1, ==,
+ extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p)));
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+#define TEST(name, flags) \
+ { #name, test_cfmt_ ## name, flags, 0, NULL }
+
+struct testcase_t cell_format_tests[] = {
+ TEST(relay_header, 0),
+ TEST(begin_cells, 0),
+ TEST(connected_cells, 0),
+ TEST(create_cells, 0),
+ TEST(created_cells, 0),
+ TEST(extend_cells, 0),
+ TEST(extended_cells, 0),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_config.c b/src/test/test_config.c
index ff251a24d..e20fe7329 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -1,11 +1,13 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "or.h"
+#include "addressmap.h"
#include "config.h"
+#include "confparse.h"
#include "connection_edge.h"
#include "test.h"
@@ -40,6 +42,11 @@ test_config_addressmap(void *arg)
config_get_lines(buf, &(get_options_mutable()->AddressMap), 0);
config_register_addressmaps(get_options());
+/* Use old interface for now, so we don't need to rewrite the unit tests */
+#define addressmap_rewrite(a,s,eo,ao) \
+ addressmap_rewrite((a),(s),AMR_FLAG_USE_IPV4_DNS|AMR_FLAG_USE_IPV6_DNS, \
+ (eo),(ao))
+
/* MapAddress .invalidwildcard.com .torserver.exit - no match */
strlcpy(address, "www.invalidwildcard.com", sizeof(address));
test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
@@ -156,6 +163,8 @@ test_config_addressmap(void *arg)
strlcpy(address, "www.torproject.org", sizeof(address));
test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+#undef addressmap_rewrite
+
done:
;
}
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index 45898df4e..005e102e2 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -1,16 +1,17 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "or.h"
+#include "fp_pair.h"
#include "test.h"
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
* *<b>b</b>. */
static int
-_compare_strs(const void **a, const void **b)
+compare_strs_(const void **a, const void **b)
{
const char *s1 = *a, *s2 = *b;
return strcmp(s1, s2);
@@ -28,7 +29,7 @@ compare_strs_for_bsearch_(const void *a, const void **b)
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
* *<b>b</b>, excluding a's first character, and ignoring case. */
static int
-_compare_without_first_ch(const void *a, const void **b)
+compare_without_first_ch_(const void *a, const void **b)
{
const char *s1 = a, *s2 = *b;
return strcasecmp(s1+1, s2);
@@ -66,8 +67,8 @@ test_container_smartlist_basic(void)
test_eq(4, smartlist_len(sl));
/* test isin. */
- test_assert(smartlist_isin(sl, (void*)3));
- test_assert(!smartlist_isin(sl, (void*)99));
+ test_assert(smartlist_contains(sl, (void*)3));
+ test_assert(!smartlist_contains(sl, (void*)99));
done:
smartlist_free(sl);
@@ -185,7 +186,7 @@ test_container_smartlist_strings(void)
/* Test swapping, shuffling, and sorting. */
smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0);
test_eq(7, smartlist_len(sl));
- smartlist_sort(sl, _compare_strs);
+ smartlist_sort(sl, compare_strs_);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc,"and,arma,by,nickm,onion,router,the");
tor_free(cp_alloc);
@@ -195,37 +196,37 @@ test_container_smartlist_strings(void)
tor_free(cp_alloc);
smartlist_shuffle(sl);
test_eq(7, smartlist_len(sl));
- test_assert(smartlist_string_isin(sl, "and"));
- test_assert(smartlist_string_isin(sl, "router"));
- test_assert(smartlist_string_isin(sl, "by"));
- test_assert(smartlist_string_isin(sl, "nickm"));
- test_assert(smartlist_string_isin(sl, "onion"));
- test_assert(smartlist_string_isin(sl, "arma"));
- test_assert(smartlist_string_isin(sl, "the"));
+ test_assert(smartlist_contains_string(sl, "and"));
+ test_assert(smartlist_contains_string(sl, "router"));
+ test_assert(smartlist_contains_string(sl, "by"));
+ test_assert(smartlist_contains_string(sl, "nickm"));
+ test_assert(smartlist_contains_string(sl, "onion"));
+ test_assert(smartlist_contains_string(sl, "arma"));
+ test_assert(smartlist_contains_string(sl, "the"));
/* Test bsearch. */
- smartlist_sort(sl, _compare_strs);
+ smartlist_sort(sl, compare_strs_);
test_streq("nickm", smartlist_bsearch(sl, "zNicKM",
- _compare_without_first_ch));
- test_streq("and", smartlist_bsearch(sl, " AND", _compare_without_first_ch));
- test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", _compare_without_first_ch));
+ compare_without_first_ch_));
+ test_streq("and", smartlist_bsearch(sl, " AND", compare_without_first_ch_));
+ test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", compare_without_first_ch_));
/* Test bsearch_idx */
{
int f;
smartlist_t *tmp = NULL;
- test_eq(0, smartlist_bsearch_idx(sl," aaa",_compare_without_first_ch,&f));
+ test_eq(0, smartlist_bsearch_idx(sl," aaa",compare_without_first_ch_,&f));
test_eq(f, 0);
- test_eq(0, smartlist_bsearch_idx(sl," and",_compare_without_first_ch,&f));
+ test_eq(0, smartlist_bsearch_idx(sl," and",compare_without_first_ch_,&f));
test_eq(f, 1);
- test_eq(1, smartlist_bsearch_idx(sl," arm",_compare_without_first_ch,&f));
+ test_eq(1, smartlist_bsearch_idx(sl," arm",compare_without_first_ch_,&f));
test_eq(f, 0);
- test_eq(1, smartlist_bsearch_idx(sl," arma",_compare_without_first_ch,&f));
+ test_eq(1, smartlist_bsearch_idx(sl," arma",compare_without_first_ch_,&f));
test_eq(f, 1);
- test_eq(2, smartlist_bsearch_idx(sl," armb",_compare_without_first_ch,&f));
+ test_eq(2, smartlist_bsearch_idx(sl," armb",compare_without_first_ch_,&f));
test_eq(f, 0);
- test_eq(7, smartlist_bsearch_idx(sl," zzzz",_compare_without_first_ch,&f));
+ test_eq(7, smartlist_bsearch_idx(sl," zzzz",compare_without_first_ch_,&f));
test_eq(f, 0);
/* Test trivial cases for list of length 0 or 1 */
@@ -266,25 +267,25 @@ test_container_smartlist_strings(void)
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
cp_alloc = smartlist_pop_last(sl);
- test_eq(cp_alloc, NULL);
+ test_eq_ptr(cp_alloc, NULL);
/* Test uniq() */
smartlist_split_string(sl,
"50,noon,radar,a,man,a,plan,a,canal,panama,radar,noon,50",
",", 0, 0);
- smartlist_sort(sl, _compare_strs);
- smartlist_uniq(sl, _compare_strs, _tor_free);
+ smartlist_sort(sl, compare_strs_);
+ smartlist_uniq(sl, compare_strs_, tor_free_);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc, "50,a,canal,man,noon,panama,plan,radar");
tor_free(cp_alloc);
- /* Test string_isin and isin_case and num_isin */
- test_assert(smartlist_string_isin(sl, "noon"));
- test_assert(!smartlist_string_isin(sl, "noonoon"));
- test_assert(smartlist_string_isin_case(sl, "nOOn"));
- test_assert(!smartlist_string_isin_case(sl, "nooNooN"));
- test_assert(smartlist_string_num_isin(sl, 50));
- test_assert(!smartlist_string_num_isin(sl, 60));
+ /* Test contains_string, contains_string_case and contains_int_as_string */
+ test_assert(smartlist_contains_string(sl, "noon"));
+ test_assert(!smartlist_contains_string(sl, "noonoon"));
+ test_assert(smartlist_contains_string_case(sl, "nOOn"));
+ test_assert(!smartlist_contains_string_case(sl, "nooNooN"));
+ test_assert(smartlist_contains_int_as_string(sl, 50));
+ test_assert(!smartlist_contains_int_as_string(sl, 60));
/* Test smartlist_choose */
{
@@ -292,12 +293,12 @@ test_container_smartlist_strings(void)
int allsame = 1;
int allin = 1;
void *first = smartlist_choose(sl);
- test_assert(smartlist_isin(sl, first));
+ test_assert(smartlist_contains(sl, first));
for (i = 0; i < 100; ++i) {
void *second = smartlist_choose(sl);
if (second != first)
allsame = 0;
- if (!smartlist_isin(sl, second))
+ if (!smartlist_contains(sl, second))
allin = 0;
}
test_assert(!allsame);
@@ -365,15 +366,15 @@ test_container_smartlist_overlap(void)
smartlist_add_all(sl, odds);
smartlist_intersect(sl, primes);
test_eq(smartlist_len(sl), 3);
- test_assert(smartlist_isin(sl, (void*)3));
- test_assert(smartlist_isin(sl, (void*)5));
- test_assert(smartlist_isin(sl, (void*)7));
+ test_assert(smartlist_contains(sl, (void*)3));
+ test_assert(smartlist_contains(sl, (void*)5));
+ test_assert(smartlist_contains(sl, (void*)7));
/* subtract */
smartlist_add_all(sl, primes);
smartlist_subtract(sl, odds);
test_eq(smartlist_len(sl), 1);
- test_assert(smartlist_isin(sl, (void*)2));
+ test_assert(smartlist_contains(sl, (void*)2));
done:
smartlist_free(odds);
@@ -389,14 +390,14 @@ test_container_smartlist_digests(void)
{
smartlist_t *sl = smartlist_new();
- /* digest_isin. */
+ /* contains_digest */
smartlist_add(sl, tor_memdup("AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN));
smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN));
smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN));
- test_eq(0, smartlist_digest_isin(NULL, "AAAAAAAAAAAAAAAAAAAA"));
- test_assert(smartlist_digest_isin(sl, "AAAAAAAAAAAAAAAAAAAA"));
- test_assert(smartlist_digest_isin(sl, "\00090AAB2AAAAaasdAAAAA"));
- test_eq(0, smartlist_digest_isin(sl, "\00090AAB2AAABaasdAAAAA"));
+ test_eq(0, smartlist_contains_digest(NULL, "AAAAAAAAAAAAAAAAAAAA"));
+ test_assert(smartlist_contains_digest(sl, "AAAAAAAAAAAAAAAAAAAA"));
+ test_assert(smartlist_contains_digest(sl, "\00090AAB2AAAAaasdAAAAA"));
+ test_eq(0, smartlist_contains_digest(sl, "\00090AAB2AAABaasdAAAAA"));
/* sort digests */
smartlist_sort_digests(sl);
@@ -445,11 +446,11 @@ test_container_smartlist_join(void)
} SMARTLIST_FOREACH_JOIN_END(cp1, cp2);
SMARTLIST_FOREACH(sl3, const char *, cp,
- test_assert(smartlist_isin(sl2, cp) &&
- !smartlist_string_isin(sl, cp)));
+ test_assert(smartlist_contains(sl2, cp) &&
+ !smartlist_contains_string(sl, cp)));
SMARTLIST_FOREACH(sl4, const char *, cp,
- test_assert(smartlist_isin(sl, cp) &&
- smartlist_string_isin(sl2, cp)));
+ test_assert(smartlist_contains(sl, cp) &&
+ smartlist_contains_string(sl2, cp)));
joined = smartlist_join_strings(sl3, ",", 0, NULL);
test_streq(joined, "Anemias,Anemias,Crossbowmen,Work");
tor_free(joined);
@@ -528,18 +529,18 @@ test_container_digestset(void)
}
set = digestset_new(1000);
SMARTLIST_FOREACH(included, const char *, cp,
- if (digestset_isin(set, cp))
+ if (digestset_contains(set, cp))
ok = 0);
test_assert(ok);
SMARTLIST_FOREACH(included, const char *, cp,
digestset_add(set, cp));
SMARTLIST_FOREACH(included, const char *, cp,
- if (!digestset_isin(set, cp))
+ if (!digestset_contains(set, cp))
ok = 0);
test_assert(ok);
for (i = 0; i < 1000; ++i) {
crypto_rand(d, DIGEST_LEN);
- if (digestset_isin(set, d))
+ if (digestset_contains(set, d))
++false_positives;
}
test_assert(false_positives < 50); /* Should be far lower. */
@@ -558,7 +559,7 @@ typedef struct pq_entry_t {
/** Helper: return a tristate based on comparing two pq_entry_t values. */
static int
-_compare_strings_for_pqueue(const void *p1, const void *p2)
+compare_strings_for_pqueue_(const void *p1, const void *p2)
{
const pq_entry_t *e1=p1, *e2=p2;
return strcmp(e1->val, e2->val);
@@ -588,7 +589,7 @@ test_container_pqueue(void)
#define OK() smartlist_pqueue_assert_ok(sl, cmp, offset)
- cmp = _compare_strings_for_pqueue;
+ cmp = compare_strings_for_pqueue_;
smartlist_pqueue_add(sl, cmp, offset, &cows);
smartlist_pqueue_add(sl, cmp, offset, &zebras);
smartlist_pqueue_add(sl, cmp, offset, &fish);
@@ -677,12 +678,12 @@ test_container_strmap(void)
test_eq(strmap_size(map), 0);
test_assert(strmap_isempty(map));
v = strmap_set(map, "K1", (void*)99);
- test_eq(v, NULL);
+ test_eq_ptr(v, NULL);
test_assert(!strmap_isempty(map));
v = strmap_set(map, "K2", (void*)101);
- test_eq(v, NULL);
+ test_eq_ptr(v, NULL);
v = strmap_set(map, "K1", (void*)100);
- test_eq(v, (void*)99);
+ test_eq_ptr(v, (void*)99);
test_eq_ptr(strmap_get(map,"K1"), (void*)100);
test_eq_ptr(strmap_get(map,"K2"), (void*)101);
test_eq_ptr(strmap_get(map,"K-not-there"), NULL);
@@ -782,6 +783,132 @@ test_container_order_functions(void)
;
}
+static void
+test_di_map(void *arg)
+{
+ di_digest256_map_t *map = NULL;
+ const uint8_t key1[] = "In view of the fact that it was ";
+ const uint8_t key2[] = "superficially convincing, being ";
+ const uint8_t key3[] = "properly enciphered in a one-tim";
+ const uint8_t key4[] = "e cipher scheduled for use today";
+ char *v1 = tor_strdup(", it came close to causing a disaster...");
+ char *v2 = tor_strdup("I regret to have to advise you that the mission");
+ char *v3 = tor_strdup("was actually initiated...");
+ /* -- John Brunner, _The Shockwave Rider_ */
+
+ (void)arg;
+
+ /* Try searching on an empty map. */
+ tt_ptr_op(NULL, ==, dimap_search(map, key1, NULL));
+ tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
+ tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
+ dimap_free(map, NULL);
+ map = NULL;
+
+ /* Add a single entry. */
+ dimap_add_entry(&map, key1, v1);
+ tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
+ tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
+ tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
+
+ /* Now try it with three entries in the map. */
+ dimap_add_entry(&map, key2, v2);
+ dimap_add_entry(&map, key3, v3);
+ tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
+ tt_ptr_op(v2, ==, dimap_search(map, key2, NULL));
+ tt_ptr_op(v3, ==, dimap_search(map, key3, NULL));
+ tt_ptr_op(NULL, ==, dimap_search(map, key4, NULL));
+ tt_ptr_op(v1, ==, dimap_search(map, key4, v1));
+
+ done:
+ tor_free(v1);
+ tor_free(v2);
+ tor_free(v3);
+ dimap_free(map, NULL);
+}
+
+/** Run unit tests for fp_pair-to-void* map functions */
+static void
+test_container_fp_pair_map(void)
+{
+ fp_pair_map_t *map;
+ fp_pair_t fp1, fp2, fp3, fp4, fp5, fp6;
+ void *v;
+ fp_pair_map_iter_t *iter;
+ fp_pair_t k;
+
+ map = fp_pair_map_new();
+ test_assert(map);
+ test_eq(fp_pair_map_size(map), 0);
+ test_assert(fp_pair_map_isempty(map));
+
+ memset(fp1.first, 0x11, DIGEST_LEN);
+ memset(fp1.second, 0x12, DIGEST_LEN);
+ memset(fp2.first, 0x21, DIGEST_LEN);
+ memset(fp2.second, 0x22, DIGEST_LEN);
+ memset(fp3.first, 0x31, DIGEST_LEN);
+ memset(fp3.second, 0x32, DIGEST_LEN);
+ memset(fp4.first, 0x41, DIGEST_LEN);
+ memset(fp4.second, 0x42, DIGEST_LEN);
+ memset(fp5.first, 0x51, DIGEST_LEN);
+ memset(fp5.second, 0x52, DIGEST_LEN);
+ memset(fp6.first, 0x61, DIGEST_LEN);
+ memset(fp6.second, 0x62, DIGEST_LEN);
+
+ v = fp_pair_map_set(map, &fp1, (void*)99);
+ test_eq(v, NULL);
+ test_assert(!fp_pair_map_isempty(map));
+ v = fp_pair_map_set(map, &fp2, (void*)101);
+ test_eq(v, NULL);
+ v = fp_pair_map_set(map, &fp1, (void*)100);
+ test_eq(v, (void*)99);
+ test_eq_ptr(fp_pair_map_get(map, &fp1), (void*)100);
+ test_eq_ptr(fp_pair_map_get(map, &fp2), (void*)101);
+ test_eq_ptr(fp_pair_map_get(map, &fp3), NULL);
+ fp_pair_map_assert_ok(map);
+
+ v = fp_pair_map_remove(map, &fp2);
+ fp_pair_map_assert_ok(map);
+ test_eq_ptr(v, (void*)101);
+ test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
+ test_eq_ptr(fp_pair_map_remove(map, &fp2), NULL);
+
+ fp_pair_map_set(map, &fp2, (void*)101);
+ fp_pair_map_set(map, &fp3, (void*)102);
+ fp_pair_map_set(map, &fp4, (void*)103);
+ test_eq(fp_pair_map_size(map), 4);
+ fp_pair_map_assert_ok(map);
+ fp_pair_map_set(map, &fp5, (void*)104);
+ fp_pair_map_set(map, &fp6, (void*)105);
+ fp_pair_map_assert_ok(map);
+
+ /* Test iterator. */
+ iter = fp_pair_map_iter_init(map);
+ while (!fp_pair_map_iter_done(iter)) {
+ fp_pair_map_iter_get(iter, &k, &v);
+ test_eq_ptr(v, fp_pair_map_get(map, &k));
+
+ if (tor_memeq(&fp2, &k, sizeof(fp2))) {
+ iter = fp_pair_map_iter_next_rmv(map, iter);
+ } else {
+ iter = fp_pair_map_iter_next(map, iter);
+ }
+ }
+
+ /* Make sure we removed fp2, but not the others. */
+ test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
+ test_eq_ptr(fp_pair_map_get(map, &fp5), (void*)104);
+
+ fp_pair_map_assert_ok(map);
+ /* Clean up after ourselves. */
+ fp_pair_map_free(map, NULL);
+ map = NULL;
+
+ done:
+ if (map)
+ fp_pair_map_free(map, NULL);
+}
+
#define CONTAINER_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_container_ ## name }
@@ -796,6 +923,8 @@ struct testcase_t container_tests[] = {
CONTAINER_LEGACY(strmap),
CONTAINER_LEGACY(pqueue),
CONTAINER_LEGACY(order_functions),
+ { "di_map", test_di_map, 0, NULL, NULL },
+ CONTAINER_LEGACY(fp_pair_map),
END_OF_TESTCASES
};
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 7f4347a41..f92bfd673 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1,13 +1,18 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CRYPTO_PRIVATE
+#define CRYPTO_CURVE25519_PRIVATE
#include "or.h"
#include "test.h"
#include "aes.h"
+#include "util.h"
+#ifdef CURVE25519_ENABLED
+#include "crypto_curve25519.h"
+#endif
/** Run unit tests for Diffie-Hellman functionality. */
static void
@@ -119,9 +124,9 @@ test_crypto_aes(void *arg)
memset(data2, 0, 1024);
memset(data3, 0, 1024);
env1 = crypto_cipher_new(NULL);
- test_neq(env1, 0);
+ test_neq_ptr(env1, 0);
env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
- test_neq(env2, 0);
+ test_neq_ptr(env2, 0);
/* Try encrypting 512 chars. */
crypto_cipher_encrypt(env1, data2, data1, 512);
@@ -152,7 +157,7 @@ test_crypto_aes(void *arg)
memset(data3, 0, 1024);
env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
- test_neq(env2, 0);
+ test_neq_ptr(env2, NULL);
for (j = 0; j < 1024-16; j += 17) {
crypto_cipher_encrypt(env2, data3+j, data1+j, 17);
}
@@ -427,6 +432,11 @@ test_crypto_pk(void)
test_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size));
test_eq(0, crypto_pk_cmp_keys(pk1, pk2));
+ /* comparison between keys and NULL */
+ tt_int_op(crypto_pk_cmp_keys(NULL, pk1), <, 0);
+ tt_int_op(crypto_pk_cmp_keys(NULL, NULL), ==, 0);
+ tt_int_op(crypto_pk_cmp_keys(pk1, NULL), >, 0);
+
test_eq(128, crypto_pk_keysize(pk1));
test_eq(1024, crypto_pk_num_bits(pk1));
test_eq(128, crypto_pk_keysize(pk2));
@@ -626,22 +636,6 @@ test_crypto_formats(void)
tor_free(data2);
}
- /* Check fingerprint */
- {
- test_assert(crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 00000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD1234 ABCD 5678 0000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD1234 ABCD 5678 00000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ACD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 00000"));
- }
-
done:
tor_free(data1);
tor_free(data2);
@@ -736,7 +730,7 @@ test_crypto_aes_iv(void *arg)
/* Decrypt with the wrong key. */
decrypted_size = crypto_cipher_decrypt_with_iv(key2, decrypted2, 4095,
encrypted1, encrypted_size);
- test_memneq(plain, decrypted2, encrypted_size);
+ test_memneq(plain, decrypted2, decrypted_size);
/* Alter the initialization vector. */
encrypted1[0] += 42;
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
@@ -827,6 +821,293 @@ test_crypto_base32_decode(void)
;
}
+static void
+test_crypto_kdf_TAP(void *arg)
+{
+ uint8_t key_material[100];
+ int r;
+ char *mem_op_hex_tmp = NULL;
+
+ (void)arg;
+#define EXPAND(s) \
+ r = crypto_expand_key_material_TAP( \
+ (const uint8_t*)(s), strlen(s), \
+ key_material, 100)
+
+ /* Test vectors generated with a little python script; feel free to write
+ * your own. */
+ memset(key_material, 0, sizeof(key_material));
+ EXPAND("");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "5ba93c9db0cff93f52b521d7420e43f6eda2784fbf8b4530d8"
+ "d246dd74ac53a13471bba17941dff7c4ea21bb365bbeeaf5f2"
+ "c654883e56d11e43c44e9842926af7ca0a8cca12604f945414"
+ "f07b01e13da42c6cf1de3abfdea9b95f34687cbbe92b9a7383");
+
+ EXPAND("Tor");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "776c6214fc647aaa5f683c737ee66ec44f03d0372e1cce6922"
+ "7950f236ddf1e329a7ce7c227903303f525a8c6662426e8034"
+ "870642a6dabbd41b5d97ec9bf2312ea729992f48f8ea2d0ba8"
+ "3f45dfda1a80bdc8b80de01b23e3e0ffae099b3e4ccf28dc28");
+
+ EXPAND("AN ALARMING ITEM TO FIND ON A MONTHLY AUTO-DEBIT NOTICE");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "a340b5d126086c3ab29c2af4179196dbf95e1c72431419d331"
+ "4844bf8f6afb6098db952b95581fb6c33625709d6f4400b8e7"
+ "ace18a70579fad83c0982ef73f89395bcc39493ad53a685854"
+ "daf2ba9b78733b805d9a6824c907ee1dba5ac27a1e466d4d10");
+
+ done:
+ tor_free(mem_op_hex_tmp);
+
+#undef EXPAND
+}
+
+static void
+test_crypto_hkdf_sha256(void *arg)
+{
+ uint8_t key_material[100];
+ const uint8_t salt[] = "ntor-curve25519-sha256-1:key_extract";
+ const size_t salt_len = strlen((char*)salt);
+ const uint8_t m_expand[] = "ntor-curve25519-sha256-1:key_expand";
+ const size_t m_expand_len = strlen((char*)m_expand);
+ int r;
+ char *mem_op_hex_tmp = NULL;
+
+ (void)arg;
+
+#define EXPAND(s) \
+ r = crypto_expand_key_material_rfc5869_sha256( \
+ (const uint8_t*)(s), strlen(s), \
+ salt, salt_len, \
+ m_expand, m_expand_len, \
+ key_material, 100)
+
+ /* Test vectors generated with ntor_ref.py */
+ memset(key_material, 0, sizeof(key_material));
+ EXPAND("");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "d3490ed48b12a48f9547861583573fe3f19aafe3f81dc7fc75"
+ "eeed96d741b3290f941576c1f9f0b2d463d1ec7ab2c6bf71cd"
+ "d7f826c6298c00dbfe6711635d7005f0269493edf6046cc7e7"
+ "dcf6abe0d20c77cf363e8ffe358927817a3d3e73712cee28d8");
+
+ EXPAND("Tor");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "5521492a85139a8d9107a2d5c0d9c91610d0f95989975ebee6"
+ "c02a4f8d622a6cfdf9b7c7edd3832e2760ded1eac309b76f8d"
+ "66c4a3c4d6225429b3a016e3c3d45911152fc87bc2de9630c3"
+ "961be9fdb9f93197ea8e5977180801926d3321fa21513e59ac");
+
+ EXPAND("AN ALARMING ITEM TO FIND ON YOUR CREDIT-RATING STATEMENT");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "a2aa9b50da7e481d30463adb8f233ff06e9571a0ca6ab6df0f"
+ "b206fa34e5bc78d063fc291501beec53b36e5a0e434561200c"
+ "5f8bd13e0f88b3459600b4dc21d69363e2895321c06184879d"
+ "94b18f078411be70b767c7fc40679a9440a0c95ea83a23efbf");
+
+ done:
+ tor_free(mem_op_hex_tmp);
+#undef EXPAND
+}
+
+#ifdef CURVE25519_ENABLED
+static void
+test_crypto_curve25519_impl(void *arg)
+{
+ /* adapted from curve25519_donna, which adapted it from test-curve25519
+ version 20050915, by D. J. Bernstein, Public domain. */
+
+ const int randomize_high_bit = (arg != NULL);
+
+#ifdef SLOW_CURVE25519_TEST
+ const int loop_max=10000;
+ const char e1_expected[] = "4faf81190869fd742a33691b0e0824d5"
+ "7e0329f4dd2819f5f32d130f1296b500";
+ const char e2k_expected[] = "05aec13f92286f3a781ccae98995a3b9"
+ "e0544770bc7de853b38f9100489e3e79";
+ const char e1e2k_expected[] = "cd6e8269104eb5aaee886bd2071fba88"
+ "bd13861475516bc2cd2b6e005e805064";
+#else
+ const int loop_max=200;
+ const char e1_expected[] = "bc7112cde03f97ef7008cad1bdc56be3"
+ "c6a1037d74cceb3712e9206871dcf654";
+ const char e2k_expected[] = "dd8fa254fb60bdb5142fe05b1f5de44d"
+ "8e3ee1a63c7d14274ea5d4c67f065467";
+ const char e1e2k_expected[] = "7ddb98bd89025d2347776b33901b3e7e"
+ "c0ee98cb2257a4545c0cfb2ca3e1812b";
+#endif
+
+ unsigned char e1k[32];
+ unsigned char e2k[32];
+ unsigned char e1e2k[32];
+ unsigned char e2e1k[32];
+ unsigned char e1[32] = {3};
+ unsigned char e2[32] = {5};
+ unsigned char k[32] = {9};
+ int loop, i;
+
+ char *mem_op_hex_tmp = NULL;
+
+ for (loop = 0; loop < loop_max; ++loop) {
+ curve25519_impl(e1k,e1,k);
+ curve25519_impl(e2e1k,e2,e1k);
+ curve25519_impl(e2k,e2,k);
+ if (randomize_high_bit) {
+ /* We require that the high bit of the public key be ignored. So if
+ * we're doing this variant test, we randomize the high bit of e2k, and
+ * make sure that the handshake still works out the same as it would
+ * otherwise. */
+ uint8_t byte;
+ crypto_rand((char*)&byte, 1);
+ e2k[31] |= (byte & 0x80);
+ }
+ curve25519_impl(e1e2k,e1,e2k);
+ test_memeq(e1e2k, e2e1k, 32);
+ if (loop == loop_max-1) {
+ break;
+ }
+ for (i = 0;i < 32;++i) e1[i] ^= e2k[i];
+ for (i = 0;i < 32;++i) e2[i] ^= e1k[i];
+ for (i = 0;i < 32;++i) k[i] ^= e1e2k[i];
+ }
+
+ test_memeq_hex(e1, e1_expected);
+ test_memeq_hex(e2k, e2k_expected);
+ test_memeq_hex(e1e2k, e1e2k_expected);
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_crypto_curve25519_wrappers(void *arg)
+{
+ curve25519_public_key_t pubkey1, pubkey2;
+ curve25519_secret_key_t seckey1, seckey2;
+
+ uint8_t output1[CURVE25519_OUTPUT_LEN];
+ uint8_t output2[CURVE25519_OUTPUT_LEN];
+ (void)arg;
+
+ /* Test a simple handshake, serializing and deserializing some stuff. */
+ curve25519_secret_key_generate(&seckey1, 0);
+ curve25519_secret_key_generate(&seckey2, 1);
+ curve25519_public_key_generate(&pubkey1, &seckey1);
+ curve25519_public_key_generate(&pubkey2, &seckey2);
+ test_assert(curve25519_public_key_is_ok(&pubkey1));
+ test_assert(curve25519_public_key_is_ok(&pubkey2));
+ curve25519_handshake(output1, &seckey1, &pubkey2);
+ curve25519_handshake(output2, &seckey2, &pubkey1);
+ test_memeq(output1, output2, sizeof(output1));
+
+ done:
+ ;
+}
+
+static void
+test_crypto_curve25519_encode(void *arg)
+{
+ curve25519_secret_key_t seckey;
+ curve25519_public_key_t key1, key2, key3;
+ char buf[64];
+
+ (void)arg;
+
+ curve25519_secret_key_generate(&seckey, 0);
+ curve25519_public_key_generate(&key1, &seckey);
+ tt_int_op(0, ==, curve25519_public_to_base64(buf, &key1));
+ tt_int_op(CURVE25519_BASE64_PADDED_LEN, ==, strlen(buf));
+
+ tt_int_op(0, ==, curve25519_public_from_base64(&key2, buf));
+ test_memeq(key1.public_key, key2.public_key, CURVE25519_PUBKEY_LEN);
+
+ buf[CURVE25519_BASE64_PADDED_LEN - 1] = '\0';
+ tt_int_op(CURVE25519_BASE64_PADDED_LEN-1, ==, strlen(buf));
+ tt_int_op(0, ==, curve25519_public_from_base64(&key3, buf));
+ test_memeq(key1.public_key, key3.public_key, CURVE25519_PUBKEY_LEN);
+
+ /* Now try bogus parses. */
+ strlcpy(buf, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$=", sizeof(buf));
+ tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf));
+
+ strlcpy(buf, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", sizeof(buf));
+ tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf));
+
+ strlcpy(buf, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", sizeof(buf));
+ tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf));
+
+ done:
+ ;
+}
+
+static void
+test_crypto_curve25519_persist(void *arg)
+{
+ curve25519_keypair_t keypair, keypair2;
+ char *fname = tor_strdup(get_fname("curve25519_keypair"));
+ char *tag = NULL;
+ char *content = NULL;
+ const char *cp;
+ struct stat st;
+ size_t taglen;
+
+ (void)arg;
+
+ tt_int_op(0,==,curve25519_keypair_generate(&keypair, 0));
+
+ tt_int_op(0,==,curve25519_keypair_write_to_file(&keypair, fname, "testing"));
+ tt_int_op(0,==,curve25519_keypair_read_from_file(&keypair2, &tag, fname));
+ tt_str_op(tag,==,"testing");
+ tor_free(tag);
+
+ test_memeq(keypair.pubkey.public_key,
+ keypair2.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN);
+ test_memeq(keypair.seckey.secret_key,
+ keypair2.seckey.secret_key,
+ CURVE25519_SECKEY_LEN);
+
+ content = read_file_to_str(fname, RFTS_BIN, &st);
+ tt_assert(content);
+ taglen = strlen("== c25519v1: testing ==");
+ tt_int_op(st.st_size, ==, 32+CURVE25519_PUBKEY_LEN+CURVE25519_SECKEY_LEN);
+ tt_assert(fast_memeq(content, "== c25519v1: testing ==", taglen));
+ tt_assert(tor_mem_is_zero(content+taglen, 32-taglen));
+ cp = content + 32;
+ test_memeq(keypair.seckey.secret_key,
+ cp,
+ CURVE25519_SECKEY_LEN);
+ cp += CURVE25519_SECKEY_LEN;
+ test_memeq(keypair.pubkey.public_key,
+ cp,
+ CURVE25519_SECKEY_LEN);
+
+ tor_free(fname);
+ fname = tor_strdup(get_fname("bogus_keypair"));
+
+ tt_int_op(-1, ==, curve25519_keypair_read_from_file(&keypair2, &tag, fname));
+ tor_free(tag);
+
+ content[69] ^= 0xff;
+ tt_int_op(0, ==, write_bytes_to_file(fname, content, (size_t)st.st_size, 1));
+ tt_int_op(-1, ==, curve25519_keypair_read_from_file(&keypair2, &tag, fname));
+
+ done:
+ tor_free(fname);
+ tor_free(content);
+ tor_free(tag);
+}
+
+#endif
+
static void *
pass_data_setup_fn(const struct testcase_t *testcase)
{
@@ -858,6 +1139,15 @@ struct testcase_t crypto_tests[] = {
{ "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" },
{ "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"evp" },
CRYPTO_LEGACY(base32_decode),
+ { "kdf_TAP", test_crypto_kdf_TAP, 0, NULL, NULL },
+ { "hkdf_sha256", test_crypto_hkdf_sha256, 0, NULL, NULL },
+#ifdef CURVE25519_ENABLED
+ { "curve25519_impl", test_crypto_curve25519_impl, 0, NULL, NULL },
+ { "curve25519_impl_hibit", test_crypto_curve25519_impl, 0, NULL, (void*)"y"},
+ { "curve25519_wrappers", test_crypto_curve25519_wrappers, 0, NULL, NULL },
+ { "curve25519_encode", test_crypto_curve25519_encode, 0, NULL, NULL },
+ { "curve25519_persist", test_crypto_curve25519_persist, 0, NULL, NULL },
+#endif
END_OF_TESTCASES
};
diff --git a/src/test/test_data.c b/src/test/test_data.c
index de2f9f58e..5f0f7cba0 100644
--- a/src/test/test_data.c
+++ b/src/test/test_data.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** First of 3 example authority certificates for unit testing. */
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 83c612045..56ac3b34c 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -1,14 +1,18 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
+#include <math.h>
+
#define DIRSERV_PRIVATE
#define DIRVOTE_PRIVATE
#define ROUTER_PRIVATE
+#define ROUTERLIST_PRIVATE
#define HIBERNATE_PRIVATE
#include "or.h"
+#include "config.h"
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
@@ -70,22 +74,24 @@ test_dir_nicknames(void)
static void
test_dir_formats(void)
{
- char buf[8192], buf2[8192];
+ char *buf = NULL;
+ char buf2[8192];
char platform[256];
char fingerprint[FINGERPRINT_LEN+1];
- char *pk1_str = NULL, *pk2_str = NULL, *pk3_str = NULL, *cp;
- size_t pk1_str_len, pk2_str_len, pk3_str_len;
+ char *pk1_str = NULL, *pk2_str = NULL, *cp;
+ size_t pk1_str_len, pk2_str_len;
routerinfo_t *r1=NULL, *r2=NULL;
- crypto_pk_t *pk1 = NULL, *pk2 = NULL, *pk3 = NULL;
- routerinfo_t *rp1 = NULL;
+ crypto_pk_t *pk1 = NULL, *pk2 = NULL;
+ routerinfo_t *rp1 = NULL, *rp2 = NULL;
addr_policy_t *ex1, *ex2;
routerlist_t *dir1 = NULL, *dir2 = NULL;
+ or_options_t *options = get_options_mutable();
+ const addr_policy_t *p;
pk1 = pk_generate(0);
pk2 = pk_generate(1);
- pk3 = pk_generate(2);
- test_assert(pk1 && pk2 && pk3);
+ test_assert(pk1 && pk2);
hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
@@ -125,31 +131,36 @@ test_dir_formats(void)
r2->or_port = 9005;
r2->dir_port = 0;
r2->onion_pkey = crypto_pk_dup_key(pk2);
+ r2->onion_curve25519_pkey = tor_malloc_zero(sizeof(curve25519_public_key_t));
+ curve25519_public_from_base64(r2->onion_curve25519_pkey,
+ "skyinAnvardNostarsNomoonNowindormistsorsnow");
r2->identity_pkey = crypto_pk_dup_key(pk1);
r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000;
r2->exit_policy = smartlist_new();
- smartlist_add(r2->exit_policy, ex2);
smartlist_add(r2->exit_policy, ex1);
+ smartlist_add(r2->exit_policy, ex2);
r2->nickname = tor_strdup("Fred");
test_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str,
&pk1_str_len));
test_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str,
&pk2_str_len));
- test_assert(!crypto_pk_write_public_key_to_string(pk3 , &pk3_str,
- &pk3_str_len));
- memset(buf, 0, 2048);
- test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
+ /* XXXX025 router_dump_to_string should really take this from ri.*/
+ options->ContactInfo = tor_strdup("Magri White "
+ "<magri@elsewhere.example.com>");
+ buf = router_dump_router_to_string(r1, pk2);
+ tor_free(options->ContactInfo);
+ test_assert(buf);
strlcpy(buf2, "router Magri 18.244.0.1 9000 0 9003\n"
"or-address [1:2:3:4::]:9999\n"
"platform Tor "VERSION" on ", sizeof(buf2));
strlcat(buf2, get_uname(), sizeof(buf2));
strlcat(buf2, "\n"
- "opt protocols Link 1 2 Circuit 1\n"
+ "protocols Link 1 2 Circuit 1\n"
"published 1970-01-01 00:00:00\n"
- "opt fingerprint ", sizeof(buf2));
+ "fingerprint ", sizeof(buf2));
test_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1));
strlcat(buf2, fingerprint, sizeof(buf2));
strlcat(buf2, "\nuptime 0\n"
@@ -161,14 +172,18 @@ test_dir_formats(void)
strlcat(buf2, pk1_str, sizeof(buf2));
strlcat(buf2, "signing-key\n", sizeof(buf2));
strlcat(buf2, pk2_str, sizeof(buf2));
- strlcat(buf2, "opt hidden-service-dir\n", sizeof(buf2));
+ strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
+ strlcat(buf2, "contact Magri White <magri@elsewhere.example.com>\n",
+ sizeof(buf2));
strlcat(buf2, "reject *:*\nrouter-signature\n", sizeof(buf2));
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
* twice */
test_streq(buf, buf2);
+ tor_free(buf);
- test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
+ buf = router_dump_router_to_string(r1, pk2);
+ test_assert(buf);
cp = buf;
rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL);
test_assert(rp1);
@@ -182,35 +197,67 @@ test_dir_formats(void)
test_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0);
//test_assert(rp1->exit_policy == NULL);
-#if 0
- /* XXX Once we have exit policies, test this again. XXX */
- strlcpy(buf2, "router tor.tor.tor 9005 0 0 3000\n", sizeof(buf2));
+ strlcpy(buf2,
+ "router Fred 1.1.1.1 9005 0 0\n"
+ "platform Tor "VERSION" on ", sizeof(buf2));
+ strlcat(buf2, get_uname(), sizeof(buf2));
+ strlcat(buf2, "\n"
+ "protocols Link 1 2 Circuit 1\n"
+ "published 1970-01-01 00:00:05\n"
+ "fingerprint ", sizeof(buf2));
+ test_assert(!crypto_pk_get_fingerprint(pk1, fingerprint, 1));
+ strlcat(buf2, fingerprint, sizeof(buf2));
+ strlcat(buf2, "\nuptime 0\n"
+ "bandwidth 3000 3000 3000\n", sizeof(buf2));
+ strlcat(buf2, "onion-key\n", sizeof(buf2));
strlcat(buf2, pk2_str, sizeof(buf2));
strlcat(buf2, "signing-key\n", sizeof(buf2));
strlcat(buf2, pk1_str, sizeof(buf2));
- strlcat(buf2, "accept *:80\nreject 18.*:24\n\n", sizeof(buf2));
- test_assert(router_dump_router_to_string(buf, 2048, &r2, pk2)>0);
+ strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
+ strlcat(buf2, "ntor-onion-key "
+ "skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2));
+ strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
+ strlcat(buf2, "router-signature\n", sizeof(buf2));
+
+ buf = router_dump_router_to_string(r2, pk1);
+ buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
+ * twice */
test_streq(buf, buf2);
+ tor_free(buf);
+ buf = router_dump_router_to_string(r2, pk1);
cp = buf;
- rp2 = router_parse_entry_from_string(&cp,1);
+ rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL);
test_assert(rp2);
- test_streq(rp2->address, r2.address);
- test_eq(rp2->or_port, r2.or_port);
- test_eq(rp2->dir_port, r2.dir_port);
- test_eq(rp2->bandwidth, r2.bandwidth);
+ test_streq(rp2->address, r2->address);
+ test_eq(rp2->or_port, r2->or_port);
+ test_eq(rp2->dir_port, r2->dir_port);
+ test_eq(rp2->bandwidthrate, r2->bandwidthrate);
+ test_eq(rp2->bandwidthburst, r2->bandwidthburst);
+ test_eq(rp2->bandwidthcapacity, r2->bandwidthcapacity);
+ test_memeq(rp2->onion_curve25519_pkey->public_key,
+ r2->onion_curve25519_pkey->public_key,
+ CURVE25519_PUBKEY_LEN);
test_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0);
test_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0);
- test_eq(rp2->exit_policy->policy_type, EXIT_POLICY_ACCEPT);
- test_streq(rp2->exit_policy->string, "accept *:80");
- test_streq(rp2->exit_policy->address, "*");
- test_streq(rp2->exit_policy->port, "80");
- test_eq(rp2->exit_policy->next->policy_type, EXIT_POLICY_REJECT);
- test_streq(rp2->exit_policy->next->string, "reject 18.*:24");
- test_streq(rp2->exit_policy->next->address, "18.*");
- test_streq(rp2->exit_policy->next->port, "24");
- test_assert(rp2->exit_policy->next->next == NULL);
+ test_eq(smartlist_len(rp2->exit_policy), 2);
+
+ p = smartlist_get(rp2->exit_policy, 0);
+ test_eq(p->policy_type, ADDR_POLICY_ACCEPT);
+ test_assert(tor_addr_is_null(&p->addr));
+ test_eq(p->maskbits, 0);
+ test_eq(p->prt_min, 80);
+ test_eq(p->prt_max, 80);
+
+ p = smartlist_get(rp2->exit_policy, 1);
+ test_eq(p->policy_type, ADDR_POLICY_REJECT);
+ test_assert(tor_addr_eq(&p->addr, &ex2->addr));
+ test_eq(p->maskbits, 8);
+ test_eq(p->prt_min, 24);
+ test_eq(p->prt_max, 24);
+
+#if 0
/* Okay, now for the directories. */
{
fingerprint_list = smartlist_new();
@@ -220,24 +267,6 @@ test_dir_formats(void)
add_fingerprint_to_dir("Fred", buf, fingerprint_list);
}
- {
- char d[DIGEST_LEN];
- const char *m;
- /* XXXX NM re-enable. */
- /* Make sure routers aren't too far in the past any more. */
- r1->cache_info.published_on = time(NULL);
- r2->cache_info.published_on = time(NULL)-3*60*60;
- test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
- test_eq(dirserv_add_descriptor(buf,&m,""), ROUTER_ADDED_NOTIFY_GENERATOR);
- test_assert(router_dump_router_to_string(buf, 2048, r2, pk1)>0);
- test_eq(dirserv_add_descriptor(buf,&m,""), ROUTER_ADDED_NOTIFY_GENERATOR);
- get_options()->Nickname = tor_strdup("DirServer");
- test_assert(!dirserv_dump_directory_to_string(&cp,pk3, 0));
- crypto_pk_get_digest(pk3, d);
- test_assert(!router_parse_directory(cp));
- test_eq(2, smartlist_len(dir1->routers));
- tor_free(cp);
- }
#endif
dirserv_free_fingerprint_list();
@@ -247,12 +276,11 @@ test_dir_formats(void)
if (r2)
routerinfo_free(r2);
+ tor_free(buf);
tor_free(pk1_str);
tor_free(pk2_str);
- tor_free(pk3_str);
if (pk1) crypto_pk_free(pk1);
if (pk2) crypto_pk_free(pk2);
- if (pk3) crypto_pk_free(pk3);
if (rp1) routerinfo_free(rp1);
tor_free(dir1); /* XXXX And more !*/
tor_free(dir2); /* And more !*/
@@ -422,10 +450,8 @@ test_dir_split_fps(void *testdata)
"0123456789ABCdef0123456789ABCdef0123456789ABCdef0123456789ABCdef"
#define B64_1 "/g2v+JEnOJvGdVhpEjEjRVEZPu4"
#define B64_2 "3q2+75mZmZERERmZmRERERHwC6Q"
-#define B64_3 "sz/wDbM/8A2zP/ANsz/wDbM/8A0"
#define B64_256_1 "8/Pz8/u7vz8/Pz+7vz8/Pz+7u/Pz8/P7u/Pz8/P7u78"
#define B64_256_2 "zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMw"
-#define B64_256_3 "ASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8"
/* no flags set */
dir_split_resource_into_fingerprints("A+C+B", sl, NULL, 0);
@@ -525,7 +551,7 @@ test_dir_split_fps(void *testdata)
}
static void
-test_dir_measured_bw(void)
+test_dir_measured_bw_kb(void)
{
measured_bw_line_t mbwl;
int i;
@@ -581,7 +607,7 @@ test_dir_measured_bw(void)
for (i = 0; strcmp(lines_pass[i], "end"); i++) {
//fprintf(stderr, "Testing: %s %d\n", lines_pass[i], TOR_ISSPACE('\n'));
test_assert(measured_bw_line_parse(&mbwl, lines_pass[i]) == 0);
- test_assert(mbwl.bw == 1024);
+ test_assert(mbwl.bw_kb == 1024);
test_assert(strcmp(mbwl.node_hex,
"557365204145532d32353620696e73746561642e") == 0);
}
@@ -590,6 +616,83 @@ test_dir_measured_bw(void)
return;
}
+#define MBWC_INIT_TIME 1000
+
+/** Do the measured bandwidth cache unit test */
+static void
+test_dir_measured_bw_kb_cache(void)
+{
+ /* Initial fake time_t for testing */
+ time_t curr = MBWC_INIT_TIME;
+ /* Some measured_bw_line_ts */
+ measured_bw_line_t mbwl[3];
+ /* For receiving output on cache queries */
+ long bw;
+ time_t as_of;
+
+ /* First, clear the cache and assert that it's empty */
+ dirserv_clear_measured_bw_cache();
+ test_eq(dirserv_get_measured_bw_cache_size(), 0);
+ /*
+ * Set up test mbwls; none of the dirserv_cache_*() functions care about
+ * the node_hex field.
+ */
+ memset(mbwl[0].node_id, 0x01, DIGEST_LEN);
+ mbwl[0].bw_kb = 20;
+ memset(mbwl[1].node_id, 0x02, DIGEST_LEN);
+ mbwl[1].bw_kb = 40;
+ memset(mbwl[2].node_id, 0x03, DIGEST_LEN);
+ mbwl[2].bw_kb = 80;
+ /* Try caching something */
+ dirserv_cache_measured_bw(&(mbwl[0]), curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 1);
+ /* Okay, let's see if we can retrieve it */
+ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, &as_of));
+ test_eq(bw, 20);
+ test_eq(as_of, MBWC_INIT_TIME);
+ /* Try retrieving it without some outputs */
+ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL, NULL));
+ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, NULL));
+ test_eq(bw, 20);
+ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL,&as_of));
+ test_eq(as_of, MBWC_INIT_TIME);
+ /* Now expire it */
+ curr += MAX_MEASUREMENT_AGE + 1;
+ dirserv_expire_measured_bw_cache(curr);
+ /* Check that the cache is empty */
+ test_eq(dirserv_get_measured_bw_cache_size(), 0);
+ /* Check that we can't retrieve it */
+ test_assert(!dirserv_query_measured_bw_cache_kb(mbwl[0].node_id, NULL,NULL));
+ /* Try caching a few things now */
+ dirserv_cache_measured_bw(&(mbwl[0]), curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 1);
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_cache_measured_bw(&(mbwl[1]), curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 2);
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_cache_measured_bw(&(mbwl[2]), curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 3);
+ curr += MAX_MEASUREMENT_AGE / 4 + 1;
+ /* Do an expire that's too soon to get any of them */
+ dirserv_expire_measured_bw_cache(curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 3);
+ /* Push the oldest one off the cliff */
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_expire_measured_bw_cache(curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 2);
+ /* And another... */
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_expire_measured_bw_cache(curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 1);
+ /* This should empty it out again */
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_expire_measured_bw_cache(curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 0);
+
+ done:
+ return;
+}
+
static void
test_dir_param_voting(void)
{
@@ -761,6 +864,17 @@ generate_ri_from_rs(const vote_routerstatus_t *vrs)
strlen(r->cache_info.signed_descriptor_body);
r->exit_policy = smartlist_new();
r->cache_info.published_on = ++published + time(NULL);
+ if (rs->has_bandwidth) {
+ /*
+ * Multiply by 1000 because the routerinfo_t and the routerstatus_t
+ * seem to use different units (*sigh*) and because we seem stuck on
+ * icky and perverse decimal kilobytes (*double sigh*) - see
+ * router_get_advertised_bandwidth_capped() of routerlist.c and
+ * routerstatus_format_entry() of dirserv.c.
+ */
+ r->bandwidthrate = rs->bandwidth_kb * 1000;
+ r->bandwidthcapacity = rs->bandwidth_kb * 1000;
+ }
return r;
}
@@ -781,15 +895,328 @@ get_detached_sigs(networkstatus_t *ns, networkstatus_t *ns2)
return r;
}
-/** Run unit tests for generating and parsing V3 consensus networkstatus
- * documents. */
+/**
+ * Generate a routerstatus for v3_networkstatus test
+ */
+static vote_routerstatus_t *
+gen_routerstatus_for_v3ns(int idx, time_t now)
+{
+ vote_routerstatus_t *vrs=NULL;
+ routerstatus_t *rs;
+ tor_addr_t addr_ipv6;
+
+ switch (idx) {
+ case 0:
+ /* Generate the first routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.2.14");
+ rs->published_on = now-1500;
+ strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
+ memset(rs->identity_digest, 3, DIGEST_LEN);
+ memset(rs->descriptor_digest, 78, DIGEST_LEN);
+ rs->addr = 0x99008801;
+ rs->or_port = 443;
+ rs->dir_port = 8000;
+ /* all flags but running cleared */
+ rs->is_flagged_running = 1;
+ break;
+ case 1:
+ /* Generate the second routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.2.0.5");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
+ memset(rs->identity_digest, 5, DIGEST_LEN);
+ memset(rs->descriptor_digest, 77, DIGEST_LEN);
+ rs->addr = 0x99009901;
+ rs->or_port = 443;
+ rs->dir_port = 0;
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ tor_addr_copy(&rs->ipv6_addr, &addr_ipv6);
+ rs->ipv6_orport = 4711;
+ rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running =
+ rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1;
+ break;
+ case 2:
+ /* Generate the third routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.0.3");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
+ memset(rs->identity_digest, 33, DIGEST_LEN);
+ memset(rs->descriptor_digest, 79, DIGEST_LEN);
+ rs->addr = 0xAA009901;
+ rs->or_port = 400;
+ rs->dir_port = 9999;
+ rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
+ rs->is_flagged_running = rs->is_valid = rs->is_v2_dir =
+ rs->is_possible_guard = 1;
+ break;
+ case 3:
+ /* Generate a fourth routerstatus that is not running. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.6.3");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
+ memset(rs->identity_digest, 34, DIGEST_LEN);
+ memset(rs->descriptor_digest, 47, DIGEST_LEN);
+ rs->addr = 0xC0000203;
+ rs->or_port = 500;
+ rs->dir_port = 1999;
+ /* Running flag (and others) cleared */
+ break;
+ case 4:
+ /* No more for this test; return NULL */
+ vrs = NULL;
+ break;
+ default:
+ /* Shouldn't happen */
+ test_assert(0);
+ }
+ if (vrs) {
+ vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
+ tor_asprintf(&vrs->microdesc->microdesc_hash_line,
+ "m 9,10,11,12,13,14,15,16,17 "
+ "sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n",
+ idx);
+ }
+
+ done:
+ return vrs;
+}
+
+/** Apply tweaks to the vote list for each voter */
+static int
+vote_tweaks_for_v3ns(networkstatus_t *v, int voter, time_t now)
+{
+ vote_routerstatus_t *vrs;
+ const char *msg = NULL;
+
+ test_assert(v);
+ (void)now;
+
+ if (voter == 1) {
+ measured_bw_line_t mbw;
+ memset(mbw.node_id, 33, sizeof(mbw.node_id));
+ mbw.bw_kb = 1024;
+ test_assert(measured_bw_line_apply(&mbw,
+ v->routerstatus_list) == 1);
+ } else if (voter == 2 || voter == 3) {
+ /* Monkey around with the list a bit */
+ vrs = smartlist_get(v->routerstatus_list, 2);
+ smartlist_del_keeporder(v->routerstatus_list, 2);
+ tor_free(vrs->version);
+ tor_free(vrs);
+ vrs = smartlist_get(v->routerstatus_list, 0);
+ vrs->status.is_fast = 1;
+
+ if (voter == 3) {
+ vrs = smartlist_get(v->routerstatus_list, 0);
+ smartlist_del_keeporder(v->routerstatus_list, 0);
+ tor_free(vrs->version);
+ tor_free(vrs);
+ vrs = smartlist_get(v->routerstatus_list, 0);
+ memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN);
+ test_assert(router_add_to_routerlist(
+ generate_ri_from_rs(vrs), &msg,0,0) >= 0);
+ }
+ }
+
+ done:
+ return 0;
+}
+
+/**
+ * Test a parsed vote_routerstatus_t for v3_networkstatus test
+ */
static void
-test_dir_v3_networkstatus(void)
+test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
+{
+ routerstatus_t *rs;
+ tor_addr_t addr_ipv6;
+
+ test_assert(vrs);
+ rs = &(vrs->status);
+ test_assert(rs);
+
+ /* Split out by digests to test */
+ if (tor_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3",
+ DIGEST_LEN) &&
+ (voter == 1)) {
+ /* Check the first routerstatus. */
+ test_streq(vrs->version, "0.1.2.14");
+ test_eq(rs->published_on, now-1500);
+ test_streq(rs->nickname, "router2");
+ test_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ test_eq(rs->addr, 0x99008801);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 8000);
+ test_eq(vrs->flags, U64_LITERAL(16)); // no flags except "running"
+ } else if (tor_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5",
+ DIGEST_LEN) &&
+ (voter == 1 || voter == 2)) {
+ test_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5",
+ DIGEST_LEN);
+
+ if (voter == 1) {
+ /* Check the second routerstatus. */
+ test_streq(vrs->version, "0.2.0.5");
+ test_eq(rs->published_on, now-1000);
+ test_streq(rs->nickname, "router1");
+ }
+ test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ test_eq(rs->addr, 0x99009901);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 0);
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ test_eq(rs->ipv6_orport, 4711);
+ if (voter == 1) {
+ test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority."
+ } else {
+ /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) */
+ test_eq(vrs->flags, U64_LITERAL(974));
+ }
+ } else if (tor_memeq(rs->identity_digest,
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33",
+ DIGEST_LEN) &&
+ (voter == 1 || voter == 2)) {
+ /* Check the measured bandwidth bits */
+ test_assert(vrs->has_measured_bw &&
+ vrs->measured_bw_kb == 1024);
+ } else {
+ /*
+ * Didn't expect this, but the old unit test only checked some of them,
+ * so don't assert.
+ */
+ /* test_assert(0); */
+ }
+
+ done:
+ return;
+}
+
+/**
+ * Test a consensus for v3_networkstatus_test
+ */
+static void
+test_consensus_for_v3ns(networkstatus_t *con, time_t now)
+{
+ (void)now;
+
+ test_assert(con);
+ test_assert(!con->cert);
+ test_eq(2, smartlist_len(con->routerstatus_list));
+ /* There should be two listed routers: one with identity 3, one with
+ * identity 5. */
+
+ done:
+ return;
+}
+
+/**
+ * Test a router list entry for v3_networkstatus test
+ */
+static void
+test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
+{
+ tor_addr_t addr_ipv6;
+
+ test_assert(rs);
+
+ /* There should be two listed routers: one with identity 3, one with
+ * identity 5. */
+ /* This one showed up in 2 digests. */
+ if (tor_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3",
+ DIGEST_LEN)) {
+ test_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ test_assert(!rs->is_authority);
+ test_assert(!rs->is_exit);
+ test_assert(!rs->is_fast);
+ test_assert(!rs->is_possible_guard);
+ test_assert(!rs->is_stable);
+ /* (If it wasn't running it wouldn't be here) */
+ test_assert(rs->is_flagged_running);
+ test_assert(!rs->is_v2_dir);
+ test_assert(!rs->is_valid);
+ test_assert(!rs->is_named);
+ /* XXXX check version */
+ } else if (tor_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5",
+ DIGEST_LEN)) {
+ /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */
+ test_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
+ DIGEST_LEN);
+ test_streq(rs->nickname, "router1");
+ test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ test_eq(rs->published_on, now-1000);
+ test_eq(rs->addr, 0x99009901);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 0);
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ test_eq(rs->ipv6_orport, 4711);
+ test_assert(!rs->is_authority);
+ test_assert(rs->is_exit);
+ test_assert(rs->is_fast);
+ test_assert(rs->is_possible_guard);
+ test_assert(rs->is_stable);
+ test_assert(rs->is_flagged_running);
+ test_assert(rs->is_v2_dir);
+ test_assert(rs->is_valid);
+ test_assert(!rs->is_named);
+ /* XXXX check version */
+ } else {
+ /* Weren't expecting this... */
+ test_assert(0);
+ }
+
+ done:
+ return;
+}
+
+/** Run a unit tests for generating and parsing networkstatuses, with
+ * the supply test fns. */
+static void
+test_a_networkstatus(
+ vote_routerstatus_t * (*vrs_gen)(int idx, time_t now),
+ int (*vote_tweaks)(networkstatus_t *v, int voter, time_t now),
+ void (*vrs_test)(vote_routerstatus_t *vrs, int voter, time_t now),
+ void (*consensus_test)(networkstatus_t *con, time_t now),
+ void (*rs_test)(routerstatus_t *rs, time_t now))
{
authority_cert_t *cert1=NULL, *cert2=NULL, *cert3=NULL;
crypto_pk_t *sign_skey_1=NULL, *sign_skey_2=NULL, *sign_skey_3=NULL;
crypto_pk_t *sign_skey_leg1=NULL;
const char *msg=NULL;
+ /*
+ * Sum the non-zero returns from vote_tweaks() we've seen; if vote_tweaks()
+ * returns non-zero, it changed net_params and we should skip the tests for
+ * that later as they will fail.
+ */
+ int params_tweaked = 0;
time_t now = time(NULL);
networkstatus_voter_info_t *voter;
@@ -798,6 +1225,7 @@ test_dir_v3_networkstatus(void)
*con_md=NULL;
vote_routerstatus_t *vrs;
routerstatus_t *rs;
+ int idx, n_rs, n_vrs;
char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL, *cp;
smartlist_t *votes = smartlist_new();
@@ -809,6 +1237,10 @@ test_dir_v3_networkstatus(void)
networkstatus_t *con2=NULL, *con_md2=NULL, *con3=NULL, *con_md3=NULL;
ns_detached_signatures_t *dsig1=NULL, *dsig2=NULL;
+ test_assert(vrs_gen);
+ test_assert(rs_test);
+ test_assert(vrs_test);
+
/* Parse certificates and keys. */
cert1 = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
test_assert(cert1);
@@ -866,69 +1298,18 @@ test_dir_v3_networkstatus(void)
smartlist_split_string(vote->net_params, "circuitwindow=101 foo=990",
NULL, 0, 0);
vote->routerstatus_list = smartlist_new();
- /* add the first routerstatus. */
- vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
- rs = &vrs->status;
- vrs->version = tor_strdup("0.1.2.14");
- rs->published_on = now-1500;
- strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
- memset(rs->identity_digest, 3, DIGEST_LEN);
- memset(rs->descriptor_digest, 78, DIGEST_LEN);
- rs->addr = 0x99008801;
- rs->or_port = 443;
- rs->dir_port = 8000;
- /* all flags but running cleared */
- rs->is_flagged_running = 1;
- smartlist_add(vote->routerstatus_list, vrs);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
-
- /* add the second routerstatus. */
- vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
- rs = &vrs->status;
- vrs->version = tor_strdup("0.2.0.5");
- rs->published_on = now-1000;
- strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
- memset(rs->identity_digest, 5, DIGEST_LEN);
- memset(rs->descriptor_digest, 77, DIGEST_LEN);
- rs->addr = 0x99009901;
- rs->or_port = 443;
- rs->dir_port = 0;
- rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running =
- rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1;
- smartlist_add(vote->routerstatus_list, vrs);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
-
- /* add the third routerstatus. */
- vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
- rs = &vrs->status;
- vrs->version = tor_strdup("0.1.0.3");
- rs->published_on = now-1000;
- strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
- memset(rs->identity_digest, 33, DIGEST_LEN);
- memset(rs->descriptor_digest, 79, DIGEST_LEN);
- rs->addr = 0xAA009901;
- rs->or_port = 400;
- rs->dir_port = 9999;
- rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
- rs->is_flagged_running = rs->is_valid = rs->is_v2_dir =
- rs->is_possible_guard = 1;
- smartlist_add(vote->routerstatus_list, vrs);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
-
- /* add a fourth routerstatus that is not running. */
- vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
- rs = &vrs->status;
- vrs->version = tor_strdup("0.1.6.3");
- rs->published_on = now-1000;
- strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
- memset(rs->identity_digest, 34, DIGEST_LEN);
- memset(rs->descriptor_digest, 47, DIGEST_LEN);
- rs->addr = 0xC0000203;
- rs->or_port = 500;
- rs->dir_port = 1999;
- /* Running flag (and others) cleared */
- smartlist_add(vote->routerstatus_list, vrs);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
+ /* add routerstatuses */
+ idx = 0;
+ do {
+ vrs = vrs_gen(idx, now);
+ if (vrs) {
+ smartlist_add(vote->routerstatus_list, vrs);
+ test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs),
+ &msg,0,0)>=0);
+ ++idx;
+ }
+ } while (vrs);
+ n_vrs = idx;
/* dump the vote and try to parse it. */
v1_text = format_networkstatus_vote(sign_skey_1, vote);
@@ -959,45 +1340,15 @@ test_dir_v3_networkstatus(void)
cp = smartlist_join_strings(v1->known_flags, ":", 0, NULL);
test_streq(cp, "Authority:Exit:Fast:Guard:Running:Stable:V2Dir:Valid");
tor_free(cp);
- test_eq(smartlist_len(v1->routerstatus_list), 4);
- /* Check the first routerstatus. */
- vrs = smartlist_get(v1->routerstatus_list, 0);
- rs = &vrs->status;
- test_streq(vrs->version, "0.1.2.14");
- test_eq(rs->published_on, now-1500);
- test_streq(rs->nickname, "router2");
- test_memeq(rs->identity_digest,
- "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
- DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- test_eq(rs->addr, 0x99008801);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 8000);
- test_eq(vrs->flags, U64_LITERAL(16)); // no flags except "running"
- /* Check the second routerstatus. */
- vrs = smartlist_get(v1->routerstatus_list, 1);
- rs = &vrs->status;
- test_streq(vrs->version, "0.2.0.5");
- test_eq(rs->published_on, now-1000);
- test_streq(rs->nickname, "router1");
- test_memeq(rs->identity_digest,
- "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
- DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- test_eq(rs->addr, 0x99009901);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 0);
- test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority."
+ test_eq(smartlist_len(v1->routerstatus_list), n_vrs);
- {
- measured_bw_line_t mbw;
- memset(mbw.node_id, 33, sizeof(mbw.node_id));
- mbw.bw = 1024;
- test_assert(measured_bw_line_apply(&mbw,
- v1->routerstatus_list) == 1);
- vrs = smartlist_get(v1->routerstatus_list, 2);
- test_assert(vrs->status.has_measured_bw &&
- vrs->status.measured_bw == 1024);
+ if (vote_tweaks) params_tweaked += vote_tweaks(v1, 1, now);
+
+ /* Check the routerstatuses. */
+ for (idx = 0; idx < n_vrs; ++idx) {
+ vrs = smartlist_get(v1->routerstatus_list, idx);
+ test_assert(vrs);
+ vrs_test(vrs, 1, now);
}
/* Generate second vote. It disagrees on some of the times,
@@ -1022,25 +1373,28 @@ test_dir_v3_networkstatus(void)
smartlist_add(vote->known_flags, tor_strdup("MadeOfCheese"));
smartlist_add(vote->known_flags, tor_strdup("MadeOfTin"));
smartlist_sort_strings(vote->known_flags);
- vrs = smartlist_get(vote->routerstatus_list, 2);
- smartlist_del_keeporder(vote->routerstatus_list, 2);
- tor_free(vrs->version);
- tor_free(vrs);
- vrs = smartlist_get(vote->routerstatus_list, 0);
- vrs->status.is_fast = 1;
- /* generate and parse. */
+
+ /* generate and parse v2. */
v2_text = format_networkstatus_vote(sign_skey_2, vote);
test_assert(v2_text);
v2 = networkstatus_parse_vote_from_string(v2_text, NULL, NS_TYPE_VOTE);
test_assert(v2);
+
+ if (vote_tweaks) params_tweaked += vote_tweaks(v2, 2, now);
+
/* Check that flags come out right.*/
cp = smartlist_join_strings(v2->known_flags, ":", 0, NULL);
test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:"
"Running:Stable:V2Dir:Valid");
tor_free(cp);
- vrs = smartlist_get(v2->routerstatus_list, 1);
- /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) */
- test_eq(vrs->flags, U64_LITERAL(974));
+
+ /* Check the routerstatuses. */
+ n_vrs = smartlist_len(v2->routerstatus_list);
+ for (idx = 0; idx < n_vrs; ++idx) {
+ vrs = smartlist_get(v2->routerstatus_list, idx);
+ test_assert(vrs);
+ vrs_test(vrs, 2, now);
+ }
/* Generate the third vote. */
vote->published = now;
@@ -1063,13 +1417,6 @@ test_dir_v3_networkstatus(void)
crypto_pk_get_digest(cert3->identity_key, voter->identity_digest);
/* This one has a legacy id. */
memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN);
- vrs = smartlist_get(vote->routerstatus_list, 0);
- smartlist_del_keeporder(vote->routerstatus_list, 0);
- tor_free(vrs->version);
- tor_free(vrs);
- vrs = smartlist_get(vote->routerstatus_list, 0);
- memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
v3_text = format_networkstatus_vote(sign_skey_3, vote);
test_assert(v3_text);
@@ -1077,6 +1424,8 @@ test_dir_v3_networkstatus(void)
v3 = networkstatus_parse_vote_from_string(v3_text, NULL, NS_TYPE_VOTE);
test_assert(v3);
+ if (vote_tweaks) params_tweaked += vote_tweaks(v3, 3, now);
+
/* Compute a consensus as voter 3. */
smartlist_add(votes, v3);
smartlist_add(votes, v1);
@@ -1119,9 +1468,12 @@ test_dir_v3_networkstatus(void)
test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:"
"Running:Stable:V2Dir:Valid");
tor_free(cp);
- cp = smartlist_join_strings(con->net_params, ":", 0, NULL);
- test_streq(cp, "circuitwindow=80:foo=660");
- tor_free(cp);
+ if (!params_tweaked) {
+ /* Skip this one if vote_tweaks() messed with the param lists */
+ cp = smartlist_join_strings(con->net_params, ":", 0, NULL);
+ test_streq(cp, "circuitwindow=80:foo=660");
+ tor_free(cp);
+ }
test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/
/* The voter id digests should be in this order. */
@@ -1136,49 +1488,15 @@ test_dir_v3_networkstatus(void)
test_same_voter(smartlist_get(con->voters, 3),
smartlist_get(v3->voters, 0));
- test_assert(!con->cert);
- test_eq(2, smartlist_len(con->routerstatus_list));
- /* There should be two listed routers: one with identity 3, one with
- * identity 5. */
- /* This one showed up in 2 digests. */
- rs = smartlist_get(con->routerstatus_list, 0);
- test_memeq(rs->identity_digest,
- "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
- DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- test_assert(!rs->is_authority);
- test_assert(!rs->is_exit);
- test_assert(!rs->is_fast);
- test_assert(!rs->is_possible_guard);
- test_assert(!rs->is_stable);
- /* (If it wasn't running it wouldn't be here) */
- test_assert(rs->is_flagged_running);
- test_assert(!rs->is_v2_dir);
- test_assert(!rs->is_valid);
- test_assert(!rs->is_named);
- /* XXXX check version */
-
- rs = smartlist_get(con->routerstatus_list, 1);
- /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */
- test_memeq(rs->identity_digest,
- "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
- DIGEST_LEN);
- test_streq(rs->nickname, "router1");
- test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- test_eq(rs->published_on, now-1000);
- test_eq(rs->addr, 0x99009901);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 0);
- test_assert(!rs->is_authority);
- test_assert(rs->is_exit);
- test_assert(rs->is_fast);
- test_assert(rs->is_possible_guard);
- test_assert(rs->is_stable);
- test_assert(rs->is_flagged_running);
- test_assert(rs->is_v2_dir);
- test_assert(rs->is_valid);
- test_assert(!rs->is_named);
- /* XXXX check version */
+ consensus_test(con, now);
+
+ /* Check the routerstatuses. */
+ n_rs = smartlist_len(con->routerstatus_list);
+ for (idx = 0; idx < n_rs; ++idx) {
+ rs = smartlist_get(con->routerstatus_list, idx);
+ test_assert(rs);
+ rs_test(rs, now);
+ }
/* Check signatures. the first voter is a pseudo-entry with a legacy key.
* The second one hasn't signed. The fourth one has signed: validate it. */
@@ -1381,21 +1699,693 @@ test_dir_v3_networkstatus(void)
ns_detached_signatures_free(dsig2);
}
+/** Run unit tests for generating and parsing V3 consensus networkstatus
+ * documents. */
+static void
+test_dir_v3_networkstatus(void)
+{
+ test_a_networkstatus(gen_routerstatus_for_v3ns,
+ vote_tweaks_for_v3ns,
+ test_vrs_for_v3ns,
+ test_consensus_for_v3ns,
+ test_routerstatus_for_v3ns);
+}
+
+static void
+test_dir_scale_bw(void *testdata)
+{
+ double v[8] = { 2.0/3,
+ 7.0,
+ 1.0,
+ 3.0,
+ 1.0/5,
+ 1.0/7,
+ 12.0,
+ 24.0 };
+ u64_dbl_t vals[8];
+ uint64_t total;
+ int i;
+
+ (void) testdata;
+
+ for (i=0; i<8; ++i)
+ vals[i].dbl = v[i];
+
+ scale_array_elements_to_u64(vals, 8, &total);
+
+ tt_int_op((int)total, ==, 48);
+ total = 0;
+ for (i=0; i<8; ++i) {
+ total += vals[i].u64;
+ }
+ tt_assert(total >= (U64_LITERAL(1)<<60));
+ tt_assert(total <= (U64_LITERAL(1)<<62));
+
+ for (i=0; i<8; ++i) {
+ double ratio = ((double)vals[i].u64) / vals[2].u64;
+ tt_double_op(fabs(ratio - v[i]), <, .00001);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_dir_random_weighted(void *testdata)
+{
+ int histogram[10];
+ uint64_t vals[10] = {3,1,2,4,6,0,7,5,8,9}, total=0;
+ u64_dbl_t inp[10];
+ int i, choice;
+ const int n = 50000;
+ double max_sq_error;
+ (void) testdata;
+
+ /* Try a ten-element array with values from 0 through 10. The values are
+ * in a scrambled order to make sure we don't depend on order. */
+ memset(histogram,0,sizeof(histogram));
+ for (i=0; i<10; ++i) {
+ inp[i].u64 = vals[i];
+ total += vals[i];
+ }
+ tt_int_op(total, ==, 45);
+ for (i=0; i<n; ++i) {
+ choice = choose_array_element_by_weight(inp, 10);
+ tt_int_op(choice, >=, 0);
+ tt_int_op(choice, <, 10);
+ histogram[choice]++;
+ }
+
+ /* Now see if we chose things about frequently enough. */
+ max_sq_error = 0;
+ for (i=0; i<10; ++i) {
+ int expected = (int)(n*vals[i]/total);
+ double frac_diff = 0, sq;
+ TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected));
+ if (expected)
+ frac_diff = (histogram[i] - expected) / ((double)expected);
+ else
+ tt_int_op(histogram[i], ==, 0);
+
+ sq = frac_diff * frac_diff;
+ if (sq > max_sq_error)
+ max_sq_error = sq;
+ }
+ /* It should almost always be much much less than this. If you want to
+ * figure out the odds, please feel free. */
+ tt_double_op(max_sq_error, <, .05);
+
+ /* Now try a singleton; do we choose it? */
+ for (i = 0; i < 100; ++i) {
+ choice = choose_array_element_by_weight(inp, 1);
+ tt_int_op(choice, ==, 0);
+ }
+
+ /* Now try an array of zeros. We should choose randomly. */
+ memset(histogram,0,sizeof(histogram));
+ for (i = 0; i < 5; ++i)
+ inp[i].u64 = 0;
+ for (i = 0; i < n; ++i) {
+ choice = choose_array_element_by_weight(inp, 5);
+ tt_int_op(choice, >=, 0);
+ tt_int_op(choice, <, 5);
+ histogram[choice]++;
+ }
+ /* Now see if we chose things about frequently enough. */
+ max_sq_error = 0;
+ for (i=0; i<5; ++i) {
+ int expected = n/5;
+ double frac_diff = 0, sq;
+ TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected));
+ frac_diff = (histogram[i] - expected) / ((double)expected);
+ sq = frac_diff * frac_diff;
+ if (sq > max_sq_error)
+ max_sq_error = sq;
+ }
+ /* It should almost always be much much less than this. If you want to
+ * figure out the odds, please feel free. */
+ tt_double_op(max_sq_error, <, .05);
+ done:
+ ;
+}
+
+/* Function pointers for test_dir_clip_unmeasured_bw_kb() */
+
+static uint32_t alternate_clip_bw = 0;
+
+/**
+ * Generate a routerstatus for clip_unmeasured_bw_kb test; based on the
+ * v3_networkstatus ones.
+ */
+static vote_routerstatus_t *
+gen_routerstatus_for_umbw(int idx, time_t now)
+{
+ vote_routerstatus_t *vrs = NULL;
+ routerstatus_t *rs;
+ tor_addr_t addr_ipv6;
+ uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ?
+ alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB;
+
+ switch (idx) {
+ case 0:
+ /* Generate the first routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.2.14");
+ rs->published_on = now-1500;
+ strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
+ memset(rs->identity_digest, 3, DIGEST_LEN);
+ memset(rs->descriptor_digest, 78, DIGEST_LEN);
+ rs->addr = 0x99008801;
+ rs->or_port = 443;
+ rs->dir_port = 8000;
+ /* all flags but running cleared */
+ rs->is_flagged_running = 1;
+ /*
+ * This one has measured bandwidth below the clip cutoff, and
+ * so shouldn't be clipped; we'll have to test that it isn't
+ * later.
+ */
+ vrs->has_measured_bw = 1;
+ rs->has_bandwidth = 1;
+ vrs->measured_bw_kb = rs->bandwidth_kb = max_unmeasured_bw_kb / 2;
+ break;
+ case 1:
+ /* Generate the second routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.2.0.5");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
+ memset(rs->identity_digest, 5, DIGEST_LEN);
+ memset(rs->descriptor_digest, 77, DIGEST_LEN);
+ rs->addr = 0x99009901;
+ rs->or_port = 443;
+ rs->dir_port = 0;
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ tor_addr_copy(&rs->ipv6_addr, &addr_ipv6);
+ rs->ipv6_orport = 4711;
+ rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running =
+ rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1;
+ /*
+ * This one has measured bandwidth above the clip cutoff, and
+ * so shouldn't be clipped; we'll have to test that it isn't
+ * later.
+ */
+ vrs->has_measured_bw = 1;
+ rs->has_bandwidth = 1;
+ vrs->measured_bw_kb = rs->bandwidth_kb = 2 * max_unmeasured_bw_kb;
+ break;
+ case 2:
+ /* Generate the third routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.0.3");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
+ memset(rs->identity_digest, 0x33, DIGEST_LEN);
+ memset(rs->descriptor_digest, 79, DIGEST_LEN);
+ rs->addr = 0xAA009901;
+ rs->or_port = 400;
+ rs->dir_port = 9999;
+ rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
+ rs->is_flagged_running = rs->is_valid = rs->is_v2_dir =
+ rs->is_possible_guard = 1;
+ /*
+ * This one has unmeasured bandwidth above the clip cutoff, and
+ * so should be clipped; we'll have to test that it isn't
+ * later.
+ */
+ vrs->has_measured_bw = 0;
+ rs->has_bandwidth = 1;
+ vrs->measured_bw_kb = 0;
+ rs->bandwidth_kb = 2 * max_unmeasured_bw_kb;
+ break;
+ case 3:
+ /* Generate a fourth routerstatus that is not running. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.6.3");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
+ memset(rs->identity_digest, 0x34, DIGEST_LEN);
+ memset(rs->descriptor_digest, 47, DIGEST_LEN);
+ rs->addr = 0xC0000203;
+ rs->or_port = 500;
+ rs->dir_port = 1999;
+ /* all flags but running cleared */
+ rs->is_flagged_running = 1;
+ /*
+ * This one has unmeasured bandwidth below the clip cutoff, and
+ * so shouldn't be clipped; we'll have to test that it isn't
+ * later.
+ */
+ vrs->has_measured_bw = 0;
+ rs->has_bandwidth = 1;
+ vrs->measured_bw_kb = 0;
+ rs->bandwidth_kb = max_unmeasured_bw_kb / 2;
+ break;
+ case 4:
+ /* No more for this test; return NULL */
+ vrs = NULL;
+ break;
+ default:
+ /* Shouldn't happen */
+ test_assert(0);
+ }
+ if (vrs) {
+ vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
+ tor_asprintf(&vrs->microdesc->microdesc_hash_line,
+ "m 9,10,11,12,13,14,15,16,17 "
+ "sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n",
+ idx);
+ }
+
+ done:
+ return vrs;
+}
+
+/** Apply tweaks to the vote list for each voter; for the umbw test this is
+ * just adding the right consensus methods to let clipping happen */
+static int
+vote_tweaks_for_umbw(networkstatus_t *v, int voter, time_t now)
+{
+ char *maxbw_param = NULL;
+ int rv = 0;
+
+ test_assert(v);
+ (void)voter;
+ (void)now;
+
+ test_assert(v->supported_methods);
+ smartlist_clear(v->supported_methods);
+ /* Method 17 is MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB */
+ smartlist_split_string(v->supported_methods,
+ "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17",
+ NULL, 0, -1);
+ /* If we're using a non-default clip bandwidth, add it to net_params */
+ if (alternate_clip_bw > 0) {
+ tor_asprintf(&maxbw_param, "maxunmeasuredbw=%u", alternate_clip_bw);
+ test_assert(maxbw_param);
+ if (maxbw_param) {
+ smartlist_add(v->net_params, maxbw_param);
+ rv = 1;
+ }
+ }
+
+ done:
+ return rv;
+}
+
+/**
+ * Test a parsed vote_routerstatus_t for umbw test.
+ */
+static void
+test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
+{
+ routerstatus_t *rs;
+ tor_addr_t addr_ipv6;
+ uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ?
+ alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB;
+
+ (void)voter;
+ test_assert(vrs);
+ rs = &(vrs->status);
+ test_assert(rs);
+
+ /* Split out by digests to test */
+ if (tor_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN)) {
+ /*
+ * Check the first routerstatus - measured bandwidth below the clip
+ * cutoff.
+ */
+ test_streq(vrs->version, "0.1.2.14");
+ test_eq(rs->published_on, now-1500);
+ test_streq(rs->nickname, "router2");
+ test_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ test_eq(rs->addr, 0x99008801);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 8000);
+ test_assert(rs->has_bandwidth);
+ test_assert(vrs->has_measured_bw);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
+ test_eq(vrs->measured_bw_kb, max_unmeasured_bw_kb / 2);
+ } else if (tor_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
+ DIGEST_LEN)) {
+
+ /*
+ * Check the second routerstatus - measured bandwidth above the clip
+ * cutoff.
+ */
+ test_streq(vrs->version, "0.2.0.5");
+ test_eq(rs->published_on, now-1000);
+ test_streq(rs->nickname, "router1");
+ test_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ test_eq(rs->addr, 0x99009901);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 0);
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ test_eq(rs->ipv6_orport, 4711);
+ test_assert(rs->has_bandwidth);
+ test_assert(vrs->has_measured_bw);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2);
+ test_eq(vrs->measured_bw_kb, max_unmeasured_bw_kb * 2);
+ } else if (tor_memeq(rs->identity_digest,
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33",
+ DIGEST_LEN)) {
+ /*
+ * Check the third routerstatus - unmeasured bandwidth above the clip
+ * cutoff; this one should be clipped later on in the consensus, but
+ * appears unclipped in the vote.
+ */
+ test_assert(rs->has_bandwidth);
+ test_assert(!(vrs->has_measured_bw));
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2);
+ test_eq(vrs->measured_bw_kb, 0);
+ } else if (tor_memeq(rs->identity_digest,
+ "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34"
+ "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34",
+ DIGEST_LEN)) {
+ /*
+ * Check the fourth routerstatus - unmeasured bandwidth below the clip
+ * cutoff; this one should not be clipped.
+ */
+ test_assert(rs->has_bandwidth);
+ test_assert(!(vrs->has_measured_bw));
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
+ test_eq(vrs->measured_bw_kb, 0);
+ } else {
+ test_assert(0);
+ }
+
+ done:
+ return;
+}
+
+/**
+ * Test a consensus for v3_networkstatus_test
+ */
+static void
+test_consensus_for_umbw(networkstatus_t *con, time_t now)
+{
+ (void)now;
+
+ test_assert(con);
+ test_assert(!con->cert);
+ // test_assert(con->consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB);
+ test_assert(con->consensus_method >= 16);
+ test_eq(4, smartlist_len(con->routerstatus_list));
+ /* There should be four listed routers; all voters saw the same in this */
+
+ done:
+ return;
+}
+
+/**
+ * Test a router list entry for umbw test
+ */
+static void
+test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
+{
+ tor_addr_t addr_ipv6;
+ uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ?
+ alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB;
+
+ test_assert(rs);
+
+ /* There should be four listed routers, as constructed above */
+ if (tor_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN)) {
+ test_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ test_assert(!rs->is_authority);
+ test_assert(!rs->is_exit);
+ test_assert(!rs->is_fast);
+ test_assert(!rs->is_possible_guard);
+ test_assert(!rs->is_stable);
+ /* (If it wasn't running it wouldn't be here) */
+ test_assert(rs->is_flagged_running);
+ test_assert(!rs->is_v2_dir);
+ test_assert(!rs->is_valid);
+ test_assert(!rs->is_named);
+ /* This one should have measured bandwidth below the clip cutoff */
+ test_assert(rs->has_bandwidth);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
+ test_assert(!(rs->bw_is_unmeasured));
+ } else if (tor_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
+ DIGEST_LEN)) {
+ /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */
+ test_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
+ DIGEST_LEN);
+ test_streq(rs->nickname, "router1");
+ test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ test_eq(rs->published_on, now-1000);
+ test_eq(rs->addr, 0x99009901);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 0);
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ test_eq(rs->ipv6_orport, 4711);
+ test_assert(!rs->is_authority);
+ test_assert(rs->is_exit);
+ test_assert(rs->is_fast);
+ test_assert(rs->is_possible_guard);
+ test_assert(rs->is_stable);
+ test_assert(rs->is_flagged_running);
+ test_assert(rs->is_v2_dir);
+ test_assert(rs->is_valid);
+ test_assert(!rs->is_named);
+ /* This one should have measured bandwidth above the clip cutoff */
+ test_assert(rs->has_bandwidth);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2);
+ test_assert(!(rs->bw_is_unmeasured));
+ } else if (tor_memeq(rs->identity_digest,
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33",
+ DIGEST_LEN)) {
+ /*
+ * This one should have unmeasured bandwidth above the clip cutoff,
+ * and so should be clipped
+ */
+ test_assert(rs->has_bandwidth);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb);
+ test_assert(rs->bw_is_unmeasured);
+ } else if (tor_memeq(rs->identity_digest,
+ "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34"
+ "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34",
+ DIGEST_LEN)) {
+ /*
+ * This one should have unmeasured bandwidth below the clip cutoff,
+ * and so should not be clipped
+ */
+ test_assert(rs->has_bandwidth);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
+ test_assert(rs->bw_is_unmeasured);
+ } else {
+ /* Weren't expecting this... */
+ test_assert(0);
+ }
+
+ done:
+ return;
+}
+
+/**
+ * Compute a consensus involving clipping unmeasured bandwidth with consensus
+ * method 17; this uses the same test_a_networkstatus() function that the
+ * v3_networkstatus test uses.
+ */
+
+static void
+test_dir_clip_unmeasured_bw_kb(void)
+{
+ /* Run the test with the default clip bandwidth */
+ alternate_clip_bw = 0;
+ test_a_networkstatus(gen_routerstatus_for_umbw,
+ vote_tweaks_for_umbw,
+ test_vrs_for_umbw,
+ test_consensus_for_umbw,
+ test_routerstatus_for_umbw);
+}
+
+/**
+ * This version of test_dir_clip_unmeasured_bw_kb() uses a non-default choice
+ * of clip bandwidth.
+ */
+
+static void
+test_dir_clip_unmeasured_bw_kb_alt(void)
+{
+ /*
+ * Try a different one; this value is chosen so that the below-the-cutoff
+ * unmeasured nodes the test uses, at alternate_clip_bw / 2, will be above
+ * DEFAULT_MAX_UNMEASURED_BW_KB and if the consensus incorrectly uses that
+ * cutoff it will fail the test.
+ */
+ alternate_clip_bw = 3 * DEFAULT_MAX_UNMEASURED_BW_KB;
+ test_a_networkstatus(gen_routerstatus_for_umbw,
+ vote_tweaks_for_umbw,
+ test_vrs_for_umbw,
+ test_consensus_for_umbw,
+ test_routerstatus_for_umbw);
+}
+
+extern time_t time_of_process_start; /* from main.c */
+
+static void
+test_dir_v2_dir(void *arg)
+{
+ /* Runs in a forked process: acts like a v2 directory just enough to make and
+ * sign a v2 networkstatus opinion */
+
+ cached_dir_t *v2 = NULL;
+ or_options_t *options = get_options_mutable();
+ crypto_pk_t *id_key = pk_generate(4);
+ (void) arg;
+
+ options->ORPort_set = 1; /* So we believe we're a server. */
+ options->DirPort_set = 1;
+ options->Address = tor_strdup("99.99.99.99");
+ options->Nickname = tor_strdup("TestV2Auth");
+ options->ContactInfo = tor_strdup("TestV2Auth <testv2auth@example.com>");
+ {
+ /* Give it a DirPort */
+ smartlist_t *ports = (smartlist_t *)get_configured_ports();
+ port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t));
+ port->type = CONN_TYPE_DIR_LISTENER;
+ port->port = 9999;
+ smartlist_add(ports, port);
+ }
+ set_server_identity_key(id_key);
+ set_client_identity_key(id_key);
+
+ /* Add a router. */
+ {
+ was_router_added_t wra;
+ const char *msg = NULL;
+ routerinfo_t *r1 = tor_malloc_zero(sizeof(routerinfo_t));
+ r1->address = tor_strdup("18.244.0.1");
+ r1->addr = 0xc0a80001u; /* 192.168.0.1 */
+ r1->cache_info.published_on = time(NULL)-60;
+ r1->or_port = 9000;
+ r1->dir_port = 9003;
+ tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::");
+ r1->ipv6_orport = 9999;
+ r1->onion_pkey = pk_generate(1);
+ r1->identity_pkey = pk_generate(2);
+ r1->bandwidthrate = 1000;
+ r1->bandwidthburst = 5000;
+ r1->bandwidthcapacity = 10000;
+ r1->exit_policy = NULL;
+ r1->nickname = tor_strdup("Magri");
+ r1->platform = tor_strdup("Tor 0.2.7.7-gamma");
+ r1->cache_info.routerlist_index = -1;
+ r1->cache_info.signed_descriptor_body =
+ router_dump_router_to_string(r1, r1->identity_pkey);
+ r1->cache_info.signed_descriptor_len =
+ strlen(r1->cache_info.signed_descriptor_body);
+ wra = router_add_to_routerlist(r1, &msg, 0, 0);
+ tt_int_op(wra, ==, ROUTER_ADDED_SUCCESSFULLY);
+ }
+
+ /* Prevent call of rep_hist_note_router_unreachable(). */
+ time_of_process_start = time(NULL);
+
+ /* Make a directory so there's somewhere to store the thing */
+#ifdef _WIN32
+ mkdir(get_fname("cached-status"));
+#else
+ mkdir(get_fname("cached-status"), 0700);
+#endif
+
+ v2 = generate_v2_networkstatus_opinion();
+ tt_assert(v2);
+
+ done:
+ crypto_pk_free(id_key);
+ cached_dir_decref(v2);
+}
+
+static void
+test_dir_fmt_control_ns(void *arg)
+{
+ char *s = NULL;
+ routerstatus_t rs;
+ (void)arg;
+
+ memset(&rs, 0, sizeof(rs));
+ rs.published_on = 1364925198;
+ strlcpy(rs.nickname, "TetsuoMilk", sizeof(rs.nickname));
+ memcpy(rs.identity_digest, "Stately, plump Buck ", DIGEST_LEN);
+ memcpy(rs.descriptor_digest, "Mulligan came up fro", DIGEST_LEN);
+ rs.addr = 0x20304050;
+ rs.or_port = 9001;
+ rs.dir_port = 9002;
+ rs.is_exit = 1;
+ rs.is_fast = 1;
+ rs.is_flagged_running = 1;
+ rs.has_bandwidth = 1;
+ rs.bandwidth_kb = 1000;
+
+ s = networkstatus_getinfo_helper_single(&rs);
+ tt_assert(s);
+ tt_str_op(s, ==,
+ "r TetsuoMilk U3RhdGVseSwgcGx1bXAgQnVjayA "
+ "TXVsbGlnYW4gY2FtZSB1cCBmcm8 2013-04-02 17:53:18 "
+ "32.48.64.80 9001 9002\n"
+ "s Exit Fast Running\n"
+ "w Bandwidth=1000\n");
+
+ done:
+ tor_free(s);
+}
+
#define DIR_LEGACY(name) \
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name }
-#define DIR(name) \
- { #name, test_dir_##name, 0, NULL, NULL }
+#define DIR(name,flags) \
+ { #name, test_dir_##name, (flags), NULL, NULL }
struct testcase_t dir_tests[] = {
DIR_LEGACY(nicknames),
DIR_LEGACY(formats),
DIR_LEGACY(versions),
DIR_LEGACY(fp_pairs),
- DIR(split_fps),
- DIR_LEGACY(measured_bw),
+ DIR(split_fps, 0),
+ DIR_LEGACY(measured_bw_kb),
+ DIR_LEGACY(measured_bw_kb_cache),
DIR_LEGACY(param_voting),
DIR_LEGACY(v3_networkstatus),
+ DIR(random_weighted, 0),
+ DIR(scale_bw, 0),
+ DIR_LEGACY(clip_unmeasured_bw_kb),
+ DIR_LEGACY(clip_unmeasured_bw_kb_alt),
+ DIR(v2_dir, TT_FORK),
+ DIR(fmt_control_ns, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
new file mode 100644
index 000000000..69c115222
--- /dev/null
+++ b/src/test/test_introduce.c
@@ -0,0 +1,528 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "crypto.h"
+#include "or.h"
+#include "test.h"
+
+#define RENDSERVICE_PRIVATE
+#include "rendservice.h"
+
+extern const char AUTHORITY_SIGNKEY_1[];
+
+static uint8_t v0_test_plaintext[] =
+ /* 20 bytes of rendezvous point nickname */
+ { 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v1_test_plaintext[] =
+ /* Version byte */
+ { 0x01,
+ /* 42 bytes of dummy rendezvous point hex digest */
+ 0x24, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30,
+ 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30,
+ 0x37, 0x30, 0x38, 0x30, 0x39, 0x30, 0x41, 0x30,
+ 0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, 0x30,
+ 0x46, 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x31,
+ 0x33, 0x00,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v2_test_plaintext[] =
+ /* Version byte */
+ { 0x02,
+ /* 4 bytes rendezvous point's IP address */
+ 0xc0, 0xa8, 0x00, 0x01,
+ /* 2 bytes rendezvous point's OR port */
+ 0x23, 0x5a,
+ /* 20 bytes dummy rendezvous point's identity digest */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 2 bytes length of onion key */
+ 0x00, 0x8c,
+ /* Onion key (140 bytes taken from live test) */
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
+ 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
+ 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
+ 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
+ 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
+ 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
+ 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
+ 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
+ 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
+ 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
+ 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
+ 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
+ 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
+ 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
+ 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
+ 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
+ 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v3_no_auth_test_plaintext[] =
+ /* Version byte */
+ { 0x03,
+ /* Auth type (0 for no auth len/auth data) */
+ 0x00,
+ /* Timestamp */
+ 0x50, 0x0b, 0xb5, 0xaa,
+ /* 4 bytes rendezvous point's IP address */
+ 0xc0, 0xa8, 0x00, 0x01,
+ /* 2 bytes rendezvous point's OR port */
+ 0x23, 0x5a,
+ /* 20 bytes dummy rendezvous point's identity digest */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 2 bytes length of onion key */
+ 0x00, 0x8c,
+ /* Onion key (140 bytes taken from live test) */
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
+ 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
+ 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
+ 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
+ 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
+ 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
+ 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
+ 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
+ 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
+ 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
+ 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
+ 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
+ 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
+ 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
+ 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
+ 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
+ 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v3_basic_auth_test_plaintext[] =
+ /* Version byte */
+ { 0x03,
+ /* Auth type (1 for REND_BASIC_AUTH) */
+ 0x01,
+ /* Auth len (must be 16 bytes for REND_BASIC_AUTH) */
+ 0x00, 0x10,
+ /* Auth data (a 16-byte dummy descriptor cookie) */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ /* Timestamp */
+ 0x50, 0x0b, 0xb5, 0xaa,
+ /* 4 bytes rendezvous point's IP address */
+ 0xc0, 0xa8, 0x00, 0x01,
+ /* 2 bytes rendezvous point's OR port */
+ 0x23, 0x5a,
+ /* 20 bytes dummy rendezvous point's identity digest */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 2 bytes length of onion key */
+ 0x00, 0x8c,
+ /* Onion key (140 bytes taken from live test) */
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
+ 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
+ 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
+ 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
+ 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
+ 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
+ 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
+ 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
+ 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
+ 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
+ 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
+ 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
+ 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
+ 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
+ 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
+ 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
+ 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static void do_decrypt_test(uint8_t *plaintext, size_t plaintext_len);
+static void do_early_parse_test(uint8_t *plaintext, size_t plaintext_len);
+static void do_late_parse_test(uint8_t *plaintext, size_t plaintext_len);
+static void do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase);
+static ssize_t make_intro_from_plaintext(
+ void *buf, size_t len, crypto_pk_t *key, void **cell_out);
+
+#define EARLY_PARSE_ONLY 1
+#define DECRYPT_ONLY 2
+#define ALL_PARSING 3
+
+static void
+do_early_parse_test(uint8_t *plaintext, size_t plaintext_len)
+{
+ do_parse_test(plaintext, plaintext_len, EARLY_PARSE_ONLY);
+}
+
+static void
+do_decrypt_test(uint8_t *plaintext, size_t plaintext_len)
+{
+ do_parse_test(plaintext, plaintext_len, DECRYPT_ONLY);
+}
+
+static void
+do_late_parse_test(uint8_t *plaintext, size_t plaintext_len)
+{
+ do_parse_test(plaintext, plaintext_len, ALL_PARSING);
+}
+
+/** Test utility function: checks that the <b>plaintext_len</b>-byte string at
+ * <b>plaintext</b> is at least superficially parseable.
+ */
+static void
+do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
+{
+ crypto_pk_t *k = NULL;
+ ssize_t r;
+ uint8_t *cell = NULL;
+ size_t cell_len;
+ rend_intro_cell_t *parsed_req = NULL;
+ char *err_msg = NULL;
+ char digest[DIGEST_LEN];
+
+ /* Get a key */
+ k = crypto_pk_new();
+ test_assert(k);
+ r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1);
+ test_assert(!r);
+
+ /* Get digest for future comparison */
+ r = crypto_pk_get_digest(k, digest);
+ test_assert(r >= 0);
+
+ /* Make a cell out of it */
+ r = make_intro_from_plaintext(
+ plaintext, plaintext_len,
+ k, (void **)(&cell));
+ test_assert(r > 0);
+ test_assert(cell);
+ cell_len = r;
+
+ /* Do early parsing */
+ parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg);
+ test_assert(parsed_req);
+ test_assert(!err_msg);
+ test_memeq(parsed_req->pk, digest, DIGEST_LEN);
+ test_assert(parsed_req->ciphertext);
+ test_assert(parsed_req->ciphertext_len > 0);
+
+ if (phase == EARLY_PARSE_ONLY)
+ goto done;
+
+ /* Do decryption */
+ r = rend_service_decrypt_intro(parsed_req, k, &err_msg);
+ test_assert(!r);
+ test_assert(!err_msg);
+ test_assert(parsed_req->plaintext);
+ test_assert(parsed_req->plaintext_len > 0);
+
+ if (phase == DECRYPT_ONLY)
+ goto done;
+
+ /* Do late parsing */
+ r = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
+ test_assert(!r);
+ test_assert(!err_msg);
+ test_assert(parsed_req->parsed);
+
+ done:
+ tor_free(cell);
+ crypto_pk_free(k);
+ rend_service_free_intro(parsed_req);
+ tor_free(err_msg);
+}
+
+/** Given the plaintext of the encrypted part of an INTRODUCE1/2 and a key,
+ * construct the encrypted cell for testing.
+ */
+
+static ssize_t
+make_intro_from_plaintext(
+ void *buf, size_t len, crypto_pk_t *key, void **cell_out)
+{
+ char *cell = NULL;
+ ssize_t cell_len = -1, r;
+ /* Assemble key digest and ciphertext, then construct the cell */
+ ssize_t ciphertext_size;
+
+ if (!(buf && key && len > 0 && cell_out)) goto done;
+
+ /*
+ * Figure out an upper bound on how big the ciphertext will be
+ * (see crypto_pk_public_hybrid_encrypt())
+ */
+ ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD;
+ ciphertext_size += crypto_pk_keysize(key);
+ ciphertext_size += CIPHER_KEY_LEN;
+ ciphertext_size += len;
+
+ /*
+ * Allocate space for the cell
+ */
+ cell = tor_malloc(DIGEST_LEN + ciphertext_size);
+
+ /* Compute key digest (will be first DIGEST_LEN octets of cell) */
+ r = crypto_pk_get_digest(key, cell);
+ test_assert(r >= 0);
+
+ /* Do encryption */
+ r = crypto_pk_public_hybrid_encrypt(
+ key, cell + DIGEST_LEN, ciphertext_size,
+ buf, len,
+ PK_PKCS1_OAEP_PADDING, 0);
+ test_assert(r >= 0);
+
+ /* Figure out cell length */
+ cell_len = DIGEST_LEN + r;
+
+ /* Output the cell */
+ *cell_out = cell;
+
+ done:
+ return cell_len;
+}
+
+/** Test v0 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v0(void)
+{
+ do_decrypt_test(v0_test_plaintext, sizeof(v0_test_plaintext));
+}
+
+/** Test v1 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v1(void)
+{
+ do_decrypt_test(v1_test_plaintext, sizeof(v1_test_plaintext));
+}
+
+/** Test v2 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v2(void)
+{
+ do_decrypt_test(v2_test_plaintext, sizeof(v2_test_plaintext));
+}
+
+/** Test v3 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v3(void)
+{
+ do_decrypt_test(
+ v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
+ do_decrypt_test(
+ v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
+}
+
+/** Test v0 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v0(void)
+{
+ do_early_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
+}
+
+/** Test v1 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v1(void)
+{
+ do_early_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
+}
+
+/** Test v2 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v2(void)
+{
+ do_early_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
+}
+
+/** Test v3 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v3(void)
+{
+ do_early_parse_test(
+ v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
+ do_early_parse_test(
+ v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
+}
+
+/** Test v0 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v0(void)
+{
+ do_late_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
+}
+
+/** Test v1 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v1(void)
+{
+ do_late_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
+}
+
+/** Test v2 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v2(void)
+{
+ do_late_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
+}
+
+/** Test v3 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v3(void)
+{
+ do_late_parse_test(
+ v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
+ do_late_parse_test(
+ v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
+}
+
+#define INTRODUCE_LEGACY(name) \
+ { #name, legacy_test_helper, 0, &legacy_setup, test_introduce_ ## name }
+
+struct testcase_t introduce_tests[] = {
+ INTRODUCE_LEGACY(early_parse_v0),
+ INTRODUCE_LEGACY(early_parse_v1),
+ INTRODUCE_LEGACY(early_parse_v2),
+ INTRODUCE_LEGACY(early_parse_v3),
+ INTRODUCE_LEGACY(decrypt_v0),
+ INTRODUCE_LEGACY(decrypt_v1),
+ INTRODUCE_LEGACY(decrypt_v2),
+ INTRODUCE_LEGACY(decrypt_v3),
+ INTRODUCE_LEGACY(late_parse_v0),
+ INTRODUCE_LEGACY(late_parse_v1),
+ INTRODUCE_LEGACY(late_parse_v2),
+ INTRODUCE_LEGACY(late_parse_v3),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 89c578f4a..53a03a48a 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Tor Project, Inc. */
+/* Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -208,11 +208,25 @@ test_md_cache(void *data)
md3 = NULL; /* it's history now! */
/* rebuild again, make sure it stays gone. */
- microdesc_cache_rebuild(mc, 1);
+ tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));
+ /* Re-add md3, and make sure we can rebuild the cache. */
+ added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
+ SAVED_NOWHERE, 0, time3, NULL);
+ tt_int_op(1, ==, smartlist_len(added));
+ md3 = smartlist_get(added, 0);
+ smartlist_free(added);
+ added = NULL;
+ tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE);
+ tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE);
+ tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL);
+
+ tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
+ tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE);
+
done:
if (options)
tor_free(options->DataDirectory);
@@ -226,8 +240,53 @@ test_md_cache(void *data)
tor_free(fn);
}
+static const char truncated_md[] =
+ "@last-listed 2013-08-08 19:02:59\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM91vLFNaM+gGhnRIdz2Cm/Kl7Xz0cOobIdVzhS3cKUJfk867hCuTipS\n"
+ "NveLBzNopvgXKruAAzEj3cACxk6Q8lv5UWOGCD1UolkgsWSE62RBjap44g+oc9J1\n"
+ "RI9968xOTZw0VaBQg9giEILNXl0djoikQ+5tQRUvLDDa67gpa5Q1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "family @\n";
+
+static void
+test_md_cache_broken(void *data)
+{
+ or_options_t *options;
+ char *fn=NULL;
+ microdesc_cache_t *mc = NULL;
+
+ (void)data;
+
+ options = get_options_mutable();
+ tt_assert(options);
+ options->DataDirectory = tor_strdup(get_fname("md_datadir_test2"));
+
+#ifdef _WIN32
+ tt_int_op(0, ==, mkdir(options->DataDirectory));
+#else
+ tt_int_op(0, ==, mkdir(options->DataDirectory, 0700));
+#endif
+
+ tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
+ options->DataDirectory);
+
+ write_str_to_file(fn, truncated_md, 1);
+
+ mc = get_microdesc_cache();
+ tt_assert(mc);
+
+ done:
+ if (options)
+ tor_free(options->DataDirectory);
+ tor_free(fn);
+ microdesc_free_all();
+}
+
struct testcase_t microdesc_tests[] = {
{ "cache", test_md_cache, TT_FORK, NULL, NULL },
+ { "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c
new file mode 100644
index 000000000..f2b7a72ad
--- /dev/null
+++ b/src/test/test_ntor_cl.c
@@ -0,0 +1,170 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ONION_NTOR_PRIVATE
+#include "or.h"
+#include "util.h"
+#include "compat.h"
+#include "crypto.h"
+#include "crypto_curve25519.h"
+#include "onion_ntor.h"
+
+#ifndef CURVE25519_ENABLED
+#error "This isn't going to work without curve25519."
+#endif
+
+#define N_ARGS(n) STMT_BEGIN { \
+ if (argc < (n)) { \
+ fprintf(stderr, "%s needs %d arguments.\n",argv[1],n); \
+ return 1; \
+ } \
+ } STMT_END
+#define BASE16(idx, var, n) STMT_BEGIN { \
+ const char *s = argv[(idx)]; \
+ if (base16_decode((char*)var, n, s, strlen(s)) < 0 ) { \
+ fprintf(stderr, "couldn't decode argument %d (%s)\n",idx,s); \
+ return 1; \
+ } \
+ } STMT_END
+#define INT(idx, var) STMT_BEGIN { \
+ var = atoi(argv[(idx)]); \
+ if (var <= 0) { \
+ fprintf(stderr, "bad integer argument %d (%s)\n",idx,argv[(idx)]); \
+ } \
+ } STMT_END
+
+static int
+client1(int argc, char **argv)
+{
+ /* client1 nodeID B -> msg state */
+ curve25519_public_key_t B;
+ uint8_t node_id[DIGEST_LEN];
+ ntor_handshake_state_t *state = NULL;
+ uint8_t msg[NTOR_ONIONSKIN_LEN];
+
+ char buf[1024];
+
+ N_ARGS(4);
+ BASE16(2, node_id, DIGEST_LEN);
+ BASE16(3, B.public_key, CURVE25519_PUBKEY_LEN);
+
+ if (onion_skin_ntor_create(node_id, &B, &state, msg)<0) {
+ fprintf(stderr, "handshake failed");
+ return 2;
+ }
+
+ base16_encode(buf, sizeof(buf), (const char*)msg, sizeof(msg));
+ printf("%s\n", buf);
+ base16_encode(buf, sizeof(buf), (void*)state, sizeof(*state));
+ printf("%s\n", buf);
+
+ ntor_handshake_state_free(state);
+ return 0;
+}
+
+static int
+server1(int argc, char **argv)
+{
+ uint8_t msg_in[NTOR_ONIONSKIN_LEN];
+ curve25519_keypair_t kp;
+ di_digest256_map_t *keymap=NULL;
+ uint8_t node_id[DIGEST_LEN];
+ int keybytes;
+
+ uint8_t msg_out[NTOR_REPLY_LEN];
+ uint8_t *keys = NULL;
+ char *hexkeys = NULL;
+ int result = 0;
+
+ char buf[256];
+
+ /* server1: b nodeID msg N -> msg keys */
+ N_ARGS(6);
+ BASE16(2, kp.seckey.secret_key, CURVE25519_SECKEY_LEN);
+ BASE16(3, node_id, DIGEST_LEN);
+ BASE16(4, msg_in, NTOR_ONIONSKIN_LEN);
+ INT(5, keybytes);
+
+ curve25519_public_key_generate(&kp.pubkey, &kp.seckey);
+ dimap_add_entry(&keymap, kp.pubkey.public_key, &kp);
+
+ keys = tor_malloc(keybytes);
+ hexkeys = tor_malloc(keybytes*2+1);
+ if (onion_skin_ntor_server_handshake(
+ msg_in, keymap, NULL, node_id, msg_out, keys,
+ (size_t)keybytes)<0) {
+ fprintf(stderr, "handshake failed");
+ result = 2;
+ goto done;
+ }
+
+ base16_encode(buf, sizeof(buf), (const char*)msg_out, sizeof(msg_out));
+ printf("%s\n", buf);
+ base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes);
+ printf("%s\n", hexkeys);
+
+ done:
+ tor_free(keys);
+ tor_free(hexkeys);
+ return result;
+}
+
+static int
+client2(int argc, char **argv)
+{
+ struct ntor_handshake_state_t state;
+ uint8_t msg[NTOR_REPLY_LEN];
+ int keybytes;
+ uint8_t *keys;
+ char *hexkeys;
+ int result = 0;
+
+ N_ARGS(5);
+ BASE16(2, (&state), sizeof(state));
+ BASE16(3, msg, sizeof(msg));
+ INT(4, keybytes);
+
+ keys = tor_malloc(keybytes);
+ hexkeys = tor_malloc(keybytes*2+1);
+ if (onion_skin_ntor_client_handshake(&state, msg, keys, keybytes)<0) {
+ fprintf(stderr, "handshake failed");
+ result = 2;
+ goto done;
+ }
+
+ base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes);
+ printf("%s\n", hexkeys);
+
+ done:
+ tor_free(keys);
+ tor_free(hexkeys);
+ return result;
+}
+
+int
+main(int argc, char **argv)
+{
+ /*
+ client1: nodeID B -> msg state
+ server1: b nodeID msg N -> msg keys
+ client2: state msg N -> keys
+ */
+ if (argc < 2) {
+ fprintf(stderr, "I need arguments. Read source for more info.\n");
+ return 1;
+ } else if (!strcmp(argv[1], "client1")) {
+ return client1(argc, argv);
+ } else if (!strcmp(argv[1], "server1")) {
+ return server1(argc, argv);
+ } else if (!strcmp(argv[1], "client2")) {
+ return client2(argc, argv);
+ } else {
+ fprintf(stderr, "What's a %s?\n", argv[1]);
+ return 1;
+ }
+}
+
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index d3dadb9bf..80707f437 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
new file mode 100644
index 000000000..de841ad59
--- /dev/null
+++ b/src/test/test_replay.c
@@ -0,0 +1,178 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define REPLAYCACHE_PRIVATE
+
+#include "orconfig.h"
+#include "or.h"
+#include "replaycache.h"
+#include "test.h"
+
+static const char *test_buffer =
+ "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed do eiusmod"
+ " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim"
+ " veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea"
+ " commodo consequat. Duis aute irure dolor in reprehenderit in voluptate"
+ " velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint"
+ " occaecat cupidatat non proident, sunt in culpa qui officia deserunt"
+ " mollit anim id est laborum.";
+
+static void
+test_replaycache_alloc(void)
+{
+ replaycache_t *r = NULL;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_miss(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_hit(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_age(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ result =
+ replaycache_add_and_test_internal(3000, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_elapsed(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+ time_t elapsed;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), &elapsed);
+ test_eq(result, 1);
+ test_eq(elapsed, 100);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_noexpire(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(0, 0);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ result =
+ replaycache_add_and_test_internal(3000, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+#define REPLAYCACHE_LEGACY(name) \
+ { #name, legacy_test_helper, 0, &legacy_setup, test_replaycache_ ## name }
+
+struct testcase_t replaycache_tests[] = {
+ REPLAYCACHE_LEGACY(alloc),
+ REPLAYCACHE_LEGACY(miss),
+ REPLAYCACHE_LEGACY(hit),
+ REPLAYCACHE_LEGACY(age),
+ REPLAYCACHE_LEGACY(elapsed),
+ REPLAYCACHE_LEGACY(noexpire),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 6c72247e9..65d9d2f87 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -17,6 +17,7 @@
#ifdef _WIN32
#include <tchar.h>
#endif
+#include <math.h>
/* XXXX this is a minimal wrapper to make the unit tests compile with the
* changed tor_timegm interface. */
@@ -32,6 +33,75 @@ tor_timegm_wrapper(const struct tm *tm)
#define tor_timegm tor_timegm_wrapper
static void
+test_util_read_until_eof_impl(const char *fname, size_t file_len,
+ size_t read_limit)
+{
+ char *fifo_name = NULL;
+ char *test_str = NULL;
+ char *str = NULL;
+ size_t sz = 9999999;
+ int fd = -1;
+ int r;
+
+ fifo_name = tor_strdup(get_fname(fname));
+ test_str = tor_malloc(file_len);
+ crypto_rand(test_str, file_len);
+
+ r = write_bytes_to_file(fifo_name, test_str, file_len, 1);
+ tt_int_op(r, ==, 0);
+
+ fd = open(fifo_name, O_RDONLY|O_BINARY);
+ tt_int_op(fd, >=, 0);
+ str = read_file_to_str_until_eof(fd, read_limit, &sz);
+ tt_assert(str != NULL);
+
+ if (read_limit < file_len)
+ tt_int_op(sz, ==, read_limit);
+ else
+ tt_int_op(sz, ==, file_len);
+
+ test_mem_op(test_str, ==, str, sz);
+ test_assert(str[sz] == '\0');
+
+ done:
+ unlink(fifo_name);
+ tor_free(fifo_name);
+ tor_free(test_str);
+ tor_free(str);
+ if (fd >= 0)
+ close(fd);
+}
+
+static void
+test_util_read_file_eof_tiny_limit(void *arg)
+{
+ (void)arg;
+ // purposely set limit shorter than what we wrote to the FIFO to
+ // test the maximum, and that it puts the NUL in the right spot
+
+ test_util_read_until_eof_impl("tor_test_fifo_tiny", 5, 4);
+}
+
+static void
+test_util_read_file_eof_two_loops(void *arg)
+{
+ (void)arg;
+ // write more than 1024 bytes to the FIFO to test two passes through
+ // the loop in the method; if the re-alloc size is changed this
+ // should be updated as well.
+
+ test_util_read_until_eof_impl("tor_test_fifo_2k", 2048, 10000);
+}
+
+static void
+test_util_read_file_eof_zero_bytes(void *arg)
+{
+ (void)arg;
+ // zero-byte fifo
+ test_util_read_until_eof_impl("tor_test_fifo_empty", 0, 10000);
+}
+
+static void
test_util_time(void)
{
struct timeval start, end;
@@ -152,6 +222,7 @@ test_util_time(void)
test_eq(-1, parse_iso_time("2011-03-30 23:59:62 GMT", &t_res));
test_eq(-1, parse_iso_time("1969-03-30 23:59:59 GMT", &t_res));
test_eq(-1, parse_iso_time("2011-00-30 23:59:59 GMT", &t_res));
+ test_eq(-1, parse_iso_time("2147483647-08-29 14:00:00", &t_res));
test_eq(-1, parse_iso_time("2011-03-30 23:59", &t_res));
/* Test tor_gettimeofday */
@@ -731,7 +802,7 @@ test_util_strmisc(void)
{
char buf[1024];
int i;
- char *cp;
+ char *cp, *cp_tmp = NULL;
/* Test strl operations */
test_eq(5, strlcpy(buf, "Hello", 0));
@@ -934,20 +1005,20 @@ test_util_strmisc(void)
/* Test strndup and memdup */
{
const char *s = "abcdefghijklmnopqrstuvwxyz";
- cp = tor_strndup(s, 30);
- test_streq(cp, s); /* same string, */
- test_neq(cp, s); /* but different pointers. */
- tor_free(cp);
+ cp_tmp = tor_strndup(s, 30);
+ test_streq(cp_tmp, s); /* same string, */
+ test_neq_ptr(cp_tmp, s); /* but different pointers. */
+ tor_free(cp_tmp);
- cp = tor_strndup(s, 5);
- test_streq(cp, "abcde");
- tor_free(cp);
+ cp_tmp = tor_strndup(s, 5);
+ test_streq(cp_tmp, "abcde");
+ tor_free(cp_tmp);
s = "a\0b\0c\0d\0e\0";
- cp = tor_memdup(s,10);
- test_memeq(cp, s, 10); /* same ram, */
- test_neq(cp, s); /* but different pointers. */
- tor_free(cp);
+ cp_tmp = tor_memdup(s,10);
+ test_memeq(cp_tmp, s, 10); /* same ram, */
+ test_neq_ptr(cp_tmp, s); /* but different pointers. */
+ tor_free(cp_tmp);
}
/* Test str-foo functions */
@@ -983,79 +1054,6 @@ test_util_strmisc(void)
test_assert(!tor_memstr(haystack, 7, "ababcade"));
}
- /* Test wrap_string */
- {
- smartlist_t *sl = smartlist_new();
- wrap_string(sl,
- "This is a test of string wrapping functionality: woot. "
- "a functionality? w00t w00t...!",
- 10, "", "");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp,
- "This is a\ntest of\nstring\nwrapping\nfunctional\nity: woot.\n"
- "a\nfunctional\nity? w00t\nw00t...!\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "This is a test of string wrapping functionality: woot.",
- 16, "### ", "# ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp,
- "### This is a\n# test of string\n# wrapping\n# functionality:\n"
- "# woot.\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "A test of string wrapping...", 6, "### ", "# ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp,
- "### A\n# test\n# of\n# stri\n# ng\n# wrap\n# ping\n# ...\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "Wrapping test", 6, "#### ", "# ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "#### W\n# rapp\n# ing\n# test\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "Small test", 6, "### ", "#### ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "### Sm\n#### a\n#### l\n#### l\n#### t\n#### e"
- "\n#### s\n#### t\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "First null", 6, NULL, "> ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "First\n> null\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "Second null", 6, "> ", NULL);
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "> Seco\nnd\nnull\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "Both null", 6, NULL, NULL);
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "Both\nnull\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_free(sl);
-
- /* Can't test prefixes that have the same length as the line width, because
- the function has an assert */
- }
-
/* Test hex_str */
{
char binary_data[68];
@@ -1099,7 +1097,7 @@ test_util_strmisc(void)
tt_int_op(strcmp_len("blah", "", 0), ==, 0);
done:
- ;
+ tor_free(cp_tmp);
}
static void
@@ -1109,6 +1107,7 @@ test_util_pow2(void)
test_eq(tor_log2(64), 6);
test_eq(tor_log2(65), 6);
test_eq(tor_log2(63), 5);
+ test_eq(tor_log2(0), 0); /* incorrect mathematically, but as specified */
test_eq(tor_log2(1), 0);
test_eq(tor_log2(2), 1);
test_eq(tor_log2(3), 1);
@@ -1123,26 +1122,35 @@ test_util_pow2(void)
test_eq(round_to_power_of_2(130), 128);
test_eq(round_to_power_of_2(U64_LITERAL(40000000000000000)),
U64_LITERAL(1)<<55);
- test_eq(round_to_power_of_2(0), 2);
+ test_eq(round_to_power_of_2(U64_LITERAL(0xffffffffffffffff)),
+ U64_LITERAL(1)<<63);
+ test_eq(round_to_power_of_2(0), 1);
+ test_eq(round_to_power_of_2(1), 1);
+ test_eq(round_to_power_of_2(2), 2);
+ test_eq(round_to_power_of_2(3), 2);
+ test_eq(round_to_power_of_2(4), 4);
+ test_eq(round_to_power_of_2(5), 4);
+ test_eq(round_to_power_of_2(6), 4);
+ test_eq(round_to_power_of_2(7), 8);
done:
;
}
/** mutex for thread test to stop the threads hitting data at the same time. */
-static tor_mutex_t *_thread_test_mutex = NULL;
+static tor_mutex_t *thread_test_mutex_ = NULL;
/** mutexes for the thread test to make sure that the threads have to
* interleave somewhat. */
-static tor_mutex_t *_thread_test_start1 = NULL,
- *_thread_test_start2 = NULL;
+static tor_mutex_t *thread_test_start1_ = NULL,
+ *thread_test_start2_ = NULL;
/** Shared strmap for the thread test. */
-static strmap_t *_thread_test_strmap = NULL;
+static strmap_t *thread_test_strmap_ = NULL;
/** The name of thread1 for the thread test */
-static char *_thread1_name = NULL;
+static char *thread1_name_ = NULL;
/** The name of thread2 for the thread test */
-static char *_thread2_name = NULL;
+static char *thread2_name_ = NULL;
-static void _thread_test_func(void* _s) ATTR_NORETURN;
+static void thread_test_func_(void* _s) ATTR_NORETURN;
/** How many iterations have the threads in the unit test run? */
static int t1_count = 0, t2_count = 0;
@@ -1150,9 +1158,9 @@ static int t1_count = 0, t2_count = 0;
/** Helper function for threading unit tests: This function runs in a
* subthread. It grabs its own mutex (start1 or start2) to make sure that it
* should start, then it repeatedly alters _test_thread_strmap protected by
- * _thread_test_mutex. */
+ * thread_test_mutex_. */
static void
-_thread_test_func(void* _s)
+thread_test_func_(void* _s)
{
char *s = _s;
int i, *count;
@@ -1160,12 +1168,12 @@ _thread_test_func(void* _s)
char buf[64];
char **cp;
if (!strcmp(s, "thread 1")) {
- m = _thread_test_start1;
- cp = &_thread1_name;
+ m = thread_test_start1_;
+ cp = &thread1_name_;
count = &t1_count;
} else {
- m = _thread_test_start2;
- cp = &_thread2_name;
+ m = thread_test_start2_;
+ cp = &thread2_name_;
count = &t2_count;
}
@@ -1175,14 +1183,14 @@ _thread_test_func(void* _s)
tor_mutex_acquire(m);
for (i=0; i<10000; ++i) {
- tor_mutex_acquire(_thread_test_mutex);
- strmap_set(_thread_test_strmap, "last to run", *cp);
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_set(thread_test_strmap_, "last to run", *cp);
++*count;
- tor_mutex_release(_thread_test_mutex);
+ tor_mutex_release(thread_test_mutex_);
}
- tor_mutex_acquire(_thread_test_mutex);
- strmap_set(_thread_test_strmap, s, *cp);
- tor_mutex_release(_thread_test_mutex);
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_set(thread_test_strmap_, s, *cp);
+ tor_mutex_release(thread_test_mutex_);
tor_mutex_release(m);
@@ -1207,67 +1215,67 @@ test_util_threads(void)
if (1)
return;
#endif
- _thread_test_mutex = tor_mutex_new();
- _thread_test_start1 = tor_mutex_new();
- _thread_test_start2 = tor_mutex_new();
- _thread_test_strmap = strmap_new();
+ thread_test_mutex_ = tor_mutex_new();
+ thread_test_start1_ = tor_mutex_new();
+ thread_test_start2_ = tor_mutex_new();
+ thread_test_strmap_ = strmap_new();
s1 = tor_strdup("thread 1");
s2 = tor_strdup("thread 2");
- tor_mutex_acquire(_thread_test_start1);
- tor_mutex_acquire(_thread_test_start2);
- spawn_func(_thread_test_func, s1);
- spawn_func(_thread_test_func, s2);
- tor_mutex_release(_thread_test_start2);
- tor_mutex_release(_thread_test_start1);
+ tor_mutex_acquire(thread_test_start1_);
+ tor_mutex_acquire(thread_test_start2_);
+ spawn_func(thread_test_func_, s1);
+ spawn_func(thread_test_func_, s2);
+ tor_mutex_release(thread_test_start2_);
+ tor_mutex_release(thread_test_start1_);
started = time(NULL);
while (!done) {
- tor_mutex_acquire(_thread_test_mutex);
- strmap_assert_ok(_thread_test_strmap);
- if (strmap_get(_thread_test_strmap, "thread 1") &&
- strmap_get(_thread_test_strmap, "thread 2")) {
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_assert_ok(thread_test_strmap_);
+ if (strmap_get(thread_test_strmap_, "thread 1") &&
+ strmap_get(thread_test_strmap_, "thread 2")) {
done = 1;
} else if (time(NULL) > started + 150) {
timedout = done = 1;
}
- tor_mutex_release(_thread_test_mutex);
+ tor_mutex_release(thread_test_mutex_);
#ifndef _WIN32
/* Prevent the main thread from starving the worker threads. */
select(0, NULL, NULL, NULL, &tv);
#endif
}
- tor_mutex_acquire(_thread_test_start1);
- tor_mutex_release(_thread_test_start1);
- tor_mutex_acquire(_thread_test_start2);
- tor_mutex_release(_thread_test_start2);
+ tor_mutex_acquire(thread_test_start1_);
+ tor_mutex_release(thread_test_start1_);
+ tor_mutex_acquire(thread_test_start2_);
+ tor_mutex_release(thread_test_start2_);
- tor_mutex_free(_thread_test_mutex);
+ tor_mutex_free(thread_test_mutex_);
if (timedout) {
printf("\nTimed out: %d %d", t1_count, t2_count);
- test_assert(strmap_get(_thread_test_strmap, "thread 1"));
- test_assert(strmap_get(_thread_test_strmap, "thread 2"));
+ test_assert(strmap_get(thread_test_strmap_, "thread 1"));
+ test_assert(strmap_get(thread_test_strmap_, "thread 2"));
test_assert(!timedout);
}
/* different thread IDs. */
- test_assert(strcmp(strmap_get(_thread_test_strmap, "thread 1"),
- strmap_get(_thread_test_strmap, "thread 2")));
- test_assert(!strcmp(strmap_get(_thread_test_strmap, "thread 1"),
- strmap_get(_thread_test_strmap, "last to run")) ||
- !strcmp(strmap_get(_thread_test_strmap, "thread 2"),
- strmap_get(_thread_test_strmap, "last to run")));
+ test_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"),
+ strmap_get(thread_test_strmap_, "thread 2")));
+ test_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"),
+ strmap_get(thread_test_strmap_, "last to run")) ||
+ !strcmp(strmap_get(thread_test_strmap_, "thread 2"),
+ strmap_get(thread_test_strmap_, "last to run")));
done:
tor_free(s1);
tor_free(s2);
- tor_free(_thread1_name);
- tor_free(_thread2_name);
- if (_thread_test_strmap)
- strmap_free(_thread_test_strmap, NULL);
- if (_thread_test_start1)
- tor_mutex_free(_thread_test_start1);
- if (_thread_test_start2)
- tor_mutex_free(_thread_test_start2);
+ tor_free(thread1_name_);
+ tor_free(thread2_name_);
+ if (thread_test_strmap_)
+ strmap_free(thread_test_strmap_, NULL);
+ if (thread_test_start1_)
+ tor_mutex_free(thread_test_start1_);
+ if (thread_test_start2_)
+ tor_mutex_free(thread_test_start2_);
}
/** Run unit tests for compression functions */
@@ -1416,7 +1424,7 @@ test_util_mmap(void)
/* Now a zero-length file. */
write_str_to_file(fname1, "", 1);
mapping = tor_mmap_file(fname1);
- test_eq(mapping, NULL);
+ test_eq_ptr(mapping, NULL);
test_eq(ERANGE, errno);
unlink(fname1);
@@ -1474,12 +1482,28 @@ test_util_control_formats(void)
tor_free(out);
}
+#define test_feq(value1,value2) do { \
+ double v1 = (value1), v2=(value2); \
+ double tf_diff = v1-v2; \
+ double tf_tolerance = ((v1+v2)/2.0)/1e8; \
+ if (tf_diff<0) tf_diff=-tf_diff; \
+ if (tf_tolerance<0) tf_tolerance=-tf_tolerance; \
+ if (tf_diff<tf_tolerance) { \
+ TT_BLATHER(("%s ~~ %s: %f ~~ %f",#value1,#value2,v1,v2)); \
+ } else { \
+ TT_FAIL(("%s ~~ %s: %f != %f",#value1,#value2,v1,v2)); \
+ } \
+ } while (0)
+
static void
test_util_sscanf(void)
{
unsigned u1, u2, u3;
char s1[20], s2[10], s3[10], ch;
int r;
+ long lng1,lng2;
+ int int1, int2;
+ double d1,d2,d3,d4;
/* Simple tests (malformed patterns, literal matching, ...) */
test_eq(-1, tor_sscanf("123", "%i", &r)); /* %i is not supported */
@@ -1608,6 +1632,65 @@ test_util_sscanf(void)
test_eq(4, tor_sscanf("1.2.3 foobar", "%u.%u.%u%c", &u1, &u2, &u3, &ch));
test_eq(' ', ch);
+ r = tor_sscanf("12345 -67890 -1", "%d %ld %d", &int1, &lng1, &int2);
+ test_eq(r,3);
+ test_eq(int1, 12345);
+ test_eq(lng1, -67890);
+ test_eq(int2, -1);
+
+#if SIZEOF_INT == 4
+ r = tor_sscanf("-2147483648. 2147483647.", "%d. %d.", &int1, &int2);
+ test_eq(r,2);
+ test_eq(int1, -2147483647-1);
+ test_eq(int2, 2147483647);
+
+ r = tor_sscanf("-2147483679.", "%d.", &int1);
+ test_eq(r,0);
+
+ r = tor_sscanf("2147483678.", "%d.", &int1);
+ test_eq(r,0);
+#elif SIZEOF_INT == 8
+ r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
+ "%d. %d.", &int1, &int2);
+ test_eq(r,2);
+ test_eq(int1, -9223372036854775807-1);
+ test_eq(int2, 9223372036854775807);
+
+ r = tor_sscanf("-9223372036854775809.", "%d.", &int1);
+ test_eq(r,0);
+
+ r = tor_sscanf("9223372036854775808.", "%d.", &int1);
+ test_eq(r,0);
+#endif
+
+#if SIZEOF_LONG == 4
+ r = tor_sscanf("-2147483648. 2147483647.", "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,2);
+ test_eq(lng1, -2147483647 - 1);
+ test_eq(lng2, 2147483647);
+#elif SIZEOF_LONG == 8
+ r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
+ "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,2);
+ test_eq(lng1, -9223372036854775807L - 1);
+ test_eq(lng2, 9223372036854775807L);
+
+ r = tor_sscanf("-9223372036854775808. 9223372036854775808.",
+ "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,1);
+ r = tor_sscanf("-9223372036854775809. 9223372036854775808.",
+ "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,0);
+#endif
+
+ r = tor_sscanf("123.456 .000007 -900123123.2000787 00003.2",
+ "%lf %lf %lf %lf", &d1,&d2,&d3,&d4);
+ test_eq(r,4);
+ test_feq(d1, 123.456);
+ test_feq(d2, .000007);
+ test_feq(d3, -900123123.2000787);
+ test_feq(d4, 3.2);
+
done:
;
}
@@ -1735,7 +1818,7 @@ test_util_memarea(void)
/* Make sure we don't overalign. */
p1 = memarea_alloc(area, 1);
p2 = memarea_alloc(area, 1);
- test_eq(p1+sizeof(void*), p2);
+ test_eq_ptr(p1+sizeof(void*), p2);
{
malloced_ptr = tor_malloc(64);
test_assert(!memarea_owns_ptr(area, malloced_ptr));
@@ -1780,7 +1863,7 @@ test_util_memarea(void)
memarea_clear(area);
p1 = memarea_alloc(area, 1);
- test_eq(p1, p1_orig);
+ test_eq_ptr(p1, p1_orig);
memarea_clear(area);
/* Check for running over an area's size. */
@@ -2061,13 +2144,13 @@ test_util_listdir(void *ptr)
dir_contents = tor_listdir(dirname);
test_assert(dir_contents);
/* make sure that each filename is listed. */
- test_assert(smartlist_string_isin_case(dir_contents, "hopscotch"));
- test_assert(smartlist_string_isin_case(dir_contents, "mumblety-peg"));
- test_assert(smartlist_string_isin_case(dir_contents, ".hidden-file"));
- test_assert(smartlist_string_isin_case(dir_contents, "some-directory"));
+ test_assert(smartlist_contains_string_case(dir_contents, "hopscotch"));
+ test_assert(smartlist_contains_string_case(dir_contents, "mumblety-peg"));
+ test_assert(smartlist_contains_string_case(dir_contents, ".hidden-file"));
+ test_assert(smartlist_contains_string_case(dir_contents, "some-directory"));
- test_assert(!smartlist_string_isin(dir_contents, "."));
- test_assert(!smartlist_string_isin(dir_contents, ".."));
+ test_assert(!smartlist_contains_string(dir_contents, "."));
+ test_assert(!smartlist_contains_string(dir_contents, ".."));
done:
tor_free(fname1);
@@ -2136,7 +2219,7 @@ test_util_load_win_lib(void *ptr)
tt_assert(h);
done:
if (h)
- CloseHandle(h);
+ FreeLibrary(h);
}
#endif
@@ -2558,7 +2641,7 @@ test_util_join_win_cmdline(void *ptr)
};
int i;
- char *joined_argv;
+ char *joined_argv = NULL;
(void)ptr;
@@ -2570,7 +2653,7 @@ test_util_join_win_cmdline(void *ptr)
}
done:
- ;
+ tor_free(joined_argv);
}
#define MAX_SPLIT_LINE_COUNT 4
@@ -2690,6 +2773,16 @@ test_util_di_ops(void)
test_eq(neq1, !eq1);
}
+ tt_int_op(1, ==, safe_mem_is_zero("", 0));
+ tt_int_op(1, ==, safe_mem_is_zero("", 1));
+ tt_int_op(0, ==, safe_mem_is_zero("a", 1));
+ tt_int_op(0, ==, safe_mem_is_zero("a", 2));
+ tt_int_op(0, ==, safe_mem_is_zero("\0a", 2));
+ tt_int_op(1, ==, safe_mem_is_zero("\0\0a", 2));
+ tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0", 8));
+ tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 8));
+ tt_int_op(0, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 9));
+
done:
;
}
@@ -3045,7 +3138,7 @@ test_util_set_env_var_in_sl(void *ptr)
SMARTLIST_FOREACH(new_env_vars, char *, env_var,
set_environment_variable_in_smartlist(merged_env_vars,
env_var,
- _tor_free,
+ tor_free_,
1));
smartlist_sort_strings(merged_env_vars);
@@ -3077,6 +3170,48 @@ test_util_set_env_var_in_sl(void *ptr)
smartlist_free(expected_resulting_env_vars);
}
+static void
+test_util_weak_random(void *arg)
+{
+ int i, j, n[16];
+ tor_weak_rng_t rng;
+ (void) arg;
+
+ tor_init_weak_random(&rng, (unsigned)time(NULL));
+
+ for (i = 1; i <= 256; ++i) {
+ for (j=0;j<100;++j) {
+ int r = tor_weak_random_range(&rng, i);
+ tt_int_op(0, <=, r);
+ tt_int_op(r, <, i);
+ }
+ }
+
+ memset(n,0,sizeof(n));
+ for (j=0;j<8192;++j) {
+ n[tor_weak_random_range(&rng, 16)]++;
+ }
+
+ for (i=0;i<16;++i)
+ tt_int_op(n[i], >, 0);
+ done:
+ ;
+}
+
+static void
+test_util_mathlog(void *arg)
+{
+ double d;
+ (void) arg;
+
+ d = tor_mathlog(2.718281828);
+ tt_double_op(fabs(d - 1.0), <, .000001);
+ d = tor_mathlog(10);
+ tt_double_op(fabs(d - 2.30258509), <, .000001);
+ done:
+ ;
+}
+
#define UTIL_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name }
@@ -3130,6 +3265,11 @@ struct testcase_t util_tests[] = {
UTIL_TEST(envnames, 0),
UTIL_TEST(make_environment, 0),
UTIL_TEST(set_env_var_in_sl, 0),
+ UTIL_TEST(read_file_eof_tiny_limit, 0),
+ UTIL_TEST(read_file_eof_two_loops, 0),
+ UTIL_TEST(read_file_eof_zero_bytes, 0),
+ UTIL_TEST(mathlog, 0),
+ UTIL_TEST(weak_random, 0),
END_OF_TESTCASES
};
diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am
deleted file mode 100644
index 35b0a41f5..000000000
--- a/src/tools/Makefile.am
+++ /dev/null
@@ -1,22 +0,0 @@
-bin_PROGRAMS = tor-resolve tor-gencert
-noinst_PROGRAMS = tor-checkkey
-
-tor_resolve_SOURCES = tor-resolve.c
-tor_resolve_LDFLAGS =
-tor_resolve_LDADD = ../common/libor.a @TOR_LIB_MATH@ @TOR_LIB_WS32@
-
-tor_gencert_SOURCES = tor-gencert.c
-tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
-tor_gencert_LDADD = ../common/libor.a ../common/libor-crypto.a \
- @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-tor_checkkey_SOURCES = tor-checkkey.c
-tor_checkkey_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
-tor_checkkey_LDADD = ../common/libor.a ../common/libor-crypto.a \
- @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-SUBDIRS = tor-fw-helper
-DIST_SUBDIRS = tor-fw-helper
-
diff --git a/src/tools/Makefile.nmake b/src/tools/Makefile.nmake
index a30a28b2e..fda1990e0 100644
--- a/src/tools/Makefile.nmake
+++ b/src/tools/Makefile.nmake
@@ -6,8 +6,8 @@ LIBS = ..\..\..\build-alpha\lib\libevent.lib \
..\..\..\build-alpha\lib\libcrypto.lib \
..\..\..\build-alpha\lib\libssl.lib \
..\..\..\build-alpha\lib\libz.lib \
- ws2_32.lib advapi32.lib shell32.lib
-
+ ws2_32.lib advapi32.lib shell32.lib \
+ crypt32.lib gdi32.lib user32.lib
tor-gencert.exe: tor-gencert.obj
$(CC) $(CFLAGS) $(LIBS) ..\common\*.lib tor-gencert.obj
diff --git a/src/tools/include.am b/src/tools/include.am
new file mode 100644
index 000000000..54b150a80
--- /dev/null
+++ b/src/tools/include.am
@@ -0,0 +1,24 @@
+bin_PROGRAMS+= src/tools/tor-resolve src/tools/tor-gencert
+noinst_PROGRAMS+= src/tools/tor-checkkey
+
+src_tools_tor_resolve_SOURCES = src/tools/tor-resolve.c
+src_tools_tor_resolve_LDFLAGS =
+src_tools_tor_resolve_LDADD = src/common/libor.a @TOR_LIB_MATH@ @TOR_LIB_WS32@
+
+src_tools_tor_gencert_SOURCES = src/tools/tor-gencert.c
+src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
+src_tools_tor_gencert_LDADD = src/common/libor.a src/common/libor-crypto.a \
+ $(LIBDONNA) \
+ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+
+src_tools_tor_checkkey_SOURCES = src/tools/tor-checkkey.c
+src_tools_tor_checkkey_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
+src_tools_tor_checkkey_LDADD = src/common/libor.a src/common/libor-crypto.a \
+ $(LIBDONNA) \
+ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+
+include src/tools/tor-fw-helper/include.am
+
+
diff --git a/src/tools/tor-checkkey.c b/src/tools/tor-checkkey.c
index 10d13d837..a3860ca4b 100644
--- a/src/tools/tor-checkkey.c
+++ b/src/tools/tor-checkkey.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Tor Project, Inc. */
+/* Copyright (c) 2008-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CRYPTO_PRIVATE
@@ -71,7 +71,7 @@ main(int c, char **v)
return 1;
printf("%s\n",digest);
} else {
- rsa = _crypto_pk_get_rsa(env);
+ rsa = crypto_pk_get_rsa_(env);
str = BN_bn2hex(rsa->n);
printf("%s\n", str);
diff --git a/src/tools/tor-fw-helper/Makefile.am b/src/tools/tor-fw-helper/Makefile.am
deleted file mode 100644
index 393562db0..000000000
--- a/src/tools/tor-fw-helper/Makefile.am
+++ /dev/null
@@ -1,38 +0,0 @@
-if USE_FW_HELPER
-bin_PROGRAMS = tor-fw-helper
-else
-bin_PROGRAMS =
-endif
-
-tor_fw_helper_SOURCES = \
- tor-fw-helper.c \
- tor-fw-helper-natpmp.c \
- tor-fw-helper-upnp.c
-noinst_HEADERS = \
- tor-fw-helper.h \
- tor-fw-helper-natpmp.h \
- tor-fw-helper-upnp.h
-
-if NAT_PMP
-nat_pmp_ldflags = @TOR_LDFLAGS_libnatpmp@
-nat_pmp_ldadd = -lnatpmp @TOR_LIB_IPHLPAPI@
-nat_pmp_cppflags = @TOR_CPPFLAGS_libnatpmp@
-else
-nat_pmp_ldflags =
-nat_pmp_ldadd =
-nat_pmp_cppflags =
-endif
-
-if MINIUPNPC
-miniupnpc_ldflags = @TOR_LDFLAGS_libminiupnpc@
-miniupnpc_ldadd = -lminiupnpc -lm @TOR_LIB_IPHLPAPI@
-miniupnpc_cppflags = @TOR_CPPFLAGS_libminiupnpc@
-else
-miniupnpc_ldflags =
-miniupnpc_ldadd =
-miniupnpc_cppflags =
-endif
-
-tor_fw_helper_LDFLAGS = $(nat_pmp_ldflags) $(miniupnpc_ldflags)
-tor_fw_helper_LDADD = ../../common/libor.a $(nat_pmp_ldadd) $(miniupnpc_ldadd) @TOR_LIB_WS32@
-tor_fw_helper_CPPFLAGS = $(nat_pmp_cppflags) $(miniupnpc_cppflags)
diff --git a/src/tools/tor-fw-helper/include.am b/src/tools/tor-fw-helper/include.am
new file mode 100644
index 000000000..275a0e237
--- /dev/null
+++ b/src/tools/tor-fw-helper/include.am
@@ -0,0 +1,36 @@
+if USE_FW_HELPER
+bin_PROGRAMS+= src/tools/tor-fw-helper/tor-fw-helper
+endif
+
+src_tools_tor_fw_helper_tor_fw_helper_SOURCES = \
+ src/tools/tor-fw-helper/tor-fw-helper.c \
+ src/tools/tor-fw-helper/tor-fw-helper-natpmp.c \
+ src/tools/tor-fw-helper/tor-fw-helper-upnp.c
+noinst_HEADERS+= \
+ src/tools/tor-fw-helper/tor-fw-helper.h \
+ src/tools/tor-fw-helper/tor-fw-helper-natpmp.h \
+ src/tools/tor-fw-helper/tor-fw-helper-upnp.h
+
+if NAT_PMP
+nat_pmp_ldflags = @TOR_LDFLAGS_libnatpmp@
+nat_pmp_ldadd = -lnatpmp @TOR_LIB_IPHLPAPI@
+nat_pmp_cppflags = @TOR_CPPFLAGS_libnatpmp@
+else
+nat_pmp_ldflags =
+nat_pmp_ldadd =
+nat_pmp_cppflags =
+endif
+
+if MINIUPNPC
+miniupnpc_ldflags = @TOR_LDFLAGS_libminiupnpc@
+miniupnpc_ldadd = -lminiupnpc @TOR_LIB_IPHLPAPI@
+miniupnpc_cppflags = @TOR_CPPFLAGS_libminiupnpc@
+else
+miniupnpc_ldflags =
+miniupnpc_ldadd =
+miniupnpc_cppflags =
+endif
+
+src_tools_tor_fw_helper_tor_fw_helper_LDFLAGS = $(nat_pmp_ldflags) $(miniupnpc_ldflags)
+src_tools_tor_fw_helper_tor_fw_helper_LDADD = src/common/libor.a $(nat_pmp_ldadd) $(miniupnpc_ldadd) -lm @TOR_LIB_WS32@
+src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS = $(nat_pmp_cppflags) $(miniupnpc_cppflags)
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c
index 0e0b385f9..41eb9dcb7 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2012, The Tor Project, Inc. */
+ * Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -60,15 +60,15 @@ tor_natpmp_init(tor_fw_options_t *tor_fw_options, void *backend_state)
state->lease = NATPMP_DEFAULT_LEASE;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: natpmp init...\n");
+ fprintf(stderr, "V: natpmp init...\n");
r = initnatpmp(&(state->natpmp), 0, 0);
if (r == 0) {
state->init = 1;
- fprintf(stdout, "tor-fw-helper: natpmp initialized...\n");
+ fprintf(stderr, "V: natpmp initialized...\n");
return r;
} else {
- fprintf(stderr, "tor-fw-helper: natpmp failed to initialize...\n");
+ fprintf(stderr, "V: natpmp failed to initialize...\n");
return r;
}
}
@@ -80,10 +80,10 @@ tor_natpmp_cleanup(tor_fw_options_t *tor_fw_options, void *backend_state)
natpmp_state_t *state = (natpmp_state_t *) backend_state;
int r = 0;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: natpmp cleanup...\n");
+ fprintf(stderr, "V: natpmp cleanup...\n");
r = closenatpmp(&(state->natpmp));
if (tor_fw_options->verbose)
- fprintf(stdout, "V: closing natpmp socket: %d\n", r);
+ fprintf(stderr, "V: closing natpmp socket: %d\n", r);
return r;
}
@@ -93,16 +93,20 @@ wait_until_fd_readable(tor_socket_t fd, struct timeval *timeout)
{
int r;
fd_set fds;
+
+#ifndef WIN32
if (fd >= FD_SETSIZE) {
fprintf(stderr, "E: NAT-PMP FD_SETSIZE error %d\n", fd);
return -1;
}
+#endif
+
FD_ZERO(&fds);
FD_SET(fd, &fds);
r = select(fd+1, &fds, NULL, NULL, timeout);
if (r == -1) {
- fprintf(stdout, "V: select failed in wait_until_fd_readable: %s\n",
- strerror(errno));
+ fprintf(stderr, "V: select failed in wait_until_fd_readable: %s\n",
+ tor_socket_strerror(tor_socket_errno(fd)));
return -1;
}
/* XXXX we should really check to see whether fd was readable, or we timed
@@ -110,27 +114,25 @@ wait_until_fd_readable(tor_socket_t fd, struct timeval *timeout)
return 0;
}
-/** Add a TCP port mapping for a single port stored in <b>tor_fw_options</b>
- * using the <b>natpmp_t</b> stored in <b>backend_state</b>. */
int
-tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options,
- void *backend_state)
+tor_natpmp_add_tcp_mapping(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state)
{
- natpmp_state_t *state = (natpmp_state_t *) backend_state;
int r = 0;
int x = 0;
int sav_errno;
+ natpmp_state_t *state = (natpmp_state_t *) backend_state;
struct timeval timeout;
- if (tor_fw_options->verbose)
- fprintf(stdout, "V: sending natpmp portmapping request...\n");
+ if (is_verbose)
+ fprintf(stderr, "V: sending natpmp portmapping request...\n");
r = sendnewportmappingrequest(&(state->natpmp), state->protocol,
- tor_fw_options->internal_port,
- tor_fw_options->external_port,
+ internal_port,
+ external_port,
state->lease);
- if (tor_fw_options->verbose)
- fprintf(stdout, "tor-fw-helper: NAT-PMP sendnewportmappingrequest "
+ if (is_verbose)
+ fprintf(stderr, "tor-fw-helper: NAT-PMP sendnewportmappingrequest "
"returned %d (%s)\n", r, r==12?"SUCCESS":"FAILED");
do {
@@ -139,15 +141,15 @@ tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options,
if (x == -1)
return -1;
- if (tor_fw_options->verbose)
- fprintf(stdout, "V: attempting to readnatpmpreponseorretry...\n");
+ if (is_verbose)
+ fprintf(stderr, "V: attempting to readnatpmpreponseorretry...\n");
r = readnatpmpresponseorretry(&(state->natpmp), &(state->response));
- sav_errno = errno;
+ sav_errno = tor_socket_errno(state->natpmp.s);
if (r<0 && r!=NATPMP_TRYAGAIN) {
fprintf(stderr, "E: readnatpmpresponseorretry failed %d\n", r);
fprintf(stderr, "E: errno=%d '%s'\n", sav_errno,
- strerror(sav_errno));
+ tor_socket_strerror(sav_errno));
}
} while (r == NATPMP_TRYAGAIN);
@@ -163,16 +165,14 @@ tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options,
}
if (r == NATPMP_SUCCESS) {
- fprintf(stdout, "tor-fw-helper: NAT-PMP mapped public port %hu to"
+ fprintf(stderr, "tor-fw-helper: NAT-PMP mapped public port %hu to"
" localport %hu liftime %u\n",
(state->response).pnu.newportmapping.mappedpublicport,
(state->response).pnu.newportmapping.privateport,
(state->response).pnu.newportmapping.lifetime);
}
- tor_fw_options->nat_pmp_status = 1;
-
- return r;
+ return (r == NATPMP_SUCCESS) ? 0 : -1;
}
/** Fetch our likely public IP from our upstream NAT-PMP enabled NAT device.
@@ -189,7 +189,7 @@ tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options,
struct timeval timeout;
r = sendpublicaddressrequest(&(state->natpmp));
- fprintf(stdout, "tor-fw-helper: NAT-PMP sendpublicaddressrequest returned"
+ fprintf(stderr, "tor-fw-helper: NAT-PMP sendpublicaddressrequest returned"
" %d (%s)\n", r, r==2?"SUCCESS":"FAILED");
do {
@@ -200,19 +200,19 @@ tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options,
return -1;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: NAT-PMP attempting to read reponse...\n");
+ fprintf(stderr, "V: NAT-PMP attempting to read reponse...\n");
r = readnatpmpresponseorretry(&(state->natpmp), &(state->response));
- sav_errno = errno;
+ sav_errno = tor_socket_errno(state->natpmp.s);
if (tor_fw_options->verbose)
- fprintf(stdout, "V: NAT-PMP readnatpmpresponseorretry returned"
+ fprintf(stderr, "V: NAT-PMP readnatpmpresponseorretry returned"
" %d\n", r);
if ( r < 0 && r != NATPMP_TRYAGAIN) {
fprintf(stderr, "E: NAT-PMP readnatpmpresponseorretry failed %d\n",
r);
fprintf(stderr, "E: NAT-PMP errno=%d '%s'\n", sav_errno,
- strerror(sav_errno));
+ tor_socket_strerror(sav_errno));
}
} while (r == NATPMP_TRYAGAIN );
@@ -223,15 +223,15 @@ tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options,
return r;
}
- fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
+ fprintf(stderr, "tor-fw-helper: ExternalIPAddress = %s\n",
inet_ntoa((state->response).pnu.publicaddress.addr));
tor_fw_options->public_ip_status = 1;
if (tor_fw_options->verbose) {
- fprintf(stdout, "V: result = %u\n", r);
- fprintf(stdout, "V: type = %u\n", (state->response).type);
- fprintf(stdout, "V: resultcode = %u\n", (state->response).resultcode);
- fprintf(stdout, "V: epoch = %u\n", (state->response).epoch);
+ fprintf(stderr, "V: result = %u\n", r);
+ fprintf(stderr, "V: type = %u\n", (state->response).type);
+ fprintf(stderr, "V: resultcode = %u\n", (state->response).resultcode);
+ fprintf(stderr, "V: epoch = %u\n", (state->response).epoch);
}
return r;
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h
index 54f541bcf..2d924ce75 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h
+++ b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2012, The Tor Project, Inc. */
+ * Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -7,8 +7,8 @@
**/
#ifdef NAT_PMP
-#ifndef _TOR_FW_HELPER_NATPMP_H
-#define _TOR_FW_HELPER_NATPMP_H
+#ifndef TOR_TOR_FW_HELPER_NATPMP_H
+#define TOR_TOR_FW_HELPER_NATPMP_H
#include <natpmp.h>
@@ -36,8 +36,8 @@ int tor_natpmp_init(tor_fw_options_t *tor_fw_options, void *backend_state);
int tor_natpmp_cleanup(tor_fw_options_t *tor_fw_options, void *backend_state);
-int tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options,
- void *backend_state);
+int tor_natpmp_add_tcp_mapping(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state);
int tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options,
void *backend_state);
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-upnp.c b/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
index 7c104f11c..692186d37 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2012, The Tor Project, Inc. */
+ * Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -91,7 +91,7 @@ tor_upnp_init(tor_fw_options_t *options, void *backend_state)
assert(options);
r = UPNP_GetValidIGD(devlist, &(state->urls), &(state->data),
state->lanaddr, UPNP_LANADDR_SZ);
- fprintf(stdout, "tor-fw-helper: UPnP GetValidIGD returned: %d (%s)\n", r,
+ fprintf(stderr, "tor-fw-helper: UPnP GetValidIGD returned: %d (%s)\n", r,
r==UPNP_SUCCESS?"SUCCESS":"FAILED");
freeUPNPDevlist(devlist);
@@ -141,7 +141,7 @@ tor_upnp_fetch_public_ip(tor_fw_options_t *options, void *backend_state)
goto err;
if (externalIPAddress[0]) {
- fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
+ fprintf(stderr, "tor-fw-helper: ExternalIPAddress = %s\n",
externalIPAddress); tor_upnp_cleanup(options, state);
options->public_ip_status = 1;
return UPNP_ERR_SUCCESS;
@@ -154,44 +154,40 @@ tor_upnp_fetch_public_ip(tor_fw_options_t *options, void *backend_state)
return UPNP_ERR_GETEXTERNALIP;
}
-/** Add a TCP port mapping for a single port stored in <b>tor_fw_options</b>
- * and store the results in <b>backend_state</b>. */
int
-tor_upnp_add_tcp_mapping(tor_fw_options_t *options, void *backend_state)
+tor_upnp_add_tcp_mapping(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state)
{
- miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
- int r;
+ int retval;
char internal_port_str[6];
char external_port_str[6];
+ miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state;
if (!state->init) {
- r = tor_upnp_init(options, state);
- if (r != UPNP_ERR_SUCCESS)
- return r;
+ fprintf(stderr, "E: %s but state is not initialized.\n", __func__);
+ return -1;
}
- if (options->verbose)
- fprintf(stdout, "V: internal port: %d, external port: %d\n",
- (int)options->internal_port, (int)options->external_port);
+ if (is_verbose)
+ fprintf(stderr, "V: UPnP: internal port: %u, external port: %u\n",
+ internal_port, external_port);
tor_snprintf(internal_port_str, sizeof(internal_port_str),
- "%d", (int)options->internal_port);
+ "%u", internal_port);
tor_snprintf(external_port_str, sizeof(external_port_str),
- "%d", (int)options->external_port);
+ "%u", external_port);
- r = UPNP_AddPortMapping(state->urls.controlURL,
- state->data.first.servicetype,
- external_port_str, internal_port_str,
+ retval = UPNP_AddPortMapping(state->urls.controlURL,
+ state->data.first.servicetype,
+ external_port_str, internal_port_str,
#ifdef MINIUPNPC15
- state->lanaddr, UPNP_DESC, "TCP", 0);
+ state->lanaddr, UPNP_DESC, "TCP", 0);
#else
- state->lanaddr, UPNP_DESC, "TCP", 0, 0);
+ state->lanaddr, UPNP_DESC, "TCP", 0, 0);
#endif
- if (r != UPNPCOMMAND_SUCCESS)
- return UPNP_ERR_ADDPORTMAPPING;
- options->upnp_status = 1;
- return UPNP_ERR_SUCCESS;
+ return (retval == UPNP_ERR_SUCCESS) ? 0 : -1;
}
+
#endif
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-upnp.h b/src/tools/tor-fw-helper/tor-fw-helper-upnp.h
index f037c75ba..b6c7ed864 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-upnp.h
+++ b/src/tools/tor-fw-helper/tor-fw-helper-upnp.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2012, The Tor Project, Inc. */
+ * Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,8 +8,8 @@
**/
#ifdef MINIUPNPC
-#ifndef _TOR_FW_HELPER_UPNP_H
-#define _TOR_FW_HELPER_UPNP_H
+#ifndef TOR_TOR_FW_HELPER_UPNP_H
+#define TOR_TOR_FW_HELPER_UPNP_H
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
@@ -36,7 +36,8 @@ int tor_upnp_cleanup(tor_fw_options_t *options, void *backend_state);
int tor_upnp_fetch_public_ip(tor_fw_options_t *options, void *backend_state);
-int tor_upnp_add_tcp_mapping(tor_fw_options_t *options, void *backend_state);
+int tor_upnp_add_tcp_mapping(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state);
#endif
#endif
diff --git a/src/tools/tor-fw-helper/tor-fw-helper.c b/src/tools/tor-fw-helper/tor-fw-helper.c
index 0510e65d1..bb6e70aaa 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2012, The Tor Project, Inc. */
+ * Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,6 +20,9 @@
#include <getopt.h>
#include <time.h>
#include <string.h>
+#include <assert.h>
+
+#include "container.h"
#ifdef _WIN32
#include <winsock2.h>
@@ -45,7 +48,7 @@ typedef struct backends_t {
void *backend_state[MAX_BACKENDS];
} backends_t;
-/** Initalize each backend helper with the user input stored in <b>options</b>
+/** Initialize each backend helper with the user input stored in <b>options</b>
* and put the results in the <b>backends</b> struct. */
static int
init_backends(tor_fw_options_t *options, backends_t *backends)
@@ -94,13 +97,10 @@ usage(void)
{
fprintf(stderr, "tor-fw-helper usage:\n"
" [-h|--help]\n"
- " [-T|--Test]\n"
+ " [-T|--test-commandline]\n"
" [-v|--verbose]\n"
" [-g|--fetch-public-ip]\n"
- " -i|--internal-or-port [TCP port]\n"
- " [-e|--external-or-port [TCP port]]\n"
- " [-d|--internal-dir-port [TCP port]\n"
- " [-p|--external-dir-port [TCP port]]]\n");
+ " [-p|--forward-port ([<external port>]:<internal port>)]\n");
}
/** Log commandline options to a hardcoded file <b>tor-fw-helper.log</b> in the
@@ -125,7 +125,7 @@ log_commandline_options(int argc, char **argv)
if (retval < 0)
goto error;
- retval = fprintf(stdout, "ARG: %d: %s\n", i, argv[i]);
+ retval = fprintf(stderr, "ARG: %d: %s\n", i, argv[i]);
if (retval < 0)
goto error;
}
@@ -152,82 +152,141 @@ tor_fw_fetch_public_ip(tor_fw_options_t *tor_fw_options,
int r = 0;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: tor_fw_fetch_public_ip\n");
+ fprintf(stderr, "V: tor_fw_fetch_public_ip\n");
for (i=0; i<backends->n_backends; ++i) {
if (tor_fw_options->verbose) {
- fprintf(stdout, "V: running backend_state now: %i\n", i);
- fprintf(stdout, "V: size of backend state: %u\n",
+ fprintf(stderr, "V: running backend_state now: %i\n", i);
+ fprintf(stderr, "V: size of backend state: %u\n",
(int)(backends->backend_ops)[i].state_len);
- fprintf(stdout, "V: backend state name: %s\n",
+ fprintf(stderr, "V: backend state name: %s\n",
(char *)(backends->backend_ops)[i].name);
}
r = backends->backend_ops[i].fetch_public_ip(tor_fw_options,
backends->backend_state[i]);
- fprintf(stdout, "tor-fw-helper: tor_fw_fetch_public_ip backend %s "
+ fprintf(stderr, "tor-fw-helper: tor_fw_fetch_public_ip backend %s "
" returned: %i\n", (char *)(backends->backend_ops)[i].name, r);
}
}
-/** Iterate over each of the supported <b>backends</b> and attempt to add a
- * port forward for the OR port stored in <b>tor_fw_options</b>. */
+/** Print a spec-conformant string to stdout describing the results of
+ * the TCP port forwarding operation from <b>external_port</b> to
+ * <b>internal_port</b>. */
static void
-tor_fw_add_or_port(tor_fw_options_t *tor_fw_options,
- backends_t *backends)
+tor_fw_helper_report_port_fw_results(uint16_t internal_port,
+ uint16_t external_port,
+ int succeded,
+ const char *message)
+{
+ char *report_string = NULL;
+
+ tor_asprintf(&report_string, "%s %s %u %u %s %s\n",
+ "tor-fw-helper",
+ "tcp-forward",
+ external_port, internal_port,
+ succeded ? "SUCCESS" : "FAIL",
+ message);
+ fprintf(stdout, "%s", report_string);
+ fflush(stdout);
+ tor_free(report_string);
+}
+
+#define tor_fw_helper_report_port_fw_fail(i, e, m) \
+ tor_fw_helper_report_port_fw_results((i), (e), 0, (m))
+
+#define tor_fw_helper_report_port_fw_success(i, e, m) \
+ tor_fw_helper_report_port_fw_results((i), (e), 1, (m))
+
+/** Return a heap-allocated string containing the list of our
+ * backends. It can be used in log messages. Be sure to free it
+ * afterwards! */
+static char *
+get_list_of_backends_string(backends_t *backends)
{
+ char *backend_names = NULL;
int i;
- int r = 0;
+ smartlist_t *backend_names_sl = smartlist_new();
- if (tor_fw_options->verbose)
- fprintf(stdout, "V: tor_fw_add_or_port\n");
+ assert(backends->n_backends);
- for (i=0; i<backends->n_backends; ++i) {
- if (tor_fw_options->verbose) {
- fprintf(stdout, "V: running backend_state now: %i\n", i);
- fprintf(stdout, "V: size of backend state: %u\n",
- (int)(backends->backend_ops)[i].state_len);
- fprintf(stdout, "V: backend state name: %s\n",
- (const char *) backends->backend_ops[i].name);
- }
- r = backends->backend_ops[i].add_tcp_mapping(tor_fw_options,
- backends->backend_state[i]);
- fprintf(stdout, "tor-fw-helper: tor_fw_add_or_port backend %s "
- "returned: %i\n", (const char *) backends->backend_ops[i].name, r);
- }
+ for (i=0; i<backends->n_backends; ++i)
+ smartlist_add(backend_names_sl, (char *) backends->backend_ops[i].name);
+
+ backend_names = smartlist_join_strings(backend_names_sl, ", ", 0, NULL);
+ smartlist_free(backend_names_sl);
+
+ return backend_names;
}
/** Iterate over each of the supported <b>backends</b> and attempt to add a
- * port forward for the Dir port stored in <b>tor_fw_options</b>. */
+ * port forward for the port stored in <b>tor_fw_options</b>. */
static void
-tor_fw_add_dir_port(tor_fw_options_t *tor_fw_options,
- backends_t *backends)
+tor_fw_add_ports(tor_fw_options_t *tor_fw_options,
+ backends_t *backends)
{
int i;
int r = 0;
+ int succeeded = 0;
if (tor_fw_options->verbose)
- fprintf(stdout, "V: tor_fw_add_dir_port\n");
+ fprintf(stderr, "V: %s\n", __func__);
- for (i=0; i<backends->n_backends; ++i) {
- if (tor_fw_options->verbose) {
- fprintf(stdout, "V: running backend_state now: %i\n", i);
- fprintf(stdout, "V: size of backend state: %u\n",
- (int)(backends->backend_ops)[i].state_len);
- fprintf(stdout, "V: backend state name: %s\n",
- (char *)(backends->backend_ops)[i].name);
+ /** Loop all ports that need to be forwarded, and try to use our
+ * backends for each port. If a backend succeeds, break the loop,
+ * report success and get to the next port. If all backends fail,
+ * report failure for that port. */
+ SMARTLIST_FOREACH_BEGIN(tor_fw_options->ports_to_forward,
+ port_to_forward_t *, port_to_forward) {
+
+ succeeded = 0;
+
+ for (i=0; i<backends->n_backends; ++i) {
+ if (tor_fw_options->verbose) {
+ fprintf(stderr, "V: running backend_state now: %i\n", i);
+ fprintf(stderr, "V: size of backend state: %u\n",
+ (int)(backends->backend_ops)[i].state_len);
+ fprintf(stderr, "V: backend state name: %s\n",
+ (const char *) backends->backend_ops[i].name);
+ }
+
+ r =
+ backends->backend_ops[i].add_tcp_mapping(port_to_forward->internal_port,
+ port_to_forward->external_port,
+ tor_fw_options->verbose,
+ backends->backend_state[i]);
+ if (r == 0) { /* backend success */
+ tor_fw_helper_report_port_fw_success(port_to_forward->internal_port,
+ port_to_forward->external_port,
+ backends->backend_ops[i].name);
+ succeeded = 1;
+ break;
+ }
+
+ fprintf(stderr, "tor-fw-helper: tor_fw_add_port backend %s "
+ "returned: %i\n",
+ (const char *) backends->backend_ops[i].name, r);
}
- r = backends->backend_ops[i].add_tcp_mapping(tor_fw_options,
- backends->backend_state[i]);
- fprintf(stdout, "tor-fw-helper: tor_fw_add_dir_port backend %s "
- "returned: %i\n", (const char *)backends->backend_ops[i].name, r);
- }
+
+ if (!succeeded) { /* all backends failed */
+ char *list_of_backends_str = get_list_of_backends_string(backends);
+ char *fail_msg = NULL;
+ tor_asprintf(&fail_msg, "All port forwarding backends (%s) failed.",
+ list_of_backends_str);
+ tor_fw_helper_report_port_fw_fail(port_to_forward->internal_port,
+ port_to_forward->external_port,
+ fail_msg);
+ tor_free(list_of_backends_str);
+ tor_free(fail_msg);
+ }
+
+ } SMARTLIST_FOREACH_END(port_to_forward);
}
/** Called before we make any calls to network-related functions.
* (Some operating systems require their network libraries to be
* initialized.) (from common/compat.c) */
static int
-network_init(void)
+tor_fw_helper_network_init(void)
{
#ifdef _WIN32
/* This silly exercise is necessary before windows will allow
@@ -247,6 +306,67 @@ network_init(void)
return 0;
}
+/** Parse the '-p' argument of tor-fw-helper. Its format is
+ * [<external port>]:<internal port>, and <external port> is optional.
+ * Return NULL if <b>arg</b> was c0rrupted. */
+static port_to_forward_t *
+parse_port(const char *arg)
+{
+ smartlist_t *sl = smartlist_new();
+ port_to_forward_t *port_to_forward = NULL;
+ char *port_str = NULL;
+ int ok;
+ int port;
+
+ smartlist_split_string(sl, arg, ":", 0, 0);
+ if (smartlist_len(sl) != 2)
+ goto err;
+
+ port_to_forward = tor_malloc(sizeof(port_to_forward_t));
+ if (!port_to_forward)
+ goto err;
+
+ port_str = smartlist_get(sl, 0); /* macroify ? */
+ port = (int)tor_parse_long(port_str, 10, 1, 65535, &ok, NULL);
+ if (!ok && strlen(port_str)) /* ":1555" is valid */
+ goto err;
+ port_to_forward->external_port = port;
+
+ port_str = smartlist_get(sl, 1);
+ port = (int)tor_parse_long(port_str, 10, 1, 65535, &ok, NULL);
+ if (!ok)
+ goto err;
+ port_to_forward->internal_port = port;
+
+ goto done;
+
+ err:
+ tor_free(port_to_forward);
+
+ done:
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+
+ return port_to_forward;
+}
+
+/** Report a failure of epic proportions: We didn't manage to
+ * initialize any port forwarding backends. */
+static void
+report_full_fail(const smartlist_t *ports_to_forward)
+{
+ if (!ports_to_forward)
+ return;
+
+ SMARTLIST_FOREACH_BEGIN(ports_to_forward,
+ const port_to_forward_t *, port_to_forward) {
+ tor_fw_helper_report_port_fw_fail(port_to_forward->internal_port,
+ port_to_forward->external_port,
+ "All backends (NAT-PMP, UPnP) failed "
+ "to initialize!"); /* XXX hardcoded */
+ } SMARTLIST_FOREACH_END(port_to_forward);
+}
+
int
main(int argc, char **argv)
{
@@ -259,22 +379,20 @@ main(int argc, char **argv)
memset(&tor_fw_options, 0, sizeof(tor_fw_options));
memset(&backend_state, 0, sizeof(backend_state));
+ // Parse CLI arguments.
while (1) {
int option_index = 0;
static struct option long_options[] =
{
{"verbose", 0, 0, 'v'},
{"help", 0, 0, 'h'},
- {"internal-or-port", 1, 0, 'i'},
- {"external-or-port", 1, 0, 'e'},
- {"internal-dir-port", 1, 0, 'd'},
- {"external-dir-port", 1, 0, 'p'},
+ {"port", 1, 0, 'p'},
{"fetch-public-ip", 0, 0, 'g'},
{"test-commandline", 0, 0, 'T'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "vhi:e:d:p:gT",
+ c = getopt_long(argc, argv, "vhp:gT",
long_options, &option_index);
if (c == -1)
break;
@@ -282,14 +400,31 @@ main(int argc, char **argv)
switch (c) {
case 'v': tor_fw_options.verbose = 1; break;
case 'h': tor_fw_options.help = 1; usage(); exit(1); break;
- case 'i': sscanf(optarg, "%hu", &tor_fw_options.private_or_port);
- break;
- case 'e': sscanf(optarg, "%hu", &tor_fw_options.public_or_port);
- break;
- case 'd': sscanf(optarg, "%hu", &tor_fw_options.private_dir_port);
- break;
- case 'p': sscanf(optarg, "%hu", &tor_fw_options.public_dir_port);
+ case 'p': {
+ port_to_forward_t *port_to_forward = parse_port(optarg);
+ if (!port_to_forward) {
+ fprintf(stderr, "E: Failed to parse '%s'.\n", optarg);
+ usage();
+ exit(1);
+ }
+
+ /* If no external port was given (it's optional), set it to be
+ * equal with the internal port. */
+ if (!port_to_forward->external_port) {
+ assert(port_to_forward->internal_port);
+ if (tor_fw_options.verbose)
+ fprintf(stderr, "V: No external port was given. Setting to %u.\n",
+ port_to_forward->internal_port);
+ port_to_forward->external_port = port_to_forward->internal_port;
+ }
+
+ if (!tor_fw_options.ports_to_forward)
+ tor_fw_options.ports_to_forward = smartlist_new();
+
+ smartlist_add(tor_fw_options.ports_to_forward, port_to_forward);
+
break;
+ }
case 'g': tor_fw_options.fetch_public_ip = 1; break;
case 'T': tor_fw_options.test_commandline = 1; break;
case '?': break;
@@ -297,98 +432,68 @@ main(int argc, char **argv)
}
}
- if (tor_fw_options.verbose) {
- fprintf(stderr, "V: tor-fw-helper version %s\n"
- "V: We were called with the following arguments:\n"
- "V: verbose = %d, help = %d, pub or port = %u, "
- "priv or port = %u\n"
- "V: pub dir port = %u, priv dir port = %u\n"
- "V: fetch_public_ip = %u\n",
- tor_fw_version, tor_fw_options.verbose, tor_fw_options.help,
- tor_fw_options.private_or_port, tor_fw_options.public_or_port,
- tor_fw_options.private_dir_port, tor_fw_options.public_dir_port,
- tor_fw_options.fetch_public_ip);
+ { // Verbose output
+
+ if (tor_fw_options.verbose)
+ fprintf(stderr, "V: tor-fw-helper version %s\n"
+ "V: We were called with the following arguments:\n"
+ "V: verbose = %d, help = %d, fetch_public_ip = %u\n",
+ tor_fw_version, tor_fw_options.verbose, tor_fw_options.help,
+ tor_fw_options.fetch_public_ip);
+
+ if (tor_fw_options.verbose && tor_fw_options.ports_to_forward) {
+ fprintf(stderr, "V: TCP forwarding:\n");
+ SMARTLIST_FOREACH(tor_fw_options.ports_to_forward,
+ const port_to_forward_t *, port_to_forward,
+ fprintf(stderr, "V: External: %u, Internal: %u\n",
+ port_to_forward->external_port,
+ port_to_forward->internal_port));
+ }
}
if (tor_fw_options.test_commandline) {
return log_commandline_options(argc, argv);
}
- /* At the very least, we require an ORPort;
- Given a private ORPort, we can ask for a mapping that matches the port
- externally.
- */
- if (!tor_fw_options.private_or_port && !tor_fw_options.fetch_public_ip) {
- fprintf(stderr, "E: We require an ORPort or fetch_public_ip"
- " request!\n");
+ // See if the user actually wants us to do something.
+ if (!tor_fw_options.fetch_public_ip && !tor_fw_options.ports_to_forward) {
+ fprintf(stderr, "E: We require a port to be forwarded or "
+ "fetch_public_ip request!\n");
usage();
exit(1);
- } else {
- /* When we only have one ORPort, internal/external are
- set to be the same.*/
- if (!tor_fw_options.public_or_port && tor_fw_options.private_or_port) {
- if (tor_fw_options.verbose)
- fprintf(stdout, "V: We're setting public_or_port = "
- "private_or_port.\n");
- tor_fw_options.public_or_port = tor_fw_options.private_or_port;
- }
- }
- if (!tor_fw_options.private_dir_port) {
- if (tor_fw_options.verbose)
- fprintf(stdout, "V: We have no DirPort; no hole punching for "
- "DirPorts\n");
-
- } else {
- /* When we only have one DirPort, internal/external are
- set to be the same.*/
- if (!tor_fw_options.public_dir_port && tor_fw_options.private_dir_port) {
- if (tor_fw_options.verbose)
- fprintf(stdout, "V: We're setting public_or_port = "
- "private_or_port.\n");
-
- tor_fw_options.public_dir_port = tor_fw_options.private_dir_port;
- }
- }
-
- if (tor_fw_options.verbose) {
- fprintf(stdout, "V: pub or port = %u, priv or port = %u\n"
- "V: pub dir port = %u, priv dir port = %u\n",
- tor_fw_options.private_or_port, tor_fw_options.public_or_port,
- tor_fw_options.private_dir_port,
- tor_fw_options.public_dir_port);
}
// Initialize networking
- if (network_init())
+ if (tor_fw_helper_network_init())
exit(1);
// Initalize the various fw-helper backend helpers
r = init_backends(&tor_fw_options, &backend_state);
- if (r)
- printf("tor-fw-helper: %i NAT traversal helper(s) loaded\n", r);
-
- if (tor_fw_options.fetch_public_ip) {
- tor_fw_fetch_public_ip(&tor_fw_options, &backend_state);
+ if (!r) { // all backends failed:
+ // report our failure
+ report_full_fail(tor_fw_options.ports_to_forward);
+ fprintf(stderr, "tor-fw-helper: All backends failed.\n");
+ exit(1);
+ } else { // some backends succeeded:
+ fprintf(stderr, "tor-fw-helper: %i NAT traversal helper(s) loaded\n", r);
}
- if (tor_fw_options.private_or_port) {
- tor_fw_options.internal_port = tor_fw_options.private_or_port;
- tor_fw_options.external_port = tor_fw_options.private_or_port;
- tor_fw_add_or_port(&tor_fw_options, &backend_state);
+ // Forward TCP ports.
+ if (tor_fw_options.ports_to_forward) {
+ tor_fw_add_ports(&tor_fw_options, &backend_state);
}
- if (tor_fw_options.private_dir_port) {
- tor_fw_options.internal_port = tor_fw_options.private_dir_port;
- tor_fw_options.external_port = tor_fw_options.private_dir_port;
- tor_fw_add_dir_port(&tor_fw_options, &backend_state);
+ // Fetch our public IP.
+ if (tor_fw_options.fetch_public_ip) {
+ tor_fw_fetch_public_ip(&tor_fw_options, &backend_state);
}
- r = (((tor_fw_options.nat_pmp_status | tor_fw_options.upnp_status)
- |tor_fw_options.public_ip_status));
- if (r > 0) {
- fprintf(stdout, "tor-fw-helper: SUCCESS\n");
- } else {
- fprintf(stderr, "tor-fw-helper: FAILURE\n");
+ // Cleanup and exit.
+ if (tor_fw_options.ports_to_forward) {
+ SMARTLIST_FOREACH(tor_fw_options.ports_to_forward,
+ port_to_forward_t *, port,
+ tor_free(port));
+ smartlist_free(tor_fw_options.ports_to_forward);
}
exit(r);
diff --git a/src/tools/tor-fw-helper/tor-fw-helper.h b/src/tools/tor-fw-helper/tor-fw-helper.h
index 058afc4e0..0b0d17993 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper.h
+++ b/src/tools/tor-fw-helper/tor-fw-helper.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2012, The Tor Project, Inc. */
+ * Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -7,8 +7,8 @@
* \brief The main header for our firewall helper.
**/
-#ifndef _TOR_FW_HELPER_H
-#define _TOR_FW_HELPER_H
+#ifndef TOR_TOR_FW_HELPER_H
+#define TOR_TOR_FW_HELPER_H
#include <stdint.h>
#include <stdio.h>
@@ -17,24 +17,26 @@
#include <time.h>
/** The current version of tor-fw-helper. */
-#define tor_fw_version "0.1"
+#define tor_fw_version "0.2"
/** This is an arbitrary hard limit - We currently have two (NAT-PMP and UPnP).
We're likely going to add the Intel UPnP library but nothing else comes to
mind at the moment. */
#define MAX_BACKENDS 23
+/** Forward traffic received in port <b>external_port</b> in the
+ * external side of our NAT to <b>internal_port</b> in this host. */
+typedef struct {
+ uint16_t external_port;
+ uint16_t internal_port;
+} port_to_forward_t;
+
/** This is where we store parsed commandline options. */
typedef struct {
int verbose;
int help;
int test_commandline;
- uint16_t private_dir_port;
- uint16_t private_or_port;
- uint16_t public_dir_port;
- uint16_t public_or_port;
- uint16_t internal_port;
- uint16_t external_port;
+ struct smartlist_t *ports_to_forward;
int fetch_public_ip;
int nat_pmp_status;
int upnp_status;
@@ -50,8 +52,8 @@ typedef struct tor_fw_backend_t {
int (*init)(tor_fw_options_t *options, void *backend_state);
int (*cleanup)(tor_fw_options_t *options, void *backend_state);
int (*fetch_public_ip)(tor_fw_options_t *options, void *backend_state);
- int (*add_tcp_mapping)(tor_fw_options_t *options, void *backend_state);
+ int (*add_tcp_mapping)(uint16_t internal_port, uint16_t external_port,
+ int is_verbose, void *backend_state);
} tor_fw_backend_t;
-
#endif
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index c7ab8dc61..3809b22d4 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -82,10 +82,11 @@ crypto_log_errors(int severity, const char *doing)
if (!lib) lib = "(null)";
if (!func) func = "(null)";
if (doing) {
- log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
- doing, msg, lib, func);
+ tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
+ doing, msg, lib, func);
} else {
- log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", msg, lib, func);
+ tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)",
+ msg, lib, func);
}
}
}
@@ -227,7 +228,7 @@ generate_key(int bits)
crypto_pk_t *env = crypto_pk_new();
if (crypto_pk_generate_key_with_bits(env,bits)<0)
goto done;
- rsa = _crypto_pk_get_rsa(env);
+ rsa = crypto_pk_get_rsa_(env);
rsa = RSAPrivateKey_dup(rsa);
done:
crypto_pk_free(env);
@@ -401,7 +402,7 @@ static int
get_fingerprint(EVP_PKEY *pkey, char *out)
{
int r = 1;
- crypto_pk_t *pk = _crypto_new_pk_from_rsa(EVP_PKEY_get1_RSA(pkey));
+ crypto_pk_t *pk = crypto_new_pk_from_rsa_(EVP_PKEY_get1_RSA(pkey));
if (pk) {
r = crypto_pk_get_fingerprint(pk, out, 0);
crypto_pk_free(pk);
@@ -414,7 +415,7 @@ static int
get_digest(EVP_PKEY *pkey, char *out)
{
int r = 1;
- crypto_pk_t *pk = _crypto_new_pk_from_rsa(EVP_PKEY_get1_RSA(pkey));
+ crypto_pk_t *pk = crypto_new_pk_from_rsa_(EVP_PKEY_get1_RSA(pkey));
if (pk) {
r = crypto_pk_get_digest(pk, out);
crypto_pk_free(pk);
diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c
index 4ef84f491..306f6c66a 100644
--- a/src/tools/tor-resolve.c
+++ b/src/tools/tor-resolve.c
@@ -1,10 +1,9 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
- * Copyright (c) 2007-2012, The Tor Project, Inc.
+ * Copyright (c) 2007-2013, The Tor Project, Inc.
*/
/* See LICENSE for licensing information */
#include "orconfig.h"
-
#include "compat.h"
#include "../common/util.h"
#include "address.h"
@@ -74,23 +73,29 @@ build_socks_resolve_request(char **out,
memcpy((*out)+8+strlen(username)+1, hostname, strlen(hostname)+1);
} else if (version == 5) {
int is_ip_address;
- struct in_addr in;
+ tor_addr_t addr;
size_t addrlen;
- is_ip_address = tor_inet_aton(hostname, &in);
+ int ipv6;
+ is_ip_address = tor_addr_parse(&addr, hostname) != -1;
if (!is_ip_address && reverse) {
log_err(LD_GENERAL, "Tried to do a reverse lookup on a non-IP!");
return -1;
}
- addrlen = reverse ? 4 : 1 + strlen(hostname);
+ ipv6 = reverse && tor_addr_family(&addr) == AF_INET6;
+ addrlen = reverse ? (ipv6 ? 16 : 4) : 1 + strlen(hostname);
len = 6 + addrlen;
*out = tor_malloc(len);
(*out)[0] = 5; /* SOCKS version 5 */
(*out)[1] = reverse ? '\xF1' : '\xF0'; /* RESOLVE_PTR or RESOLVE */
(*out)[2] = 0; /* reserved. */
- (*out)[3] = reverse ? 1 : 3;
if (reverse) {
- set_uint32((*out)+4, in.s_addr);
+ (*out)[3] = ipv6 ? 4 : 1;
+ if (ipv6)
+ memcpy((*out)+4, tor_addr_to_in6_addr8(&addr), 16);
+ else
+ set_uint32((*out)+4, tor_addr_to_ipv4n(&addr));
} else {
+ (*out)[3] = 3;
(*out)[4] = (char)(uint8_t)(addrlen - 1);
memcpy((*out)+5, hostname, addrlen - 1);
}
@@ -109,7 +114,7 @@ build_socks_resolve_request(char **out,
static int
parse_socks4a_resolve_response(const char *hostname,
const char *response, size_t len,
- uint32_t *addr_out)
+ tor_addr_t *addr_out)
{
uint8_t status;
tor_assert(response);
@@ -140,7 +145,7 @@ parse_socks4a_resolve_response(const char *hostname,
return -1;
}
- *addr_out = ntohl(get_uint32(response+4));
+ tor_addr_from_ipv4n(addr_out, get_uint32(response+4));
return 0;
}
@@ -179,9 +184,9 @@ socks5_reason_to_string(char reason)
static int
do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
int reverse, int version,
- uint32_t *result_addr, char **result_hostname)
+ tor_addr_t *result_addr, char **result_hostname)
{
- int s;
+ int s = -1;
struct sockaddr_in socksaddr;
char *req = NULL;
ssize_t len = 0;
@@ -190,7 +195,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
tor_assert(result_addr);
tor_assert(version == 4 || version == 5);
- *result_addr = 0;
+ tor_addr_make_unspec(result_addr);
*result_hostname = NULL;
s = tor_open_socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
@@ -205,28 +210,28 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
socksaddr.sin_addr.s_addr = htonl(sockshost);
if (connect(s, (struct sockaddr*)&socksaddr, sizeof(socksaddr))) {
log_sock_error("connecting to SOCKS host", s);
- return -1;
+ goto err;
}
if (version == 5) {
char method_buf[2];
if (write_all(s, "\x05\x01\x00", 3, 1) != 3) {
log_err(LD_NET, "Error sending SOCKS5 method list.");
- return -1;
+ goto err;
}
if (read_all(s, method_buf, 2, 1) != 2) {
log_err(LD_NET, "Error reading SOCKS5 methods.");
- return -1;
+ goto err;
}
if (method_buf[0] != '\x05') {
log_err(LD_NET, "Unrecognized socks version: %u",
(unsigned)method_buf[0]);
- return -1;
+ goto err;
}
if (method_buf[1] != '\x00') {
log_err(LD_NET, "Unrecognized socks authentication method: %u",
(unsigned)method_buf[1]);
- return -1;
+ goto err;
}
}
@@ -234,12 +239,12 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
version))<0) {
log_err(LD_BUG,"Error generating SOCKS request");
tor_assert(!req);
- return -1;
+ goto err;
}
if (write_all(s, req, len, 1) != len) {
log_sock_error("sending SOCKS request", s);
tor_free(req);
- return -1;
+ goto err;
}
tor_free(req);
@@ -247,22 +252,22 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
char reply_buf[RESPONSE_LEN_4];
if (read_all(s, reply_buf, RESPONSE_LEN_4, 1) != RESPONSE_LEN_4) {
log_err(LD_NET, "Error reading SOCKS4 response.");
- return -1;
+ goto err;
}
if (parse_socks4a_resolve_response(hostname,
reply_buf, RESPONSE_LEN_4,
result_addr)<0) {
- return -1;
+ goto err;
}
} else {
- char reply_buf[4];
+ char reply_buf[16];
if (read_all(s, reply_buf, 4, 1) != 4) {
log_err(LD_NET, "Error reading SOCKS5 response.");
- return -1;
+ goto err;
}
if (reply_buf[0] != 5) {
log_err(LD_NET, "Bad SOCKS5 reply version.");
- return -1;
+ goto err;
}
/* Give a user some useful feedback about SOCKS5 errors */
if (reply_buf[1] != 0) {
@@ -276,32 +281,44 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
"to Tor; we suggest an application that uses SOCKS 4a.",
hostname);
}
- return -1;
+ goto err;
}
if (reply_buf[3] == 1) {
/* IPv4 address */
if (read_all(s, reply_buf, 4, 1) != 4) {
log_err(LD_NET, "Error reading address in socks5 response.");
- return -1;
+ goto err;
+ }
+ tor_addr_from_ipv4n(result_addr, get_uint32(reply_buf));
+ } else if (reply_buf[3] == 4) {
+ /* IPv6 address */
+ if (read_all(s, reply_buf, 16, 1) != 16) {
+ log_err(LD_NET, "Error reading address in socks5 response.");
+ goto err;
}
- *result_addr = ntohl(get_uint32(reply_buf));
+ tor_addr_from_ipv6_bytes(result_addr, reply_buf);
} else if (reply_buf[3] == 3) {
+ /* Domain name */
size_t result_len;
if (read_all(s, reply_buf, 1, 1) != 1) {
log_err(LD_NET, "Error reading address_length in socks5 response.");
- return -1;
+ goto err;
}
result_len = *(uint8_t*)(reply_buf);
*result_hostname = tor_malloc(result_len+1);
if (read_all(s, *result_hostname, result_len, 1) != (int) result_len) {
log_err(LD_NET, "Error reading hostname in socks5 response.");
- return -1;
+ goto err;
}
(*result_hostname)[result_len] = '\0';
}
}
+ tor_close_socket(s);
return 0;
+ err:
+ tor_close_socket(s);
+ return -1;
}
/** Print a usage message and exit. */
@@ -322,10 +339,8 @@ main(int argc, char **argv)
int isSocks4 = 0, isVerbose = 0, isReverse = 0;
char **arg;
int n_args;
- struct in_addr a;
- uint32_t result = 0;
+ tor_addr_t result;
char *result_hostname = NULL;
- char buf[INET_NTOA_BUF_LEN];
log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
init_logging();
@@ -423,9 +438,7 @@ main(int argc, char **argv)
if (result_hostname) {
printf("%s\n", result_hostname);
} else {
- a.s_addr = htonl(result);
- tor_inet_ntoa(&a, buf, sizeof(buf));
- printf("%s\n", buf);
+ printf("%s\n", fmt_addr(&result));
}
return 0;
}
diff --git a/src/win32/Makefile.am b/src/win32/Makefile.am
deleted file mode 100644
index 7f5d74248..000000000
--- a/src/win32/Makefile.am
+++ /dev/null
@@ -1,3 +0,0 @@
-
-EXTRA_DIST = orconfig.h
-
diff --git a/src/win32/include.am b/src/win32/include.am
new file mode 100644
index 000000000..dad59af3a
--- /dev/null
+++ b/src/win32/include.am
@@ -0,0 +1,3 @@
+
+EXTRA_DIST+= src/win32/orconfig.h
+
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index d780d5d73..f5d5cf446 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -145,9 +145,15 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
+/* Define to 1 if you have the `_vscprintf' function. */
+#define HAVE__VSCPRINTF 1
+
/* Define to 1 iff NULL is represented by a 0 in memory. */
#define NULL_REP_IS_ZERO_BYTES 1
+/* Define to 1 iff memset(0) sets doubles to 0.0 */
+#define DOUBLE_0_REP_IS_ZERO_BYTES 1
+
/* Name of package */
#define PACKAGE "tor"
@@ -190,6 +196,9 @@
/* The size of a `long long', as computed by sizeof. */
#undef SIZEOF_LONG_LONG
+/* The size of `pid_t', as computed by sizeof. */
+#define SIZEOF_PID_T 0
+
/* The size of a `short', as computed by sizeof. */
#define SIZEOF_SHORT 2
@@ -232,7 +241,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.2.3.18-rc-dev"
+#define VERSION "0.2.4.10-alpha-dev"
@@ -242,3 +251,9 @@
#define FLEXIBLE_ARRAY_MEMBER 0
#define HAVE_EVENT2_EVENT_H
#define SHARE_DATADIR ""
+#define HAVE_EVENT2_DNS_H
+#define HAVE_EVENT_BASE_LOOPEXIT
+#define CURVE25519_ENABLED
+#define USE_CURVE25519_DONNA
+
+#define ENUM_VALS_ARE_SIGNED 1
diff --git a/tor.spec.in b/tor.spec.in
deleted file mode 100644
index b452c9bb3..000000000
--- a/tor.spec.in
+++ /dev/null
@@ -1,360 +0,0 @@
-## NOTE: tor.spec is autogenerated from tor.spec.in . Edit the latter,
-## not the former.
-
-## Things that need to be edited frequently
-#
-# This should be incremented whenever the spec file changes, but
-# can drop back to zero at a new Tor version
-
-%define specver 1
-
-## Things users may want to change
-#
-# User (and group) name under which the Tor daemon runs.
-
-%define toruser @TORUSER@
-%define torgroup @TORGROUP@
-
-## Version song and dance
-#
-# This should be the Tor version number, as it appears on the tarball,
-# including any "pre<x>" or "rc<y>" suffix. This gets massaged to
-# create the RPM version number, in a way that depends on the Tor
-# numbering scheme.
-%define native_version @VERSION@
-
-%define version %(echo %{native_version} | sed -e 's/-/./g')
-
-## Define output filename
-#
-# This creates filenames based upon the value of target_cpu defined above
-
-## Release and OS identification song and dance
-#
-# This identifies the lineage of the spec file. This file is the
-# standard one that comes with Tor; various distributions may
-# have their own ideas about the right ways to do things.
-%define pkgspec tor
-
-# This spec is intended to build and install on multiple distributions
-# (someday). Detect the distribution we're building on.
-
-%define is_rh %(test -e /etc/redhat-release && echo 1 || echo 0)
-%define is_fc %(test -e /etc/fedora-release && echo 1 || echo 0)
-%define is_mdk %(test -e /etc/mandrake-release && echo 1 || echo 0)
-%define is_suse %(test -e /etc/SuSE-release && echo 1 || echo 0)
-%define is_rfl %(test -e /etc/redflag-release && echo 1 || echo 0)
-
-%if %{is_fc}
-%define ostag %(sed -e 's/^.*release /fc/' -e 's/ .*$//' -e 's/\\./_/g' < /etc/fedora-release)
-%endif
-
-%if %{is_rh}
-%define ostag %(sed -e 's/^.*release /rh/' -e 's/ .*$//' -e 's/\\./_/g' < /etc/redhat-release)
-%endif
-
-%if %{is_mdk}
-%define ostag mdk
-%endif
-
-%if %{is_suse}
-%define ostag suse%(grep openSUSE /etc/SuSE-release | awk '{print $2}' | sed -e 's/\\./_/')
-%endif
-
-%if %{is_rfl}
-%define ostag %(sed -e 's/^.*Desktop /redflag/' -e 's/ .*$//' -e 's/\\./_/g' < /etc/redflag-release)
-%endif
-
-# Using the build date ensures that every build really does get
-# a different release number. We use this trick for CVS versions.
-# For release versions, we don't want or need it.
-%define is_dev_version %(echo %{native_version} | grep 'dev' > /dev/null && echo 1 || echo 0)
-
-%if %{is_dev_version}
-%define blddate %(date -u +"%Y%m%d%H%M")
-%define release %{pkgspec}.%{specver}.%{ostag}.%{blddate}
-%else
-%define release %{pkgspec}.%{specver}.%{ostag}
-%endif
-
-## General-purpose macros
-#
-# Some systems don't have some macros. If a macro doesn't seem
-# to exist on your system, add it here...
-
-%if %{!?__make:1}%{?__make:0}
-%define __make make
-%endif
-
-%if %{!?make:1}%{?make:0}
-%define make %{__make}
-%endif
-
-%if %{!?_localstatedir:1}%{?_localstatedir:0}
-%define _localstatedir @LOCALSTATEDIR@
-%endif
-
-## Package information
-#
-Name: tor
-Version: %{version}
-Release: %{release}
-
-Summary: Anonymizing overlay network for TCP (The onion router)
-URL: https://www.torproject.org/
-Group: System Environment/Daemons
-
-License: 3-clause BSD
-Vendor: The Tor Project (https://torproject.org)
-Packager: Erinn Clark <erinn@torproject.org>
-
-Requires: openssl >= 0.9.7, libevent >= 1.4.13
-BuildRequires: openssl-devel >= 0.9.7, libevent-devel >= 1.4.13, asciidoc
-
-# Fedora 16 and RHEL 5 have following conflicting packages according to rpm search
-%if %{is_rh}
-Conflicts: tor-core, tor-lsb, tor-upstart
-%endif
-
-Requires(pre): /usr/bin/id, /bin/date, /bin/sh
-Requires(pre): %{_sbindir}/useradd, %{_sbindir}/groupadd
-
-Source0: https://www.torproject.org/dist/%{name}-%{native_version}.tar.gz
-
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
-
-%description
-Tor is a connection-based low-latency anonymous communication system.
-
-This package provides the "tor" program, which serves as both a client and
-a relay node. Scripts will automatically create a "%{toruser}" user and
-a "%{torgroup}" group, and set tor up to run as a daemon when the system
-is rebooted.
-
-Applications connect to the local Tor proxy using the SOCKS
-protocol. The tor client chooses a path through a set of relays, in
-which each relay knows its predecessor and successor, but no
-others. Traffic flowing down the circuit is unwrapped by a symmetric
-key at each relay, which reveals the downstream relay.
-
-Warnings: Tor does no protocol cleaning. That means there is a danger
-that application protocols and associated programs can be induced to
-reveal information about the initiator. Tor depends on Privoxy or
-similar protocol cleaners to solve this problem. This is alpha code,
-and is even more likely than released code to have anonymity-spoiling
-bugs. The present network is small -- this further reduces the
-strength of the anonymity provided. Tor is not presently suitable
-for high-stakes anonymity.
-
-%prep
-%setup -q -n %{name}-%{native_version}
-
-%build
-%if %{is_suse}
-%configure --with-tor-user=%{toruser} --with-tor-group=%{torgroup} --docdir=%{_docdir}/%{name}
-%else
-%configure --with-tor-user=%{toruser} --with-tor-group=%{torgroup}
-%endif
-%make
-
-%install
-%makeinstall
-
-# Install init script and control script
-%__mkdir_p ${RPM_BUILD_ROOT}%{_initrddir}
-%if %{is_suse}
-%__install -p -m 755 contrib/suse/tor.sh ${RPM_BUILD_ROOT}%{_initrddir}/%{name}
-%else
-%__install -p -m 755 contrib/tor.sh ${RPM_BUILD_ROOT}%{_initrddir}/%{name}
-%endif
-%__install -p -m 755 contrib/torctl ${RPM_BUILD_ROOT}%{_bindir}
-
-# Set up config file; "sample" file implements a basic user node.
-%__install -p -m 644 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/torrc.sample ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/torrc
-
-# Install the logrotate control file.
-%__mkdir_p -m 755 ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d
-%__install -p -m 644 contrib/tor.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}
-
-# Directories that don't have any preinstalled files
-%__mkdir_p -m 700 ${RPM_BUILD_ROOT}%{_localstatedir}/lib/%{name}
-%__mkdir_p -m 755 ${RPM_BUILD_ROOT}%{_localstatedir}/run/%{name}
-%__mkdir_p -m 755 ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}
-%__mkdir_p -m 700 ${RPM_BUILD_ROOT}%{_localstatedir}/tmp/%{name}
-
-%clean
-[ "${RPM_BUILD_ROOT}" != "/" ] && rm -rf ${RPM_BUILD_ROOT}
-
-# These scripts are probably wrong for Mandrake or SuSE. They're certainly
-# wrong for Debian, but what are you doing using RPM on Debian?
-
-%pre
-
-# If tor is already installed and running (whether installed by RPM
-# or not), then kill it, but remember that it was running.
-%__rm -f /%{_localstatedir}/tmp/${name}-was-running-%{version}-%{release}
-if [ -f %{_initrddir}/%{name} ] && /sbin/service %{name} status ; then
- /sbin/service %{name} stop
- touch /%{_localstatedir}/tmp/${name}-was-running-%{version}-%{release}
-fi
-
-#
-# Create a user and group if need be
-#
-if [ ! -n "`/usr/bin/id -g %{torgroup} 2>/dev/null`" ]; then
- # One would like to default the GID, but doing that properly would
- # require thought.
- %{_sbindir}/groupadd %{torgroup} 2> /dev/null
-fi
-if [ ! -n "`/usr/bin/id -u %{toruser} 2>/dev/null`" ]; then
- # One would also like to default the UID, but doing that properly would
- # also require thought.
- if [ -x %{_sbindir}/nologin ]; then
- %{_sbindir}/useradd -r -g %{torgroup} -d %{_localstatedir}/lib/%{name} -s %{_sbindir}/nologin %{toruser} 2> /dev/null
- else
- %{_sbindir}/useradd -r -g %{torgroup} -d %{_localstatedir}/lib/%{name} -s /bin/false %{toruser} 2> /dev/null
- fi
-fi
-exit 0
-
-%post
-
-# If this is a new installation, use chkconfig to put tor in the
-# default set of runlevels. If it's an upgrade, leave the existing
-# configuration alone.
-if [ $1 -eq 1 ]; then
- /sbin/chkconfig --add %{name}
- /sbin/chkconfig %{name} on
-fi
-
-# Older tor RPMS used a different username for the tor daemon.
-# Make sure the runtime data have the right ownership.
-%__chown -R %{toruser}.%{torgroup} %{_localstatedir}/{lib,log,run}/%{name}
-
-if [ -f /%{_localstatedir}/tmp/${name}-was-running-%{version}-%{release} ]; then
- /sbin/service %{name} start
- %__rm -f /%{_localstatedir}/tmp/${name}-was-running-%{version}-%{release}
-fi
-exit 0
-
-%preun
-
-# If no instances of tor will be installed when we're done, make
-# sure that it gets killed. We *don't* want to kill it or delete
-# any of its data on uninstall if it's being upgraded to a new
-# version, because the new version will actually already have
-# been installed and started before the uninstall script for
-# the old version is run, and we'd end up hosing it.
-if [ $1 -le 0 ]; then
- if [ -f %{_initrddir}/%{name} ] && /sbin/service %{name} status ; then
- /sbin/service %{name} stop
- fi
- %/sbin/chkconfig --del %{name}
- %__rm -f ${_localstatedir}/lib/%{name}/cached-directory
- %__rm -f ${_localstatedir}/lib/%{name}/bw_accounting
- %__rm -f ${_localstatedir}/lib/%{name}/control_auth_cookie
- %__rm -f ${_localstatedir}/lib/%{name}/router.desc
- %__rm -f ${_localstatedir}/lib/%{name}/fingerprint
-fi
-exit 0
-
-%files
-%defattr(-,root,root)
-%if %{is_suse}
-%doc INSTALL LICENSE README ChangeLog doc/HACKING doc/TODO doc/*html
-%endif
-%doc INSTALL LICENSE README ChangeLog doc/HACKING doc/TODO
-%{_mandir}/man*/*
-%{_bindir}/tor
-%{_bindir}/torctl
-%{_bindir}/torify
-%{_bindir}/tor-resolve
-%{_bindir}/tor-gencert
-%if %{is_suse}
-%else
-%{_docdir}/*
-%endif
-%{_datadir}/tor/geoip
-%config %{_initrddir}/%{name}
-%config(noreplace) %attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}
-%dir %attr(0755,root,%{torgroup}) %{_sysconfdir}/%{name}/
-%config(noreplace) %attr(0644,root,%{torgroup}) %{_sysconfdir}/%{name}/*
-%attr(0700,%{toruser},%{torgroup}) %dir %{_localstatedir}/lib/%{name}
-%attr(0750,%{toruser},%{torgroup}) %dir %{_localstatedir}/run/%{name}
-%attr(0750,%{toruser},%{torgroup}) %dir %{_localstatedir}/log/%{name}
-
-%changelog
-* Thu Jun 21 2012 Ondrej Mikle <ondrej.mikle@gmail.com>
-- fixed to work with both rpmbuild and mock on RHEL/Fedora
-- removed unnecessary files from rpm such as .git repo
-- fixed build dependencies and package conflicts
-- fixed creating _tor user on Fedora 17 (ancient typo)
-- added/updated build instructions for RPM creation
-- confirmed to build and run on EL5, EL6, Fedora 16/17, OpenSuse 12.1
-
-* Fri Aug 20 2010 Erinn Clark <erinn@torproject.org>
-- add conflicts for Fedora packages
-- add logic for SuSE since it requires special doc handling
-
-* Mon Feb 22 2010 Erinn Clark <erinn@torproject.org>
-- remove AUTHORS from %doc line since it no longer exists upstream
-- switch maintainers
-
-* Fri May 01 2009 Andrew Lewman <andrew@torproject.org>
-- clean up distro detection and remove dead comment blocks
-
-* Sun Feb 22 2009 Andrew Lewman <andrew@torproject.org>
-- update the description, vendor, and packager
-
-* Thu Sep 11 2008 Andrew Lewman <phobos@rootme.org>
-- See r16867
-- http://archives.seul.org/or/cvs/Sep-2008/msg00156.html
-
-* Tue Feb 27 2007 Andrew Lewman <phobos@rootme.org>
-- Fix a potential race condition in how we determine the running state of tor. Found by Stefan Nordhausen.
-- see OR-CVS for details
-
-* Fri May 26 2006 Andrew Lewman <phobos@rootme.org>
-- Add in a few "SUSEisms" to make dist-rpm actually work on suse
-- Turn Tor "on" via chkconfig
-- Update -mcpu to -mtune to make GCC happy
-- see OR-CVS for details
-
-* Tue Mar 28 2006 Andrew Lewman <phobos@rootme.org>
-- converted to build the specified target cpu and arch
-- override related rpm macros to build correctly
-- see OR-CVS for details
-
-* Mon Jan 17 2005 John Bashinski <jbash@velvet.com>
-- Take runtime user and group names from configure system. Default
- user/group names are now "_tor"; blame Roger...
-- Make logrotate control file a separate file in the source distribution,
- rather than creating it from the spec file.
-- Properly handle the order in which RPM executes scriptlets on upgrade.
- The old code would kill the daemon on upgrade.
-- Start the tor daemon after installation if and only if it was
- running before installation. Preserve runlevel setup on upgrade.
-- Package the torctl script; the init script is now a wrapper around it.
-
-* Tue Nov 5 2004 John Bashinski <jbash@velvet.com>
-- Add skeletal support for multiple distributions
-- Even more ridiculous level of macro-ization
-- Modify version numbers so RPM can determine when it has a newer version
-- Return to including distribution name in package release number
-- Sharply trim description
-- Change user/group name from "tor" to "tordmn"; "tor" is a common
- given name (reported by Marius Hjelle)
-- Change group to "System Environment/Daemons" (suggested by Marius Hjelle)
-- Create logrotate file (suggested by Marius Hjelle)
-- Make Tor run as a user proxy by default (suggested by Marius Hjelle)
-- Autogenerate spec file from GNU autotools data, substituting version
- and whatnot
-- Be perhaps excessively paranoid with config file and directory modes
-- Remove auto-start and auto-stop at installation time; there's some kind
- of weird race going on, and it's arguably a bad thing anyway.
-
-* Mon Jun 06 2004 Nick Mathewson <nickm@freehaven.net> 0.0.7-0.std.0.1.rc2
-- Make spec file more happy with fc2 packaging
-
-* Sat Jan 17 2004 John Bashinski <jbash@velvet.com>
-- Basic spec file; tested with Red Hat 9.