Hi everyone
I have followed EZ for quite a while now and i have been mostly a spectator.
So now that i can afford more free time, i hope i can be more active/productive and contribute to the development of this lovely community.
Sorry for my bad English, am not a native speaker.
IntroductionThis topic deals with openvpn tunneling and how one may want to do some online tasks out of the tunnel, this have occurred to me and wanted to share the idea with you and get some feedback.
When using a vpn connection all the traffic goes through the vpn tunnel which is great to prevent leaks. But on the other hand it is not cautious to use the same connection to do the bad guy and then connect to your twitter or gmail account. Anything related to your true identity should go out of the tunnel.
First idea that comes to mind is setting multiple vpn connections but many people who have tried this, have stumbled on issues with packets being redirected to the wrong vpn.
Although one way to maintain different connections is to use vpn in Virtual Machines, i think that it is not interesting to start a VM for the sole purpose of running Firefox and checking personal stuff.
So here is a workaround that involves linux routing and this works with layer 3 tunneling using openvpn.
Openvpn tunnelingActually what openvpn does to establish layer 3 tunneling is creating a virtual-network device TUN, then all packets sent by the system to the vpn server go through the TUN device.
The TUN interface provides packet reception and transmission for user space programs. It can be viewed as a simple Point-to-Point or Ethernet device, which instead of receiving packets from a physical media, receives them from user space program and instead of sending packets via physical media writes them to the user space program.[learn more]
Network interfaces before and after tunnel creation:
$ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: wlp8s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT qlen 1000
link/ether 02:09:90:02:ad:c5 brd ff:ff:ff:ff:ff:ff
$ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: wlp8s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT qlen 1000
link/ether 02:09:90:02:ad:c5 brd ff:ff:ff:ff:ff:ff
6: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 100
link/none
Network routes before and after tunnel creation:
$ip route show
default via 192.168.1.1 dev wlp8s0 proto static
192.168.1.0/24 dev wlp8s0 proto kernel scope link src 192.168.1.10 metric 9
$ip route show
default via 10.10.36.97 dev tun0 proto static
10.10.0.1 via 10.10.36.97 dev tun0 proto static
10.10.36.97 dev tun0 proto kernel scope link src 10.10.36.98
151.0.49.13 via 192.168.1.1 dev wlp8s0 proto static
192.168.1.0/24 dev wlp8s0 proto kernel scope link src 192.168.1.10 metric 9
As indicated in the last routes listing, after tunnel creation all the traffic goes through the tunnel gateway"10.10.36.97" (accessible through the TUN interface), so in order to get the job done we should redirect certain packets (twitter, gmail,..) back to the normal gateway "192.168.1.1" (accessible through the wireless interface wlp8s0).
Now this is the delicate part, how are we gonna route specific packets through a different path?
Packets routingThis can be done by configuring linux routing policy. In fact, the default behavior is sending all packets through the default gateway which in this case is the tunnel gateway. What we can do is adding a new rule stating that packets having a certain criteria will take a different path. The simplest criteria would be the source address. Normally, the source address is only selected at the network layer but application may as well select the source address explicitly with bind().
Finally two types of packets will hit the network layer, the default ones with no source address explicitly selected that will go through the default configured gateway (which is the tunnel since vpn connection is on) and the others ones, with explicitly selected source address at application layer, will take a different path.
Now let's translate this into linux commands:
1/
First we're going to create a new routing table "offTunnel" which will be used to route packets out of the tunnel. It's simply a copy of the main routing table before the vpn connection was enabled.
# echo 200 offTunnel >> /etc/iproute2/rt_tables
# ip route add table offTunnel 192.168.1.0/24 dev wlp8s0 proto kernel scope link src 192.168.1.10 metric 9
# ip route add table offTunnel default via 192.168.1.1 dev wlp8s0 proto static
# ip route show table offTunnel
default via 192.168.1.1 dev wlp8s0 proto static
192.168.1.0/24 dev wlp8s0 proto kernel scope link src 192.168.1.10 metric 9
2/
Now we're going to add the policy routing rule which states that packets with explicitly selected source address at application layer, will be routed using the "offTunnel" routing table in order to reach the internet gateway without getting through the TUN device.
# ip rule add from 192.168.1.10 lookup offTunnel
# ip rule show
0: from all lookup local
32765: from 192.168.1.10 lookup offTunnel
32766: from all lookup main
32767: from all lookup default
"192.168.1.10" is the ip of the wifi interface (with internet connection).
3/
The last thing to do is to start the involved application or process and explicitly select the source address of its packets. But generally, end-user programs, with few exceptions like ping (-I param), do not provide this option.
So the trick is to use LD_PRELOAD variable to hijack the bind() function used by the program.
Here is a nice code snippet that makes this possible:
Binding application to specific ip, and that i used next.
$ BIND_ADDR="192.168.1.10" LD_PRELOAD=./bind.so firefox -no-remote
BIND_ADDR : the source ip address and should be the ip assigned to a network interface with internet connection.
LD_PRELOAD: library containing the alternative bind() function.
firefox -no-remote: starting a new instance of firefox (supposing that there already is an instance of firefox running)
Finally, we have two firefox instances, one with traffic going through vpn connection (private and anonymous navigation) and the second one not using tunneling. If We check the ip online, we will find different addresses.
ConclusionWell.. that was a little bit too longer than what i expected. Just some details that i could not have skipped.Anyway, i think that once those commands are assimilated and scripted this will make the transition between the two connections easy and practical.
Hope that this can be useful for you.