Archiv der Kategorie: pppoe failover ucarp linux freenas freebsd

PPPoE Failover mit uCARP zwischen Linux (Debian) und FreeNAS Containern

plitc_pppoe_failover

Die „PPPoE (ADSL) Modem“ Einwahl soll mit Hilfe von 2 Containern ausfallsicher werden.
Mit uCARP gibt es ein universellen Vermittler zwischen Linux und FreeNAS (FreeBSD).
Da das FreeNAS OS (Image) selbst als „Storagelösung“ getrimmt wird, bauen wir uns, für diesen Anwendungsfall, in einer „Buildumgebung“ die fehlenden „PPP“ und „PPPoE“ Kernelmodule nach.

Die Kriterien an den Containern sind wie folgt:
1. PPPoE Dialin (Debian/FreeBSD)
2. Routing (Debian/FreeBSD)
3. NAT – iptables unter Debian / ipfw unter FreeBSD
4. Beschränkung auf 1 (virtuelles) Netzwerk Interface
5. Container Umgebung unter Debian Linux ist lxc-to-go

In den ersten Schritten wird das Debian HOST System eingerichtet, anschließend folgt die Einrichtung des LXC Containers.
Nach dessen Abschluss widmen wir uns dem FreeNAS HOST System und richten auch dort zeitnah den JAIL Container ein.
Zu guter Letzt gibt es ein kurzen „Failover“ Test.

Routing-Container 1 (LXC) : „routux“
Routing-Container 2 (JAIL mit VIMAGE support!): „routbert“

Ich gehe von einem aktuellen Debian 8 (Jessie) HOST System, mit DEFAULT Kernel, aus.

1. System auf den aktuellsten Stand bringen

$
apt-get autoclean; apt-get clean; apt-get update; apt-get upgrade
$

2. Umgebungs-/Debugtools installieren

$
apt-get install git iptables tcpdump sockstat iputils-ping
$

3. Kernelmodule laden

$
vi /etc/modules

### pppoe routing // ###
pppoe
ip_tables
ip6_tables
ip6t_MASQUERADE
## ("pkttype" packet type match support) filter multicast
xt_pkttype
tun
### // pppoe routing ###

modprobe pppoe ip_tables ip6_tables ip6t_MASQUERADE xt_pkttype tun
$

4. LXC-to-GO installieren

$
mkdir /github; cd /github
git clone https://github.com/plitc/lxc-to-go
/github/lxc-to-go/lxc-to-go.sh bootstrap
$

WICHTIG: Bei der Ersteinrichtung muss „DESKTOP“ als LXC-to-GO Netzwerkumgebung ausgewählt werden, da unser Routing Container nur eine Anbindung über eine Bridge ohne ProxyARP/ProxyNDP! benötigt.

5. „routux“ Container: erstellen

$
lxc-to-go create
$

6. Container stoppen und LXC-Container-Config anpassen (für pppoe kernel support)

$
lxc-to-go stop
vi /var/lib/lxc/routux/config

#// ppp/pppoe support
lxc.cgroup.devices.allow = c 108:0 rwm
lxc.mount.entry = /dev/ppp dev/ppp none bind,optional,create=file
#// lxc-to-go bridge 1
lxc.network.link=vswitch0
$

WICHTIG: durch das LXC-to-GO Netzwerkschema muss! vswitch1 nach vswitch0 umgeschrieben werden, damit „routux“ direkt über die erste Bridge angebunden wird und nicht an der zweiten Bridge, die hinter dem LXC-to-GO „managed“ Container, angeknüpft ist!

7. „routux“ Container: starten und einloggen

$
lxc-to-go start
lxc-to-go login

root@routux:~#
$

Der Container sollte automatisch per DHCP eine IP Adresse zugewiesen bekommen.

8. „routux“ Container: ucarp und pppoeconf installieren

$
apt-get autoclean; apt-get clean; apt-get update; apt-get upgrade

apt-get install ucarp pppoeconf
$

9. „routux“ Container: pppoe einrichten

$
pppoeconf
$

10. „routux“ Container: Netzwerk Interface Konfiguration

