Bu bölümde Linux çekirdeğinin filtreleme (filter) tablosunu düzenleyip, gelen ve giden paketlerimizi filtrelemeyi inceleyeceğiz. Filter tablosunda hali hazırda tablosunda 3 tane zincir (chain) vardır:
Bu zincirleri bir diagramda inceleyelim:
_____
Gelen / \ Giden
-->[Yönlendirme]--->|FORWARD|------->
[ Kararı ] \_____/ ^
| |
v ____
___ / \
/ \ |OUTPUT|
|INPUT| \____/
\___/ ^
| |
----> Yerel İşlemler ----
Zincirler, paketler için uygulanacak kuralların listesi olarak da düşünülebilir. Bir paket, bir zincire vardığında, paketin kaderini belirlemek için bu zincirdeki kurallara sırayla bakılır. Eğer paket, herhangi bir kuralda belirtilen koşullara uyuyorsa, bu kurala göre paket reddedilir (DROP ya da REJECT) veya paket kabul edilir (ACCEPT). Eğer paket, zincirde tanımlanan kuralların hiçbiri ile eşleşmemiş ise, zincirin varsayılan politikası (policy) uygulanır.
Her bir kural, paketler için belli koşullar belirler. Ve bu koşullara uyan paketlere ne yapılacağını tanımlar. Örneğin ICMP protokolü kullanılarak bize gelen bütün paketleri (INPUT) görmezden gelmek (DROP) istediğimizi düşünelim. Bu durumda kurallımızın koşulu gelen paketin protokolünün ICMP olması, hedefi ise DROP’tur. Bu kuralı yaratmadan önce test için ping aracı ile kendi bilgisayarımıza ICMP paketleri gönderelim:
# ping -c 4 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.053 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.039 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.035 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.041 ms
--- 127.0.0.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2997ms
rtt min/avg/max/mdev = 0.035/0.042/0.053/0.006 ms
Yukarıda görüldüğü gibi, 127.0.0.1 IP adresine (kendi bilgisayarımız) gönderdiğimiz ICMP paketleri kabul edildi. Şimdi iptables INPUT zincirinde bir kural tanımlayıp ICMP paketlerini görmezden gelelim:
# iptables -A INPUT -p icmp -j DROP
Bu komuttaki -A (append) parametresi, belirtilen zincirin sonuna bir kural ekler (Bizim örneğimizde INPUT zinciri). Bu kural -p (protocol) parametresi ile paketler için ICMP protokolü koşulunu tanımlamıştır. Yani bu kural sadece ICMP paketlerini etkileyecek bir kuraldır. Kısaca bu kuralın söylediği şey; gelen (INPUT) ICMP paketleri (-p icmp), DROP hedefine (-j DROP) gönderilir. Hedef, bir diğer deyişle paketin kaderidir. -j parametresi ile belirtebileceğimiz hedefler:
Tanımladığımız bu kuraldan sonra, tekrar ICMP paketleri göndermeyi deneyelim:
# ping -c 4 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
--- 127.0.0.1 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3012ms
Bir süre bekledikten sonra zaman aşımına uğrayıp, ping uygulaması cevap beklemekten vazgeçecek.
Zincirleri ve bu zincirlerdeki kuralları listelemek için --list
(ya da kısaca -L) parametresini kullanabiliriz:
# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP icmp -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Çıktıyı incelediğimizde, INPUT, FORWARD ve OUTPUT isminde üç tane zincirimiz olduğunu ve INPUT zincirinde bir tane kuralımız olduğunu görürüz.
Bir kuralı silmek için; iptables uygulamasının -D (delete) parametresine silmek istediğimiz kuralın bulunduğu zincir ile birlikte, kuralın bu zincirde göründüğü sıra numarasını belirtmeliyiz. Örneğin iptables -L komutu ile INPUT zincirinde gördüğümüz 1. kuralı silmek için:
# iptables -D INPUT 1
komutunu kullanabiliriz. Bir kuralı silmenin bir başka yöntemi, onu tanımladığımız komuttaki -A parametresini -D ile değiştirip, komunun geri kalanını aynı bırakmaktır. Örneğin iptables -A INPUT -p icmp -j DROP komutu ile oluşturduğumuz kuralı silmek için:
# iptables -D INPUT -p icmp -j DROP
komutunu kullanabiliriz. Bir zincirde çok fazla kural bulunduğunda, silinmesi istenen kuralın kaçıncı sırada olduğunu bulmak zorlaşacağı için, bu yöntem kullanışlıdır (Birden fazla aynı kural bulunduğu durumda, sadece zincirde ilk karşılaşılan kural silinecektir).
Belge boyunca denemelerinizi yaparken, zincirleri sık sık temizlemeniz gerekecek. Çünkü -A parametresi ile eklediğiniz her kural zincirin sonuna eklenir. Dolayısıyla yapacağınız testleri önceden tanımladığınız kurallar da etkileyecektir. Kuralları tek tek temizlemek yerine, bütün zincirlerdeki kuralları silmek için –flush (ya da -F) parametresini kullanabilirsiniz:
# iptables -F
Eğer sadece belli bir zincirdeki kuralları temizlemek istiyorsanız
-F parametresinden sonra, ilgili zincirin adını verebilirsiniz. Örneğin:
# iptables -F INPUT
Bir paket zincirdeki hiç bir kuralla eşleşmediği durumda, zincirin
politikası (policy) uygulanır. Zincir için geçerli olan
politikayı değiştirmek için -P parametresini
kullanabilirsiniz (bütün zincirler için varsayılan politika
ACCEPT’tir). Örneğin INPUT
zincirinin politikasını DROP yapalım:
# iptables -P INPUT DROP
Böylelikle, bir paket, INPUT zincirindeki hiç bir kural ile
eşleşmediği vakit engellenecektir.
Dikkat! iptables -F komutu zincirler için varsayılan politikaları ayarlamaz. Sizin her seferinde iptables -P komutu ile ayarlamanız gerekir.
Paketin kaynağına göre (paketi gönderene) göre filtreleme yapmak için iptables uygulamasının -s (ya da --source, --src) parametresini kullanabiliriz. Aynı şekilde paketin hedefine göre (paketin gönderileceği adrese) filtreleme yapmak için -d (ya da --destination, --dst) parametresini kullanabiliriz.
Kaynak ya da hedef adresi belirtilirken IP adresi kullanıldığı gibi, alan adı veya bir IP aralığı da belirtilebilir. Örneğin:
# iptables -A INPUT -s www.linuxum.com -j DROP
komutu www.linuxum.com adresinden gelen bütün paketleri engelleyecektir. Alan adı yerine IP adresi ile bir örnek verelim:
# iptables -A OUTPUT -d 78.188.77.207 -j DROP
komutu, 78.188.77.207 IP adresine giden bütün paketleri
engelleyecektir.
IP aralığı kullanarak bir örnek verelim:
# iptables -A OUTPUT -s 10.1.0.0/24 -j DROP
komutu, 10.1.0.0 - 10.1.0.255 aralığındaki bütün IP adreslerinden gelen paketleri engeller (IP aralığı kullanılırken CIDR gösterimi yerine netmask’te kullanılabilir. Örneğin 10.1.0.0/24 yerine 10.1.0.0/255.255.255.0 yazmanız aynı anlama gelecektir).
Ayrıca -s ve -d parametrelerini bir arada da kullanabiliriz:
# iptables -A OUTPUT -s 10.1.0.0/24 -d www.linuxum.com -j DROP
komutu, 10.1.0.0 - 10.1.0.255 aralığındaki bütün IP adreslerinden
gelip www.linuxum.com adresine giden paketleri engeller.
Bazı Iptables parametrelerinin önüne ! işareti konularak, istenen özellik tersine çevrilebilir. Örneğin 10.1.0.0/24 IP adresi aralığının dışındaki IP adreslerini belirtmek için -s ! 10.1.0.0/24 şeklinde kullanılabilir:
# iptables -A OUTPUT -s ! 10.1.0.0/24 -j DROP
! işareti, sadece -s paremetresi ile değil aynı
zamanda -d parametresi ve daha bir çok Iptables parametresi
ile birlikte de kullanılabilir.
Protokole göre filtreleme yapmak için Iptables’ın -p parametresini kullanırız (Daha önceki örneklerimizde ICMP protokolü ile ilgili işlemler yaparken, -p parametresini kullanmıştık). -p parametresine icmp yanında, tcp ya da udp değerini de verebiliriz (-p parametresinin alacağı değerler büyük/küçük harf duyarsızdır. Yani tcp ile TCP aynı şeydir).
-p parametresi ile birlikte değil ! işareti de kullanılabilir. Örneğin bir kural içerisinde -p ! tcp şeklinde kullanıldığında bu kural TCP dışındaki diğer protokolleri etkiler. Örneğin:
# iptables -A OUTPUT -s 10.1.0.0/24 -p ! tcp -j DROP
komutu, 10.1.0.0/24 IP aralığındaki bilgisayarların tcp protokolü
dışındaki protokolleri kullanmalarını engeller.
Linux’ta fiziksel ethernet kartınızla, bir arayüz ismi ile iletişim kurarsınız (Örneğin sisteminizdeki birinci ethernet kartının arayüz ismi eth0 iken, bir diğerinin ki eth1 veya başka bir isimde olabilir). Iptables kurallarınızı tanımlarken, bu kuralın sadece belirli bir arayüz için geçerli olmasını istiyorsanız -i (ya da --in-interface) parametresini veya -o (ya da --out-interface) parametresini kullanabilirsiniz.
INPUT zinciri için kural tanımlarken, ortada giden paket olmayacağı için -o parametresini kullanmak anlamsızdır. INPUT zinciri ile sadece -i parametresini kullanmalısınız. INPUT zincirinde -o parametresi belirtilerek tanımlanmış kurallar hiçbir paketle eşleşmeyecektir. Aynı şekilde OUTPUT zinciri için kural tanımlarken, -i parametresini kullanmak anlamsızdır. OUTPUT zincirini için kural tanımlarken yalnızca -o parametresini kullanmalısınız.
Örneğin:
# iptables -A INPUT -i eth0 -j DROP
kuralı eth0’a gelen paketleri engelleyecektir.
# iptables -A OUTPUT -o eth1 -j ACCEPT
kuralı eth1’den giden paketlere izin verecektir.
Yalnızca FORWARD zinciri için tanımlanan kurallarda hem -i hem de -o parametresi kullanılabilir.
Kural tanımlarında arayüz belirtilirken arayüzün o anda aktif olması (up) zorunlu değildir. Aktif olmayan arayüzler için tanımlanan kurallar, arayüz aktif hale geldiğinde etkili olacaktır.
Ayrıca arayüz belirtirken, arayüz isminin sonunda + belirtilmesi durumunda, belirttiğiniz isimle başlayan bütün arayüzler bu kuraldan etkilenecektir. Örneğin -i eth+ şeklinde bir tanımlama, eth0, eth1 ... gibi eth ile başlayan bütün arayüzleri etkiler.
Son olarak -i ya da -o parametresinden sonra !
işaretini, belirtilen arayüz dışındaki arayüzleri kastetmek amacıyla
kullanabilirsiniz. Örneğin -i ! eth+ parametresi ile
tanımlanmış bir kural, eth ile başlamayan arayüzleri
etkileyecektir.
Var olan zincirlerin yanında, -N parametresi ile kendiniz de zincir tanımlayabilirsiniz:
# iptables -N TCPKURALLARI
Yarattığımız bu zincire bir kural ekleyelim:
# iptables -A TCPKURALLARI -s 10.1.0.116 -p tcp -j DROP
Yarattığımız bu zincirin kullanılması için, bu zincirin tanımladığınız kurallardan birinin hedefi olması gerekir. Örneğin:
# iptables -A INPUT -p tcp -j TCPKURALLARI
Bir paket kullanıcı tanımlı zincirdeki hiçbir kural ile eşleşmez
ise, geldiği zincire geri döner. Yukarıdaki örneğimizde gelen paket
TCPKURALLARI içerisindeki hiçbir kural ile eşleşmediği durumda,
TCPKURALLARI zincirinden çıkılıp; INPUT zincirindeki, bir sonraki
kuraldan devam edilir. Bu yüzden, kullanıcı tanımlı zincirler için
politika belirtemezsiniz.
Bir zinciri silmek için, önce -F ZINCIRADI parametresi ile o zincirdeki bütün kuralları temizlemeli, ardından boş olan zinciri silmek için, -X ZINCIRADI parametresini kullanmalısınız. Örneğin:
# iptables -F TCPKURALLARI
# iptables -X TCPKURALLARI
-X parametresi zincir adı belirtilmeden kullanıldığında, boş olan tüm kullanıcı tanımlı zincirleri silecektir.
Iptables’ı eklenti kullanarak genişleyebilir yapıya sahiptir. Örneğin, -p parametresi ile protokol belirttiğinizde belirttiğiniz protokole özgü eklenti otomatik olarak yüklenip size ekstra koşullar (testler) sunar.
Iptables’a -p tcp parametresi verdiğinizde TCP eklentileri otomatik olarak yüklenir. Bu eklenti hakkında bilgi almak için:
# iptables -p tcp --help
komutunu çalıştırıp, çıktının en altında TCP eklentisinin sürümünü ve seçeneklerini görebilirsiniz.
TCP eklentisinin bize sağladığı bazı testleri inceleyelim:
--source-port (ya da --sport) TCP paketinin kaynak portuna göre bir kural tanımlamamızı sağlar. 80 gibi port numarası yerine www gibi isimler de kullanılabilir (bu kullanılan isimlerin port numarası karşılıkları /etc/services dosyasına bakılarak bulunur). Ayrıca belli port aralıkları da belirtilebilir. Örneğin --source-port 4400:4500 şeklinde kullanıldığında, 4400 ve 4500 aralığındaki bütün portlar kastedilir. Ayrıca tanımlanan kuralın 4400 den büyük portlar ile eşlenmesi isteniyorsa --source-port 4400: şeklinde, 4400 den küçük portlar ile eşlenmesi isteniyorsa --source-port :4400 şeklinde kullanılabilir. Örneğin 22 ve 23 numaralı porta dışarıdan bağlanılmasına izin verelim:
# iptables -A INPUT -p tcp --dport 22 -j ACCEPT
--destination-port (ya da –dport) TCP paketinin hedef
portuna göre bir kural tanımlamamızı sağlar. Kullanım şekli --source-port
ile aynıdır.
--tcp-flags parametresi, TCP bayrakları üzerinde maskeleme yapıp, belli bayrakların durumunu kontrol etmemizi sağlar. Kullanımı:
--tcp-flags maske karşılaştırma
şeklindedir. Örneğin, 23 numaralı porta gelen SYN paketlerine izin vermek istemiyorsak:
# iptables -A INPUT -p tcp --dport 23 --tcp-flags SYN,ACK,RST,FIN SYN -j DROP
--syn parametresi --tcp-flags SYN,RST,ACK,FIN SYN parametresi için kısa addır.
UDP eklentileri, iptables’a -p udp parametresini
verdiğimizde otomatik olarak yüklenir. UDP Eklentileri ile birlikte
gelen parametreler, TCP eklentisinde olduğu gibi --source-port (--sport)
ve --destination-port (--dport) tur. Aynı şekilde kullanılır.