Paketové filtry v Linuxu

Martin Kotlář, xkotlar@fi.muni.cz


Obsah


Typy a použití firewallů

Firewally se používají lze používat z nejrůznějších důvodů, např.: zvýšení bezpečnosti privátních sítí proti vnějším útokům, omezení toku dat mezi sítěmi, monitorování toků dat, přesnější specifikace práv jednotlivých uživatelů, znemožnění zmapování vnitřích chráněných sítí a soustředění přístupu do jednoho místa, atd.

Typy firewalů lze rodělit na dvě hlavní skupiny:

  1. Paketové filtry: Pracují se síťovou a transportní vrstvou ISO/OSI modelu a tedy filtrují pakety procházejích přes firewall na základě zdrojových a cílových IP adres a zdrojových a cílových portů. Paketové filtry jsou transparentní a ne příliš náročné, rychlé protože pracují na úrovni jádra, ale omezené pravě na kontrolu pouze spodních vrstev OSI modelu.
  2. Aplikační brány: Aplikační brány pracují s aplikační vrstvou ISO/OSI modelu. Jsou to proxy servery umožňující autentizaci každého spojení zvlášť. Lze kontrolovat na úrovní uživatelů, není potřeba dělat zásahy do jádra operačního systému, ale zase je nutno poupravit aplikace, každé spojení má určitou režii atd.
Obě možnosti lze i kombinovat a vytvořit tak komplexnější formy firewallů.


Paketové filtry v Linuxu

V historii vývoje Linuxu existují zatím 4 verze paketového filtru.


Netfilter - stavový firewall pro Linux verze 2.4

Struktura netfilteru

Průchod paketu systémem netfilteru:


   --->[PREROUTING]--->[ROUTE]--->[FORWARD]--->[POSTROUTING]--->
                          |                 ^
                          |                 |
                          |              [ROUTE]
                          v                 |
                       [INPUT]           [OUTPUT]
                          |                 ^
                          |                 |
                          v                 |
                       -------------------------
                       |     Local processes   |
                       -------------------------
						  

Systém netfilteru se skládá z několika tabulek (tables) obsahujících řetězy pravidel (chains) pro filtrování a případnou úpravu procházejících paketů (NAT):

Netfilter obsahuje 5 základních řetězů pro nastavení pravidel pro filtrování a překlad paketů, ale je možné si nadefinovat vlastní řetezy a do nich přesměrovat určité pakety (zejména pro zvýšení přehlednosti nastavení netfiltru a zjednodušení pravidel):

Netfilter oproti ipchains mimo jiné obsahuje i modul pro sledování spojení (connection tracking), jež zvyšuje možnosti kontroly filtrovaných paketů. Udržuje si informace o otevřených spojeních jež lze rozlišit do 4 skupin:



Kompilace a nastavení jádra

Aby bylo možno linuxový paketový filtr použít je nutno při kompilaci jádra povolit některé volby (kompilace netfilteru pro jádro verze 2.4.14) :

CONFIG_PACKET - tato volba umožňuje některým aplikacím a programům, které to vyžadují, přímý přístup k síťovým zařízením. Příkladem je třeba tcpdump nebo snort.

CONFIG_NETFILTER - tato volba je nutná pokud chceme používat počítač jako firewall nebo gateway do internetu. Je pro nás nezbytně nutná ;-).

CONFIG_IP_NF_CONNTRACK - tento modul je nutný pro sledování spojení, je nutný pokud chceme používat NAT (Masquerading).

CONFIG_IP_NF_FTP - modul potřebný pro sledování FTP spojení, je nezbytný pokud chceme nechat projít FTP spojení přes firewall korektně.

CONFIG_IP_NF_IPTABLES - tato volba je nezbytně nutná pokud chceme provádět jakékoliv filtrování, maškarádu nebo NAT.

