Domeka
07.02.2012., 16:09:10 *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Search GoogleTagged Contact Login Register  
Pages: [1]   Go Down
  Print  
Author Topic: Filtriranje mrežnog prometa na aplikacijskoj razini pomoću Linuxa - I. dio  (Read 1222 times)
0 Members and 1 Guest are viewing this topic.
The MasteR
Administrator
Full Member
*****

Karma: +20/-0
Offline Offline

Gender: Male
Posts: 168



View Profile WWW
« on: 17.08.2009., 13:54:38 »

Uvod:

Mrežni filtar tj. firewall postao je dio "mrežne svakodnevice" sredinom 80-tih godina prošlog stoljeća, još od pojave usmjernika (routera). Velika većina firewalla ima mogućnost filtriranja mrežnog prometa isključivo na drugom, trećem i četvrtom OSI sloju (podatkovni, mrežni i prijenosni slojevi), tj. prema MAC adresi, IP adresi, priključnoj točki (portu usluge) i stanju konekcije. Sve masovnija upotreba računalnih mreža dovodi do potrebe kontroliranja mrežnog prometa na sedmom sloju tj. aplikacijskoj razini. Mrežni se promet filtrira prema protokolima koji se koriste na ovoj razini OSI modela, pa čak i prema samim vrstama datoteka koje se prenose mrežom. Uz komercijalne proizvode (npr. Check Point VPN-1) pojavila su se i rješenja bazirana na open-source tehnologijama, a jedno takvo rješenje objašnjeno je u ovom članku.

Kako ovaj postupak zahtijeva "patchiranje" i (pre)kompajliranje kernela, preporuka je da ovo ne pokušavate na produkcijskom poslužitelju, nego da za ovu namjenu izdvojite zasebno računalo, koje ne mora biti najnovije. Tako ulogu mrežnog filtra i DHCP poslužitelja za otprilike 50-ak računala, u mom slučaju, sasvim zadovoljavajuće obavlja Pentium III na 800MHz s 256MB radne memorije, tvrdim diskom od 20GB i dvije mrežne kartice.

Za početak, potrebno je ukratko objasniti nama interesantan način rada mrežne kartice. Red čekanja (queue) je privremena memorija (buffer) ili lokacija, koja sadrži konačan broj paketa, koji čekaju da se nad njima obavi neka akcija. Svako mrežno sučelje ima svoj predefinirani red čekanja, a u njemu postoje 3 moguće akcije: ulazak paketa u red (enqueue), njegov izlazak iz reda (dequeue) i njegovo brisanje (drop). U najjednostavnijem se obliku paketi u redu čekanja prosljeđuju po FIFO principu i bez drugih mehanizama nije moguće kontrolirati njihovo ponašanje. Metode upravljanja redovima (queuing disciplines - qdiscs) su algoritmi kojima se kontrolira način ulaska paketa u redove i njihovog izlaska. Ukratko, potrebno je prepoznati željeni protokol tj. paket koji pripada interesantnom toku podataka (match), nekako ga označiti (mark) i onda ga na neki način oblikovati (shape). Više o tome možete pročitati u Linux Advanced Routing and Traffic Control HOWTO dokumentu (lartc.org).

Instalacija:

Sama instalacija nije komplicirana, a najviše vremena oduzima (pre) kompajliranje kernela.

Potrebni paketi na računalu su:

- 2.4 ili 2.6 kernel source (kernel.org) - preferirano 2.6
- iptables source
- iproute2
- l7-filter
- definicije protokola

Napomena: trenutna verzija l7 filtra nije kompatibilna s kernel verzijom 2.6.20.x.

Za potrebe ovog članka svi paketi skinuti su u direktorij /usr/src/.

Da bi uključili podršku za l7 filtar, potrebno je patchirati kernel source i iptables. Patchevi za odgovarajuće verzije nalaze se unutar l7-filter paketa, pa prvo raspakiramo paket l7-filter u proizvoljni direktorij (u primjeru je korišten direktorij /usr/src/netfilter-layer7):

Code:
tar xzvf netfilter-layer7-vX.Y.tar.gz /root/netfilter-l7

Nakon što smo nabavili kernel source, raspakiramo ga unutar /usr/src direktorija i pozicioniramo se u dobiveni direktorij /usr/src/linux-2.6.X.Y:

Code:
tar xzvf linux-2.6.X.Y.tar.gz

Code:
cd linux-2.6.X.Y

Zatim je potrebno patchirati kernel source:

Code:
patch -p1 < /usr/src/netfilter-layer7/kernel-2.6.X-layer7-Y.patch