$
vi /etc/network/interfaces

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
        address 172.22.99.91
        netmask 255.255.255.0
        gateway 172.22.99.4
    #/ ucarp-vid      1
    #/ ucarp-vip      172.22.99.90
    #/ ucarp-password TOPSECRET
    #/ ucarp-advskew  1
    #/ ucarp-advbase  1
    #/ ucarp-master   yes
    #/ ucarp-downscript  /usr/share/ucarp/vip-down
    #/ ucarp-upscript    /usr/share/ucarp/vip-up
        up /usr/sbin/ucarp -i eth0 -f daemon -B -p TOPSECRET -P -z -u /usr/share/ucarp/vip-up -d /usr/share/ucarp/vip-down -b 1 -k 1 -s 172.22.99.91 -a 172.22.99.4 -v 1
        up ping -S 172.22.99.4 -c 2 -q 172.22.99.7 # force arp to switch ip
        down pkill ucarp

# The carp network interface, on top of eth0
iface eth0:ucarp inet static
        #/ address 172.22.99.90
        address 172.22.99.4
        netmask 255.255.255.0

#/ iface eth0 inet6 static
#/        address 2001::fuu
#/        netmask 64
#/        # gateway fe80::fuu
#/        gateway fe80::fuu

auto dsl-provider
iface dsl-provider inet ppp
pre-up /bin/ip link set eth0 up # line maintained by pppoeconf
provider dsl-provider

# EOF
$

11. „routux“ Container: damit nach dem failover Moduswechsel (von BACKUP auf MASTER) auch der tatsächliche Switch die neue MAC Adresse zur virtuellen (virtual shared) IP erhält, wird das ucarp-up Skript angepasst indem man einfach ein Ping anschließend senden lässt

$
vi /usr/share/ucarp/vip-up

#!/bin/sh

/sbin/ifup $1:ucarp

sleep 1 && ping -S 172.22.99.4 -c 2 -q 172.22.99.7
$

12. „routux“ Container: /etc/sysctl.conf & /etc/rc.local anpassen

$
vi /etc/sysctl.conf

### ### ### ROUTING // ### ### ###
net.ipv4.conf.all.forwarding=1
net.ipv6.conf.eth0.accept_ra=0
### ### ### // ROUTING ### ### ###

# EOF
$
$
vi /etc/rc.local

#!/bin/sh
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
#
### ### ### PLITC // ### ### ###


#/ echo "stage0"
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

ip6tables -F
ip6tables -X
ip6tables -t nat -F
ip6tables -t nat -X
ip6tables -t mangle -F
ip6tables -t mangle -X
ip6tables -P INPUT ACCEPT
ip6tables -P FORWARD ACCEPT
ip6tables -P OUTPUT ACCEPT

#/ echo "stage1"
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
sysctl net.ipv4.conf.default.forwarding=1 > /dev/null 2>&1
sysctl net.ipv4.conf.eth0.forwarding=1 > /dev/null 2>&1

exit 0
### ### ### PLITC // ### ### ###
# EOF
$

Sofern ich an dieser Stelle nichts nennenswertes vergessen habe zu erwähnen, sollte nach einem Container Neustart die PPPoE Einwahl und das Routing schon funktionieren

FreeNAS

Jetzt folgt die Einrichtung auf dem FreeNAS System.

Da wir zunächst ein „Buildenvironment“ benötigen, erstellen wir uns über die FreeNAS Web GUI eine Jail mit der Bezeichnung „buildbert“

1. „buildbert“ Container: login

$
jls

   JID  IP Address      Hostname                      Path
     1  -               buildbert                     /mnt/zroot/jails/buildbert

jexec 1 /bin/sh
$

2. „buildbert“ Container: auf den aktuellsten Stand bringen

$
pkg update; pkg upgrade
$

3. „buildbert“ Container: FreeNAS (9.3) selbst bauen, dazu bitte der Anleitung unter github.com/freenas/freenas folgen

WICHTIG: damit nun die NetGraph PPP/PPPoE Module mitgebaut werden, müssen folgende Zeilen, in der Konfig, angepasst werden, siehe Zeilennummer:

$
vi /mnt/zroot/jails/buildbert/buildbert/freenas/build/nano_env

159 add_nano_modules netgraph/ppp netgraph/pppoe netgraph/nat netgraph/car netgraph/echo

166 add_nano_modules netgraph/ether netgraph/socket netgraph/ppp netgraph/pppoe netgraph/nat netgraph/car netgraph/echo

339 #WITHOUT_PPP=true
$

