FreeBSD firewall - IPFW

Petr Bezděk, xbezdek@fi.muni.cz


Obsah


Úvod

Účelem tohoto dokumentu není podrobný popis typů firewallů a jejich realizace, ale průvodce konfigurací paketového firewallu IPFW pod FreeBSD.


Proč firewall


Typy firewallů

Firewally můžeme rozdělit na dva základní typy:

Aplikační brána

Pracuje na aplikační vrstvě. Střeží tedy jednotlivé aplikace. Veškerá komunikace probíhá prostřednictvím proxy serverů, tzv. zástupných serverů. Místo klasických démonů (telnetd, ftpd atd.) běží speciálně upravené proxy servery. Uživatelé přistupují ke službách prostřednictvím těchto proxy serverů transparentně nebo pomocí upravených klientů.
Komunikace mezi serverem a klientem vypadá následovně: klient chce kontaktovat server, místo toho kontaktuje proxy server na firewallu a ten dále komunikuje se skutečným serverem dle daných pravidel.

+ možnost autentizace na úrovni uživatelů
+ není potřeba zasahovat do jádra
- nutnost úpravy aplikací
- nutnost zvláštního programu pro každou aplikaci

Paketový filter

Pracuje na síťové vrstvě. Zkoumá hlavičky každého paketu a podle seznamu pravidel se rozhodne jak s daným paketem naloží. Tedy daný paket může např. zahodit, anebo pustit k dalšímu zpracování.

+ není potřeba upravovat aplikace
+ rychlost, většina operací se odehrává uvnitř jádra
+ nenáročný, lze vyrobit firewall na jedné disketě
- autentizace jen podle IP adres či čísla portů


Paketový filtr IPFW

IPFW je nativní paketový filter a traffic-shapper pod FreeBSD. Jako další volbu pro paketový filtr pod FreeBSD lze použít IP Filter, jemuž se v tomto dokumentu věnovat nebudu. Porovnání IPFW a IP Filtru je shrnuto zde.

Pro pochopení a následnou tvorbu pravidel paketového filtru je potřeba vědět, jak pakety putují jádrem. Data příjdou na fyzické síťové rozhraní ze sítě a jádro si je vyzvedne a zpracuje do formy paketu. Podle cílové IP adresy jádro určí, zda paket patří tomuto počítači nebo jinému a bude forwardován (forwardování se musí zapnout pomocí sysctl -w net.inet.ip.forwarding=1). Další možnost je, že aplikace na našem počítači vygeneruje nějaká data a ty jsou poslána síťovým rozhraním směrem ven do sítě.
Cestování paketů jádrem popisuje následující obrázek:

Incoming -->[Routing ]----------------> Outgoing
            [Decision]                ^
                v                     |
                |                     |
                |                     |
                ---> Local Process ---

Pro tvorbu pravidel se používá program ipfw. Jednotlivá pravidla jsou očíslovaná od 1 do 65535. Pravidlo číslo 65535 je natvrdo nastaveno při kompilaci jádra, a to na implicitně vše zakázat. Volbou IPFIREWALL_DEFAULT_TO_ACCEPT v konfiguračním souboru jádra můžeme implicitně vše povolit.

Každý paket je porovnáván se seznamem pravidel a pokud paket vyhoví některému pravidlu, je provedena akce spojená s pravidlem. IPFW podporuje také stavový filter, kdy pakety jsou porovnávány proti záznamům ve stavové tabulce. Tedy na data procházející firewallem se nepohlíží jako na jednotlivé pakety, ale jako na konexe. Pro každou konexi se vytvoří dynamické pravidlo s omezenou životností a zapíše se do stavové tabulky.

Každé pravidlo v seznamu má následující čítače:
- čítač paketů prošlých daným pravidlem
- čítač bytů prošlých daným pravidlem
- čítač paketů prošlých daným pravidlem, které se logovaly
a časové razítko udávající, kdy naposledy paket vyhověl danému pravidlu.
Jednotlivé čítače lze zobrazit a také nulovat.

