Opened 6 years ago

Last modified 8 months ago

#7590 needs_revision enhancement

[PATCH] New option LocalOutboundBindAddress

Reported by: ac Owned by:
Priority: Medium Milestone: Tor: unspecified
Component: Core Tor/Tor Version:
Severity: Normal Keywords: tor-client, tor-hs, hs-integration, hs-app-support, review-group-29, 034-triage-20180328, 034-removed-20180328
Cc: trac.torproject.org@… Actual Points:
Parent ID: Points:
Reviewer: Sponsor:

Description

LocalOutboundBindAddress works just like OutboundBindAddress, but instead of excluding connections to loopback addresses, it affects only connections to loopback addresses.

(This is a patch to the git head.)

[1/2] https://lists.torproject.org/pipermail/tor-dev/2012-November/004177.html

[2/2] https://lists.torproject.org/pipermail/tor-dev/2012-November/004176.html

Child Tickets

Attachments (1)

local_outbound_bind_address.patch (8.4 KB) - added by ac 6 years ago.

Download all attachments as: .zip

Change History (31)

comment:1 Changed 6 years ago by ac

Cc: trac.torproject.org@… added

comment:2 Changed 6 years ago by asn

Component: - Select a componentTor
Keywords: tor-client added
Milestone: Tor: 0.2.4.x-final
Status: newneeds_review

comment:3 Changed 6 years ago by nickm

From the patch:

+    Like OutboundBindAddress, but _only_ for connections to loopback
+    addresses (e.g., inbound connections to local hidden services).
+    This is useful to distinguish Tor traffic from local traffic in
+    the log files of your hidden services. +
+ +
+    The IP should be in the 127.0.0.0/8 range for maximum compatibility.
+    I recommend using 127.84.111.114, since 84.111.114 is the ASCII
+    encoding of "Tor".  I also recommend adding \'127.84.111.114 tor' to
+    your /etc/hosts file.
+

(copying-and-pasting there here in case anybody else was wondering what this is for)

comment:4 Changed 6 years ago by nickm

Some notes on the basic idea:

  • So, the idea is that you've got a hidden service on 127.0.0.1 and you want to tell when Tor is connecting to it vs when some other thing is connecting to it. Why would you do that? Is this so you can have the server for the HS treat anonymous connections differently from local admin connections or something?
  • If this is the application, maybe this should be a hidden-service-specific feature rather than a local-specific feature. IOW, maybe it should be HSOutboundBindAddress instead?
  • Is there a reason to make this a per-HS configuration item, so that different hidden services get a different address, or is that overkill?

Some notes on the code:

  • I know we do it in a few places, but I don't really like code of the form:
      for (i=0;i<2;++i) {
        thing_t thing1 = i ? foo : bar;
        widget_t widget1 = i ? baz: quux;
        do stuff...
        do stuff...
      } 
    

Instead, it seems much cleaner to do:

static void do_stuff(thing_t *thing1, widget_t *widget1)
{
  do stuff ...
  do stuff...
}
...
  do_stuff(bar, quux);
  do_stuff(foo, baz);

Other than that, it looks okay at first glance.

Changed 6 years ago by ac

comment:5 in reply to:  4 Changed 6 years ago by ac

Replying to nickm:

  • So, the idea is that you've got a hidden service on 127.0.0.1 and you want to tell when Tor is connecting to it vs when some other thing is connecting to it. Why would you do that? Is this so you can have the server for the HS treat anonymous connections differently from local admin connections or something?

Basically, yes. More specifically, in my personal case, I have hidden services forwarding to ssh and apache. When I check my apache logs, or log in via ssh and type 'w', I want to see connections from 'tor' rather than 'localhost'. And when I log in the next time I want it to say "last login from tor". So my own motivation is solely logging-related. But it would also be useful to have distinct security rules for connections from Tor in one's apache configuration, and such.

  • If this is the application, maybe this should be a hidden-service-specific feature rather than a local-specific feature. IOW, maybe it should be HSOutboundBindAddress instead?

I don't know whether you're talking about the name, or the behavior. At the moment, the name matches the behavior: OutboundBindAddress governs _all_ connections except local connections; LocalOutboundBindAddress governs _all_ connections not governed by OutboundBindAddress. The combination of the two allows Tor's outbound address to be configured in every case where Tor makes a connection (at least, using connection_connect()).

It is possible for Tor to make loopback connections that are not connections to hidden services. For example, someone could set ExitPolicyRejectPrivate to 0. The current patch would affect the connections enabled by that setting. To me, that behavior seems more useful than limiting the effect to hidden services would. Someone with "ExitPolicyRejectPrivate 0" might find LocalOutboundBindAddress useful even without having any hidden services enabled.

Tor might also make loopback connections in other situations.

  • Is there a reason to make this a per-HS configuration item, so that different hidden services get a different address, or is that overkill?

A per-HS outbound bind address might make sense (in fact, I noticed it's mentioned in doc/TODO.future). This would mean, I presume, specifying the bind address as a parameter to connection_connect(), with the caller of that function determining the purpose of the connection and applying the appropriate fine-grained option. But this functionality would make the most sense as an override to the current (and proposed) global bind address settings.

Even with per-HS bind address settings, the global settings would still be useful as defaults, or for any case where there is no finer-grained bind address option (e.g., localhost exits with ExitPolicyRejectPrivate), or where the administrator wanted to ensure Tor would not make connections from 127.0.0.1 without having to specify a setting for each type of connection made by Tor.

(Also, a per-HS outbound bind address ought to override not just LocalOutboundBindAddress, but also OutboundBindAddress. The HS might not be local.)

Some notes on the code:

OK, I made that change. I also fixed a mistake where V(LocalOutboundBindAddress) was out of alphabetical order. I attached the patch.

(The attached patch _replaces_ the patches previously posted to the mailing list.)

comment:6 Changed 6 years ago by nickm

Code seems better now.

Is it meaningful to do this with IPv6? In other words, the only loopback IPv6 address appears to be ::1. Can you actually set LocalOutboundBindAddress to any IPv6 address other than ::1 and still have it work?

comment:7 in reply to:  6 Changed 6 years ago by ac

Replying to nickm:

To reiterate what I said on IRC -- Another IP address can be added to a loopback interface and it becomes a loopback address no different from ::1. At the very least, Linux supports this. It also possible to bind an address that is on any other interface and make a loopback connection.

For good measure, I ran the following commands:

  ip addr add ::54:6f72/128 dev lo
  ssh -6 -b  ::54:6f72 ::1
  w # from ssh session

I verified that "w" showed a login from ::0.84.111.114

I couldn't get an IPv6 hidden service working at all, though -- with or without LocalOutboundBindAddress set. So I haven't actually tested the IPv6 case, although the ssh test demonstrates that setting the bind address does work for IPv6 loopback connections.

comment:8 Changed 6 years ago by andrea

I'm not sure how portable this loopback trick is; I think if we're going to do this we should have Tor test whether it's possible to:

1.) bind() two different addresses of the form 127.0.0.x for random x
2.) listen() on one and then connect() to it with the other

... and warn the user if it looks like the behavior this depends on doesn't work.

I can go ahead and implement this test if we merge this, though.

comment:9 in reply to:  8 Changed 6 years ago by ac

Replying to andrea:

That test isn't quite proper I think... the random 127/8 address:port may well be taken. Also, it might not even be on the same interface as specified by this option. If you want to do a run-time test, better to bind the address specified by the user and test that, I think.

(However, I don't think the test is necessary. bind() will fail if it's not going to work.)

comment:10 Changed 6 years ago by nickm

Milestone: Tor: 0.2.4.x-finalTor: 0.2.5.x-final

Bumping to 0.2.5, along with all other remaining noncritical enhancements.

comment:11 Changed 5 years ago by ac

I'm currently using this workaround:

UID=debian-tor

iptables -t nat -A POSTROUTING -s 127.0.0.1/32 -m owner --uid-owner $UID -j SNAT --to-source 127.84.111.114

comment:12 Changed 5 years ago by nickm

Milestone: Tor: 0.2.5.x-finalTor: 0.2.???

comment:13 Changed 2 years ago by teor

Milestone: Tor: 0.2.???Tor: 0.3.???

Milestone renamed

comment:14 Changed 2 years ago by nickm

Keywords: tor-03-unspecified-201612 added
Milestone: Tor: 0.3.???Tor: unspecified

Finally admitting that 0.3.??? was a euphemism for Tor: unspecified all along.

comment:15 Changed 19 months ago by nickm

Keywords: tor-03-unspecified-201612 removed

Remove an old triaging keyword.

comment:16 Changed 19 months ago by nickm

Keywords: tor-hs hs-integration hs-app-support added
Severity: Normal

comment:17 Changed 12 months ago by ac

LOL @ 5 years

comment:18 Changed 12 months ago by teor

Milestone: Tor: unspecifiedTor: 0.3.4.x-final
Status: needs_reviewneeds_revision

alecmuffett does something similar to this in his hidden service setup, by making the *remote* side (web server) listen on a custom local subnet address, and then having Tor connect to that address. This workaround should not need any changes to Tor, or any iptables rules:

