Wstęp

Na początek niezbędne założenia, odnośnie interfejsów sieciowych oraz podłączonych łącz. Są one takie same jak w dokumentacji, z drugim łączem dołączonym do dodatkowego interfejsu eth2.

Przypominając i kompletując te informacje. Dysponujemy routerem z trzema interfejsami. Do interfejsu eth0 podłączone jest łącze podstawowe a do eth1 sieć lokalna LAN. Drugie łącze podłączone jest do interfejsu eth2. Adres publiczny po stronie pierwszego łącza to 198.51.100.100/24, adres po stronie drugiego łącza to 203.0.113.100/24 a adres po stronie sieci LAN to 192.168.0.1/24. Adresacja sieci LAN to 192.168.0.0/24.

Obydwa łącza to łącza asymetryczne o przepustowościach odpowiednio 8000kb/s na 500kb/s oraz 10000kb/s na 600kb/s.

Sposobów na wykorzystanie dwóch łączy, czyli Load Balancing, jest wiele. Opisywany scenariusz to "przerzucenie" na drugie łącze ruchu www oraz poczty e-mail. Zarówno www jak i poczta charakteryzują się "sporadycznością" ruchu. Dzięki temu, że ruch ten rzadko generuje długotrwałe i stałe obciążenie (w przeciwieństwie do ruchu p2p), dostępne pasmo bardzo dobrze współdzieli się na znaczną liczbę hostów. Dodatkowo poza wysyceniem downloadu (http, imap i pop3 - pobieranie), postaramy się wykorzystać upload drugiego łącza, wysyłając nim ruch smtp.

Routing

Tworzymy plik wykonywalny, np. /usr/local/sbin/routing.sh, który będzie służył do przeładowywania konfiguracji routingu, markowania pakietów, NATowania oraz uruchomienie NiceShapera.
FILEPATH="/usr/local/sbin/routing.sh"
touch ${FILEPATH}
chown root:root ${FILEPATH}
chmod 750 ${FILEPATH}
Skrypt ten powinien być uruchamiany automatycznie, w trakcie startu systemu. Najlepiej poprzez dodanie ścieżki do niego do kompletnego skryptu startowego lub po prostu do /etc/rc.local.

Skrypt zapewni, że wszystkie pakiety TCP o porcie docelowym wymienionym w zmiennej isp2_ports_tcp, zostaną oznaczone znacznikiem 0x2. Spowoduje to, w połączeniu z odpowiednią konfiguracją, że pakiety te będą routowane drugim łączem oraz kontrolowane przez odpowiednie sekcje NiceShapera.

Do utworzonego wcześniej pliku wklejamy poniższą zawartość, odpowiednio modyfikując, zmienne zdefiniowane na samym jego początku w części "Konfiguracja".

#!/bin/sh

# === Konfiguracja ===

wan1_iface="eth0"
wan1_net="198.51.100.0/24"
wan1_ip="198.51.100.100"
wan1_gw="198.51.100.2"

lan_iface="eth1"
lan_net="192.168.0.0/24"

wan2_iface="eth2"
wan2_net="203.0.113.0/24"
wan2_ip="203.0.113.100"
wan2_gw="203.0.113.2"

isp2_ports_tcp="80,443,25,465,143,993,110,995"

# === Ustawienia systemu operacyjnego ===

IP=`which ip`
IPT=`which iptables`
NS=`which niceshaper`
ECHO=`which echo`

if [ -z "$IP" ]; then
echo "Brak programu ip (iproute)"
exit 255
fi

if [ -z "$IPT" ]; then
echo "Brak programu iptables"
exit 255
fi

if [ -z "$NS" ]; then
echo "Brak programu niceshaper"
exit 255
fi

if [ -z "$ECHO" ]; then
echo "Brak programu echo"
exit 255
fi

$ECHO 1 > /proc/sys/net/ipv4/ip_forward
$ECHO 0 > /proc/sys/net/ipv4/conf/all/rp_filter

# === NiceShaper ===

$ECHO "Zatrzymanie NiceShapera"

$NS stop

# === Routing ===

$ECHO "Routing - Czyszczenie"

$IP route flush table 241 2>/dev/null
$IP route flush table 242 2>/dev/null
$IP rule del fwmark 0x1 table 241 2>/dev/null
$IP rule del fwmark 0x2 table 242 2>/dev/null

$ECHO "Routing - Tabela 241"