Dále pravidla lze združovat do množin a s množinami nakladat jako s celkem. Množiny lze povolovat, zakazovat, prohazovat, přesouvat pravidla z jedné množiny do druhé a samozřejmě mazat.


Zprovoznění IPFW

Máme dvě možnosti:

1) Zavést modul ipfw.ko do jádra
$ kldload ipfw
Pozor: jestliže zavádíte modul vzdáleně, je potřeba to udělat nějak takto:
$ kldload ipfw && ipfw add allow all from any to any
jinak si pod sebou podřežete větev...

2) Kompilací jádra s podporou IPFW
$ cd /usr/src/sys/i386/conf && vim JADRO

# podpora pro samotný IPFW
options IPFIREWALL 

# IPv6 varianta
options IPV6FIREWALL

# logovaní paketů přes syslog, pokud nezkompilujete jádro s touto volbou a budete
# zadávat pravidla do IPFW s volbou log, pakety nebudou nikdy logovány.
options IPFIREWALL_VERBOSE 

# IPv6 varianta
options IPV6FIREWALL_VERBOSE 

# udává počet paketů logovaných přes syslog na každé pravidlo,
# přes syslog reporty (daily, weekly apod.) je možné zasílat info o tom,
# že byl dosažen limit logování paketů pro dané pravidlo
options IPFIREWALL_VERBOSE_LIMIT=N

# IPv6 varianta
options IPV6FIREWALL_VERBOSE_LIMIT=N

# implicitně povolí vše (bez této volby je implicitně vše zakázáno)
options IPFIREWALL_DEFAULT_TO_ACCEPT 

# IPv6 varianta
options IPV6FIREWALL_DEFAULT_TO_ACCEPT 

# umožní forwardovat pakety na jinou IP/port pomocí akce fwd příkazu ipfw
options IPFIREWALL_FORWARD 

# umožní dělat NAT pomocí natd
options IPDIVERT

# zatajení firewallu před nmap (jádro ignoruje pakety s příznaky SYN+FIN),
# odstraňte pokud provozujete web server
options   TCP_DROP_SYNFIN 

# ICMP_BANDLIM umožní omezení šiřky pásma pro ICMP errory,
# většinou se používá pro ochránění před D.O.S
options   ICMP_BANDLIM 

# zatajení firewallu před traceroute
options   IPSTEALTH 

$ /usr/sbin/config JADRO
$ cd ../../config/JADRO
$ make depend
$ make
$ make install
$ reboot 

Startovací skripty

/etc/rc.conf a možné volby
# zapnutí IPFW (sysctl -w net.inet.ip.fw.enable=1)
firewall_enable="YES"

# cesta k souboru s pravidly
firewall_script="/etc/rc.firewall"

# prednastavené firewally: open, client, simple, closed, custom
firewall_type="UNKNOWN"

# při "YES" se nebudou při bootu vypisovat pravidla
firewall_quiet="NO"

# zapne logování přes syslog (sysctl -w net.inet.ip.fw.verbose=1)
firewall_logging="YES"

# zapne forwardovaní mezi síťovými rozhraními (sysctl -w net.inet.ip.forwarding=1)
gateway_enable="YES"

# při nastavení čísla většího jak 0 se budou logovat spojení,
# které se pokoušely připojit na porty, na kerých neposlouchá žádný socket
log_in_vain="0"

# Nastavení na YES způsobí to, že jádro bude ignorovat TCP rámce, které mají
# nastaven SYN a FIN bit.
tcp_drop_synfin="NO"

# Nastavení na YES způsobí to, že jádro bude ignorovat ICMP REDIRECT pakety.
icmp_drop_redirect="NO"

# Nastavení na YES způsobí to, že jádro bude logovat ICMP REDIRECT pakety. 
icmp_log_redirect="NO"

Výpis a mazání pravidel

výpis pravidel
$ ipfw list
výpis pravidel včetně časového razítka, kdy naposledy paket vyhověl danému pravidlu
$ ipfw -t list
výpis pravidel včetně čítačů
$ ipfw -a list
nebo
$ ipfw show
smazání pravidel
$ ipfw -f flush

Základní syntaxe

ipfw příkaz [číslo_pravidla] akce protokol from zdroj [zdrojový_port] to cíl [cílový_port] [[in/out] via interface] 
příkazy:
- add
- delete

akce:
- allow | pass | permit = povolení paketu
- deny | drop = zahození paketu
- fwd | forward ipaddr[,port] = forwardování na ipaddr[:port]
- reset = zahození paketu a zaslání TCP paketu s RST bitem
- count = zvýší se čítače a pokračuje se dál
- unreach code = zahození paketu a zaslaní ICMP zprávy, kde code může být net, host, protocol, port, ...
- skipto číslo_pravidla = skok na dané číslo pravidla

Př.:
# zákaz všeho
ipfw add 1000 deny all from any to any

Specifikování protokolu

Protokoly: tcp, udp, icmp, ...
více viz. /etc/protocols
ipfw prikaz [číslo_pravidla] akce protokol from zdroj to cíl 
Př.:
# povolení TCP odkudkoliv kamkoliv
ipfw add allow tcp from any to any

Specifikování zdrojové a cílové adresy

Zdrojové a cílové adresy můžeme zadávat jako jména nebo IP adresy. Pokud je protokol TCP nebo UDP můžeme určit i číslo portu.

Př.:
ipfw add 1000 allow udp from myhost 1024-65535 to neco.cz 21 
nebo
ipfw add 1100 allow tcp from 192.168.0.1 1024-65535 to any 
rovnež můžeme používat i masku sítě
ipfw add 2000 allow all from 192.168.0.0/16 to any
ipfw add 2100 deny all from any to 10.0.0.0:255.0.0.0 
nebo můžeme použít příkaz NOT
# zákaz všech paketů kromě pořítače s IP 192.168.0.3
ipfw add 1100 deny all from not 192.168.0.3 


Specifikování portu

Zdrojové a cílové porty můžeme zadávat ve tvaru port, jako rozsah port_od-port_do nebo výčtem oddělým čárkami.
# povolení TCP na IP 192.168.0.5 a port 25
add 1000 allow tcp from any to 192.168.0.5 25

# povolení TCP na IP 192.168.0.5 a porty 1021-1023
ipfw add 1000 allow tcp from any to 192.168.0.5 1021-1023

# povolení TCP na IP 192.168.0.5 a porty 21,22,23
ipfw add 1000 allow tcp from any to 192.168.0.5 21,22,23  

Interface a kontrola toku

# povolení všech paketů dovnitř
ipfw add 1000 allow all from any to any in

# povolení všech paketů ven
ipfw add 1000 allow all from any to any out 

# povolení všech paketů dovnitř přes kterýkoliv interface
ipfw add 1000 allow all from any to any in via any 

# povolení všech paketů dovnitř přes interface xl0
ipfw add 1000 allow all from any to any in via xl0 

ICMP typy

icmptypes typ = pravidlu vyhoví ICMP pakety určitého typu.

Pokud je před icmptypes přidán '!', potom vyhovují všechny pakety, které nejsou tohoto typu.

Je 15 typu ICMP:
0-Echo Reply
3-Destination Unreachable
4-Source Quench
5-Redirect
8-Echo Request
9-Router Advertisement
10-Router Silicitation
11-Time-to-Live Exceeded
12-IP header bad
13-Timestamp Request
14-Timestamp Reply
15-Information Request
16-Information Reply
17-Address Mask Request
18-Address Mask Reply
Př.:
# povolí pakety typu 8 (echo request) ven
ipfw add 1000 allow icmp from any to any out icmptypes 8

