Title: Aggregate internet links with mlvpn | |
Author: Solène | |
Date: 28 March 2020 | |
Tags: openbsd | |
Description: | |
In this article I'll explain how to aggregate internet access bandwidth | |
using | |
**mlvpn** software. I struggled a lot to set this up so I wanted to | |
share a | |
how-to. | |
## Pre-requisites | |
**mlvpn** is meant to be used with DSL / fiber links, not wireless or | |
4G links | |
with variable bandwidth or packet loss. | |
**mlvpn** requires to be run on a server which will be the public | |
internet | |
access and on the client on which you want to aggregate the links, this | |
is like | |
doing multiples VPN to the same remote server with a VPN per link, and | |
aggregate them. | |
Multi-wan roundrobin / load balancer doesn't allow to stack bandwidth | |
but | |
doesn't require a remote server, depend on what you want to do, this | |
may be | |
enough and mlvpn may not be required. | |
**mlvpn** should be OS agnostic between client / server but I only | |
tried | |
between two OpenBSD hosts, your setup may differ. | |
## Some network diagram | |
Here is a simple network, the client has access to 2 ISP through two | |
ethernet | |
interfaces. | |
em0 and em1 will have to be on different rdomains (it's a feature to | |
separate | |
routing tables). | |
Let's say the public ip of the server is 1.2.3.4. | |
[internet] | |
↑ | |
| (public ip on em0) | |
#-------------# | |
| | | |
| Server | | |
| | | |
#-------------# | |
| | | |
| | | |
| | | |
| | | |
(internet) | | (internet) | |
#-------------# #-------------# | |
| | | | | |
| ISP 1 | | ISP 2 | | |
| | | | (you certainly don't control | |
those) | |
#-------------# #-------------# | |
| | | |
| | | |
(dsl1 via em0)| | (dsl1 via em1) | |
#-------------# | |
| | | |
| Client | | |
| | | |
#-------------# | |
## Network configuration | |
As said previously, em0 and em1 must be on different rdomains, it can | |
easily be | |
done by adding `rdomain 1` and `rdomain 2` to the interfaces | |
configuration. | |
Example in **/etc/hostname.em0** | |
rdomain 1 | |
dhcp | |
## mlvpn installation | |
On OpenBSD the installation is as easy as `pkg_add mlvpn` (should work | |
starting | |
from 6.7 because it required patching). | |
## mlvpn configuration | |
Once the network configuration is done on the client, there are 3 steps | |
to do | |
to get aggregation working: | |
1. mlvpn configuration on the server | |
2. mlvpn configuration on the client | |
3. activating NAT on the client | |
### Server configuration | |
On the server we will use the UDP ports 5080 et 5081. | |
Connections speed must be defined in bytes to allow **mlvpn** to | |
correctly | |
balance the traffic over the links, this is really important. | |
The line `bandwidth_upload = 1468006` is the maximum **download | |
bandwidth of the | |
client** on the specified link in bytes. If you have a download speed | |
of 1.4 MB/s | |
then you can choose a value of 1.4\*1024\*1024 => 1468006. | |
The line `bandwidth_download = 102400` is the maximum **upload | |
bandwidth of the | |
client** on the specified link in bytes. If you have an upload speed of | |
100 kB/s | |
then you can choose a value of 100*1024 => 102400. | |
The **password** line must be a very long random string, it's a shared | |
secret | |
between the client and the server. | |
# config you don't need to change | |
[general] | |
statuscommand = "/etc/mlvpn/mlvpn_updown.sh" | |
protocol = "tcp" | |
loglevel = 4 | |
mode = "server" | |
tuntap = "tun" | |
interface_name = "tun0" | |
cleartext_data = 0 | |
ip4 = "10.44.43.2/30" | |
ip4_gateway = "10.44.43.1" | |
password = | |
"apoziecxjvpoxkvpzeoirjdskpoezroizepzdlpojfoiezjrzanzaoinzoi" | |
bindhost = "1.2.3.4" | |
bindport = 5080 | |
bandwidth_upload = 1468006 | |
bandwidth_download = 102400 | |
bindhost = "1.2.3.4" | |
bindport = 5081 | |
bandwidth_upload = 1468006 | |
bandwidth_download = 102400 | |
### Client configuration | |
The `password` value must match the one on the server, the values of | |
`ip4` and | |
`ip4_gateway` must be reversed compared to the server configuration | |
(this is so | |
in the following example). | |
The `bindfib` lines must correspond to the according rdomain values of | |
your | |
interfaces. | |
# config you don't need to change | |
[general] | |
statuscommand = "/etc/mlvpn/mlvpn_updown.sh" | |
loglevel = 4 | |
mode = "client" | |
tuntap = "tun" | |
interface_name = "tun0" | |
ip4 = "10.44.43.1/30" | |
ip4_gateway = "10.44.43.2" | |
timeout = 30 | |
cleartext_data = 0 | |
"apoziecxjvpoxkvpzeoirjdskpoezroizepzdlpojfoiezjrzanzaoinzoi" | |
remotehost = "1.2.3.4" | |
remoteport = 5080 | |
bindfib = 1 | |
remotehost = "1.2.3.4" | |
remoteport = 5081 | |
bindfib = 2 | |
### NAT configuration (server side) | |
As with every VPN you must enable packet forwarding and create a pf | |
rule for | |
the NAT. | |
**Enable forwarding** | |
Add this line in **/etc/sysctl.conf**: | |
net.inet.ip.forwarding=1 | |
You can enable it now with `sysctl net.inet.ip.forwarding=1` instead of | |
waiting | |
for a reboot. | |
In pf.conf you must allow the UDP ports 5080 and 5081 on the public | |
interface | |
and enable nat, this can be done with the following lines in pf.conf | |
but you | |
should obviously adapt to your configuration. | |
# allow NAT on VPN | |
pass in on tun0 | |
pass out quick on em0 from 10.44.43.0/30 to any nat-to em0 | |
pass in on egress inet proto udp from any to (egress) port | |
5080:5081 | |
## Start mlvpn | |
On both server and client you can run mlvpn with rcctl: | |
rcctl enable mlvpn | |
rcctl start mlvpn | |
You should see a new tun0 device on both systems and being able to ping | |
them | |
through tun0. | |
Now, on the client **you have to add a default gateway through the | |
mlvpn | |
tunnel** with the command ` route add -net default 10.44.43.2` (adapt | |
if you | |
use others addresses). I still didn't find how to automatize it | |
properly. | |
Your client should now use both WAN links and being visible with the | |
remote | |
server public IP address. | |
**mlvpn** can be used for more links, you only need to add new | |
sections. | |
**mlvpn** also support IPv6 but I didn't take time to find how to make | |
it work, | |
si if you are comfortable with ipv6 it may be easy to set up IPv6 with | |
the | |
variables `ip6` and `ip6_gateway` in mlvpn.conf. |