4. sofern der „make release“ abgeschlossen wurde, können die benötigten Kernelmodule ins FreeNAS System kopiert und geladen werden

$
cp /mnt/zroot/jails/buildbert/buildbert/freenas/objs/os-base/amd64/buildbert/freenas/FreeBSD/src/sys/FREENAS.amd64/modules/buildbert/freenas/FreeBSD/src/sys/modules/netgraph/ppp/ng_ppp.ko /boot/kernel
cp /mnt/zroot/jails/buildbert/buildbert/freenas/objs/os-base/amd64/buildbert/freenas/FreeBSD/src/sys/FREENAS.amd64/modules/buildbert/freenas/FreeBSD/src/sys/modules/netgraph/pppoe/ng_pppoe.ko /boot/kernel
cp /mnt/zroot/jails/buildbert/buildbert/freenas/objs/os-base/amd64/buildbert/freenas/FreeBSD/src/sys/FREENAS.amd64/modules/buildbert/freenas/FreeBSD/src/sys/modules/netgraph/nat/ng_nat.ko /boot/kernel
cp /mnt/zroot/jails/buildbert/buildbert/freenas/objs/os-base/amd64/buildbert/freenas/FreeBSD/src/sys/FREENAS.amd64/modules/buildbert/freenas/FreeBSD/src/sys/modules/netgraph/car/ng_car.ko /boot/kernel
cp /mnt/zroot/jails/buildbert/buildbert/freenas/objs/os-base/amd64/buildbert/freenas/FreeBSD/src/sys/FREENAS.amd64/modules/buildbert/freenas/FreeBSD/src/sys/modules/netgraph/echo/ng_echo.ko /boot/kernel
$

Download PLITC: freenas_9.3_amd64_netgraph_pppoe.tar.gz*

$
MD5 (freenas_9.3_amd64_netgraph_pppoe.tar.gz) = 0be216df688c0ba9257fbbfe7a910a6b
$

*Download ohne Gewähr

5. NetGraph Kernelmodule laden

$
kldstat
kldload ng_ppp ng_pppoe ng_socket ng_nat ng_car ng_echo
kldstat
$

6. damit auch die NetGraph Module bei einem Systemstart mitgeladen werden, müssen über die FreeNAS Web GUI, ein paar Tunables gesetzt werden

System -> Tunables

plitc_pppoe_failover_freenas

Wichtig ist ebenso die „pfil“ Einträge zu setzen! sonst werden die PPPoE Pakete, auf der FreeNAS Bridge, gedroppt!

Erklärung dazu unter: FreeBSD if_bridge

7. FreeNAS Reboot!

$
reboot
$

8. Nach dem FreeNAS Systemreboot kann jetzt per Web GUI die JAIL: „routbert“ erstellt und eingerichtet werden

9. „routbert“ Container: ucarp installieren

$
pkg install ucarp
$

10. „routbert“ Container: ucarp up & down scripts

$
vi /root/ucarp_up.sh

#!/bin/sh
### ### ### PLITC // ### ### ###
#// Load variables from rc.conf
. /etc/rc.subr
load_rc_config ucarp
/sbin/ifconfig $ucarp_if alias $ucarp_addr/24
#// force arp refresh for the shared ip
ping -S 172.22.99.4 -c 2 -q 172.22.99.7 > /dev/null
#// delete default gateway
route -n delete default >/dev/null 2>&1
#// clean ppp log
echo "" > /var/log/ppp.log
#// dialin
/usr/sbin/ppp -ddial telekom
#// load firewall after being successful pppoe connection
while true ; do
   CHECKPPP=$(cat /var/log/ppp.log | grep -c "Pap Input: SUCCESS")
   if [ "$CHECKPPP" -eq 1 ]
   then
      sleep 5
      /etc/rc.firewall.local
      break
   else
      sleep 1
   fi
done
### ### ### // PLITC ### ### ###
# EOF

chmod 0755 /root/ucarp_up.sh
$

Die „while true“ Schleife ist notwendig, da ipfw mit dem laden der Regelsätze abbricht wenn ein (noch nicht) vorhandenes Device (in dem Fall: tun0) auf Firewallregeln matchen soll

$
vi /root/ucarp_down.sh

