Server mit VPN Routing

ostfriese

Junior Member
Hallo,

ich bin oft unterwegs in Hotelzimmern und möchte, da ich oft abends arbeite und nebenbei Streams, gerne auch aus England und Amerika, schaue folgendes bauen:

Ich habe auf einem Raspberry(172.16.0.150 verbunden über wlan0) im Heimnetz, Router Fritzbox (172.16.0.1), auf tun0 einen VPN-Server laufen. Auf tun1 nur als Bsp. eine Verbindung zu Amsterdam, auf tun2 eine Verbindung nach Rotterdam und so weiter. Mein Server nutzt "topology-subnet", so dass ich mich als client1, client2 oder client3 einloggen kann. Ich möchte nun, dass, wenn ich mich als client1 einlogge, tun0 mich nach tun1 weiter routet, als client2 aber nach tun2 weiter routet. Also, ich als client1 eine public ip aus Amsterdam habe und als client2 eine public ip aus Rotterdam. (nur als Beispiel)

Hier die relevanten Auszüge aus den Config-Dateien:
Code:
dev tun0
proto udp
port 443
client-config-dir ccd
...
server 10.8.1.0 255.255.255.0
topology subnet
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
push "topology subnet"
...

in ccd client1:
Code:
ifconfig-push    10.8.1.2 10.8.1.1
in ccd client2:
Code:
ifconfig-push    10.8.2.2 10.8.2.1

Auf dem Server läuft nun af tun1 als Beispiel eine Verbindung nach perfect-privacy-Amsterdam und
auf tun2 eine Verbindung nach perfect-privacy- Rotterdam. In beiden Configs ist:

Code:
route-nopull

aktiviert.

Die Routing-Tabelle sieht dann so aus:
Code:
Kernel-IP-Routentabelle
Ziel            Router          Genmask         Flags Metric Ref    Use Iface
default         fritz.box       0.0.0.0         UG    0      0        0 wlan0
default         fritz.box       0.0.0.0         UG    303    0        0 wlan0
10.8.1.0        *               255.255.255.0   U     0      0        0 tun0
10.15.22.0      *               255.255.255.0   U     0      0        0 tun1
10.16.32.0      *               255.255.255.0   U     0      0        0 tun2
172.16.0.0      *               255.255.0.0     U     0      0        0 wlan0
172.16.0.0      *               255.255.0.0     U     303    0        0 wlan0

Als Firewall-Skript habe ich:

Code:
#! /bin/sh
sysctl -w net.ipv4.ip_forward=1
iptables -F -t nat
iptables -F
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE

und auf dem Client ist ip_forward aktiviert.

Natürlich kann das so noch nicht funktionieren. Es fehlt ja das Routing. Und genau das ist meine Frage. Welche Routen muss ich genau (am besten mit "route add" Befehlen, da leichter in einem Script zu verarbeiten) einfügen, damit das so, wie oben beschrieben funktioniert. Das die IP der VPN-Verbindungen von perfect-privacy sich ändern, ist kein Problem, da es ein leichtes für mich ist, das mit Python zu erledigen, wenn ich einmal die Systematik des Routens erkannt habe.

Ich hoffe, ich habe klar machen können, was ich bauen will. Ich hoffe auf eure Hilfe, weil ich mit dem Routing schon mehre lange Nächte mit try und error verbracht habe, ohne nennenswerten Erfolg.
 
ich generiere aus den pp-openvpn-Dateien per script meine eigenen Configs. Die sehen dann so aus:
Beispiel für Düsseldorf:
Code:
...
route-nopull
route-noexec

...
route-delay 2
route-up /etc/openvpn/scripts/Duesseldorf.sh
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/scripts/Duesseldorf_down.sh
log-append /var/log/openvpn-Duesseldorf.log

im Script Verzeichnis gibt es dann ein script generic.sh und jeweils links auf dieses script mit dem jeweiligen Städtenamen:
Code:
Duesseldorf.sh -> generic.sh
für jedes tun (1..14) device habe ich eine eigene routing Tabelle in /etc/iproute2
Code:
#
# reserved values
#
255  local
254  main
253  default
0  unspec
#
# local
#
#1  inr.ruhep
1 mail_table
2 pp_table1
...
14 pp_table13
15 pp_table14