CONFIG_IP_NF_MATCH_LIMIT - tento modul není nezbytně nutný, ale přídává možnost určit kolik paketů za minutu může projít přes určité pravidlo, lze ho s výhodou použít pro zabránění Denial of Service útokům.

CONFIG_IP_NF_MATCH_MAC - tento modul umožňuje určovat pakety podle MAC adres (Ethernetové adresy síťových karet).

CONFIG_IP_NF_MATCH_MARK - tato volba umožnuje označovat a kontrolovat z předchozích pravidel označené pakety. Ty jejichž cíl je MARK.

CONFIG_IP_NF_MATCH_MULTIPORT - tento modul umožňuje v jednom pravidle specifikovat celý rozsah zdrojových/cílových portů, což by normálně nebylo možné

CONFIG_IP_NF_MATCH_TOS - touto volbou umožníme filtrování paketů na základě pole TOS (Type of Service), TOS může být určitými pravidly modifikován v tabulce mangle, viz CONFIG_IP_NF_TARGET_TOS.

CONFIG_IP_NF_MATCH_TCPMSS - umožní sledovat TCP SYN pakety na základě pole MSS.

CONFIG_IP_NF_MATCH_STATE - tato volba je největší novinkou v jádrech 2.4.x. Je to stavová kontrola spojení.

CONFIG_IP_NF_FILTER - tento module přidává do netfilteru základní tabulku filter - pro filtrování paketů v řetězech input, forward, output. Nutná pro jakékoliv filtrování paketů.

CONFIG_IP_NF_TARGET_REJECT - modul přídávající cíl REJECT, místo zahazování odmítaných paketů se posílají nazpět ICMP error zprávy.

CONFIG_IP_NF_TARGET_MIRROR - modul umožňující vracení nepříjímaných paketů tím, že se prohodí zdrojová a cílová adresa a paket se odešle, např. jako odpověď na DoS attack (aby nevznikaly nekonečně přeposílané pakety v případě, že by cílový počítač měl také nastavený cíl MIRROR se paketům bude snižovat TTL)

CONFIG_IP_NF_NAT - tento modul umožňuje NAT v různých formách, jako je přesměrování portů, maškaráda atd. Nutný pro masquerading privátních sítí.

CONFIG_IP_NF_TARGET_MASQUERADE - tento module přídává cíl MASQ pro masquerading, je vhodnější než SNAT v případě, že neznáme předem internetovou IP adresu (PPP, DHCP, SLIP), je ale trošku náročnější než SNAT.

CONFIG_IP_NF_TARGET_REDIRECT - modul přídávající cíl REDIRECT, užitečný např. pro transparentní proxy. Místo propuštění paketu skrz ho přemapujeme pro lokální počítač - vytvoříme transparentní proxy.

CONFIG_IP_NF_MANGLE - module přídávajíci do netfilteru tabulku mangle pro upravování paketů a změnu filtrování.

CONFIG_IP_NF_TARGET_TOS - module přídávajíci cíl TOS pro úpravu pole Type of Service.

CONFIG_IP_NF_TARGET_MARK - module přídávajíci cíl MARK pro označování paketů.

CONFIG_IP_NF_TARGET_LOG - modul přídávající cíl LOG, nutný pro logování paketů přes syslogd. Dobrý pro ladění a sledování firewallů.

CONFIG_IP_NF_TARGET_TCPMSS - řeší problém se servery ISP blokující ICMP Fragmentation needed, použítím cíle TCPMSS a předejitím problému tím, že se MSS (Maximum Segment Size) nastaví na PMTU (Path Maximum Transmit Unit).

CONFIG_IP_NF_COMPAT_IPCHAINS - přídává modul pro zpětnou kompatibilitu s ipchains.

CONFIG_IP_NF_COMPAT_IPFWADM - přídává modul pro zpětnou kompatibilitu s ipfwadm.


Po kompilaci nového jádra a jeho zavedení je ještě nutné zapnout směrování:

