Opened 4 years ago

Closed 3 years ago

#10067 closed enhancement (implemented)

Have `reject *` as the default exit policy

Reported by: lunar Owned by:
Priority: Medium Milestone: Tor: 0.2.6.x-final
Component: Core Tor/Tor Version:
Severity: Keywords: tor-relay, 026-triaged-1, 026-deferrable, nickm-patch
Cc: mk7332 Actual Points:
Parent ID: Points:
Reviewer: Sponsor:

Description

Quoting arma in a discussion on tor-relays:

On Thu, Oct 31, 2013 at 06:12:47PM -0700, Andy Isaacson wrote:

That's correct, it takes a deliberate action on the part of the
administrator to become a relay; and another deliberate action to become
an exit relay.

Actually, that second part isn't true. Once you decide to become a relay,
the default is to exit to most popular ports.

The main reason for this choice is the number of people who've told us
that they are only able to run exit relays because "it's what Tor does
when you run a relay", and their institution wouldn't let them do it if
it required a manual config change to become an exit.

Then again, that was a long time ago, and maybe it's gotten harder to
sustain exits these days?

I think the change is actually worth making as I have seen two users being surprised by the current default behaviour. People running an exit while not fully aware of what it means usually turn unhappy.

(In any cases, we can discuss and wontfix if the previous rationale still hold.)

Child Tickets

Change History (18)

comment:1 Changed 4 years ago by arma

I'm inclined to agree with the idea -- first because the Internet abuse landscape has changed a lot since 'the old days', but mainly because I worry about the "slash and burn agriculture" approach to running Tor relays, where you set up an exit relay, and if anybody gets angry you move on to another ISP. That approach is really appealing since it's simple, but it assumes the Internet is infinite. If in fact we're destroying land without regard to sustainability, and we run out of land...

Today's interactions with ISPs influence Tor's future viability. So if people are accidentally exit relays without knowing it, I worry as much about the damage to the ISP's view of Tor as I do about the temporary hassle for the operator.

comment:2 Changed 4 years ago by nickm

  • Keywords tor-relay added
  • Milestone set to Tor: 0.2.5.x-final

I've got no objection here. The discussion on tor-dev seems generally positive.

Do we want to concern ourselves with migration issues and try to make sure that anybody who intentionally is using the default policy now doesn't unwillingly turn into a non-exit?

Do we want to add a way to get the "default" exit policy, now that 'don't specify an exit policy' isn't sufficient?

comment:3 Changed 4 years ago by lunar

To mitigate the surprise for such a change, we could go through the current policy of every exit nodes and write a personal email to the one that match the current default. That involves some work in a not-so-distant future, but it should not be unreasonable.

comment:4 Changed 4 years ago by arma

If we want to get fancier, we should look at exit policies which inherit the default exit policy, not just ones that match it exactly. For example, somebody whose current exit policy is "reject *:80" will still be influenced by this change.

I also think we'll want a log_notice for people who don't specify any exit policy lines. I haven't figured out exactly how we should do it though. For example, that approach would preclude putting an explicit "reject *.*" line in the sample torrc file (which would help people understand what the default is), since then we wouldn't be able to tell whether the user had written her own exit policy or what. Maybe we want a log_notice in any case if the state file was written by 0.2.4.x or earlier, to let the operator know if she happens to be looking at the logs for the one time that they upgrade happened. Hm.

comment:5 follow-up: Changed 4 years ago by nickm

We could have a new "ExitNode" flag, defaulting to "auto", and say that:

  • if ExitNode is 1, you're an exit node.
  • If ExitNode is 0, you are definitely not.
  • If ExitNode is "auto" and you have a non-reject *:* exit policy set, you are an exit node, and we issue a warning.
  • Finally, if ExitNode is "auto" and you have no exit policy set, you are not an exit node.

This last case is one I don't like, since it would break all exit nodes using exactly the default exit policy. Are there very many such nodes?

comment:6 Changed 4 years ago by atagar

Are there very many such nodes?

Just realized working with the default policy via stem is a little clunky. I should fix that. Anyway, in practice policies seem to mostly stick to reject-all or the default...

