Mozilla VPN - How to make a VPN gateway

Mozilla VPN logo

I recently bought the new Mozilla VPN because I think it's a good way to support the foundation.

For now, the VPN is compatible with Windows 10, macOS, Android, iOS and Ubuntu. Which is already not bad but not enough for me as I'm an ArchLinux user. So I created an VPN gateway under Ubuntu in my network to make me able to use it from non compatible machines.

⚠️ Mozilla VPN licence allows you to use up to 5 devices. The goal of this topic is not to bypass this limit. ⚠️

Network Architecture

Gateway VPN Architecture
My network architecture.

Ubuntu (VPN Gateway)

Ubuntu logo

⚠️ Mozilla VPN can work on Ubuntu Focal Fossa 20.04 and Bionic Beaver 18.04 only.

Install Mozilla VPN

  • Add repository package and install :
user@ubuntu:~$ sudo add-apt-repository ppa:mozillacorp/mozillavpn
user@ubuntu:~$ sudo sudo apt-get update
user@ubuntu:~$ sudo apt-get install mozillavpn
  • Launch Mozilla VPN :
user@ubuntu:~$ mozillavpn
  • Enable Mozilla VPN :
Mozilla VPN | Enable VPN

IPv4

Enable ip forwarding

  • Temporarily :
user@ubuntu:~$ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
  • To make it persistent, edit /etc/sysctl.conf and uncomment this line :
net.ipv4.ip_forward=1
    • Load new parameters :
user@ubuntu:~$ sudo sysctl -p

Create a netfilter masquerade rule

  • Create a NAT rule that masquerade outgoing traffic to moz0 interface :
user@ubuntu:~$ sudo iptables -t nat -A POSTROUTING -o moz0 -j MASQUERADE

IPv6

Get ipv6 local address

  • Note ipv6 address :
user@ubuntu:~$ ip -6 addr sh
2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet6 2001:db8::/64 scope global dynamic mngtmpaddr 
       valid_lft 86187sec preferred_lft 14187sec
    inet6 fe80::fe80::aaff:874a:dead:beef/64 scope link 
       valid_lft forever preferred_lft forever

Enable ip forwarding

  • Temporarily :
user@ubuntu:~$ echo 1 | sudo tee /proc/sys/net/ipv6/conf/all/forwarding
  • To make it persistent, edit /etc/sysctl.conf and uncomment this line :
net.ipv6.conf.all.forwarding=1
    • Load new parameters :
user@ubuntu:~$ sudo sysctl -p

Create a netfilter masquerade rule

  • Create a NAT rule that masquerade outgoing traffic to moz0 interface :
user@ubuntu:~$ sudo ip6tables -t nat -A POSTROUTING -o moz0 -j MASQUERADE

ArchLinux (Client)

Arch linux logo

IPv4

Here we can choose between routing all traffic or to use the Port Based Routing, wich consits of routing specific protocols to our Ubuntu gateway.

Port Based Routing

PBR consists in marking frames we want to route to VPN gateway. Only frames which are marked with 0x80 value will be routed to VPN.

VPN table
  • Create vpn table :
root@arch:~# echo "200	vpn" >> /etc/iproute2/rt_tables
root@arch:~# ip rule add fwmark 0x80 table vpn
  • Add default gateway for the vpn table :
root@arch:~# ip route add default via 172.31.0.200 dev ens160 table vpn
  • Check vpn table :
root@arch:~# ip route list table vpn
default via 172.31.0.200 dev ens160
nftables rules

For the example we will mark http and https frames.

  • Create a nftables MANGLE chain :
root@arch:~# nft add chain ip filter MANGLE { type route hook output priority -150\; policy accept \; }
  • Mark every http and https frames but ones for LAN (172.31.0.0/24, 10.0.0.0/24) :
root@arch:~# nft insert rule ip filter MANGLE tcp dport { 80, 443 } ip daddr \!= { 172.31.0.0/24, 10.0.0.0/24 } meta mark set 0x80 counter
  • If we want we can Mark also every outbound tcp frames :
root@arch:~# nft insert rule ip filter MANGLE tcp sport \>= 1024 ip daddr \!= { 172.31.0.0/24, 10.0.0.0/24 } meta mark set 0x80 counter
  • If we want we can Mark also every outbound udp frames :
root@arch:~# nft insert rule ip filter MANGLE udp sport \>= 1024 ip daddr \!= { 172.31.0.0/24, 10.0.0.0/24  } meta mark set 0x80 counter

Route all traffic

Easier we can simply route all traffic to our VPN gateway :

  • Remove the current default route :
root@arch:~# route del default
  • Add default route :
root@arch:~# route add default via 172.31.0.200 dev ens160

Check

  • Get current public ipv4 address :
root@arch:~# curl ipinfo.io/ip

IPv6

Change default route

  • Remove the current default route :
root@arch:~# ip -6 route del default
  • Add default route :
root@arch:~# ip -6 route add default via fe80::aaff:874a:dead:beef dev ens160 metric 1

Check

  • Get current public ipv6 address :
root@arch:~# telnet -6 ipv6.telnetmyip.com

Check ips addresses with WebExtension

  • I've developped a small WebExtension to get current public ipv4 and ipv6 addresses, you can download it here :
shebangtheip webextension to get current ipv4 and ipv6 addresses
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Contact :