bash# echo 1 > /proc/sys/net/ipv4/ip_forward
a v případě, že máme dynamicky přidělovanou IP adresu (PPP) můžeme zapnout i:
bash# echo 1 > /proc/sys/net/ipv4/ip_dynaddr



Ovládání netfilteru - iptables

Hlavním programem pro ovládání netfilteru je program iptables. Dalšími pomocnými programy jsou ješte iptables-save (pro uložení nastavení netfilteru do souboru) a iptables-restore (pro nahrání nastavení netfilteru ze souboru vytvořeného iptables-save).

Pomocí programu iptables lze určitým chainům přidávat pravidla, která se prochází v tom pořadí, v jakém byla zadána. Pokud paket odpovídá nejakému pravidlu, které přímo určí jeho cíl (ne LOG, MARK, apod.), je vyhodnocování ukončeno. Každému řetězu pravidel (chain) lze nastavit i implicitní politiku - tzn. co provést s paketem, který nebyl vyhodnocen žádným pravidlem.

Jak taková pravidla a příkazy manipulace s chainy vypadají obecně:

iptables -[ADC] chain rule-specification [options]
iptables -[RI] chain rulenum rule-specification [options]
iptables -D chain rulenum [options]
iptables -[LFZ] [chain] [options]
iptables -[NX] chain
iptables -P chain target [options]
iptables -E old-chain-name new-chain-nam

manipulace s chainy:

  1. vytvořit nový chain (-N)
  2. zrušit prázdný chain (-X) (INPUT, OUTPUT a FORWARD zrušit nejde)
  3. změnit policy vestavěného chainu (-P) (uživatelské chainy policy nemají)
  4. vypsat pravidla chainu (-L)
  5. vymazat pravidla z chainu (-F)
  6. vynulovat počítadla paketů/bajtů na všech pravidlech v chainu (-Z)

manipulace s pravidly v rámci chainu:

  1. přidat na konec chainu nové pravidlo (-A)
  2. vložit na zadané místo do chainu nové pravidlo (-I)
  3. nahradit pravidlo na dané pozici v chainu (-R)
  4. odstranit pravidlo na dané pozici z chainu (-D)
  5. smazat první odpovídající pravidlo z chainu (-D) (od předchozího se liší syntaxí)

některé důležité nebo zajímavé parametry v rámci specifikace pravidla:

A konečně nějaké příklady:

bash# iptables -P FORWARD DROP
- nastavení politiky (chain policy) chainu FORWARD na DROP
bash# iptables -A INPUT -d 127.0.0.0/8 -j DROP
- zahazování paketů pro localhost
bash# iptables -A INPUT -s 193.86.135.0/24 -j ACCEPT
- důvěryhodná síť, přijímáme všechno
bash# iptables -A OUTPUT -d www.microsoft.cz -p tcp --destination-port http -j DROP
- zákaz přístupu na webserver www.microsoft.cz
bash# iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT 
- ochrana proti syn-floodingu
bash# iptables -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
- ochrana proti ping-of-death
bash# iptables -t nat -A POSTROUTING -o ppp+ -j MASQUERADE
- maškaráda pro pakety vycházející ze zařízení ppp0, ppp1, ...
bash# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 81
- přesměrování TCP paketů přícházejících na port 80 na port 81




Příklad startovacího skriptu firewallu

Příklad startovacího skriptu firewallu pro distribuce RedHat:

#!/bin/bash
#
# Firewall Script

# chkconfig: 2345 11 89
# description: firewall script for 2.4.x kernel


################################################
#  Fill in the values below to match your
#  local network.

LAN_IP_RANGE="192.168.0.0/24"
LAN_IP="192.168.0.1/32"
INET_IP="123.124.125.126/32"
LAN_BCAST_ADRESS="192.168.0.255/32"
LOCALHOST_IP="127.0.0.1/32"
INET_IFACE="eth1"
LAN_IFACE="eth0"
LO_IFACE="lo"

IPTABLES="/sbin/iptables"

################################################

