Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Selective tunneling #35

Closed
RossBoylan opened this issue Jun 14, 2020 · 10 comments
Closed

Selective tunneling #35

RossBoylan opened this issue Jun 14, 2020 · 10 comments
Milestone

Comments

@RossBoylan
Copy link
Contributor

RossBoylan commented Jun 14, 2020

WHY

The standard way this tool, and AFAIK other UCSF VPN clients, work is that all traffic gets sent through the UCSF network. This seemed undesirable to me because

  1. It cut off my local network. I couldn't print, and other computers in my house couldn't use my machine, which, among other things was serving as the internet gateway and primary server.
  2. It meant that personal, non-work-related traffic would still flow through the UCSF network, exposing me to potential snooping as well as the charge of abusing the UCSF network for improper uses such as streaming a video for personal entertainment.
  3. The extra fuss of the VPN seemed likely to degrade connection quality, and increase CPU use, for things like video streaming.

On the other hand:

  1. Sending everything through the VPN, according to some messages, is now mandatory, at least on the Windows/Mac platforms where one has to take what UCSF gives. The justification was added security because it would prevent outside networks from getting in via the connections that didn't go through the VPN. This seems a little thin to me, since one can still get a virus when not connected and then have it spread once connected. (Yes, I know other security software is supposed to prevent that, but nothing is perfect.)
  2. My understanding that all traffic goes through the VPN may be wrong, at least now. That is, local networks like 192.168.x.y may not go through the VPN. Even if that's true, accessing email on my ISP's servers might be challenging if I had to go through the VPN.

HOW

The selective branch of https://github.com/RossBoylan/ucsf-vpn/ has the code I've been using for quite awhile to do selective tunneling. Most of the action is in the selectiveTunnel script, which is a modified version of the standard helper script that openConnect uses to manage networking. It works in connection with a file of the IP ranges that make up the internal network to which one is connecting. UCSF network services has requested that this not be made public, and so it is not on github.

ucsf-vpn needs two types of changes. It needs to call openconnect with the name of the revised helper script; for now that is hard-coded. Second, the selective tunneling violates some of the assumptions the script makes in identifying whether one is connected. It does this by executing

 curl --silent https://ipinfo.io/json

and seeing what comes back. But, since ipinfo.io is not inside the VPN, the traffic doesn't go through the VPN, and so the info that comes back indicates there is no VPN connection--even though there is.

When I discovered that curl had an --interface argument I thought I could use it to guarantee that the query went out through the VPN. But nothing ever comes back when I do that. I don't know why.

If you go a couple of commits back, to 7974b85, you'll see the code I was using that was working. That was based on a much older version of master, which used different strategies for figuring out the connection info. Those strategies also needed to be tweaked for the selective tunneling. The current code in master is more robust, but it still can't deal with the selective tunneling.

I should also note that the new code in selectiveTunnel works for me on Debian GNU/Linux 10. It will probably work on most linux's; it is unlikely it will work in other OS's.

QUESTIONS

Do you think selective tunneling is a desirable feature? A security risk?

How can we determine if we have a connection to the VPN when selective tunneling is in place?

STATUS

If you use the current tip of my selective branch it won't work [actually it will with either of the 2 approaches describe in later posts]. You'll get a selective connection, but ucsf-vpn won't realize that. Also, it won't work unless you have a list of IP ranges considered inside the vpn in /etc/vpnc/UCSFIntranet.

I'm going to continue using the older version mentioned above pending a better solution.

@HenrikBengtsson
Copy link
Owner

Quick comment: use option --validate=pid to skip the ipinfo validation. This can also be controlled via an env var (see the help).

@RossBoylan
Copy link
Contributor Author

RossBoylan commented Jun 14, 2020

I'll have to try that. Thanks for the tip. I assume using it causes some loss of reliability of the tests.

Alternately, there's a simple solution that involves no code change. Just add the IP range for the server ipinfo.io to the file of intranet IPs and everything works. I used

# ensure that our queries go through VPN
# a totally non-robust hack
# ipinfo.io
# # dig +noall +answer ipinfo.io
# ipinfo.io.		300	IN	A	216.239.38.21
# ipinfo.io.		300	IN	A	216.239.34.21
# ipinfo.io.		300	IN	A	216.239.36.21
# ipinfo.io.		300	IN	A	216.239.32.21
216.239.32.0/21

It would be more robust to do a dns lookup dynamically, parse the results, and forward just for those specific IPs. That would involve code changes, the need to identify a dns lookup tool, etc.