https://github.com/alecmuffett/the-onion-diaries/blob/master/basic-production-onion-server.md

This patch needs revision, because we added OutboundBindAddressExit and OR since it was created.
If you'd like, we can take a look at this in 0.3.4 (the code freeze for 0.3.3 is only a few weeks away).

I can't see any need for a unit test, I'm not sure we have any for the other OutboundBindAddress options.
If we do, it should be a parse test, not a bind test.

comment:19 Changed 12 months ago by Sebastian

Maybe this has enough working alternatives that we don't need to change tor at all?

comment:20 Changed 12 months ago by ac

The workarounds are insufficient because:

  1. iptables, while fully-functional, requires kernel access that is not always available. (It is not available to me in an actual VM that I rent where I do, in fact, run tor.)

I wouldn't be surprised if (e.g.) Windows didn't even have this capability exposed to users.

  1. Reconfiguring every single daemon to each individually work around the lack of functionality is inadequate and would require patching the code of some of those daemons.

For example, I currently have hidden services postfix, ssh, and apache. Apache runs several CGI type programs, for example the configuration interface for cups.

cups and postfix, by default, grant privileged access to connections from IP localhost. So you cannot expose them to tor connections through that address, without messing around with them. cups is a reverse proxy to a lighttpd daemon so you can mess around with the lighttpd configuratoin file in addition to the apache one. But what about postfix? You can probably make it listen on random additional ports or addresses, but can you configure it so that it overrides the trust default based on its own *listening* address? Such capability cannot be assumed to be present in most software, even if it is possible to do with apache.

ssh does not grant privileged access to local connections by default, but I personally do not want anonymous connections from all-and-sundry showing up in output from w or in logs as localhost when they are fundamentally the polar opposite of that. Again, you cannot hope to configure ssh to do this based on its own *listening* address or port. Even though ssh will listen on any number of addresses or ports, it does not let you change how it logs the remote IP conditional on its local address (why would it?).

Even if all those daemons supported the necessary workarounds -- which they don't -- I would have to mess with 4 different configuration file formats (lighttpd, postfix, apache, ssh) trying to get them to behave the way I want conditional on something (the listening port) that normally isn't a condition of behavior, so it's a giant complicated mess. Better to use iptables, or patch tor.

Certainly I wouldn't be trying to get the necessary patch into postfix or ssh to work around this, because such a patch would make no sense. Unlike this patch, which makes perfect sense and does a completely straightforward and sensible thing: sets the bind address on an outgoing connection to whatever the user specifies.

It just makes sense. You are making a connection, you have an opportunity to set the bind address, you give it to the user as a configuration option. Simple, straightforward, sensible, standard practice, no reason to think twice.

There's no reason this can't be done in 2 weeks, or 2 days, or 2 hours.

comment:21 Changed 12 months ago by teor

Please revise the patch so it applies to master.
If that's done early enough, it will go in a review queue before the 0.3.3 freeze.

If you don't have time to revise the patch, that's ok, but it might be a while before someone gets to it,

comment:23 Changed 12 months ago by teor

Milestone: Tor: 0.3.4.x-finalTor: 0.3.3.x-final
Status: needs_revisionneeds_review

Thanks!
Now this patch needs review, testing, and a changes file.

comment:24 Changed 12 months ago by nickm

Keywords: review-group-28 added

comment:25 Changed 11 months ago by nickm

Status: needs_reviewneeds_revision

Review:

  • The conn_get_outbound_address function should have its documentation updated to explain what the new argument does, and how the function behaves now.
  • There should be tests for this, and a changes file.

Otherwise this looks great to me!

comment:26 Changed 11 months ago by nickm

Keywords: review-group-29 added; review-group-28 removed

comment:27 Changed 10 months ago by nickm

Milestone: Tor: 0.3.3.x-finalTor: 0.3.4.x-final

Mark a lot of assigned/needs_revision tickets as 0.3.4. If you think this should happen in 0.3.3 instead, just let me know?

comment:28 Changed 9 months ago by nickm

Keywords: 034-triage-20180328 added

comment:29 Changed 9 months ago by nickm

Keywords: 034-removed-20180328 added

Per our triage process, these tickets are pending removal from 0.3.4.

comment:30 Changed 8 months ago by nickm

Milestone: Tor: 0.3.4.x-finalTor: unspecified

These needs_revision, tickets, tagged with 034-removed-*, are no longer in-scope for 0.3.4. We can reconsider any of them, if somebody does the necessary revision.

Note: See TracTickets for help on using tickets.