# some handy generic values to use
ANY=0.0.0.0/0
ALLONES=255.255.255.255

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

# Check kernel version
if [ ! -x $IPTABLES ]; then
	echo "$IPTABLES not found - cannot run firewall !!!"
	exit 0
fi

if [ ! -f /proc/net/ip_tables_names ]; then
	modprobe ip_tables > /dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo "CANNOT RUN FIREWALL !!!"
		exit 1
	fi
fi

# See how we are called
case "$1" in
  start)
        # Start providing access
        action "Starting firewall: " /bin/true

        # Flush all lists
        $IPTABLES -F

        # Turn on packet forwarding
        echo 1 > /proc/sys/net/ipv4/ip_forward

        # Plug up everything
        $IPTABLES -I INPUT -i ! lo -j DROP
        $IPTABLES -I FORWARD -j DROP
        $IPTABLES -I OUTPUT -o ! lo -j DROP

        ##
        ## Install Modules 
        ##
        # Insert the active ftp module.  This will allow non-passive ftp to machines
        # on the local network (but not to the router since it is not masq'd)
		needed_mods="ipt_LOG ip_nat_ftp ipt_REJECT ipt_MASQUERADE ip_conntrack_ftp"
		for mod in $needed_mods; do
	        if ! ( /sbin/lsmod | /bin/grep $mod > /dev/null ); then
        	    /sbin/modprobe $mod || echo "Cannot load module : $mod"
	        fi
		done
	
        ##
        ## Some Security Stuff
        ##
        # turn on Source Address Verification and get spoof protection
        # on all current and future interfaces.
        if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ]; then
            for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
                echo 1 > $f
            done
        else
            echo
            echo "PROBLEMS SETTING UP IP SPOOFING PROTECTION.  BE WORRIED."
            echo
        fi

	########
	## Firewall rules
	##

	#
	# POSTROUTING chain in the nat table
	#
	$IPTABLES -t nat -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
	$IPTABLES -t nat -A POSTROUTING -o $INET_IFACE -j MASQUERADE

	#
	# Bad TCP packets we don't want
	#

	$IPTABLES -A FORWARD -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "New not syn:"
	$IPTABLES -A FORWARD -p tcp ! --syn -m state --state NEW -j DROP

	#
	# Accept the packets we actually want to forward
	#

	$IPTABLES -A FORWARD -i $LAN_IFACE -j ACCEPT
	$IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT 
	$IPTABLES -A FORWARD -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT FORWARD packet died: "

	#
	# Set default policies for the INPUT, FORWARD and OUTPUT chains
	#

	$IPTABLES -P INPUT DROP
	$IPTABLES -P OUTPUT DROP
	$IPTABLES -P FORWARD DROP

	#
	# Create separate chains for ICMP, TCP and UDP to traverse
	#

	$IPTABLES -N icmp_packets
	$IPTABLES -N tcp_packets
	$IPTABLES -N udp_in_packets

	#
	# The allowed chain for TCP connections
	#

	$IPTABLES -N allowed
	$IPTABLES -A allowed -p TCP --syn -j ACCEPT
	$IPTABLES -A allowed -p TCP -m state --state ESTABLISHED,RELATED -j ACCEPT
	$IPTABLES -A allowed -p TCP -j LOG --log-prefix "TCP not established: "
	$IPTABLES -A allowed -p TCP -j DROP

	#
	# ICMP rules
	#

	$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 0 -j ACCEPT
	$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 3 -j ACCEPT
	$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 5 -j ACCEPT
	$IPTABLES -A icmp_packets -p ICMP -s 0/0 --icmp-type 11 -j ACCEPT

	#
	# TCP rules
	#

	$IPTABLES -A tcp_packets -p TCP -s 0/0 --dport 22 -j allowed	# SSH
	$IPTABLES -A tcp_packets -p TCP -s 0/0 --dport 25 -j allowed	# SMTP
	$IPTABLES -A tcp_packets -p TCP -s 0/0 --dport 80 -j allowed	# WWW
	$IPTABLES -A tcp_packets -p TCP -s 0/0 --dport 113 -j allowed	# auth

	#
	# UDP ports
	#

	$IPTABLES -A udp_in_packets -p UDP -s 0/0 --sport 53 -j ACCEPT	# DNS
	$IPTABLES -A udp_in_packets -p UDP -s 0/0 --sport 123 -j ACCEPT	# NTP

	#
	# PREROUTING chain.
	#
	# Do some checks for obviously spoofed IP's 
	#

	$IPTABLES -t nat -A PREROUTING -i $INET_IFACE -s 192.168.0.0/16 -j DROP
	$IPTABLES -t nat -A PREROUTING -i $INET_IFACE -s 10.0.0.0/8 -j DROP


	#
	# INPUT chain
	#
	# Take care of bad TCP  packets that we don't want
	#

	$IPTABLES -A INPUT -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "New not syn:"
	$IPTABLES -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

	#
	# Rules for incoming packets from the internet
	#

	$IPTABLES -A INPUT -p ICMP -i $INET_IFACE -j icmp_packets
	$IPTABLES -A INPUT -p TCP -i $INET_IFACE -j tcp_packets
	$IPTABLES -A INPUT -p UDP -i $INET_IFACE -j udp_in_packets

	#
	# Rules for special networks not part of the Internet
	#

	$IPTABLES -A INPUT -p ALL -i $LAN_IFACE -d $LAN_BCAST_ADRESS -j ACCEPT
	$IPTABLES -A INPUT -p ALL -i $LO_IFACE -d $LOCALHOST_IP -j ACCEPT
	$IPTABLES -A INPUT -p ALL -i $LO_IFACE -d $LAN_IP -j ACCEPT
	$IPTABLES -A INPUT -p ALL -i $LAN_IFACE -d $LAN_IP -j ACCEPT
	$IPTABLES -A INPUT -p ALL -i $INET_IFACE -m state --state ESTABLISHED,RELATED -j ACCEPT
	$IPTABLES -A INPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT INPUT packet died: "
	
	#
	# OUTPUT chain
	#

	$IPTABLES -A OUTPUT -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "New not syn:"
	$IPTABLES -A OUTPUT -p tcp ! --syn -m state --state NEW -j DROP

	$IPTABLES -A OUTPUT -p ALL -s $LOCALHOST_IP -j ACCEPT
	$IPTABLES -A OUTPUT -p ALL -s $LAN_IP -j ACCEPT
	$IPTABLES -A OUTPUT -p ALL -o $INET_IFACE -j ACCEPT
	$IPTABLES -A OUTPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT OUTPUT packet died: "
	
	#######
	# Let's open the plug
        $IPTABLES -D INPUT 1
        $IPTABLES -D FORWARD 1
        $IPTABLES -D OUTPUT 1

        ;;

  stop)
        action "Stoping firewall: " /bin/true
        echo 0 > /proc/sys/net/ipv4/ip_forward
        $IPTABLES -F INPUT
        $IPTABLES -F OUTPUT
        $IPTABLES -F FORWARD
        $IPTABLES -t nat -F PREROUTING
        $IPTABLES -t nat -F POSTROUTING
        $IPTABLES -F allowed
        $IPTABLES -F tcp_packets
        $IPTABLES -F icmp_packets
        $IPTABLES -F udp_in_packets
        $IPTABLES -X allowed
        $IPTABLES -X tcp_packets
        $IPTABLES -X icmp_packets
        $IPTABLES -X udp_in_packets
        
	echo
        ;;

  restart)
        action "Restarting firewall: " /bin/true
        $0 stop
        $0 start

        echo
        ;;

  status)
        # List out settings
        $IPTABLES -L
        ;;
  *)
        echo "Usage: $0 {start|stop|restart|status}"
        exit 1

esac

Odkazy a dokumentace