Nakon toga, slijedi podešavanje kernela po želji (npr. pomoću make menuconfig metode - lokacije vrijede za verziju 2.6.18), uz obavezno uključenje sljedećih opcija:

- "Prompt for development and/or incomplete code/drivers" (pod "Code maturity level options")
- "Network packet filtering" (Networking › Networking options › Network packet filtering )
- "Netfilter Xtables support" (Networking › Networking options ›Network packet filtering › Core Netfilter Configuration)
- "Connection tracking" (Networking › Networking options › Network packet filtering › IP: Netfilter Configuration)
- "Connection tracking flow accounting" (u istom izborniku kao i prethodna opcija)
- "IP tables support" (u istom izborniku)
- "Layer 7 match support" (u istom izborniku)

Ostale Netfilter opcije nisu nužne, ali su poželjne (naročito FTP support).

Slijedi uobičajeno kompajliranje i instalacija kernela te restart računala:

Code:
make all
Code:
make modules_install
Code:
make install
Code:
mkinitrd -o /boot/initrd.img-2.6.18 2.6.18

uz podešavanje boot loadera (lilo/grub ili nešto treće).

Na redu je iptables. Prvo otpakiramo paket (npr. u /usr/src/iptables):

Code:
tar xzvf iptables-X.Y /usr/src/iptables
cd iptables

i zatim patchiramo iptables source:

Code:
patch -p1 < /usr/src/ netfilter-layer7/iptables-layer7-2.x.patch

Još je potrebno dodati pravo izvršavanja na datoteku ".layer7-test" unutar /root/iptables/extension direktorija:

Code:
chmod +x extensions/.layer7-test

Slijedi kompajliranje iptables-a:

Code:
make KERNEL_DIR=/putanja/do/patchiranog/kernela (u našem slučaju /usr/src/linux-2.6.X.Y)

i zatim instalacija (kao root):

Code:
make install KERNEL_DIR=/putanja/do/patchiranog/kernela (u našem slučaju /usr/src/linux-2.6.X.Y)

Za uspješnu instalaciju potrebno je imati već patchirani i konfigurirani kernel source.

Slijedi postavljanje definicija protokola koje je najbolje staviti u /etc/l7-protocols direktorij:

Code:
tar xzvf l7-protocols-YYYY-MM-DD.tar.gz /etc/l7-protocols

Moguća je njihova instalacija u proizvoljni direktorij, ali je za korištenje istih potrebno navesti njihovu lokaciju sa opcijom --l7dir.

Iz razloga što na paketu iproute2 nisu potrebne nikakve intervencije, dovoljno ih je instalirati:

Code:
apt-get update
Code:
apt-get install iproute

Upotreba:

Sad ste spremni za rad. Moguće radnje su: blokiranje određenih protokola, kontroliranje pojasne širine i praćenje stanja na mreži. Svaka navedena radnja bit će opisana dalje u tekstu.

l7-filtar koristi standardnu iptables sintaksu, a osnovna sintaksa glasi:

Code:
iptables [tablica i lanac] -m layer7 --l7proto [ime_protokola] -j [akcija]

Iptables sintaksu možete naći na netfilter.org.

l7-filtar treba "vidjeti" sav mrežni promet koji želimo kontrolirati, što znači da promet treba proći pravila l7-filtra. To se postiže upotrebom POSTROUTING lanca u mangle tablici:

Code:
iptables -t mangle -A POSTROUTING -m layer7 --l7proto [itd.]

Napomena: ukoliko se koristi l7-filter verzija starija od 2.7, potrebno je ručno učitati ip_conntrack modul za kernel da bi l7-filtar ispravno radio. Novije verzije ga učitaju automatski.

Blokiranje:

Blokiranje nije najpoželjniji način kontrole mrežnog prometa, i to iz više razloga:

- l7-filtar "matching" nije neotporan, tj. može se dogoditi da jedan protokol izgleda kao drugi (false positive)
- skoro svaka vrsta mrežnog prometa je legitimna (primjer su P2P protokoli koji se koriste za legalno razmjenjivanje i distribuciju besplatnih i slobodnih programa i dokumenata, a istovremeno se koriste za masovno kršenje autorskih prava)

Treba imati na umu da l7-filtar nije dizajniran s namjerom da se mrežni promet blokira, pa bi ovu radnju trebalo koristiti samo u nuždi.

Kontrola pojasne širine:

Za kontrolu pojasne širine koristi se Netfilter za označavanje paketa (mark) i zatim se pomoću QoS (Quality of Service) tehnika može oblikovati promet označenih paketa. Samo označavanje radi se s opcijom:

Code:
-j MARK --set-mark [integer]

dok se za oblikovanje koristi tc komandna linija koja je dio IPROUTE paketa. Slijedi primjer označavanja i filtriranja paketa koji koristi imap protokol:

Code:
iptables -t mangle -A POSTROUTING -m layer7 --l7proto imap -j MARK --set-mark 3

Vrijednost [integer] varijable je proizvoljna.

Oblikovanje mrežnog prometa tog označenog paketa se može izvoditi na sljedeći način:

Code:
tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 3 fw flowid 1:3

Time smo označeni imap promet usmjerili na treću podklasu prio metode za upravljanje redom čekanja (više o metodama za upravljanje slijedi kasnije u članku).

Komplicirana i nerazumljiva sintaksa tc komandne linije opisana je u LARTC HOWTO dokumentu, a za konkretnu upotrebu i lakši početak, u prilogu članka su dvije gotove skripte za oblikovanje mrežnog prometa. Jedna je skripta za premosnike (bridges), a jedna za "ne-premosnike" (non-bridges). Skriptu je potrebno modificirati na način da se odredi protokol koji se želi pratiti tj. oblikovati. Također, u slučaju ne-premosnika, potrebno je konfigurirati i NAT servis, a primjer NAT skripte je u prilogu. Skriptu treba modificirati na način da se promjeni IP adresa na kojoj se nalazi računalo koje obavlja NAT. Preporučljivo je da se skripte stave unutar /etc/init.d/ direktorija te se stave u startup proceduru sustava naredbom:

Code:
update-rc.d -f <ime_skripte> defaults

Podržan je priličan broj protokola, a to su uglavnom (nepoželjni) P2P protokoli te protokoli koje koriste računalne igre. Također je moguće napisati definicije za nove protokole, ukoliko za to postoji potreba. Uz protokole, moguće je definirati i tipove datoteka čiji promet želimo kontrolirati. Tako su podržane datoteke exe, gif, jpeg, pdf, rar, zip itd. Listu podržanih protokola i tipova datoteka možete naći pri kraju članka.

Praćenje prometa na mreži:

Ako vas samo zanima kojim se intenzitetom koriste protokoli koje ste definirali unutar prve skripte, moguće je koristiti gornju naredbu, ali bez -j opcije. Na primjer:

Code:
iptables -t mangle -A POSTROUTING -m layer7 --l7proto imap

Statistika se u tom slučaju može pratiti pomoću naredbe:

Code:
iptables  -t mangle -L -v

Već smo rekli da su metode upravljanja redovima algoritmi kojima se kontrolira način ulaska paketa u red i njihov izlazak. Ti algoritmi uključuju odlučivanje o tome koji se paketi propuštaju, kojim redoslijedom i brzinom, a to se radi unošenjem kašnjenja, preraspodjelom redoslijeda paketa i njihovim prioritiziranjem. Naravno, postoji više vrsta metoda za upravljanje, a u sljedećih nekoliko članaka sistematizirat ću osnovne metode upravljanja redovima čekanja i time olakšati odabir odgovarajuće metode ili više njih.

Linkovi:

l7-filter home page
podržani protokoli i tipovi datoteka
Linux Advanced Routing and Traffic Control

Skripte koje se spominju u tekstu će biti naknadno dodane.
Logged

Bavim se mreznom implementacijom - sistemac - Linux, CCNA, CCNP
The MasteR
Administrator
Full Member
*****

Karma: +20/-0
Offline Offline

Gender: Male
Posts: 168



View Profile WWW
« Reply #1 on: 17.08.2009., 14:02:43 »

Skripta za premosnike (bridges):

Code:
#!/bin/bash

# Somewhat simple script that controls bandwidth usage.
#
# This script assumes that the following are installed. 
# Userspace tools: iptables, ebtables, tc.
# Kernel stuff: Netfilter with layer7 patch, QoS, Ethernet bridging tables
#
# It also assumes (naturally) that this computer is acting as a bridge,
# although it should be very easy modify it to handle other situations.
#
# By Matthew Strait, 2003.  May be distributed under the GPL version 2,
# http://www.gnu.org/licenses/gpl.txt

# tc needs to be told about the physical devices, even if you're a bridge
physdevs="eth0 eth1"

# syntax: "<match type> = <match arg> , <tc speed>".
# Match types are "layer7" and "port".
# "port" matches source or destination for tcp or udp.
# "kbps" means "KBytes/second".  This is tc's fault.
actions=(
"port = 80, 40kbps"
"layer7 = ftp, 20kbps"
)

# Hopefully, nothing below this line needs to be edited
#########################################################################