#!/bin/sh
# Load variables from rc.conf
. /etc/rc.subr
load_rc_config ucarp
/sbin/ifconfig $ucarp_if -alias $ucarp_addr
pkill -9 ppp
#// default gateway
route add default 172.22.99.4
# EOF

chmod 0755 /root/ucarp_down.sh
$

11. „routbert“ Container: /etc/ppp/ppp.conf (PPPoE Config!)

$
vi /etc/ppp/ppp.conf

default:
        set log Chat Command Connect Filter Phase tun Error Alert

telekom:
        set device PPPoE:epair1b
        set redial 1 0
        set reconnect 3 23
        set mtu max 1492
        set mru max 1492
        set speed sync
        set server /var/run/internet "" 0177
        set dial
        set login
        set authname "000000000000000000000000#0001@t-online.de"
        set authkey "00000000"
        disable acfcomp protocomp
        disable ipv6cp
        enable mssfixup
        enable dns
        enable lqr
        enable echo
        accept lqr
        add default HISADDR
        set timeout 0
        open
$

12. „routbert“ Container: /etc/sysctl.conf

$
vi /etc/sysctl.conf

# $FreeBSD: releng/9.3/etc/sysctl.conf 112200 2003-03-13 18:43:50Z mux $
#
#  This file is read when going to multi-user and its contents piped thru
#  ``sysctl'' to adjust kernel values.  ``man 5 sysctl.conf'' for details.
#

# Uncomment this to prevent users from seeing information about processes that
# are being run under another UID.
#security.bsd.see_other_uids=0

net.inet.ip.forwarding=1
$

13. „routbert“ Container: /etc/rc.conf

$
vi /etc/rc.conf

### ### ### /etc/rc.conf ### ### ###
portmap_enable="NO"
sshd_enable="NO"
sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
hostname="routbert"
devfs_enable="YES"
devfs_system_ruleset="devfsrules_common"
inet6_enable="YES"
ip6addrctl_enable="YES"

ucarp_enable="YES"
ucarp_if="epair1b"
ucarp_vhid="1"
ucarp_pass="TOPSECRET"
ucarp_preempt="YES"
ucarp_facility="daemon"
ucarp_src="172.22.99.92"
ucarp_addr="172.22.99.4"
ucarp_advbase="1"
ucarp_advskew="10"
ucarp_upscript="/root/ucarp_up.sh"
ucarp_downscript="/root/ucarp_down.sh"

cloned_interfaces="tun"
gateway_enable="YES"
firewall_enable="YES"
# firewall_type="OPEN"
firewall_logging="YES"
firewall_type="/etc/firewall.rules"
firewall_script="/etc/rc.firewall.local"

ppp_enable="YES"
ppp_mode="ddial"
# ppp_nat="YES" # if you want to enable nat for your local network, otherwise NO (or nat with ipfw)
ppp_user="root"
ppp_profile="telekom"
# EOF
$

14. „routbert“ Container: /etc/rc.local

$
vi /etc/rc.local

#!/bin/sh
NEWINTERFACE=$(ifconfig | grep "flags" | grep "epair" | awk '{print $1}' | sed 's/://')
find /etc -name "rc.conf" -type f -exec sed -i "" 's/epair[0-9]b/'"$NEWINTERFACE"'/g' {} \;
find /etc -name "firewall.rules" -type f -exec sed -i "" 's/epair[0-9]b/'"$NEWINTERFACE"'/g' {} \;
find /etc/ppp -name "ppp.conf" -type f -exec sed -i "" 's/epair[0-9]b/'"$NEWINTERFACE"'/g' {} \;
/usr/local/etc/rc.d/ucarp start
exit 0
# EOF

chmod 0755 /etc/rc.local
$

15. „routbert“ Container: /etc/firewall.rules

$
vi /etc/firewall.rules

### ### ### etc/firewall.rules ### ### ###

### stage0 // ###
#/ add 00001 check-state
#/ add 00003 deny tcp from any to any established in via epair1b
### // statefull ###
#
add 00002 deny all from any to any frag in via epair1b
#
### // stage0 ###

### stage1 - Uplink Filter // ###
# Throw away RFC 1918 networks
#/ add 10 drop all from 10.0.0.0/8 to any in via epair1b
#/ add 11 drop all from 172.16.0.0/12 to any in via epair1b
#/ add 12 drop all from 192.168.0.0/16 to any in via epair1b
#
add 00045 count icmp from any to any via epair1b
add 00046 count ipv6-icmp from any to any via epair1b
add 00047 count icmp from any to any via tun0
add 00048 count ipv6-icmp from any to any via tun0
### // stage1 - Uplink Filter ###