% python default_exit_policy_count.py
4705 reject *:*
1417 default
2 accept 173.213.78.126:443, reject *:*
2 accept *:9980, accept *:9981, accept 192.0.2.80:*, accept 10.8.6.1:*, default
2 accept 78.47.218.190:80, accept 5.9.28.163:80, accept 5.9.28.163:443, accept 5.9.28.186/30:80, accept 5.9.28.186/30:443, accept 5.9.30.12:80, accept 5.9.30.12:443, accept 5.9.236.224/28:80, accept 5.9.236.224/28:443, reject *:*
2 accept 173.213.78.125:80, reject *:*
2 accept 173.213.78.126:443, reject *:*
...
from stem.descriptor import remote

# prefix of the default policy that's static

STATIC_DEFAULT = "reject 0.0.0.0/8:*, reject 169.254.0.0/16:*, reject 127.0.0.0/8:*, reject 192.168.0.0/16:*, reject 10.0.0.0/8:*, reject 172.16.0.0/12:*"

def replace_default(policy):
  """ 
  Quick and dirty method to replace the default exit policy with 'default'.
  Without this most policies are unique, since they include a reject clause for
  their own IP.
  """

  policy_str = str(policy)
  static_prefix = policy_str.find(STATIC_DEFAULT)

  if static_prefix == -1: 
    return policy_str
  elif static_prefix == 0:
    return 'default'
  else:
    return policy_str[:static_prefix] + 'default'

policy_counts = {}

for desc in remote.DescriptorDownloader().get_server_descriptors():
  policy = replace_default(desc.exit_policy)
  policy_counts[policy] = policy_counts.setdefault(policy, 0) + 1 

# exit policies sorted by their count

counts = sorted(policy_counts.values(), reverse = True)

for count in counts:
  for policy, policy_count in policy_counts.items():
    if count == policy_count:
      print "%i %s" % (count, policy)

comment:7 Changed 4 years ago by nickm

I may be reading that code wrong, but if I'm not, it doesn't do the right thing. The STATIC_DEFAULT string there just encodes "reject private:*". The default exit policy, on the other hand, is

  "reject *:25,reject *:119,reject *:135-139,reject *:445,"         \
  "reject *:563,reject *:1214,reject *:4661-4666,"                  \
  "reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*"

comment:8 Changed 4 years ago by atagar

Bah! You're completely right. Guess this'll need to collapse both. One sec...

comment:9 Changed 4 years ago by atagar

There, that gives a much more even distribution. Thanks!

