1

I'm trying to configure a network set up for a custom VPN CLIENT library.


What I can't figure out

I need to be able to forward the traffic in a normal VPN set up so that my C++ script can read/write to the tunnel. If I'm not mistaken, the set up should be something like this:

       Normal Setup           How I think my setup should be
------------------------------------------------------------
Start → Aplication → Finish    Start → Aplication → Finish
          ↓   ↑                          ↓   ↑ 
       iface-enp0s3                   iface-enp0s3
          ↓   ↑                          ↓   ↑
        interwebs                      iface-tun1
                                         ↓   ↑
                                       c++ script
                                         ↓   ↑
                                       vpn-server
                                         ↓   ↑
                                       interwebs

I do know that my C++ script does not currently do this, currently it just reads data from the tun1 adapter. For the time being, that is all that I'm trying to achieve. However, I can't seem to get the routes working properly.

When I visit http://google.com from my client system, I want to see those packets displayed in the C++ script, and the traffic to go no where else.

Once I'm able to properly route all traffic excluding the port that the VPN is connected on through the C++ script using the tunnel interface, I will begin sending it through the VPN client library.

The C++ script currently works, as far as I know. When I ping 10.0.0.2 (the tun1 adapter), I can see the packets come through.

I've tried a few different things, namely the following:

sudo iptables -t nat -A POSTROUTING --out-interface tun1 -j MASQUERADE
sudo iptables -A FORWARD --in-interface enp0s3 -j ACCEPT

This did not work.

Note: I've already made sure that net.ipv4.ip_forward is set to 1 and I've run sudo sysctl -p.

See below for information on the current set up.

Note: I'm running Ubuntu 16.04 Desktop.


My Current Adapters

Note: enp0s3 is my primary adapter. This is running on a virtual machine. enp0s3 is my connection to the internet.

enp0s3    Link encap:Ethernet  HWaddr 08:00:27:ea:97:d2  
           inet addr:10.0.2.15  Bcast:10.0.2.255  Mask:255.255.255.0
           inet6 addr: fe80::8ec8:60b7:f404:77c5/64 Scope:Link
           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
           RX packets:58668 errors:0 dropped:0 overruns:0 frame:0
           TX packets:39067 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 txqueuelen:1000 
           RX bytes:39002535 (39.0 MB)  TX bytes:7442839 (7.4 MB)

tun1      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
           inet addr:10.0.0.1  P-t-P:10.0.0.2  Mask:255.255.255.255
           inet6 addr: fe80::fed9:4107:8688:8501/64 Scope:Link
           UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
           RX packets:0 errors:0 dropped:0 overruns:0 frame:0
           TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 txqueuelen:500 
           RX bytes:0 (0.0 B)  TX bytes:984 (984.0 B)

How I set up my tun1 adapter

$ sudo ip tuntap add dev tun1 mode tun

$ sudo ifconfig tun1 10.0.0.1 dstaddr 10.0.0.2 up


The C++ script I have listening to tun1

 // Includes ommited.

 using namespace std;

 typedef void data_receiver(char* data, int length);

 struct receive_handle {
     data_receiver* receiver;
 } typedef receive_handle;

 // Function used to retrieve the interface.
 static int if_nametofd(char *name)
 {
     int interface = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
     ifreq ifr;
     memset(&ifr, 0, sizeof(ifr));
     ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
     strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
     if (ioctl(interface, TUNSETIFF, &ifr)) {
         perror("Cannot get TUN interface");
         exit(1);
     }

     return interface;
 }

 // Called when a packet is received from the tun0 interface.
 void received_data(char* data, int length)
 {
     // Truncate the packet so that we only see the first 15 bytes.
     // This way we don't spam the console.
     for(int i=0; i<15; ++i)
         std::cout << std::hex << (int)data[i];

     std::cout << endl;
 }

 int main()
 {
     cout << "Getting interface..." << endl;

     int iface = if_nametofd("tun1");
     cout << "Using interface: " << iface << endl;

     cout << "Creating handler..." << endl;
     receive_handle* handle = (receive_handle*)malloc(sizeof(receive_handle));
     handle->receiver = received_data;

     char packet[1024];
     cout << "Listening..." << endl;
     while (true)
     {
         if (read(iface, packet, sizeof(packet)) > 0) {
             handle->receiver(packet, sizeof(packet));
         }
     }

     return 0;
 }

This scripts only purpose is to latch onto the tun1 adapter and continuously read from it.


1 Answer 1

1

You need to change the default gateway of your workstation. If you issue the following command, you will see your system default gateway.

ip route show table main
default via 1.2.3.4 dev wanif

You could change it by using ip route replace (man ip-route).

Better, you can use open vpn trick to override the default route, without having to delete it (--redirect-gateway def1).

This work by adding two routes covering the whole IPv4 address space. As each of this two routes is more specific than the default route, the default route is practically overriden.

This is done like this:

ip route add 0.0.0.0/1 via 10.0.2.15 dev tun1
ip route add 128.0.0.0/1 via 10.0.2.15 dev tun1

where 10.0.2.15 is your tunnel local endpoint.

since your script needs to connect somewhere "via the regular interweb" to provide some meaningful tunneling service, you need to add your remote endpoint like this to avoid being covered by the above rule:

ip route add 7.8.9.10/32 via 1.2.3.4 dev wanif

where 7.8.9.10 is your remote endpoint, and 1.2.3.4 your ISP default gateway.

Remember the basic rules of routing rules: the most specific ones apply over the less specific ones

4
  • How does this process avoid effecting the socket that the C++ script is using to connect to the VPN server?
    – Nathan F.
    Commented Apr 1, 2018 at 18:34
  • 1
    you add a /32 route to the other tunnel endpoint Commented Apr 1, 2018 at 19:01
  • That seemed to work :) At least with preliminary tests, I'll need to finish with the rest of it and test to be sure. Thanks!
    – Nathan F.
    Commented Apr 1, 2018 at 19:56
  • you're welcome. Don't hesitate to look at open vpn resources for endless source of tips on tunnels ;) Commented Apr 1, 2018 at 19:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .