commit cd9f82fbbe6ec4205fa3c8695cd277a03da39833
Author: juga0 <juga(a)riseup.net>
Date: Mon Feb 8 15:04:58 2021 +0000
fix: relaylist: Remove duplicated can exit methods
After refactoring and making clear when we were using exit(s) that can
exit to all public IPs (and a port) or only some, refactor them
removing the duplicated code and adding the `strict` argument.
---
sbws/core/scanner.py | 8 ++--
sbws/lib/relaylist.py | …
[View More]64 +++++++++++--------------------
tests/integration/lib/test_destination.py | 6 +--
3 files changed, 29 insertions(+), 49 deletions(-)
diff --git a/sbws/core/scanner.py b/sbws/core/scanner.py
index 1499264..903f09f 100644
--- a/sbws/core/scanner.py
+++ b/sbws/core/scanner.py
@@ -215,7 +215,7 @@ def _pick_ideal_second_hop(relay, dest, rl, cont, is_exit):
# In the case that a concrete exit can't exit to the Web server, it is not
# a problem since the relay will be measured in the next loop with other
# random exit.
- candidates = rl.exits_not_bad_allowing_port_some_ips(dest.port) \
+ candidates = rl.exits_not_bad_allowing_port(dest.port) \
if is_exit else rl.non_exits
if not len(candidates):
return None
@@ -340,7 +340,7 @@ def measure_relay(args, conf, destinations, cb, rl, relay):
# exit, then pick a non-exit. Otherwise pick an exit.
# Instead of ensuring that the relay can exit to all IPs, try first with
# the relay as an exit, if it can exit to some IPs.
- if relay.is_exit_not_bad_allowing_port_some_ips(dest.port):
+ if relay.is_exit_not_bad_allowing_port(dest.port):
circ_fps, nicknames = create_path_relay_as_exit(relay, dest, rl, cb)
else:
circ_fps, nicknames = create_path_relay_as_entry(relay, dest, rl, cb)
@@ -365,7 +365,7 @@ def measure_relay(args, conf, destinations, cb, rl, relay):
# to the Web server, try again using it as entry, to avoid that it would
# always fail when there's only one Web server.
if not is_usable and \
- relay.is_exit_not_bad_allowing_port_all_ips(dest.port):
+ relay.is_exit_not_bad_allowing_port(dest.port):
log.info(
"Exit %s (%s) that can't exit all ips failed to connect to "
" %s via circuit %s (%s). Trying again with it as entry.",
@@ -377,7 +377,7 @@ def measure_relay(args, conf, destinations, cb, rl, relay):
"Exit %s (%s) that can't exit all ips, failed to create "
" circuit as entry: %s (%s).", relay.fingerprint,
relay.nickname, circ_fps, nicknames)
- return error_no_circuit(relay, circ_fps, nicknames, reason, dest,
+ return error_no_circuit(circ_fps, nicknames, reason, relay, dest,
our_nick)
log.debug('Built circuit with path %s (%s) to measure %s (%s)',
diff --git a/sbws/lib/relaylist.py b/sbws/lib/relaylist.py
index 3ff1f73..9c6d12a 100644
--- a/sbws/lib/relaylist.py
+++ b/sbws/lib/relaylist.py
@@ -178,21 +178,32 @@ class Relay:
"""Number of times the relay was in a conensus."""
return len(self.relay_in_recent_consensus)
- def can_exit_to_port_all_ips(self, port):
+ def can_exit_to_port(self, port, strict=False):
"""
Returns True if the relay has an exit policy and the policy accepts
- exiting to the given portself or False otherwise.
+ exiting to the given port or False otherwise.
+
+ If ``strict`` is true, it only returns the exits that can exit to all
+ IPs and that port.
The exits that are IPv6 only or IPv4 but rejecting some public networks
will return false.
On July 2020, there were 67 out of 1095 exits like this.
+
+ If ``strict`` is false, it returns any exit that can exit to some
+ public IPs and that port.
+
+ Note that the EXIT flag exists when the relay can exit to 443 **and**
+ 80. Currently all Web servers are using 443, so it would not be needed
+ to check the EXIT flag too, using this function.
+
"""
assert isinstance(port, int)
# if dind't get the descriptor, there isn't exit policy
# When the attribute is gotten in getattr(self._desc, "exit_policy"),
# is possible that stem's _input_rules is None and raises an exception
# (#29899):
- # File "/usr/lib/python3/dist-packages/sbws/lib/relaylist.py", line 117, in can_exit_to_port_all_ips # noqa
+ # File "/usr/lib/python3/dist-packages/sbws/lib/relaylist.py", line 117, in can_exit_to_port # noqa
# if not self.exit_policy:
# File "/usr/lib/python3/dist-packages/stem/exit_policy.py", line 512, in __len__ # noqa
# return len(self._get_rules())
@@ -202,50 +213,23 @@ class Relay:
# Therefore, catch the exception here.
try:
if self.exit_policy:
- # Using `strict` to ensure it can exit to ALL domains
- # and ips and that port. See #40006.
# Using `strip_private` to ignore reject rules to private
# networks.
- # We could increase the chances that the exit can exit
- # checking IPv6 with:
- # ``or self.exit_policy_v6.can_exit_to(port=443, strict=True)``
- # But if it can still not exit to our Web server, then we
- # should retry to measure it as entry.
- return (
- self.exit_policy.strip_private()
- .can_exit_to(port=port, strict=True)
- )
- except TypeError:
- return False
- return False
-
- def can_exit_to_port_some_ips(self, port):
- """
- Returns True if the relay has an exit policy and the policy accepts
- exiting to the given port and some public IPs or False otherwise.
- """
- assert isinstance(port, int)
- try:
- if self.exit_policy:
- # Not using argument `strict`, to know whether it can exit
- # some public IPs, though not all.
+ # When ``strict`` is true, We could increase the chances that
+ # the exit can exit via IPv6 too (``exit_policy_v6``). However,
+ # in theory that is only known using microdescriptors.
return (
self.exit_policy.strip_private()
- .can_exit_to(port=port)
+ .can_exit_to(port=port, strict=strict)
)
except TypeError:
return False
return False
- def is_exit_not_bad_allowing_port_all_ips(self, port):
+ def is_exit_not_bad_allowing_port(self, port, strict=False):
return (Flag.BADEXIT not in self.flags and
Flag.EXIT in self.flags and
- self.can_exit_to_port_all_ips(port))
-
- def is_exit_not_bad_allowing_port_some_ips(self, port):
- return (Flag.BADEXIT not in self.flags and
- Flag.EXIT in self.flags and
- self.can_exit_to_port_some_ips(port))
+ self.can_exit_to_port(port, strict))
def increment_relay_recent_measurement_attempt(self):
"""
@@ -476,13 +460,9 @@ class RelayList:
"""Number of times a new consensus was obtained."""
return len(self._recent_consensus)
- def exits_not_bad_allowing_port_all_ips(self, port):
- return [r for r in self.exits
- if r.is_exit_not_bad_allowing_port_all_ips(port)]
-
- def exits_not_bad_allowing_port_some_ips(self, port):
+ def exits_not_bad_allowing_port(self, port, strict=False):
return [r for r in self.exits
- if r.is_exit_not_bad_allowing_port_some_ips(port)]
+ if r.is_exit_not_bad_allowing_port(port, strict)]
def increment_recent_measurement_attempt(self):
"""
diff --git a/tests/integration/lib/test_destination.py b/tests/integration/lib/test_destination.py
index d305b0e..98ed89f 100644
--- a/tests/integration/lib/test_destination.py
+++ b/tests/integration/lib/test_destination.py
@@ -26,7 +26,7 @@ def test_connect_to_destination_over_circuit_success(persistent_launch_tor,
relay = [r for r in rl.relays
if r.nickname == 'relay1mbyteMAB'][0]
# Choose an exit, for this test it does not matter the bandwidth
- helper = rl.exits_not_bad_allowing_port_some_ips(destination.port)[0]
+ helper = rl.exits_not_bad_allowing_port(destination.port)[0]
circuit_path = [relay.fingerprint, helper.fingerprint]
# build a circuit
circuit_id, _ = cb.build_circuit(circuit_path)
@@ -46,7 +46,7 @@ def test_connect_to_destination_over_circuit_fail(persistent_launch_tor,
relay = [r for r in rl.relays
if r.nickname == 'relay1mbyteMAB'][0]
# Choose an exit, for this test it does not matter the bandwidth
- helper = rl.exits_not_bad_allowing_port_some_ips(bad_destination.port)[0]
+ helper = rl.exits_not_bad_allowing_port(bad_destination.port)[0]
circuit_path = [relay.fingerprint, helper.fingerprint]
# Build a circuit.
circuit_id, _ = cb.build_circuit(circuit_path)
@@ -75,7 +75,7 @@ def test_functional_destinations(conf, cb, rl, persistent_launch_tor):
relay = [r for r in rl.relays
if r.nickname == 'relay1mbyteMAB'][0]
# Choose an exit, for this test it does not matter the bandwidth
- helper = rl.exits_not_bad_allowing_port_some_ips(bad_destination.port)[0]
+ helper = rl.exits_not_bad_allowing_port(bad_destination.port)[0]
circuit_path = [relay.fingerprint, helper.fingerprint]
# Build a circuit.
circuit_id, _ = cb.build_circuit(circuit_path)
[View Less]
commit 50377680448d66bc95a09fc5333da9465bd1b791
Author: juga0 <juga(a)riseup.net>
Date: Mon Feb 8 16:24:11 2021 +0000
fix: scanner: remove relay to measure as helper
---
sbws/core/scanner.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/sbws/core/scanner.py b/sbws/core/scanner.py
index c7ee1ee..40e3093 100644
--- a/sbws/core/scanner.py
+++ b/sbws/core/scanner.py
@@ -219,6 +219,12 @@ def _pick_ideal_second_hop(relay, dest, rl, cont, is_exit):
if is_exit else rl.…
[View More]non_exits
if not len(candidates):
return None
+ # In the case the helper is an exit, the entry could be an exit too
+ # (#40041), so ensure the helper is not the same as the entry, likely to
+ # happen in a test network.
+ if is_exit:
+ candidates = [c for c in candidates
+ if c.fingerprint != relay.fingerprint]
min_relay_bw = rl.exit_min_bw() if is_exit else rl.non_exit_min_bw()
log.debug('Picking a 2nd hop to measure %s from %d choices. is_exit=%s',
relay.nickname, len(candidates), is_exit)
[View Less]
commit 294fc29786c47fbffac62cbbebdfad3186906fe3
Author: juga0 <juga(a)riseup.net>
Date: Tue Feb 2 13:07:57 2021 +0000
minor: scanner: Change logic creating the path
When the relay is not an exit, instead of choosing exits that can
exit to all IPs, try with exits that can exit to some IPs, since the
relay will be measured again with a different exit in other loop.
When the relay is an exit, instead of ensuring it can exit all IPs, try
using it as exit …
[View More]if it can exit to some IPs.
If it fails connecting to the Web server, then try a 2nd time using it
as entry to avoid that it will fail in all loops if there is only one
Web server, cause it will be used again as an exit.
Also, the helper exits don't need to be able to exit all IPs. When a
helper exit fails to exit (maybe cause it can not exit to the Web
sever IP), it's not a problem cause in a next loop other exit will be
choosen.
This change of logic also solves the bug where non exits were being
used as exits, because we were trying to measure again a relay that
was used as entry, because it could not exit all IPs, which includes
also the non exits.
Closes: #40041.
---
sbws/core/scanner.py | 50 ++++++++++++++++++++++++-------
tests/integration/lib/test_destination.py | 6 ++--
2 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/sbws/core/scanner.py b/sbws/core/scanner.py
index aa17452..1499264 100644
--- a/sbws/core/scanner.py
+++ b/sbws/core/scanner.py
@@ -209,8 +209,14 @@ def _pick_ideal_second_hop(relay, dest, rl, cont, is_exit):
destination **dest**, pick a second relay that is or is not an exit
according to **is_exit**.
'''
- candidates = rl.exits_not_bad_allowing_port_all_ips(dest.port) if is_exit \
- else rl.non_exits
+ # 40041: Instead of using exits that can exit to all IPs, to ensure that
+ # they can make requests to the Web servers, try with the exits that
+ # allow some IPs, since there're more.
+ # In the case that a concrete exit can't exit to the Web server, it is not
+ # a problem since the relay will be measured in the next loop with other
+ # random exit.
+ candidates = rl.exits_not_bad_allowing_port_some_ips(dest.port) \
+ if is_exit else rl.non_exits
if not len(candidates):
return None
min_relay_bw = rl.exit_min_bw() if is_exit else rl.non_exit_min_bw()
@@ -332,20 +338,20 @@ def measure_relay(args, conf, destinations, cb, rl, relay):
# Pick a relay to help us measure the given relay. If the given relay is an
# exit, then pick a non-exit. Otherwise pick an exit.
- if relay.is_exit_not_bad_allowing_port_all_ips(dest.port):
+ # Instead of ensuring that the relay can exit to all IPs, try first with
+ # the relay as an exit, if it can exit to some IPs.
+ if relay.is_exit_not_bad_allowing_port_some_ips(dest.port):
circ_fps, nicknames = create_path_relay_as_exit(relay, dest, rl, cb)
else:
circ_fps, nicknames = create_path_relay_as_entry(relay, dest, rl, cb)
# Build the circuit
circ_id, reason = cb.build_circuit(circ_fps)
- if not circ_id and relay.fingerprint == circ_fps[0]:
- # We detected that some exits fail to build circuits as 1st hop.
- # If that's the case, try again using them as 2nd hop.
- # We could reuse the helper, but it does not need to be an exit now,
- # so choose other again.
- create_path_relay_as_exit(relay, dest, rl, cb)
- circ_id, reason = cb.build_circuit(circ_fps)
+
+ # If the circuit failed to get created, bad luck, it will be created again
+ # with other helper.
+ # Here we won't have the case that an exit tried to build the circuit as
+ # entry and failed (#40029), cause not checking that it can exit all IPs.
if not circ_id:
return error_no_circuit(circ_fps, nicknames, reason, relay, dest,
our_nick)
@@ -354,6 +360,30 @@ def measure_relay(args, conf, destinations, cb, rl, relay):
# Make a connection to the destination
is_usable, usable_data = connect_to_destination_over_circuit(
dest, circ_id, s, cb.controller, dest._max_dl)
+
+ # In the case that the relay was used as an exit, but could not exit
+ # to the Web server, try again using it as entry, to avoid that it would
+ # always fail when there's only one Web server.
+ if not is_usable and \
+ relay.is_exit_not_bad_allowing_port_all_ips(dest.port):
+ log.info(
+ "Exit %s (%s) that can't exit all ips failed to connect to "
+ " %s via circuit %s (%s). Trying again with it as entry.",
+ relay.fingerprint, relay.nickname, dest, circ_fps, nicknames)
+ circ_fps, nicknames = create_path_relay_as_entry(relay, dest, rl, cb)
+ circ_id, reason = cb.build_circuit(circ_fps)
+ if not circ_id:
+ log.warning(
+ "Exit %s (%s) that can't exit all ips, failed to create "
+ " circuit as entry: %s (%s).", relay.fingerprint,
+ relay.nickname, circ_fps, nicknames)
+ return error_no_circuit(relay, circ_fps, nicknames, reason, dest,
+ our_nick)
+
+ log.debug('Built circuit with path %s (%s) to measure %s (%s)',
+ circ_fps, nicknames, relay.fingerprint, relay.nickname)
+ is_usable, usable_data = connect_to_destination_over_circuit(
+ dest, circ_id, s, cb.controller, dest._max_dl)
if not is_usable:
log.debug('Destination %s unusable via circuit %s (%s), %s',
dest.url, circ_fps, nicknames, usable_data)
diff --git a/tests/integration/lib/test_destination.py b/tests/integration/lib/test_destination.py
index 19f6617..d305b0e 100644
--- a/tests/integration/lib/test_destination.py
+++ b/tests/integration/lib/test_destination.py
@@ -26,7 +26,7 @@ def test_connect_to_destination_over_circuit_success(persistent_launch_tor,
relay = [r for r in rl.relays
if r.nickname == 'relay1mbyteMAB'][0]
# Choose an exit, for this test it does not matter the bandwidth
- helper = rl.exits_not_bad_allowing_port_all_ips(destination.port)[0]
+ helper = rl.exits_not_bad_allowing_port_some_ips(destination.port)[0]
circuit_path = [relay.fingerprint, helper.fingerprint]
# build a circuit
circuit_id, _ = cb.build_circuit(circuit_path)
@@ -46,7 +46,7 @@ def test_connect_to_destination_over_circuit_fail(persistent_launch_tor,
relay = [r for r in rl.relays
if r.nickname == 'relay1mbyteMAB'][0]
# Choose an exit, for this test it does not matter the bandwidth
- helper = rl.exits_not_bad_allowing_port_all_ips(bad_destination.port)[0]
+ helper = rl.exits_not_bad_allowing_port_some_ips(bad_destination.port)[0]
circuit_path = [relay.fingerprint, helper.fingerprint]
# Build a circuit.
circuit_id, _ = cb.build_circuit(circuit_path)
@@ -75,7 +75,7 @@ def test_functional_destinations(conf, cb, rl, persistent_launch_tor):
relay = [r for r in rl.relays
if r.nickname == 'relay1mbyteMAB'][0]
# Choose an exit, for this test it does not matter the bandwidth
- helper = rl.exits_not_bad_allowing_port_all_ips(bad_destination.port)[0]
+ helper = rl.exits_not_bad_allowing_port_some_ips(bad_destination.port)[0]
circuit_path = [relay.fingerprint, helper.fingerprint]
# Build a circuit.
circuit_id, _ = cb.build_circuit(circuit_path)
[View Less]
commit 72b43570589d10a668039341895948ded0f1bfd7
Author: juga0 <juga(a)riseup.net>
Date: Tue Feb 9 13:08:44 2021 +0000
fix:scanner: Rm condition assigning helper
---
sbws/core/scanner.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/sbws/core/scanner.py b/sbws/core/scanner.py
index 97829f4..5fd917a 100644
--- a/sbws/core/scanner.py
+++ b/sbws/core/scanner.py
@@ -267,12 +267,12 @@ def error_no_helper(relay, dest, our_nick=""):
def …
[View More]create_path_relay(relay, dest, rl, cb, relay_as_entry=True):
- if relay_as_entry:
- helper = _pick_ideal_second_hop(
- relay, dest, rl, cb.controller, is_exit=True)
- else:
- helper = _pick_ideal_second_hop(
- relay, dest, rl, cb.controller, is_exit=False)
+ # the helper `is_exit` arg (should be better called `helper_as_exit`),
+ # is True when the relay is the entry (helper has to be exit)
+ # and False when the relay is not the entry, ie. is the exit (helper does
+ # not have to be an exit)
+ helper = _pick_ideal_second_hop(
+ relay, dest, rl, cb.controller, is_exit=relay_as_entry)
if not helper:
return error_no_helper(relay, dest)
if relay_as_entry:
[View Less]
commit 15da07d6a447d8310354124f6020b4cf74b75488
Author: juga0 <juga(a)riseup.net>
Date: Thu Dec 17 14:37:58 2020 +0000
fix: stem: Remove torrc option that is the default
to avoid conflict when comparing the options that should be set and the
ones are set, since the SocksPort will be differently in chutney.
---
docs/source/config_tor.rst | 1 -
sbws/globals.py | 3 ---
2 files changed, 4 deletions(-)
diff --git a/docs/source/config_tor.rst b/docs/source/…
[View More]config_tor.rst
index e609468..b204ca2 100644
--- a/docs/source/config_tor.rst
+++ b/docs/source/config_tor.rst
@@ -9,7 +9,6 @@ connection to an existing Tor daemon.
Default configuration:
-- ``SocksPort auto``: To proxy requests over Tor.
- ``CookieAuthentication 1``: The easiest way to authenticate to Tor.
- ``UseEntryGuards 0``: To avoid path bias warnings.
- ``UseMicrodescriptors 0``: Because full server descriptors are needed.
diff --git a/sbws/globals.py b/sbws/globals.py
index 2e4481c..2434685 100644
--- a/sbws/globals.py
+++ b/sbws/globals.py
@@ -22,9 +22,6 @@ SPEC_VERSION = '1.5.0'
# Options that are known at runtime (from configuration file) are added
# in utils/stem.py launch_tor
TORRC_STARTING_POINT = {
- # We will find out via the ControlPort and not setting something static
- # means a lower chance of conflict
- 'SocksPort': 'auto',
# Easier than password authentication
'CookieAuthentication': '1',
# To avoid path bias warnings
[View Less]
commit 2d5a6b65704857b8abde4a867f0f6590c181325c
Author: juga0 <juga(a)riseup.net>
Date: Thu Dec 17 14:40:36 2020 +0000
fix: stem: Move torrc option that does not depend on config
It seems we forgot this option when refactoring in #28738.
---
sbws/globals.py | 6 +++++-
sbws/util/stem.py | 4 ----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/sbws/globals.py b/sbws/globals.py
index 2434685..f5b3ec6 100644
--- a/sbws/globals.py
+++ b/sbws/globals.py
@@ -…
[View More]40,7 +40,11 @@ TORRC_STARTING_POINT = {
'FetchDirInfoEarly': '1',
'FetchDirInfoExtraEarly': '1',
# To make Tor keep fetching descriptors, even when idle.
- 'FetchUselessDescriptors': '1'
+ 'FetchUselessDescriptors': '1',
+ # Things needed to make circuits fail a little faster. We get the
+ # circuit_timeout as a string instead of an int on purpose: stem only
+ # accepts strings.
+ 'LearnCircuitBuildTimeout': '0',
}
# Options that need to be set at runtime.
TORRC_RUNTIME_OPTIONS = {
diff --git a/sbws/util/stem.py b/sbws/util/stem.py
index 5835237..4e8f321 100644
--- a/sbws/util/stem.py
+++ b/sbws/util/stem.py
@@ -206,10 +206,6 @@ def launch_tor(conf):
'NOTICE file {}'.format(os.path.join(conf.getpath('tor', 'log'),
'notice.log')),
],
- # Things needed to make circuits fail a little faster. We get the
- # circuit_timeout as a string instead of an int on purpose: stem only
- # accepts strings.
- 'LearnCircuitBuildTimeout': '0',
'CircuitBuildTimeout': conf['general']['circuit_timeout'],
})
[View Less]