% python default_exit_policy_count.py
4696 reject *:*
516 default
70 accept *:20-23, accept *:43, accept *:53, accept *:79-81, accept *:88, accept *:110, accept *:143, accept *:194, accept *:220, accept *:389, accept *:443, accept *:464, accept *:531, accept *:543-544, accept *:554, accept *:563, accept *:636, accept *:706, accept *:749, accept *:873, accept *:902-904, accept *:981, accept *:989-995, accept *:1194, accept *:1220, accept *:1293, accept *:1500, accept *:1533, accept *:1677, accept *:1723, accept *:1755, accept *:1863, accept *:2082, accept *:2083, accept *:2086-2087, accept *:2095-2096, accept *:2102-2104, accept *:3128, accept *:3389, accept *:3690, accept *:4321, accept *:4643, accept *:5050, accept *:5190, accept *:5222-5223, accept *:5228, accept *:5900, accept *:6660-6669, accept *:6679, accept *:6697, accept *:8000, accept *:8008, accept *:8074, accept *:8080, accept *:8087-8088, accept *:8332-8333, accept *:8443, accept *:8888, accept *:9418, accept *:9999, accept *:10000, accept *:11371, accept *:12350, accept *:19294, accept *:19638, accept *:23456, accept *:33033, accept *:64738, reject *:*
51 accept *:20-23, accept *:43, accept *:53, accept *:79-81, accept *:88, accept *:110, accept *:143, accept *:194, accept *:220, accept *:389, accept *:443, accept *:464, accept *:531, accept *:543-544, accept *:554, accept *:563, accept *:636, accept *:706, accept *:749, accept *:873, accept *:902-904, accept *:981, accept *:989-995, accept *:1194, accept *:1220, accept *:1293, accept *:1500, accept *:1533, accept *:1677, accept *:1723, accept *:1755, accept *:1863, accept *:2082, accept *:2083, accept *:2086-2087, accept *:2095-2096, accept *:2102-2104, accept *:3128, accept *:3389, accept *:3690, accept *:4321, accept *:4643, accept *:5050, accept *:5190, accept *:5222-5223, accept *:5228, accept *:5900, accept *:6660-6669, accept *:6679, accept *:6697, accept *:8000, accept *:8008, accept *:8074, accept *:8080, accept *:8087-8088, accept *:8332-8333, accept *:8443, accept *:8888, accept *:9418, accept *:9999, accept *:10000, accept *:11371, accept *:19294, accept *:19638, reject *:*
38 accept *:20-23, accept *:43, accept *:53, accept *:79-81, accept *:88, accept *:110, accept *:143, accept *:194, accept *:220, accept *:389, accept *:443, accept *:464, accept *:531, accept *:543-544, accept *:554, accept *:563, accept *:636, accept *:706, accept *:749, accept *:873, accept *:902-904, accept *:981, accept *:989-995, accept *:1194, accept *:1220, accept *:1293, accept *:1500, accept *:1533, accept *:1677, accept *:1723, accept *:1755, accept *:1863, accept *:2082, accept *:2083, accept *:2086-2087, accept *:2095-2096, accept *:2102-2104, accept *:3128, accept *:3389, accept *:3690, accept *:4321, accept *:4643, accept *:5050, accept *:5190, accept *:5222-5223, accept *:5228, accept *:5900, accept *:6660-6669, accept *:6679, accept *:6697, accept *:8000, accept *:8008, accept *:8074, accept *:8080, accept *:8087-8088, accept *:8332-8333, accept *:8443, accept *:8888, accept *:9418, accept *:9999, accept *:10000, accept *:11371, accept *:12350, accept *:19294, accept *:19638, accept *:23456, accept *:33033, reject *:*
38 accept *:80, accept *:443, accept *:110, accept *:143, accept *:993, accept *:995, accept *:6660-6669, accept *:6697, accept *:7000-7001, accept *:706, accept *:1863, accept *:5050, accept *:5190, accept *:5222, accept *:5223, accept *:8300, accept *:8888, reject *:*
38 accept *:20-23, accept *:43, accept *:53, accept *:79-81, accept *:88, accept *:110, accept *:143, accept *:194, accept *:220, accept *:389, accept *:443, accept *:464, accept *:531, accept *:543-544, accept *:554, accept *:563, accept *:636, accept *:706, accept *:749, accept *:873, accept *:902-904, accept *:981, accept *:989-995, accept *:1194, accept *:1220, accept *:1293, accept *:1500, accept *:1533, accept *:1677, accept *:1723, accept *:1755, accept *:1863, accept *:2082, accept *:2083, accept *:2086-2087, accept *:2095-2096, accept *:2102-2104, accept *:3128, accept *:3389, accept *:3690, accept *:4321, accept *:4643, accept *:5050, accept *:5190, accept *:5222-5223, accept *:5228, accept *:5900, accept *:6660-6669, accept *:6679, accept *:6697, accept *:8000, accept *:8008, accept *:8074, accept *:8080, accept *:8087-8088, accept *:8332-8333, accept *:8443, accept *:8888, accept *:9418, accept *:9999, accept *:10000, accept *:11371, accept *:12350, accept *:19294, accept *:19638, accept *:23456, accept *:33033, reject *:*
38 accept *:80, accept *:443, accept *:110, accept *:143, accept *:993, accept *:995, accept *:6660-6669, accept *:6697, accept *:7000-7001, accept *:706, accept *:1863, accept *:5050, accept *:5190, accept *:5222, accept *:5223, accept *:8300, accept *:8888, reject *:*
35 accept *:80, accept *:443, reject *:*
26 accept *:6660-6667, reject *:*
24 accept *:*
23 accept *:80, accept *:443, accept *:110, accept *:143, accept *:993, accept *:995, reject *:*
19 accept *:80, reject *:*
16 accept *:443, reject *:*
13 accept *:53, reject *:*
11 reject *:25, accept *:*
...
import re

from stem.descriptor import remote

PRIVATE_PREFIX = re.compile(r"^(reject 0.0.0.0/8:\*, reject 169.254.0.0/16:\*, .* 172.16.0.0/12:\*, reject .*:\*, )(.*)")
DEFAULT_POLICY = "reject *:25, reject *:119, reject *:135-139, reject *:445, reject *:563, reject *:1214, reject *:4661-4666, reject *:6346-6429, reject *:6699, reject *:6881- 6999, accept *:*"

