[Markdown] 

Linux hints: linux multihomed routing and vpn (part 1)

routing in multihomed networks in linux, vps uplinks via vpn

some time ago i am faced interesting task, i needed to route some traffic via different uplinks (incoming and outgoing both). in linux it’s possible to use source based routing, uid/gid based routing via iproute2 and iptables.

  1. define additional routing tables in
/etc/iproute2/rt_tables

file already contain few predefined routing tables in following format:

table_id table_name

you can add something like:

1 my_table

you can ad as many table as you need.

  1. add needed rules to routing table,

now you can add rules to added routing tables, you need to add one more argument to “ip route” - table like:

ip route add default via 10.10.10.1 dev tap13 table my_table
ip route add 192.168.0.0/24 dev eth0 table my_table

something like this, second rule necessary for apps to be able to reach local network, if it’s needed.

  1. rules (something interesting begins here)
ip rule add from 10.10.10.2/32 table my_table

this will route traffic from address 10.10.10.2 via “my_table” routing table

ip rule add fwmark 3 table my_table

this will route all traffic marked with “3” via “my_table” routing table, how to mark traffic will be explained later

  1. iptables

i have used iptables for traffic marking.
most simple and efficient enough is marking based on uid/gid, you can do this like this:

iptables -t mangle -A OUTPUT -m owner --uid-owner pleroma -j MARK --set-mark 3

in step 3 i added rule to route all traffic marked with “3” via “my_table” routing table,
and now i marked all traffic from uid pleroma with “3” so it will go via routing table as well.
here required little hack for this to work, as by default “default” routing table is used, source address for this marked traffic most probably be incorrect and routing will be confused and nothing work, to prevent this we need to change source address like this:

iptables -t nat -A POSTROUTING -o tap13 -j SNAT --to-source=10.10.10.2
  1. openvpn

as you may already noticed, i am using tap interface, it’s used by vpn implementation and as vpn implementation i using openvpn, i will not write much about openvpn here, instead i will post working openvpn configs for server and client, as it maybe a little tricky to write one:

server:

mode server
tls-server
port 12345
proto udp4
dev-type tap
dev tap13
ca /etc/openvpn/server/vps-ca.crt
cert /etc/openvpn/server/vps-server.crt
key /etc/openvpn/server/vps-server.key
dh /etc/openvpn/server/vps/dh4096.pem
server 10.10.10.0 255.255.255.0
push "route 10.10.10.0 255.255.255.0"
client-config-dir /etc/openvpn/server/vps/ccd
client-to-client
keepalive 30 240
max-clients 10
persist-key
persist-tun
status /var/log/openvpn/vps-status.log
verb 4
mute 20
tls-cipher "DHE-RSA-AES128-GCM-SHA256"
cipher AES-128-GCM
ncp-ciphers AES-128-GCM
tls-crypt /etc/openvpn/server/vps/shared_key
compress lzo
float
fast-io
verify-client-cert require

client:

tls-client
remote 127.0.0.1 #write server ip here instead
port 12345
proto udp4
dev-type tap
dev tap13
ca /etc/openvpn/client/vps-ca.crt
cert /etc/openvpn/client/vps-user.crt
key /etc/openvpn/client/vps-user.key
dh /etc/openvpn/dh4096.pem
keepalive 30 240
persist-key
persist-tun
verb 4
mute 20
tls-cipher "DHE-RSA-AES128-GCM-SHA256"
cipher AES-128-GCM
ncp-ciphers AES-128-GCM
tls-crypt /etc/openvpn/client/vps3-shared_key
compress lzo
float
fast-io
verify-client-cert require

aes cipher is used here because hw crypto available on cpu on both sides of connection, without hw crypto it’s better to set chacha20 for tls and cammelia for blocks instead of aes, 128 bit key size used for performance, if you need better security, set 256.
most probably few options is useless in client config, like dh , compress, verify-client,keep-alive .

  1. conclusion, notes, hints

this short article does not cover firewall rules to route traffic from vps to client (this machine which we configuring in this article), it’s as trivial as FORWARD + PREROUTING, figure out it yourself as part of homework )
also, now exists another vpn implementations like wireguard https://www.wireguard.com/, which is kernel-space and should be more efficient than openvpn, also here is ipsec, l2tp and even pptp, i choose openvpn because it flexible and because i do not need very high bandwidth, so openvpn performance is suffice for me.