@RossBoylan
Copy link
Contributor Author

Just for the record, --validate=pid also allowed the program to conclude it was on the VPN.

@RossBoylan
Copy link
Contributor Author

ipinfo.io is not the only server the script uses to check status. There is also
UCSF_VPN_PING_SERVER Ping server to validate internet (default: 9.9.9.9).
This has caused me no trouble, but if the point is to see if it is reachable through the VPN that probably should be added to the list of IPs to send through the VPN (the one with 216.239.32.0/21 above).

@RossBoylan
Copy link
Contributor Author

When I connect I frequently get a message that I'm not connected along with a string indicating a connection through my ISP rather than UCSF. But the connection works, and when I test status again all is well.

I suspect this is a race condition in which the commands that reset the routing info, in particular for 216.239.3x.21, have either not executed or not taken effect before the status check. The route is reset by the modified version of vpnc-script I use.

@HenrikBengtsson
Copy link
Owner

When I discovered that curl had an --interface argument I thought I could use it to guarantee that the query went out through the VPN. But nothing ever comes back when I do that. I don't know why.

I started to dig into this. I got this working. As a starter, when I'm connected to the VPN, my IP routing shows:

$ ip route show | grep -E "^default "
default dev tun0 scope link 
default via 192.168.1.1 dev wlp0s20f3 proto dhcp metric 600 

Based on this, I use:

$ interface=$(ip route show | grep -E "^default " | grep -vF " tun" | cut -d ' ' -f 5)
$ echo "$interface"
wlp0s20f3

When I use this network interface with curl, I circumvent the VPN connection;

$ curl --interface "${interface}" https://ipinfo.io/json
{
  "ip": "123.123.123.123",
  "hostname": "123.123.123.123.example.org",
  "city": "SomeCity",
  "region": "SomeState",
  "country": "SomeCountry",
  "loc": "123.123,123.123",
  "org": "AS12312 Foo Bar",
  "postal": "12312",
  "timezone": "America/Los_Angeles",
  "readme": "https://ipinfo.io/missingauth"
}

@HenrikBengtsson
Copy link
Owner

HenrikBengtsson commented Apr 28, 2024

ucsf vpn routing will now report on this interface;

$ ucsf vpn routing
Default non-VPN network interface: wlp0s20f3
IP routing table (126 entries):
default dev tun0 scope link 
default via 192.168.1.1 dev wlp0s20f3 proto dhcp metric 600 
...

$ ucsf vpn --version
5.7.0-9006

@HenrikBengtsson
Copy link
Owner

It cut off my local network. I couldn't print, and other computers in my house couldn't use my machine, which, among other things was serving as the internet gateway and primary server.

This seems to no longer be the case, or, at least it's not happening to me. I can access my local 192.168.1.* network after connecting to the VPN. I think the proof lies in:

$ ucsf vpn status
OpenConnect status: 'openconnect' process running (PID=1469057)
Connected to the VPN

$ ip route show | grep -E "^192[.]168[.]"
192.168.1.0/24 dev wlp0s20f3 proto kernel scope link src 192.168.1.19 metric 600

FWIW, I have the above both when I'm connected to the VPN and not.

Testing it while connected gives:

$ ping -c 1 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=2.78 ms

--- 192.168.1.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 2.777/2.777/2.777/0.000 ms

$ curl --head 192.168.1.41
HTTP/1.1 411 Length Required
Cache-Control: no-cache
Content-Length: 974
Content-Type: text/html
Connection: close
Server: debut/1.30
Pragma: no-cache

This is with:

$ bin/ucsf-vpn --version --full
ucsf-vpn 5.7.0-9009
OpenConnect 8.20-1

@HenrikBengtsson
Copy link
Owner

I've updated ucsf-vpn so that it passes any options following --args to the openconnect tool, e.g.

ucsf vpn start --args --script=$PWD/selectiveTunnel

@RossBoylan , could you please see if this works for your selectiveTunnel script? You need to grab bin/ucsf-vpn from the develop branch. If this works, then it's the first baby step towards providing built-in support for selective tunneling.

@HenrikBengtsson HenrikBengtsson modified the milestones: Next release, 5.8.0 May 18, 2024
@HenrikBengtsson
Copy link
Owner

I've got everything working for manually tweaking the IP routing using ucsf vpn start --args --script=$PWD/selectiveTunnel. I've also started on a more user-friendly approach to customize this. The skeleton for this is in the new ucsf-vpn 5.8.0, but more to come next.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants