DEV Community

Jacopo Valanzano
Jacopo Valanzano

Posted on

Free Internet

Free internet

You might sometimes find yourself behind a captive portal, or your SIM card plan may run out of data. Although an internet connection is not viable in such cases, you can still access the internet using a technique called DNS Tunneling.

DNS tunnels are perfectly legal, though a bit slow, and, like a VPS, they provide a good way to protect yourself from malicious attackers.

Iodine is a well-known, efficient, and open-source software that allows you to tunnel IPv4 data through a DNS server. With just one server running Iodine and a network connection, you can connect to the internet, although the speed is typically very poor in most cases.
Installing Iodine is beyond the scope of this guide, but you can find numerous guides on Google detailing how to install and run Iodine.
If you are happy with Iodine's speed, you don't need this guide, although it will be almost impossible to download large files or watch YouTube videos with a single tunnel.

In this guide, we will learn how to merge multiple connections and tunnels into a single, optimized internet connection. This guide is not for the faint-hearted.

Premise:

We are using a Linux system.

Prerequisites:

  • A VPS or Server with Iodine installed ( requires a domain name pointing to your VPS/server ).
  • Multiple active network connections, such as Wi-Fi and mobile data (SIM card), USB tethering and the like. Each connection does not require internet access but must be able to perform DNS queries. You can test this using commands like nslookup or dig.
  • haproxy
  • iproute2
  • net-tools
  • socat

Install each package:

root@root:~$ apt install haproxy iproute2 net-tools socat
Enter fullscreen mode Exit fullscreen mode

Part One: Testing

First, connect to the Wi-Fi, or another available network. Use nslookup or dig to test your DNS connection. If you get a reply, you're on track!

root@root:~$ nslookup 1.1.1.1
1.1.1.1.in-addr.arpa    name = one.one.one.one.

Authoritative answers can be found from:

root@root:~$ nslookup google.com
Server:     194.168.4.100
Address:    194.168.4.100#53

Non-authoritative answer:
Name:   google.com
Address: 216.58.201.110
Name:   google.com
Address: 2a00:1450:4009:823::200e
Enter fullscreen mode Exit fullscreen mode

I recommend testing Iodine as well. If it connects successfully, simply disconnect it for now.

root@root:~# sudo iodine -f -P YOUR_PASSWORD t1.yourdomain.com
Opened dns0
Opened IPv4 UDP socket
Sending DNS queries for t1.yourdomain.com to 194.168.4.100
Autodetecting DNS query type (use -T to override).
Using DNS type NULL queries
Version ok, both using protocol v 0x00000502. You are user #1
Setting IP of dns0 to 10.0.1.3
Setting MTU of dns0 to 1130
Server tunnel IP is 10.0.1.1
Testing raw UDP data to the server (skip with -r)
Server is at 77.69.9.15, trying raw login: OK
Sending raw traffic directly to 77.69.9.15
Connection setup complete, transmitting data.
Enter fullscreen mode Exit fullscreen mode

Part Two: Connecting

Now that we have proven that our Iodine DNS tunnel works, let's identify our interfaces:

root@root:~# ip route list
default via 192.168.108.147 dev usb0 proto dhcp src 192.168.108.234 metric 213 
default via 192.168.0.1 dev wlp0s20f3 proto dhcp src 192.168.0.56 metric 303 
169.254.0.0/16 dev wlp0s20f3 scope link metric 1000 
192.168.0.0/24 dev wlp0s20f3 proto dhcp scope link src 192.168.0.56 metric 303 
192.168.108.0/24 dev usb0 proto dhcp scope link src 192.168.108.234 metric 213 
Enter fullscreen mode Exit fullscreen mode

The above means that i can use usb0 and wlp0s20f3, a USB-Tethering connection and a Wi-Fi connection respectively.

To ease things up, we will take advantage of Linux Network Namespaces.