$IP route add ${wan1_net} dev ${wan1_iface} table 241 # Routing lokalny
$IP route add ${wan2_net} dev ${wan2_iface} table 241 # Routing lokalny
$IP route add ${lan_net} dev ${lan_iface} table 241 # Routing lokalny
$IP route add default via ${wan1_gw} table 241 # Routing domyślny w tabeli 241 przez łącze nr.1

$ECHO "Routing - Tabela 242"

$IP route add ${wan1_net} dev ${wan1_iface} table 242 # Routing lokalny
$IP route add ${wan2_net} dev ${wan2_iface} table 242 # Routing lokalny
$IP route add ${lan_net} dev ${lan_iface} table 242 # Routing lokalny
$IP route add default via ${wan2_gw} table 242 # Routing domyślny w tabeli 242 przez łącze nr.2

$ECHO "Routing - Rules"

$IP rule add fwmark 0x1 table 241
$IP rule add fwmark 0x2 table 242

# === Markowanie pakietów ===

$ECHO "Markowanie pakietów - Przygotowanie reguł iptables"

$IPT -t mangle -F PREROUTING 2>/dev/null

$IPT -t mangle -F routemark 2>/dev/null
$IPT -t mangle -X routemark 2>/dev/null
$IPT -t mangle -N routemark

$IPT -t mangle -A routemark -i ${wan1_iface} -j MARK --set-mark 0x1
$IPT -t mangle -A routemark -i ${wan2_iface} -j MARK --set-mark 0x2

$IPT -t mangle -A routemark -i ${lan_iface} -p tcp -m multiport --dports ${isp2_ports_tcp} -j MARK --set-mark 0x2

$IPT -t mangle -A routemark -i ${lan_iface} -m mark ! --mark 0x2 -j MARK --set-mark 0x1

$IPT -t mangle -A routemark -j CONNMARK --save-mark

$IPT -t mangle -A PREROUTING -m state --state ESTABLISHED,RELATED -j CONNMARK --restore-mark
$IPT -t mangle -A PREROUTING -m state --state NEW -j routemark

# === NAT ===

$IPT -t nat -F POSTROUTING
$IPT -t nat -A POSTROUTING -o ${wan1_iface} -s ${lan_net} -j SNAT --to ${wan1_ip}
$IPT -t nat -A POSTROUTING -o ${wan2_iface} -s ${lan_net} -j SNAT --to ${wan2_ip}

# === NiceShaper ===

$ECHO "Uruchomienie NiceShapera"

$NS start

Konfiguracja NiceShapera

Minimalna zawartość pliku config.conf:
W konfiguracji z jednym łączem i NATowaniem, markowanie pakietów uruchomione zostaje na interfejsie obsługującym pakiety wychodzące z sieci. Tutaj już na wszystkich interfejsach. Markowanie pakietów na interfejsie obsługującym download, pozwala w wygodny sposób określić, którym łączem pakiet dotarł do sieci.

Przykłady klas

Jak powinien wyglądać zestaw klas dla pojedynczego hosta? Tak jak poniżej:
Pierwsze dwie klasy odpowiadają za download. Filtry klasyfikują pakiety na podstawie adresu docelowego oraz wartości znacznika, który zmienia się w zależności od tego którym łączem pakiet dotarł do sieci.

Ostatnie dwie klasy odpowiadają za upload. Filtry klasyfikują pakiety za pomocą adresu źródłowego oraz interfejsu którym pakiet opuszcza router (interfejs klasy), który zmienia się w zależności od tego, którym łączem pakiet zostaje wyroutowany na zewnątrz sieci.

Podsumowując, jak rozróżnić którym łączem routowany jest pakiet. W przypadku downloadu należy posłużyć się wartością znacznika, gdyż w tym kierunku interfejs wyjściowy nie zmienia się. Inaczej jest w przypadku uploadu, gdzie najwygodniej jest posłużyć się interfejsem wyjściowym, który zmienia się w zależności od łącza którym pakiet opuszcza router a dodatkowo nie jest wymagane zapisywanie kolejnego testu filtra, gdyż ten interfejs jest już określony w ramach klasy.

Teraz już pozostaje zduplikować powyższy zestaw klas dla każdego komputera w sieci lokalnej, oczywiście podmieniając adresy IP.

By uprościć konfigurację, zmniejszyć objętość i zwiększyć przejrzystość pliku klas, warto posłużyć się makrem foreach-pair (lub innym). Makro to wygeneruje kopie tego zestawu klas dla każdej pary "nazwa-ostatni oktet adresu IP".