Webchat IRC #linuxon
Piatok, 18. máj 2012 Meniny majú: Dnes: Viola Zajtra: Gertrúda

Font Size

Screen

Nastavenia

Policy routing založený na uid/gid užívateľa

  • PDF
Často sa pripájam na wifiny okolo mňa a často potrebujem cez tieto wifi odosielať len časť prevádzky. Máme viac možností na základe čoho sa bude traffic posielať cez wifi, v podstate hocičo, čo sa dá zapísať ako pravidlo netfiltru (iptables). Modul netfiltru 'owner' umožnuje filtrovať prevádzku aj na základe uid/gid procesu, ktorý odosiela dáta. Vytvoril som teda novú skupinu "skupina_wlan" (;D) s gid povedzme 1003 a procesy s efektívnym gid nastaveným na 1003 posielali svoje dáta skrz wlan0, zatiaľ čo všetky ostatné cez eth0. Ako na to?

Routovacia tabuľka

Prvý krok je vytvoriť novú routovaciu tabuľku, ktorá sa bude používať len pre traffic procesov skupiny "skupina_wlan". Na pokročilejšiu manipuláciu s nastavením sieťového stacku musíte mať nainsťalovaný balík iproute2, s klasickým route tu nepochodíte. Ak ho vaša distribúcia nemá, tak asi nepoužívate linux :P. Pridať novú tabuľku je triviálne. Stačí pridať riadok do súboru /etc/iproute2/rt_tables (väčšina distribúcií ho má tam). Vytvoríme teda novú tabuľku:

/etc/iproute2/rt_table:
#
# reserved values
#
255     local
254     main
253     default
252     wlanroute
0       unspec
#
# local
#
#1      inr.ruhep

Viac v ip(8). Vytvorenie pravidiel si necháme na potom.


Niečo o značkách

Linuxový netfilter umožňuje pakety vyhovujúce definovaným pravidlám označiť značkou (mark). Značka je číselná hodnota (32 bitov a voliteľná maska). Na základe značky potom môžeme v netfiltri alebo pri nastavovaní routingu určiť akú akciu vykonať s označenými paketmi. Vytvoríme teda pravidlo, ktoré pakety od procesu s gid  1003 označí značkou, napr. 1.

iptables -t mangle -A OUTPUT -m owner --gid-owner skupina_wlan -j MARK --set-mark 1

Potom zaistíme aby sa pre pakety označené značkou 1 používala naša nová routovacia tabuľka wlanroute. Linux kernel toto samozrejme zvláda a konfigurovať ho môžeme  pomocou iproute2.

ip rule add fwmark 1 lookup wlanroute

Tabuľka wlanroute ešte neobsahuje žiadne pravidlá. Jednoducho teda pridáme pravidlá pre výchoziu bránu a komunikáciu so sieťou.

ip route add ADRESA_SIETE_NA_WLAN0/CIDR_PERFIX src IP_WLAN0 dev wlan0 table wlanroute
ip route add default via BRANA_NA_SIETI_WLAN0 dev wlan0 table wlanroute


To by malo byť všetko. To som si myslel ale nie je. Pri skúšaní sa ale ukázalo že pakety stále mali zdrojovú IP nastavenú na IP eth0 ale boli posielané smerom do siete na wlan0. Je to spôsobené tým, že keď program vytvorí nové spojenie linux ešte ignoruje našu tabuľku wlanroute lebo paket nieje označený a ak si program explicitne nezvolí zdrojovú adresu tak mu bude pridelená podľa routovacej tabuľky main. Kedže výchozia brána v main je na sieti eth0 zvolí kernel zdrojovú ip adresu eth0 (záleží na konkrétnych pravidlách ale u drvivej väčšine užívateľov len s jednoduchým pripojením na internet to tak je). Potom keď sa paket pri odchádzdaní zo systému dostane do  tabuľky mangle kde sa mu pridelí značka, kernel znova prejde RPDB (routing poilcy database) a zistí, že má používať tabuľku wlanroute a nie main. Vo wlanroute tabuľke  síce môžme mať záznam aby sa pri spojení do siete na wlan0 použila adresa wlan0, tieto záznamy ale kernel berie ako "odporúčania" keď nemá iné východisko a  nevie nastaviť zdrojovú adresu. Kedže paket už zdrojovú adresu má kernel tieto záznamy ignoruje a veselo ponechá zdrojovú ip na adresu eth0.

Poznámka: Týmto vysvetlením si niesom istý, ale dáva to zmysel.

Aj keď to možno chápem zle, istotou je, že musíme nejako prepísať zdrojovú IP. Toto som vyriešil pomocou source NATU v netfiltri.

iptables -t nat -A POSTROUTING -o wlan0 -j SNAT --to ADRESA_WLAN0

Všetko teraz funguje tak ako má. Užívateľ rattlehead, ktorého skupinou je skupina_wlan teraz všetky dáta posiela cez wlan0. V prípade potreby efektívne gid procesu si  môže užívateľ root ľubovoľne meniť (wrapper ktorý zmeni egid je otázkou pár riadkov kódu v ľubovoľnom jazyku) takže aj programy ktoré vyžadujú spustenie pod rootom  môžeme takto "routovať".

AUTOMATIZÁCIA

Kedže siete často striedam tento proces si žiada automatizáciu. Všetko som zautomatizoval na takú mieru že mi stačí spustiť dhcpcd klienta s upraveným konfiguračným  súborom.

dhcpcd po získaní nastavení štadardne upraví routovaciu tabuľku, nastavenia dns a podobne. Toto mi nechceme, chceme len aby pridelil správnu ip adresu rozhraniu. Nechceme síce aby nám modifikoval routovaciu tabuľku, ale adresu brány získanú z dhcp potrebujeme. Našťastie dhcpcd podporuje spúštatnie tzv. hook skripty ktoré sa  spúštaní pri akejkoľvek zmene stavu. Štandardne je ich možné nájsť v /lib/dhcpcd/dhcpcd-hooks/. Zrejme tam už budete mať pár skriptov, napr. resolv.conf, ktorý  upravuje nastavenia dns. Vytvoril som teda nový skript 99-wlan.sh (skripty sú spúštané v abecednom poradí):

case "$reason" in
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC)        /etc/rc.d/rc.firewall wlan_routing start $new_routers ;;
EXPIRE|FAIL|IPV4LL|NAK|NOCARRIER|RELEASE|STOP)          /etc/rc.d/rc.firewall wlan_routing check && /etc/rc.d/rc.firewall wlan_routing stop;;
esac

Premenná reason obsahuje dôvod, kvôli ktorému bol skript zavolaný, viac v dhcp-run-hooks(8) a dhcpcd(8). Skript rc.firewall používam na sieťové nastavenia všetkého druhu, parametrami je názov funkcie v ňom definovanej a parametre samotnej funkcie. Relevatné časti vyzerajú nasledovne(skript je zaprasený, niekoľko-krát prepisovaný a postihnutý, lebo som ho neplánoval zverejniť, ale prepisovať sa mi to nechce :)). Kopírovaním sa bohužiaľ stratilo odsadenie, ďalší dôvod na to aby ste ho ani nečítali a napísali si vlastný, lepší.

#!/bin/sh

IP=/sbin/ip
IPTABLES=/usr/sbin/iptables

wlan_routing()
{
WLAN0_TABLE=wlanroute
STATE=/var/run/wlan_routing

if [ "$2" = "start" ];then
IP_ACTION=add
TABLES_ACTION=-A
GATEWAY=$3

# Get wlan0 IP and network prefix, maybe we should get this from dhcpcd to avoid race conditions
WLAN=(`ip address show wlan0|awk '/inet[[:space:]]+/ { split($2, net, "/"); print net[1]" "net[2] }'`)
NET=`echo $GATEWAY|cut -d. -f1,2,3`.0   # I am lazy to write regexp for sed, also this work just with /24

# Set up routing table for wlan0
$IP route $IP_ACTION $NET/${WLAN[1]} src ${WLAN[0]} dev wlan0 table $WLAN0_TABLE
$IP route $IP_ACTION default via $GATEWAY dev wlan0 table $WLAN0_TABLE
touch $STATE
elif [ "$2" = "stop" ];then
IP_ACTION=del
TABLES_ACTION=-D
GATEWAY=`ip route show |awk '/^default/ { print $3 }'`

$IP route flush table $WLAN0_TABLE
rm $STATE
elif [ "$2" = "check" ];then
if [ -f $STATE ]; then
echo "running"
exit 1
else
echo "not running"
exit 0
fi
else
echo "Usage: $1 {start|stop|check} [gateway]"
exit 1
fi

$IPTABLES -t mangle $TABLES_ACTION OUTPUT -m owner --gid-owner skupina_wlan -j MARK --set-mark 1
$IPTABLES -t nat $TABLES_ACTION POSTROUTING -j SNAT -o wlan0 --to ${WLAN[0]}
$IP rule $IP_ACTION fwmark 1 lookup $WLAN0_TABLE
}

if [ -z $1 ]; then
echo "Usage: $0 func"
exit 1
else
$1 $*
fi



Ďalej konfiguračný súbor dhcpcd:

/etc/wlan_dhcpcd.conf:
# Respect the network MTU.
option interface_mtu
# A ServerID is required by RFC2131.
require dhcp_server_identifier
# Avoid rewriting routing tables
nogateway

nohook lookup-hostname
# No DNS settings
nohook resolv.conf
nohook yp.conf
nohook ntp.conf


Do ďalšieho konfiguračného súboru, ktorý používate ako výchozí treba pridať riadok "nohook wlan" aby sa pre iné rozhrania toto nastavenie nepoužívalo. Potom len nad wlan0 stačí pustiť dhcpcd a všetko sa nakonfiguruje samo.

dhcpcd -f /etc/wlan_dhcpcd.conf wlan0












Posledná zmena v Nedeľa, 10 Júl 2011 13:47

Navigácia Blogy Oliver Kindernay Policy routing založený na uid/gid užívateľa
Internetový portál pre užívateľov, fanúšikov, záujemcov operačného systému linux a voľne šíriteľného softvéru. Viac... | Podporte nas... | Reklama
 Hostia: 549