# povolí pakety typu 0 (echo reply) dovnitř
ipfw add 1100 allow icmp from any to any in icmptypes 0

# zakáže pakety typu 8 (echo request) dovnitř 
ipfw add 1200 deny icmp from any to any in icmptypes 8

TCP flags, setup a established

tcpflags - tomuto pravidlu bude vyhovovat každý TCP paket, jehož hlavička obsahuje jeden z následujícich příznaků.

Nebo pokud použijeme '!' pred tcpflags, budou vyhovovat všechny pakety, které nemají flag nastaven. Tyto pravidla se dají použivat pouze u TCP.

FIN = požadavek na ukončení spojení
# SYN bit je posilan pri inicializaci spojeni = nazýváno v IPFW také setup
SYN = požadavek na inicializace spojení
RST = Reset konexe
PSH = Push Flag
# ACK bit je posílán při již probíhajícím spojení = nazýváno v IPFW také established
ACK = Acknowledgement
URG = Indicate Urgent OOB data 
Př:
ipfw add deny tcp from any to any in tcpflags syn 
je stejné jako
ipfw add deny tcp from any to any in setup

Fragmentované pakety

Pro detekci fragmentovaných paketů se používá možnost frag. Přijímání mnoha fragmentovaných paketů způsobuje DoS (denial of services). Možnost frag může být použita jenom v případě že:

1) není použito tcpflags
2) není použit TCP nebo UDP port

Př.:
# zakázání frag. paketů dovnitř  
ipfw add deny all from any to any in frag 

Logování

log = je logován každý paket, který vyhovuje pravidlu.

logamount číslo = tento parametr následuje za příkazem log. Určuje kolikrát se budou pakety vyhovujicí konkretnímu pravidlu logovat. Po dosaženi určeného maxima je logování zastaveno. Čítač se musí vynulovat, aby se mohlo logovat dále (ochrana před DOS). Je-li číslo rovno nule, loguje se pořád bez omezení.

Př.:
# loguje prvních 100 paketů, které vyhovují tomuto pravidlu
ipfw add 1000 deny log loagmount 100 all from any to any

# loguje se kazdy paket, který vyhovuje pravidlu
ipfw add 1000 deny log loagmount 0 all from any to any
Pokud jsou pravidla logována jsou uvedeny v logu následující informace:
- datum a čas
- číslo pravidla
- akce
- zdrojová a cílová IP adresa
- zdrojový a cílový port
- zařízení, přes které paket přisel/odcházel

Př.:
Apr 27 01:18:58 ares /kernel: ipfw: 9900 Deny TCP 10.1.1.57:1027 10.1.1.1:445 in via fxp1

NAT

IPFW nemá přímo v sobě podporu pro NAT. K tomu účelu je zde démon natd, který překlad adres obstarává. Poslouchá na portu 8668.
[root@ares root]# grep natd /etc/services
natd            8668/divert # Network Address Translation
V jádře je potřeba mít zaplou volbu IPDIVERT.

Př.:
# adresy se překladají na zařízení fxp0
ipfw add 40000 divert natd all from any to any via fxp0
nastavení v /etc/rc.conf
# má se spuštět natd
natd_enable="YES" 

# rozhraní, na kterém se mají překládat adresy
natd_interface="fxp0"

# parametry, s kterými se spouští natd
# na rozhraní, na kterém se překládají adresy se port 5000 přesměruje na
# IP 10.1.1.53 port 22
natd_flags="-m -s -redirect_port tcp 10.1.1.53:22 5000"

Odkazy

IPFW manuál CZ
IPFW HOWTO
FreeBSD Handbook - firewall
ipfw - manuálové stránky
FreeBSD firewall
IPFW manuál
IPFW - psaní pravidel
IPFW logging
IPFW NAT HOWTO
natd - manuálové stránky