blueprint-freespeech / ricochet-refresh

Anonymous peer-to-peer instant messaging
https://www.ricochetrefresh.net
Other
187 stars 27 forks source link

Fix listen IP address on Workstation/Gateway setups #102

Closed JeremyRand closed 2 years ago

JeremyRand commented 3 years ago

Without this PR, connections fail if both peers are using Whonix; with this PR, such connections now work. (Both tests done with https://github.com/blueprint-freespeech/ricochet-refresh/pull/101 applied.)

morganava commented 3 years ago

I'm not sure if I'm understanding this correctly, but doesn't this change make it so that Ricochet-Refresh will now accept incoming network requests from the (ipv4) internet? That certainly seems like a problem.

JeremyRand commented 3 years ago

I'm not sure if I'm understanding this correctly, but doesn't this change make it so that Ricochet-Refresh will now accept incoming network requests from the (ipv4) internet? That certainly seems like a problem.

@pospeselr As per the specification at http://www.dds6qkxpwdeubwucdiaord2xgbbeyds25rbsgr73tbfpqpt4a6vjwsyd.onion/wiki/Dev/Whonix_friendly_applications_best_practices#Listen_Interface , the presence of the file /usr/share/anon-ws-base-files/workstation is used to signal to applications that the Tor daemon is running on a different machine (e.g. a Whonix setup). On such setups, listening for requests on 0.0.0.0 is the correct behavior, since a Tor daemon on a different machine won't be able to forward onion service connections to Ricochet if Ricochet is listening on 127.0.0.1. This PR doesn't change the behavior when that file isn't present. So it shouldn't be a problem.

morganava commented 3 years ago

Users in this situation would need to read the tor configuration settings (ie host, port, etc) via the various environment variables right?

Wouldn't it be more useful to use the various TOR_SKIP_LAUNCH, TOR_SOCKS_HOST, etc variables to configure this behaviour? This way, non-whonix users that are using a remote tor would also benefit? (As it stands I suspect that scenario does not work due to only accepting connections from localhost). Would it be possible to only accept incoming connections from TOR_SOCKS_HOST? Skiming the QTcpServer class documentation isn't entirely clear.

adrelanos commented 3 years ago

I think @JeremyRand is correct.

Btw /usr/share/anon-ws-base-files/workstation making this encouraging for anyone using a similar split Tor setup. (The file on purpose isn't called /usr/share/whonix-ws-base-files/workstation to avoid reference to Whonix by name where none is required.)

Wouldn't it be more useful to use the various TOR_SKIP_LAUNCH, TOR_SOCKS_HOST, etc variables to configure this behaviour?

That would be useful but for other purposes. I.e. useful for outgoing connections. Wouldn't work for incoming connections.


For incoming connections: Listening on all interfaces (or listening on TOR_SOCKS_HOST) is still required. Because that is for incoming connections from the Tor onion service.

Perhaps these environment variables:

For outgoing connections: Does ricochet set a socks user name? That would be useful anyhow for stream isolation. Then multiple applications (Tor Browser, ricochet) using the same TOR_SOCKS_HOST, TOR_SOCKS_PORT would be OK. That is, because by Tor default, socks connections using different socks user names are automatically stream isolated by Tor. That is unrelated to this PR and might be useful generally for ricochet. It could be a general privacy feature to set a different socks user name per outgoing connection. But since outgoing connections are going to different Tor onions and connections to different Tor onions are also stream isolated by default, the gain here could be minimal except for cases where one would re-use an onion for both ricochet and web.

Otherwise would it be possible to also set a socks user name? Either simply set the socks user name by default to ricochet or more advanced ricochet+randomid?

This way, non-whonix users that are using a remote tor would also benefit? (As it stands I suspect that scenario does not work due to only accepting connections from localhost).

Yes.

Would it be possible to only accept incoming connections from TOR_SOCKS_HOST?

For Whonix probably yes but how to do that in ricochet, dunno.

JeremyRand commented 3 years ago

@adrelanos are Windows workstations considered a legitimate use case (obviously not supported by Whonix devs, but some 3rd party devs/users might want it)? POSIX-style paths aren't a thing there, but environment variables would work okay, right? So it seems like using an environment variable to signal "this machine is a workstation" has at least some portability advantage over using a file. Is there a reason why Whonix chose to use a file rather than an environment variable to signal this?

morganava commented 3 years ago

I am somewhat hesitant to support a whonix-specific hack when a general solution would benefit all.

JeremyRand commented 3 years ago

Other practical advantage of using environment variables for this is that some users may have a workstation with multiple network interfaces, and they probably want to only listen for onion connections on the interface that they use to talk to the gateway. Environment variables can easily convey this need; using a file only conveys a boolean (unless we start checking the contents of the file or something).

Questions to ponder: is there ever a situation where the workstation needs to accept onion connections on a different interface than the one it uses to talk to the Tor control port? Is there ever a situation where it is nontrivial for the application to determine which interface that is, given just the Tor control IP? (I assume there's an API in most languages that tells you which interface is used to connect to a given IP, but I haven't done this recently, so not certain.)

adrelanos commented 3 years ago

Environment variables are OK.

Is there a reason why Whonix chose to use a file rather than an environment variable to signal this?

https://github.com/Whonix/proposals/blob/master/635-listen-port-convention.txt would be better but was never finalized.

are Windows workstations considered a legitimate use case

Yes.

is there ever a situation where the workstation needs to accept onion connections on a different interface than the one it uses to talk to the Tor control port?

Not that I know. From perspective of the client application using Tor control protocol, the control connections are just short or long living outgoing connections. Not incoming connections.

In Whonix, due to "Tor emulation" (anon-ws-disable-stacked-tor) any default Tor ContorlPort setting can be used such 127.0.0.1 9051 (system Tor) or 9151 (TBB) will be OK.

Is there ever a situation where it is nontrivial for the application to determine which interface that is, given just the Tor control IP?

If application uses IPs then it usually doesn't reference network interface names.

LISTEN_ON_INTERFACE=eth0 is useful if the IP is dynamically assigned.

LISTEN_ON_IP=0.0.0.0 is just easier. Less can go wrong. LISTEN_ON_ALL_INTERFACES=true would be the same but even easier.

Perhaps...

Both should work for Whonix. LISTEN_ON_IP or LISTEN_ON_INTERFACE.

Perhaps LISTEN_ON=

? If that isn't too difficult to implement.

JeremyRand commented 3 years ago

Questions to ponder: is there ever a situation where the workstation needs to accept onion connections on a different interface than the one it uses to talk to the Tor control port? Is there ever a situation where it is nontrivial for the application to determine which interface that is, given just the Tor control IP? (I assume there's an API in most languages that tells you which interface is used to connect to a given IP, but I haven't done this recently, so not certain.)

Okay, so the reason I asked this was because I was thinking we could infer the listen interface from the control port IP. But now I realize that because of setups like anon-ws-disable-stacked-tor, this is not reliable, since an application can't tell the difference between anon-ws-disable-stacked-tor and a local Tor daemon based solely on the IP address (which is 127.0.0.1 in both cases).

However, I think we could infer this from a separate environment variable TOR_LISTEN_FROM_IP, which contains the source IP that onion service connections from the Tor daemon will arrive from. In the case of local Tor, TOR_LISTEN_FROM_IP and TOR_CONTROL_HOST will both be 127.0.0.1, but in the case of anon-ws-disable-stacked-tor, TOR_LISTEN_FROM_IP will be the Gateway IP, while TOR_CONTROL_HOST will be 127.0.0.1.

I can think of 2 desirable behaviors for TOR_LISTEN_FROM_IP. First, the incoming socket should be opened only on the interface that the OS's routing table would use for that IP. Some info on how to get that routing table data is listed here:

Second, as @pospeselr suggested above, the application should immediately close any socket connections that come from other IP's. These two behaviors yield complementary security benefits: the former allows the OS to protect the application from attacks that might exploit the application, while the latter protects from situations such as multiple Workstations that share a Gateway.

AFAICT this approach should work for all the scenarios that @adrelanos mentioned, and is less effort for the user than specifying the interface name/IP explicitly.

@adrelanos @pospeselr does this approach of using a TOR_LISTEN_FROM_IP variable sound like it would meet everyone's needs?

adrelanos commented 3 years ago

Questions to ponder: is there ever a situation where the workstation needs to accept onion connections on a different interface than the one it uses to talk to the Tor control port? Is there ever a situation where it is nontrivial for the application to determine which interface that is, given just the Tor control IP? (I assume there's an API in most languages that tells you which interface is used to connect to a given IP, but I haven't done this recently, so not certain.)

Okay, so the reason I asked this was because I was thinking we could infer the listen interface from the control port IP. But now I realize that because of setups like anon-ws-disable-stacked-tor, this is not reliable, since an application can't tell the difference between anon-ws-disable-stacked-tor and a local Tor daemon based solely on the IP address (which is 127.0.0.1 in both cases).

Indeed.

However, I think we could infer this from a separate environment variable TOR_LISTEN_FROM_IP, which contains the source IP that onion service connections from the Tor daemon will arrive from. In the case of local Tor, TOR_LISTEN_FROM_IP and TOR_CONTROL_HOST will both be 127.0.0.1, but in the case of anon-ws-disable-stacked-tor, TOR_LISTEN_FROM_IP will be the Gateway IP, while TOR_CONTROL_HOST will be 127.0.0.1.

Makes sense.

Btw if you could think off a way which wouldn't even require application specific support (i.e. TOR_LISTEN_FROM_IP) then I guess this would be even better but nothing came to mind.

does this approach of using a TOR_LISTEN_FROM_IP variable sound like it would meet everyone's needs?

I guess so... Seems great!

That would be in Whonix essentially...

?

cypherbits commented 3 years ago

I think LISTEN_ON should be set to the actual internal IP address from the Whonix Workstation. Setting it to 0.0.0.0 means all interfaces and can be a little dangerous in some environments.

Adding an ALLOW_FROM (or TOR_LISTEN_FROM_IP) to set the IP of Whonix Gateway to allow only connections from this IP is even more important than LISTEN_ON since this can prevent any other IP from connecting to Ricochet and do "bad things".

I like @JeremyRand idea.

JeremyRand commented 3 years ago

I talked to @pospeselr on IRC, they think the TOR_LISTEN_FROM_IP approach is fine. I'll look at updating this PR to use that approach (not sure how fast I'll get to it); once I've done so, I'll coordinate with @adrelanos on updating Whonix to set the variable (and getting it added to the appropriate Best Practices specs). Very glad we've converged on a solution that works for everyone involved (modulo implementation, anyway).

morganava commented 2 years ago

As discussed in https://github.com/blueprint-freespeech/ricochet-refresh/pull/101 all work in this space should happen in Gosling. See: https://github.com/blueprint-freespeech/ricochet-refresh/pull/101

adrelanos commented 2 years ago

Could you merge this please?

Same reasoning as https://github.com/blueprint-freespeech/ricochet-refresh/pull/101#issuecomment-1102396436