42 ip_table1
...
54 ip_table13
55 ip_table14
56 ipv6table
die pp_tables dienen dazu den webtraffic zu routen, der von meinem Proxy kommt ==> brauchst Du nicht
Die ip_tables leiten den trafiic abhängig von der source-ip über das richtige Interface. Die source-ip wäre bei Dir die 10.8.1.1 ... usw. denke ich.
In generic.sh wird dann zunächst die Stadt ermittelt, dann die routen gesetzt:
Code:
name=$0
city=${name%.sh}
city=${city##*/}
...
#next check for extra routes and IP-based routes
tun_id=`echo $dev | sed 's/...//'`
ip_table="ip_table"${tun_id}
OIFS="$IFS"
IFS=$'\r\n'
matching_rules=( $(/bin/ip rule show | grep $ip_table | cut -d: -f2) )
IFS="$OIFS"
# first remove all ip based rules for this interface
for rule in "${matching_rules[@]}"
do
  echo "ip rule delete $rule"
  ip rule delete $rule
done
...
# below additional steps for IP-based routing
  if [ "$do_route_ip" == "1" ]
  then
  echo "new rule entry:"
  echo "ip rule add from ${ip_source}/32 table $ip_table"
  ip rule add from ${ip_source}/32 table $ip_table
  echo "ip route change $route_vpn_gateway dev $dev proto kernel scope link src $ifconfig_local table $ip_table"
  ip route change $route_vpn_gateway dev $dev proto kernel scope link src $ifconfig_local table $ip_table >/dev/null 2>&1
  if [ $? -ne 0 ] ; then
# change failed, because there was no route, add instead
  echo "ip route add $route_vpn_gateway dev $dev proto kernel scope link src $ifconfig_local $ip_table"
  ip route add $route_vpn_gateway dev $dev proto kernel scope link src $ifconfig_local table $ip_table
  fi
  echo "ip route change ${ip_source} dev $ip_interface proto kernel scope link src $ifconfig_local table $ip_table"
  ip route change ${ip_source} dev $ip_interface proto kernel scope link src $ifconfig_local table $ip_table >/dev/null 2>&1
  if [ $? -ne 0 ] ; then
# change failed, because there was no route, add instead
  echo "ip route add ${ip_source} dev $ip_interface proto kernel scope link src $ifconfig_local table $ip_table"
  ip route add ${ip_source} dev $ip_interface proto kernel scope link src $ifconfig_local table $ip_table
  fi
  echo "ip route change ${ip_source} dev $ip_interface table $ip_table"
  ip route change ${ip_source} dev $ip_interface table $ip_table >/dev/null 2>&1
  if [ $? -ne 0 ] ; then
# change failed, because there was no route, add instead
  echo "ip route add ${ip_source} dev $ip_interface table $ip_table"
  ip route add ${ip_source} dev $ip_interface table $ip_table
  fi
  echo "ip route change 127.0.0.0/8 dev lo table $ip_table"
  ip route change 127.0.0.0/8 dev lo table $ip_table >/dev/null 2>&1
  if [ $? -ne 0 ] ; then
# change failed, because there was no route, add instead
  echo "ip route add 127.0.0.0/8 dev lo table $ip_table"
  ip route add 127.0.0.0/8 dev lo table $ip_table
  fi
  echo "ip route change default dev $dev table $ip_table"
  ip route change default dev $dev table $ip_table >/dev/null 2>&1
  if [ $? -ne 0 ] ; then
# change failed, because there was no route, add instead
  echo "ip route add default dev $dev table $ip_table"
  ip route add default dev $dev table $ip_table
  fi
  echo "ip route flush cache table $ip_table"
  ip route flush cache table $ip_table
  fi

Da das generisch ist, wird das eigentliche routing über Dateien in einem Verzeichnis gesteuert:
Code:
/etc/openvpn/scripts/routes# ls -1l
total 8
lrwxrwxrwx 1 root root  38 Jan 21 17:00 192.168.0.202 -> ../generic_routes/generic_ip_Frankfurt
lrwxrwxrwx 1 root root  38 Jan  5 17:19 192.168.0.227 -> ../generic_routes/generic_ip_Nuremberg
...
lrwxrwxrwx 1 root root  35 Nov  3 15:22 www.microsoft.com -> ../generic_routes/generic_Rotterdam
Das script schaut sich an, was da steht und matched das dann mit dem jeweiligen Interface
Die Dateien selbst sind eigentlich leer (analysiert wird nur das route_via):
Code:
/etc/openvpn/scripts/routes# cat ../generic_routes/generic_ip_Frankfurt
# route_via Frankfurt

echo "IP-based routing for $ip_source via $city"
Die folgenden Variablen werden von openvpn gesetzt und sind damit im script verfügbar (aber pp setzt nicht alle):
Code:
ifconfig_pool_local_ip6
ifconfig_pool_remote_ip6
ifconfig_local  10.8.12.xxx
ifconfig_remote
ifconfig_netmask  255.255.255.0
foreign_option_1
foreign_option_2
foreign_option_3
route_vpn_gateway
Insbesondere ifconfig_local ist wichtig. Du mußt Dir für manche Zwecke noch das passende gateway ermitteln. Leider sind die pp-sites nicht alle konsistent, daher braucht man ein paar extra Regeln:
Code:
# special for site without route_vpn_gateway
preamble=`echo $ifconfig_local | cut -d '.' -f 1-3`
last_octet=`echo $ifconfig_local | cut -d '.' -f 4`
if [ "$last_octet" -gt "127" ] ; then
  route_vpn_gateway="${preamble}.129"
else
  route_vpn_gateway="${preamble}.1"
fi
# below for the few instances with a /24 network address
if [ "$ifconfig_netmask" == "255.255.255.0" ] ; then
  route_vpn_gateway="${preamble}.1"
fi
Du mußt das nicht so kompliziert machen, da Deine Umgebung deutlich überschaubarer ist, aber die Grundidee ist da. Ist gewiß noch was an Arbeit für Dich drin...
Ich mache noch ein paar Dinge mehr, z.B. werden alle routen erst auf 127.0.0.1 umgelenkt und auch beim Verbindungsabbruch wieder darauf gelegt, damit nichts am Tunnel vorbei kommt. Als backup wird das natürlich auch noch über die iptables-firewall blockiert...

Außerdem habe ich noch ein script, welches die routen testet und für meinen squid eine "known-good" route erzeugt, die dann allerdings auch mal plötzlich auf einen anderen Server geschwenkt werden kann - damit kommen aber viele Webseiten nicht klar, wenn plötzlich die Verbindung von einer anderen IP kommt - eigentlich ist http ja connectionless...

p.s. mit den zusätzlichen routing tables muß man übrigens aufpassen sonst rauft man sich die Haare, weil es in der normalen routing table ja nicht offensichtlich ist. Also immer auch die tables ansehen
und mit ip -4 route get y.x.z.w kontrollieren
 
Last edited:
WOW!!! erst einmal vielen, vielen Dank für die ausführliche Antwort. Puh, das mus ich mal analysieren, um das Bahnhof-versteh-Feeling loszuwerden.
 
Schau Dir am besten linux advanced routing an: http://lartc.org/howto/
Die rules und routing Tabellen, wie das script sie dann macht sehen so aus:
Code:
# ip rule show | grep ip_table8
32731:   from 192.168.0.6 lookup ip_table8
32732:   from 192.168.0.227 lookup ip_table8
# ip route show table ip_table8
default dev NUR8  scope link
10.30.11.1 dev NUR8  proto kernel  scope link  src 10.30.11.248
127.0.0.0/8 dev lo  scope link
192.168.0.6 dev eth0  scope link
192.168.0.227 dev eth0  scope link
Diese ganzen Einträge müssen alle sein (inklusive lo) sonst ist die Tabelle nicht vollständig und funktioniert ggf. nicht.
Bei mir ist tun8 übrigens NUR8, weil es Nürnberg ist. Entsprechende habe ich alle anderen tuns auch gesetzt. Da weiß man wenigstens welcher pp-server das ist
 
Danke dir noch einmal. Der Link zum Howto den du gepostet hast, ist wohl der Schlüssel zum Erfolg. Werde mich da mal durchwühlen.
 
Back
Top