def strip_private_prefix(policy):
  """ 
  Quick and dirty method to strip the exit policy's 'reject private' prefix.
  Without this most policies are unique, since they include a reject clause for
  their own IP.
  """

  policy_str = str(policy)
  match = PRIVATE_PREFIX.match(policy_str)

  if match:
    return match.group(2)
  else:
    return policy_str

policy_counts = {}

for desc in remote.DescriptorDownloader().get_server_descriptors():
  policy = strip_private_prefix(desc.exit_policy).replace(DEFAULT_POLICY, 'default')
  policy_counts[policy] = policy_counts.setdefault(policy, 0) + 1 

# exit policies sorted by their count

counts = sorted(policy_counts.values(), reverse = True)

for count in counts:
  for policy, policy_count in policy_counts.items():
    if count == policy_count:
      print "%i %s" % (count, policy)

comment:10 in reply to: ↑ 5 Changed 4 years ago by nickm

Replying to nickm:

We could have a new "ExitNode" flag, defaulting to "auto", and say that:

  • if ExitNode is 1, you're an exit node.
  • If ExitNode is 0, you are definitely not.
  • If ExitNode is "auto" and you have a non-reject *:* exit policy set, you are an exit node, and we issue a warning.
  • Finally, if ExitNode is "auto" and you have no exit policy set, you are not an exit node.

This last case is one I don't like, since it would break all exit nodes using exactly the default exit policy. Are there very many such nodes?

From Damian's results, it appears that my design as written above would break about 516 exits. That's too many.

We *could* go with a different result:

  • if ExitNode is 'auto' and you are a relay and have no exit policy set, then we behave as currently, but warn you that you are being an exit node, and you should set ExitNode 1 or 0. In a later version, we make ExitNode off by default.

comment:11 Changed 3 years ago by nickm

  • Milestone changed from Tor: 0.2.5.x-final to Tor: 0.2.6.x-final

comment:12 Changed 3 years ago by nickm

  • Keywords 026 added

if ExitNode is 'auto' and you are a relay and have no exit policy set, then we behave as currently, but warn you that you are being an exit node, and you should set ExitNode 1 or 0. In a later version, we make ExitNode off by default.

This still seems smart.

comment:13 Changed 3 years ago by nickm

  • Keywords 026-triaged-1 026-deferrable added; 026 removed

comment:14 Changed 3 years ago by mk7332

  • Cc mk7332 added

I hope this makes it into a release soon... The default settings should be the safest (tor relay only) for least knowledgeable users. I knew what an exit relay was and knew I didn't want to run one, but I installed TOR and didn't realize it would be an exit node by default! I ran an exit node for a day without knowing it on my home IP!

comment:15 Changed 3 years ago by nickm

  • Status changed from new to needs_review

Branch for review as "exitnode_10067" in my public repository. It takes the "add a warning, and warn that the default will change" approach discussed above.

comment:16 Changed 3 years ago by nickm

  • Keywords nickm-patch added

Add the nickm-patch keyword to some needs_review tickets where I wrote or substantially revised the patch. This helps me find which tickets I should review and which I should find reviewers for.

comment:17 Changed 3 years ago by dgoulet

commit f7776790b2dcc69280ac71ed23ca7df677d639c4

  • In or.h, structure or_options_t, seems that this comment is misleading. If set to "1", the relay is an exit node and uses the configured exit policy or default one if none given? (but not always the default one). Sorry to be picky but I got confused since it does not match what the commit says.
    +  /** Is this an exit node?  This is a tristate, where "1" means "yes,
    +   * and use the default exit policy" and "0" means "no; exit policy is
    +   * 'reject *'" and "auto" (-1) means "same as 1, but warn the user."
    +   *
    +   * XXXX Eventually, the default will be 0. */
    

Apart from that, looks good and I've tested it also. ACK.

comment:18 Changed 3 years ago by nickm

  • Resolution set to implemented
  • Status changed from needs_review to closed

Tweaked based on your comment and comments from rl1987; squashed; merged.  Thanks, all!

Note: See TracTickets for help on using tickets.