# count commas...
lastaction=`echo ${actions[*]} | tr \, '\n' | wc -l`

# extra comma and array starts at zero...
let lastaction-=2

stop-tc() {
if ! [ $1 ]; then
        echo "specify a device!"
        cleanup 1
fi

for dev in $@; do
        if tc qdisc del dev $dev root &> /dev/null; then
                echo "tc has now stopped for $dev"
        else
                echo "stopping tc for $dev failed (was probably already stopped)"
        fi
done
}

cleanup(){

# Flush the whole mangle table.
iptables -t mangle -F
if ! [ $? = "0" ]; then echo flushing iptables failed at line $LINENO; fi

ebtables -F
if ! [ $? = "0" ]; then echo flushing ebtables failed at line $LINENO; fi

# stop traffic control completely.
stop-tc $physdevs

# if called with non-zero value, exit with that value
if [[ $1 != 0 ]]; then exit $1; fi
}

# 0 = don't exit
cleanup 0

# If these aren't loaded manually, shaping of the child connections will
# not work.
for m in ip_conntrack_ftp ip_conntrack_irc ip_conntrack_tftp ip_conntrack_amanda; do
if ! lsmod | grep $m > /dev/null; then
if ! modprobe $m; then
echo failed to load module $m
fi
fi
done

# set up basic traffic control magic
for dev in $physdevs; do
tc qdisc add dev $dev root handle 1: htb default 10
if ! [ $? = "0" ]; then echo tc failed at line $LINENO; cleanup 1; fi
done

# The mark number and also the queue number.  Must start at 2 so it doesn't collide.
n=2

# index into the speeds array
index=0

for m in `seq 0 $lastaction`; do

  match=`echo ${actions[$m]} | cut -d\, -f1`
  speed=`echo ${actions[$m]} | cut -d\, -f2`

  type=`echo $match | cut -d\= -f1`
  arg=`echo $match | cut -d\= -f2`

  echo Packets matching \"$match\" will be shaped to $speed.

  if [ $type = "layer7" ]; then
iptables -t mangle -A POSTROUTING -m layer7 --l7proto $arg -j MARK --set-mark $n
  elif [ $type = "port" ]; then
ebtables -A FORWARD -p IPv4 --ip-proto tcp --ip-source-port $arg -j mark --set-mark $n
ebtables -A FORWARD -p IPv4 --ip-proto tcp --ip-destination-port $arg -j mark --set-mark $n
ebtables -A FORWARD -p IPv4 --ip-proto udp --ip-source-port $arg -j mark --set-mark $n
ebtables -A FORWARD -p IPv4 --ip-proto udp --ip-destination-port $arg -j mark --set-mark $n
  else
echo "failed to parse \"$match\""
cleanup 1
  fi

  if ! [ $? = "0" ]; then echo \[ip\|eb\]tables failed at line $LINENO; cleanup 1; fi

  for dev in $physdevs; do
  # per class traffic control black magic
  tc class  add dev $dev parent 1:  classid 1:$n htb rate $speed burst 1k
  if ! [ $? = "0" ]; then echo tc failed at line $LINENO; cleanup 1; fi

  tc qdisc  add dev $dev parent 1:$n handle  $n: sfq perturb 10
  if ! [ $? = "0" ]; then echo tc failed at line $LINENO; cleanup 1; fi

  tc filter add dev $dev protocol ip parent 1: prio 1 handle $n fw flowid 1:$n
  if ! [ $? = "0" ]; then echo tc failed at line $LINENO; cleanup 1; fi
  done

  let n++
  let index++
done

Skripta za ne-premosnike (non-bridges):

Code:
#!/bin/bash

# This is L7-Netfilter-example modifed for non-bridges

# Somewhat simple script that controls bandwidth usage.
#
# This script assumes that the following are installed. 
# Userspace tools: iptables, ebtables, tc.
# Kernel stuff: Netfilter with layer7 patch, QoS, Ethernet bridging tables
#
# It also assumes (naturally) that this computer is acting as a bridge,
# although it should be very easy modify it to handle other situations.
#
# By Matthew Strait, 2003.  May be distributed under the GPL version 2,
# http://www.gnu.org/licenses/gpl.txt

# tc needs to be told about the physical devices, even if you're a bridge
physdevs="eth0 eth1"

# syntax: "<match type> = <match arg> , <tc speed>".
# Match types are "layer7" and "port".
# "port" matches source or destination for tcp or udp.
# "kbps" means "KBytes/second".  This is tc's fault.
actions=(
"layer7 = http, 20kbps"
"layer7 = ftp, 20kbps"
"layer7 = aim, 20kbps"
)

