Presupunem un calculator Linux cu un kernel din seria 2.4 sau 2.6. Kernelul se configurează în prealabil setând opţiunea "netfilter" în "Network Options":
A 2.6.11 kernel:
< > The IPv6 protocol (EXPERIMENTAL)
[*] Network packet filtering (replaces ipchains) --->
SCTP Configuration (EXPERIMENTAL) --->
iar apoi în "Network packet filtering/Netfilter Configuration" setăm toate opţiunile pentru a fi compilate în kernel.
Trebuie apoi să instalăm pachetul iptables. În Gentoo comanda arată în felul următor:
# emerge iptables
2. O scurtă introducere în iptables
Primul lucru pe care îl facem este să vedem dacă este ceva deja activ - unele distribuţii setează reguli în iptables la startup:
# iptable -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP all -- eqnjadvip3.doubleclick.net anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP all -- eqnjadvip3.doubleclick.net anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
iptable ne informează că există trei lanţuri active: INPUT pentru pachete care intră în calculator, OUTPUT pentru pachete care ies din calculator şi FORWARD pentru pachetele care sunt routate în cazul în care calculatorul funcţionează ca un router. Pentru fiecare lanţ, putem avea un număr de reguli active.
Regulile sunt relativ uşor de citit. Cea pe care o avem mai sus se referă la toate pachetele care vin de la un server doublecklick.net. Nu este o surpriză că aceste pachete sunt rejectate; acelaşi lucru poate fi obţinut mult mai uşor instalând extensia Adblock în Firefox.
Fiecare lanţ poate fi utilizat având ca default fie să accepte orice pachet cu excepţia celor specificate în regulile aferente, fie să rejecteze orice pachet cu excepţia celor specificate. Există astfel două tipuri mari de firewall-uri: default drop şidefault accept. Trecere de la un tip la altul se face uşor folosind opţiunea -P:
# iptables -P INPUT DROP
# iptables -L
Chain INPUT (policy DROP)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
# iptables -L
Chain INPUT (policy DROP)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
3. Comenzi iptables
Parametrii comenzii iptables se împart în trei categorii:
# iptable [lanþ] [pachet] [acþiune]
În categoria lanţ avem următoarele opţiuni:
-N: (new)un nou lanþ este creat
-X: un lanþ fãrã reguli este ºters
-P: (policy) trecere de la default drop la default accept ºi invers
-F: (flush) ºterge toate regulile în lanþul respectiv
-Z: (zero) reseteazã contoarele pentru toate regulile din lanþ
-A: (add) adaugã o nouã regulã în lanþ
-I: (insert) insereazã o nouã regulã în lanþ
-R: (replace) schimbã o regulã existentã în lanþ
-D: (delete) ºterge o regulã existentã
-X: un lanþ fãrã reguli este ºters
-P: (policy) trecere de la default drop la default accept ºi invers
-F: (flush) ºterge toate regulile în lanþul respectiv
-Z: (zero) reseteazã contoarele pentru toate regulile din lanþ
-A: (add) adaugã o nouã regulã în lanþ
-I: (insert) insereazã o nouã regulã în lanþ
-R: (replace) schimbã o regulã existentã în lanþ
-D: (delete) ºterge o regulã existentã
În categoria care descrie pachetele avem:
-s, -d: adresã sursã/destinaþie IP
-p: protocol (tcp, udp, icmp)
-i: interfaþã (lo, eth0, eth1, ppp0, etc.)
-f: fragmentare
-p: protocol (tcp, udp, icmp)
-i: interfaþã (lo, eth0, eth1, ppp0, etc.)
-f: fragmentare
O serie de extensii sunt definite pentru unele din opţiunile pachet de mai sus:
Dacã '-p tcp' este specificat:
--sport, --dport: porturi sursã/destinaþie
--tcp-flags: flaguri tcp
--syn: echivalent cu '--tcp_flags SYN,RST,ACK SYN'
--tcp-option
Dacã '-p udp' este specificat:
--sport, --dport: porturi sursã/destinaþie
Dacã '-p icmp' este specificat:
--icmp-type: rulaþi '-p icmp --help' pentru o listã completã
--sport, --dport: porturi sursã/destinaþie
--tcp-flags: flaguri tcp
--syn: echivalent cu '--tcp_flags SYN,RST,ACK SYN'
--tcp-option
Dacã '-p udp' este specificat:
--sport, --dport: porturi sursã/destinaþie
Dacã '-p icmp' este specificat:
--icmp-type: rulaþi '-p icmp --help' pentru o listã completã
Mai multe extensii pot fi încărcate ca module folosind opţiunea -m:
Dacã '-m mac' este specificat:
--mac_source: adresã sursã mac
Dacã '-m limit' este specificat:
--limit: limiteazã numãrul de pachete acceptate pe secundã/minut/orã/ziuã
--limit-burst
Dacã '-m owner' este specificat, pentru pachete generate local:
--uid-owner
--gid-owner
--pid-owner
--sid-owner
Dacã '-m state' este specificat:
--state: starea conexiunii (NEW, ESTABLISHED, RELATED, INVALID)
--mac_source: adresã sursã mac
Dacã '-m limit' este specificat:
--limit: limiteazã numãrul de pachete acceptate pe secundã/minut/orã/ziuã
--limit-burst
Dacã '-m owner' este specificat, pentru pachete generate local:
--uid-owner
--gid-owner
--pid-owner
--sid-owner
Dacã '-m state' este specificat:
--state: starea conexiunii (NEW, ESTABLISHED, RELATED, INVALID)
A treia categorie descrie acţiunea care trebuie îndeplinită când un pachet este recunoscut:
-j: DROP, ACCEPT, LOG
În continuare descriem un firewall default drop.
4. Un firewall simplu
Presupunem că suntem conectaţi la o reţea de Ethernet pe interfaţa eth0. Începem prin a curăţa toate regulile existente (comanda -F), şi setăm firewall-ul pentru default drop:
# iptables -F
# iptables -P INPUT DROP
# iptables -P INPUT DROP
Avem în acest moment un firewall perfect şi total nefolositor. Toate pachetele care ajung la noi vor fi făcute pierdute de către kernel. Adăugăm o regulă simplă care să ne permită să accesăm pachetele aparţinând acelor conexiuni care au fost iniţiate de către calculatorul nostru:
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
Kernelul Linux are un modul numit conntrack care urmăreşte toate conexiunile care au loc la un moment dat. Fiecărei conexiuni îi sunt asociate una din cele patru stări posibile: NEW (o conexiune nouă), ESTABLISHED (o conexiune activă), RELEATED (conexiuni noi care sunt un rezultat al unei conexiuni existente) şi INVALID (conexiuni care au ajuns într-o stare defectă).
Revenind la comanda de mai sus, -A adaugă o nouă regulă pe lanţul INPUT. Această regulă se referă la toate pachetele care aparţin unei conexiuni în stare RELATED sau ESTABLISHED, iar aceste pachete sunt acceptate (-j). Observaţi aici lipsa stării NEW, adică toate conexiunile pornite din exterior sunt refuzate.
Apare însă o mică problemă: cineva din exterior încercând să se conecteze la calculatorul nostru poate în acest moment detecta că rulăm un firewall deoarece calculatorul nu răspunde cu pachetele standard TCP reset sau ICMP unreachable. Aceasta poate fi reparată foarte uşor adăugând următoarele două reguli:
# iptables -A INPUT -p tcp -i eth0 -j REJECT --reject-with tcp-reset
# iptables -A INPUT -p udp -i eth0 -j REJECT --teject-with icmp-port-unreachable
# iptables -A INPUT -p udp -i eth0 -j REJECT --teject-with icmp-port-unreachable
O altă mică scăpare este următoarea: dorim uneori să rulăm pe calculator un server de HTTP numai pentru uzul nostru, invizibil în exterior. Cum regulile de mai sus vor rejecta pachetele pentru conexiunile în starea NEW trebuie să adăugăm o nouă regulă ACCEPT din care să excludem interfaţa publică de Ethernet eth0:
# iptables -A input -i ! eth0 -j ACCEPT
Punem totul la un loc şi construim un script simplu:
#!/bin/bash
# fwall.sh - un firewall simplu
# dupã un exemplu de Daniel Robbins
if [ "$1" = "start" ]
then
echo "Starting firewall"
iptables -P INPUT DROP
iptables -A INPUT -i ! eth0 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -i eth0 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -i eth0 -j REJECT --reject-with icmp-port-unreachable
elif [ "$1" == "stop" ]
then
echo "Stopping firewall"
iptables -F INPUT
iptables -P INPUT ACCEPT
fi
# fwall.sh - un firewall simplu
# dupã un exemplu de Daniel Robbins
if [ "$1" = "start" ]
then
echo "Starting firewall"
iptables -P INPUT DROP
iptables -A INPUT -i ! eth0 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -i eth0 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -i eth0 -j REJECT --reject-with icmp-port-unreachable
elif [ "$1" == "stop" ]
then
echo "Stopping firewall"
iptables -F INPUT
iptables -P INPUT ACCEPT
fi
Nu avem decât să rulăm scriptul şi să-l testăm:
# ./fwall.sh start
# iptables -v -L
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- !eth0 any anywhere anywhere
82 40719 ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED
1 60 REJECT tcp -- eth0 any anywhere anywhere reject-with tcp-reset
369 59386 REJECT udp -- eth0 any anywhere anywhere reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 31329 packets, 2004K bytes)
pkts bytes target prot opt in out source destination
# iptables -v -L
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- !eth0 any anywhere anywhere
82 40719 ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED
1 60 REJECT tcp -- eth0 any anywhere anywhere reject-with tcp-reset
369 59386 REJECT udp -- eth0 any anywhere anywhere reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 31329 packets, 2004K bytes)
pkts bytes target prot opt in out source destination
O listă a conexiunilor existente poate fi găsită astfel:
# cat /proc/net/ip_conntrack
Dacă dorim să pornim acest firewall la startup, copiem fwall.sh în directorul /sbin iar apoi adăugăm linia "/sbin/fwall.sh start &" la sfârşitul fişierului /etc/conf.d/local.start. În mod asemănător, adăugăm "/sbin/fwall.sh stop &" la sfârşitul fişierului /etc/conf.d/local.stop.
scriptul original al lui Daniel Robbins este prezentat în Anexa 1, şi include o serie de îmbunătăţiri cum ar fi: disable ECN (explicit congestion notification), spoof protection, suport pentru routing (nu este necesar în cazul nostru simplu de desktop), suport pentru o serie de servicii precum ssh şi http.
5. Firewall dinamic - dynfw
Sub acest nume, gentoo.org publică un mic proiect care nu face parte oficial din distribuţia Gentoo. Constă într-o serie de scripturi original scrise de Daniel Robbins. Scopul acestor scripturi este acela de a adăuga/elimina reguli iptables fără a modifica scriptul iniţial de firewall care rulează pe calculator.
Pachetul se găseşte la http://tirpitz.iat.sfu.ca/~robbat2/dynfw-1.0.1.tar.gz. Download, dezarhivăm şi-l instalăm:
wget http://tirpitz.iat.sfu.ca/~robbat2/dynfw-1.0.1.tar.gz
tar -xzvf dynfw-1.0.1.tar.gz
cd dynfw-1.0.1
./install.sh
tar -xzvf dynfw-1.0.1.tar.gz
cd dynfw-1.0.1
./install.sh
Sunt incluse următoarele scripturi:
ipdrop - rejecteazã toate pachetele care vin de la o adresã IP specificatã
ipblock - similar cu ipdrop, rãspunde însã cu TCP reset
tcplimt - limiteazã rata noilor conexiuni pentru un port local TCP specificat
host-tcplimit - limiteazã rata noilor conexiuni de la un host extern specificat
user-outblock - un user specificat nu este lãsat sã deschidã conexiuni în exterior
ipblock - similar cu ipdrop, rãspunde însã cu TCP reset
tcplimt - limiteazã rata noilor conexiuni pentru un port local TCP specificat
host-tcplimit - limiteazã rata noilor conexiuni de la un host extern specificat
user-outblock - un user specificat nu este lãsat sã deschidã conexiuni în exterior
Să zicem că rulăm pe calculator un un server ftp (scriptul din Anexa 1 este activ cu SERVICES="ftp"), iar un utilizator de la adresa IP 1.2.3.4 insistă prea tare să încarce fişiere peste limitele acceptate, consumând o grămadă de bandwidth. Comanda arată în felul următor:
# /usr/local/sbin/ipdrop 1.2.3.4 on
# iptables -vL
Chain INPUT (policy DROP 1 packets, 60 bytes)
pkts bytes target prot opt in out source destination
2 96 DROP all -- any any 1.2.3.4 anywhere
0 0 ACCEPT all -- !eth0 any anywhere anywhere
324 182K ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED
3 144 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ftp state NEW
0 0 REJECT tcp -- eth0 any anywhere anywhere reject-with tcp-reset
1261 208K REJECT udp -- eth0 any anywhere anywhere reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 DROP all -- any any anywhere 1.2.3.4
Chain OUTPUT (policy ACCEPT 1652 packets, 129K bytes)
pkts bytes target prot opt in out source destination
0 0 DROP all -- any any anywhere 1.2.3.4
# iptables -vL
Chain INPUT (policy DROP 1 packets, 60 bytes)
pkts bytes target prot opt in out source destination
2 96 DROP all -- any any 1.2.3.4 anywhere
0 0 ACCEPT all -- !eth0 any anywhere anywhere
324 182K ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED
3 144 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ftp state NEW
0 0 REJECT tcp -- eth0 any anywhere anywhere reject-with tcp-reset
1261 208K REJECT udp -- eth0 any anywhere anywhere reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 DROP all -- any any anywhere 1.2.3.4
Chain OUTPUT (policy ACCEPT 1652 packets, 129K bytes)
pkts bytes target prot opt in out source destination
0 0 DROP all -- any any anywhere 1.2.3.4
Observăm cum o regulă DROP este adăugată pe toate cele trei lanţuri. Aceasta împedică efectiv orice fel de comunicaţie cu acest user. Pentru a curăţa aceste reguli şi a restaura firewall-ul iniţial dăm comanda:
# /usr/local/sbin/ipdrop 1.2.3.4 off
În mod similar se folosesc şi celelalte scripturi. Rulaţi comanda respectivă fără nici un parametru pentru o scurtă descriere.
6. Resurse
Articolul original al lui Daniel Robbins: http://www6.software.ibm.com/developerworks/education/l-fw/index.html(registration).
dynfw homepage: http://www.gentoo.org/proj/en/dynfw.xml
netfilter/iptable homepage: http://www.netfilter.org.
Tutorialul iptables al lui Oskar Andreasson: http://iptables-tutorial.frozentux.net/iptables-tutorial.html
HOWTO Iptables for newbies: http://gentoo-wiki.com/HOWTO_Iptables_for_newbies
Anexa 1
#!/bin/bash
#Our complete stateful firewall script. This firewall can be customized for
#a laptop, workstation, router or even a server. :)
#change this to the name of the interface that provides your "uplink"
#(connection to the Internet)
UPLINK="eth0"
#if you're a router (and thus should forward IP packets between interfaces),
#you want ROUTER="yes"; otherwise, ROUTER="no"
ROUTER="no"
#change this next line to the static IP of your uplink interface for static SNAT, or
#"dynamic" if you have a dynamic IP. If you don't need any NAT, set NAT to "" to
#disable it.
#NAT="1.2.3.4"
NAT=""
#change this next line so it lists all your network interfaces, including lo
#INTERFACES="lo eth0 eth1"
INTERFACES="lo eth0"
#change this line so that it lists the assigned numbers or symbolic names (from
#/etc/services) of all the services that you'd like to provide to the general
#public. If you don't want any services enabled, set it to ""
#SERVICES="http ftp smtp ssh rsync"
SERVICES=""
if [ "$1" = "start" ]
then
echo "Starting firewall..."
iptables -P INPUT DROP
iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#enable public access to certain services
for x in ${SERVICES}
do
iptables -A INPUT -p tcp --dport ${x} -m state --state NEW -j ACCEPT
done
iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable
#explicitly disable ECN
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
#disable spoofing on all interfaces
for x in ${INTERFACES}
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
if [ "$ROUTER" = "yes" ]
then
#we're a router of some kind, enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
if [ "$NAT" = "dynamic" ]
then
#dynamic IP address, use masquerading
echo "Enabling masquerading (dynamic ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE
elif [ "$NAT" != "" ]
then
#static IP, use SNAT
echo "Enabling SNAT (static ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP}
fi
fi
elif [ "$1" = "stop" ]
then
echo "Stopping firewall..."
iptables -F INPUT
iptables -P INPUT ACCEPT
#turn off NAT/masquerading, if any
iptables -t nat -F POSTROUTING
fi
#Our complete stateful firewall script. This firewall can be customized for
#a laptop, workstation, router or even a server. :)
#change this to the name of the interface that provides your "uplink"
#(connection to the Internet)
UPLINK="eth0"
#if you're a router (and thus should forward IP packets between interfaces),
#you want ROUTER="yes"; otherwise, ROUTER="no"
ROUTER="no"
#change this next line to the static IP of your uplink interface for static SNAT, or
#"dynamic" if you have a dynamic IP. If you don't need any NAT, set NAT to "" to
#disable it.
#NAT="1.2.3.4"
NAT=""
#change this next line so it lists all your network interfaces, including lo
#INTERFACES="lo eth0 eth1"
INTERFACES="lo eth0"
#change this line so that it lists the assigned numbers or symbolic names (from
#/etc/services) of all the services that you'd like to provide to the general
#public. If you don't want any services enabled, set it to ""
#SERVICES="http ftp smtp ssh rsync"
SERVICES=""
if [ "$1" = "start" ]
then
echo "Starting firewall..."
iptables -P INPUT DROP
iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#enable public access to certain services
for x in ${SERVICES}
do
iptables -A INPUT -p tcp --dport ${x} -m state --state NEW -j ACCEPT
done
iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with icmp-port-unreachable
#explicitly disable ECN
if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
#disable spoofing on all interfaces
for x in ${INTERFACES}
do
echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done
if [ "$ROUTER" = "yes" ]
then
#we're a router of some kind, enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
if [ "$NAT" = "dynamic" ]
then
#dynamic IP address, use masquerading
echo "Enabling masquerading (dynamic ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j MASQUERADE
elif [ "$NAT" != "" ]
then
#static IP, use SNAT
echo "Enabling SNAT (static ip)..."
iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to ${UPIP}
fi
fi
elif [ "$1" = "stop" ]
then
echo "Stopping firewall..."
iptables -F INPUT
iptables -P INPUT ACCEPT
#turn off NAT/masquerading, if any
iptables -t nat -F POSTROUTING
fi
No comments:
Post a Comment