### stage2 // ###
add 00098 allow ip4 from me to any
add 00099 allow ip6 from me6 to any
### // stage2 ###

### stage3 - Admin SSH // ###
### // stage3 - Admin SSH ###

### stage4 // ###
#
nat 1 config if tun0 reset
add 10001 nat 1 ip4 from any to any via tun0
#
### // stage4 ###

### stage9 // ###
add 60100 allow ip from any to any via lo0
add 60200 deny ip from any to 127.0.0.0/8
add 60300 deny ip from 127.0.0.0/8 to any
add 60400 deny ip from any to ::1
add 60500 deny ip from ::1 to any
add 60600 allow ipv6-icmp from :: to ff02::/16
add 60700 allow ipv6-icmp from fe80::/10 to fe80::/10
add 60800 allow ipv6-icmp from fe80::/10 to ff02::/16
add 60900 allow ipv6-icmp from any to any ip6 icmp6types 1
add 61000 allow ipv6-icmp from any to any ip6 icmp6types 2,135,136
### // stage9 ###

### stage10 // ###
add 65001 allow ip4 from any to any
add 65002 allow ip6 from any to any
### // stage10 ###

# EOF
$

16. „routbert“ Container: /etc/rc.firewall.local

$
vi /etc/rc.firewall.local

#!/bin/sh
### ### ### etc/rc.firewall.local // ### ### ###
/sbin/ipfw -q flush
/sbin/ipfw -q pipe flush
/sbin/ipfw -q queue flush
/sbin/ipfw -q /etc/firewall.rules
### ### ### // etc/rc.firewall.local ### ### ###
# EOF

chmod 0755 /etc/rc.firewall.local
$

Das sollte es gewesen sein!

Nun sollte man einmal die „routbert“ JAIL, per FreeNAS Web GUI, neustarten lassen

PPPoE Failover Test

1. „routux“ Container: stoppen

$
lxc-stop -n routux
$

Nach dem stoppen von dem „routux“ LXC sollte die „routbert“ JAIL in den Mastermode gehen

$
cat /var/log/messages

Sep 30 22:21:05 routbert ucarp[7034]: [WARNING] Switching to state: BACKUP
Sep 30 22:21:05 routbert ucarp[7034]: [WARNING] Spawning [/root/ucarp_down.sh epair1b 172.22.99.4]
Sep 30 22:21:09 routbert ucarp[7034]: [WARNING] Switching to state: MASTER
Sep 30 22:21:09 routbert ucarp[7034]: [WARNING] Spawning [/root/ucarp_up.sh epair1b 172.22.99.4]
$

und mit dem PPP dailin beginnen.

Viel Erfolg.

Nebeninfo: Arbeitsaufwand 2 1/2 Tage
2 Tage gingen nur fürs „debuggen“ drauf weil ich es in einem recht komplexen Netz mit LACP, filter source-port, multiplen VLANs Switchen eingerichtet hatte.
Im Linux LXC funktionierte der PPPoE Dailin sofort! Nur in der FreeNAS JAIL nicht.
Selbst der if_bridge.c Code brachte keine klaren Erkenntnisse.
Schlussendlich sollte man lieber die Manpage ein drittes mal aufmerksam lesen, die Deaktivierung des „pfil“ Framework ermöglichte am Ende das durchreichen der PPPoE Pakete (auf der FreeNAS Bridge)!

Ergänzung: 01.10.2015
Die Firewallregeln für iptables/ipfw sind nur beispielhaft und sollten individuell ergänzt werden!

Tcpdump (Empfehlung) für PPPoE (MAC Adresse jeweils vom anderen PPPoE Container ausblenden lassen)

$
tcpdump -e -n -i eth0 'not ip and not ip6 and not arp and not stp and not icmp6 and not vlan and not ether src bla:bla:bla and not ether dst bla:bla:bla'
$

PPPoE Timeout: CARP wechselt gleich nach 1-2 Sekunden die IP, jedoch bis die alte PPPoE Session ausgelaufen ist und die neue sich wieder aufbauen lässt können so ca. um die 120 Sekunden vergehen.