Let's create two new namespaces. For the sake of simplicity, we will name them WifiConnection and UsbConnection:

root@root:~# ip netns add "WifiConnection"
root@root:~# ip netns add "UsbConnection"
Enter fullscreen mode Exit fullscreen mode

Now let's assign an interface to each namespace:

root@root:~# ip link set wlp0s20f3 netns "WifiConnection"
root@root:~# ip link set usb0 netns "UsbConnection"
Enter fullscreen mode Exit fullscreen mode

Bring the interfaces up:

root@root:~# ip netns exec WifiConnection ip link set wlp0s20f3 up
root@root:~# ip netns exec UsbConnection ip link set usb0 up
Enter fullscreen mode Exit fullscreen mode

Assign an IP to each interface:

root@root:~# ip netns exec WifiConnection dhclient wlp0s20f3
root@root:~# ip netns exec UsbConnection dhclient usb0
Enter fullscreen mode Exit fullscreen mode

Bring the loopback interfaces up

root@root:~# ip netns exec WifiConnection ip link set lo up
root@root:~# ip netns exec UsbConnection ip link set lo up
Enter fullscreen mode Exit fullscreen mode

Now run Iodine:

root@root:~# ip netns exec WifiConnection iodine -f -P YOUR_PASSWORD 8.8.8.8 t1.yourdomain.com
root@root:~# ip netns exec UsbConnection iodine -f -P YOUR_PASSWORD 1.1.1.1 t1.yourdomain.com
Enter fullscreen mode Exit fullscreen mode

Next, open the socks5 tunnels. The ports 2240 & 2340 are random; i just like the numbers.
( you can view the IP of the remote server by looking at the output of Iodine, specifically "Server tunnel IP is 10.0.1.1" )

root@root:~# ip netns exec WifiConnection ssh srv@10.0.1.1 -D 2240
root@root:~# ip netns exec UsbConnection ssh srv@10.0.1.1 -D 2340
Enter fullscreen mode Exit fullscreen mode

Now use socat to listen to UsbConnection and WifiConnection:

root@root:~# socat tcp-listen:2241,fork,reuseaddr exec:'ip netns exec WifiConnection /usr/sbin/sshd -i',nofork
root@root:~# socat tcp-listen:2242,fork,reuseaddr exec:'ip netns exec UsbConnection /usr/sbin/sshd -i',nofork
Enter fullscreen mode Exit fullscreen mode

We can now forward the DNS tunnels:

ssh root@0.0.0.0 -p 2241 -L 2240:127.0.0.1:2240
ssh root@0.0.0.0 -p 2242 -L 2340:127.0.0.1:2340
Enter fullscreen mode Exit fullscreen mode

Amazing, we now have two socks5 connections acting as DNS tunnels: one on 127.0.0.1:2240 and another one on 127.0.0.1:2340

All that's left to do is set up a load balancer between the two connections. Keep in mind that you can use as many connections as you want!
For example, you could create a third connection by plugging one of these USB Wi-Fi adapters.

Enough with the chit-chat. Edit haproxy config file haproxy.cfg, usually /etc/haproxy/haproxy.cfg, and make sure that the default mode is set to tcp and not http.

Also, add the following lines to your HAProxy config file:

frontend socks5-in 
    bind *:1080
    default_backend socks5-out

backend socks5-out 
      balance roundrobin 
      server proxy1 127.0.0.1:2240 check 
      server proxy2 127.0.0.1:2340 check
Enter fullscreen mode Exit fullscreen mode

The configurations above will create a new socks5 connection on port 1080.
You can now use 127.0.0.1:1080 as socks5 proxy, distributing traffic evenly between the tunnels.

So, that's it. Next time you can't pay your internet bill, don't panic—just follow this guide and get back online in no time!

Sidenotes:

  • If you use Cloudflare, the NS record must be unproxied.
  • Check your Server's firewall and make sure Port 53 can accept UDP packets.

Top comments (0)