# Nothing below this line needs to be edited
#########################################################################

# count commas...
lastaction=`echo ${actions[*]} | tr \, '\n' | wc -l`

# extra comma and array starts at zero...
let lastaction-=2

stop-tc() {
if ! [ $1 ]; then
        echo "specify a device!"
        exit 1
fi

for dev in $@; do
        if tc qdisc del dev $dev root &> /dev/null; then
                echo "tc has now stopped for $dev"
        else
                echo "stopping tc for $dev failed (was probably already stopped)"
        fi
done
}

# If these aren't loaded manually, shaping of the child connections will
# not work.
for m in ip_conntrack_ftp ip_conntrack_irc ip_conntrack_tftp ip_conntrack_amanda; do
if ! lsmod | grep $m > /dev/null; then
if ! modprobe $m; then
echo failed to load module $m
fi
fi
done

# Flush the whole mangle table.
iptables -t mangle -F
if ! [ $? = "0" ]; then echo iptables failed at line $LINENO; exit 1; fi

#ebtables -F
#ebtables -t nat -F

# stop traffic control completely.
stop-tc $physdevs

# set up basic traffic control magic
for dev in $physdevs; do
tc qdisc add dev $dev root handle 1: htb default 10
if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

tc class add dev $dev parent 1:  classid 1:1  htb rate 1mbit burst 15k
if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

tc class add dev $dev parent 1:1 classid 1:2 htb rate 1mbit burst 15k
if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

tc qdisc add dev $dev parent 1:2 handle  2:  sfq perturb 10
if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi
done

# the mark number and also the queue number.  Must start at 3 so it doesn't
# collide with ones we've already set up.
n=3

# index into the speeds array
index=0

for m in `seq 0 $lastaction`; do

  match=`echo ${actions[$m]} | cut -d\, -f1`
  speed=`echo ${actions[$m]} | cut -d\, -f2`

  type=`echo $match | cut -d\= -f1`
  arg=`echo $match | cut -d\= -f2`

  echo Packets matching \"$match\" \($type, $arg\) will be shaped to $speed.

  if [ $type = "layer7" ]; then
iptables -t mangle -A POSTROUTING -m layer7 --l7proto $arg -j MARK --set-mark $n
  elif [ $type = "port" ]; then
iptables -t mangle -A POSTROUTING --protocol tcp --source-port $arg      -j MARK --set-mark $n
iptables -t mangle -A POSTROUTING --protocol udp --source-port $arg      -j MARK --set-mark $n
iptables -t mangle -A POSTROUTING --protocol tcp --destination-port $arg -j MARK --set-mark $n
iptables -t mangle -A POSTROUTING --protocol udp --destination-port $arg -j MARK --set-mark $n
  else
echo "failed to parse \"$match\""
exit 1
  fi

  if ! [ $? = "0" ]; then echo iptables failed at line $LINENO; exit 1; fi

  for dev in $physdevs; do
  # per class traffic control black magic
  tc class  add dev $dev parent 1:1  classid 1:$n htb rate $speed burst 1k
  if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

  tc qdisc  add dev $dev parent 1:$n handle  $n:  sfq perturb 10
  if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

  tc filter add dev $dev protocol ip parent 1:0 prio 1 handle $n fw flowid 1:$n
  if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi
  done

  let n++
  let index++
done

Skripta za NAT:

Code:
#!/bin/sh
#
# Startup script for nat
#


IPTABLES=/usr/local/sbin/iptables
#IPTABLES=/sbin/iptables
EXT_IF=eth0
INT_IF=eth1

case "$1" in
        start)
           echo -n "Starting nat firewall: "
           $IPTABLES --table nat --flush
           $IPTABLES --table nat --delete-chain
           $IPTABLES -t nat -A POSTROUTING -s 192.168.4.0/24 -j SNAT --to-source 172.16.3.4
           echo "Done"
        ;;
        stop)
           echo -n "Stopping nat firewall: "
           $IPTABLES --table nat --flush
           $IPTABLES --table nat --delete-chain
           echo "Done"
        ;;
        restart)
           $0 stop
           $0 start
        ;;
        *)
           echo "Usage: %s {start|stop|restart}\n" "$0"
        exit 1
esac

exit 0

Logged

Bavim se mreznom implementacijom - sistemac - Linux, CCNA, CCNP
Pages: [1]   Go Up
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.8 | SMF © 2006-2008, Simple Machines LLC | Sitemap Valid XHTML 1.0! Valid CSS!
Page created in 0.133 seconds with 23 queries.

Google visited last this page 27.01.2012., 14:59:44