Python ile IPv4 soketleri kullanarak port tarayıcı yazmak
Selamlar, bu yazımda Python ile küçük ama gerçekten işe yarayan bir TCP port tarayıcı yazacağız. Konuya yeni başlayan arkadaşlar için adım adım gideceğim, ama 'tarayıcıyı yazıp bıraktık' tarzı bir yazı değil bu - thread'lerle hızlandırma ve banner okuma kısmına da gireceğiz. Hadi başlayalım.
Açıkçası ben de soketlere ilk dokunduğumda bu kadar basit bir API ile bu kadar şey yapılabileceğine biraz şaşırmıştım. socket modülü standart kütüphanede, ekstra paket falan kurmuyoruz.
Port tarama nasıl çalışır?
TCP port tarayıcı, hedef host üzerindeki her port'a bir TCP bağlantısı denemesi yapar. Bağlantı kurulduysa port açıktır. İşletim sistemi bağlantıyı reddediyorsa port kapalıdır. Timeout ise genelde trafik bir yerlerde düşürülüyor (firewall, drop kuralı) anlamına gelir, ama tabii her zaman böyle değil; ağ tarafında başka sorunlar da timeout'a sebep olabilir.
Basit, sıralı bir tarayıcı
Hadi minimum bir örnekle başlayalım. Tek thread, sıralı çalışan bir versiyon:
import socket
def scan_port(host: str, port: int, timeout: float = 1.0) -> bool:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.settimeout(timeout)
result = sock.connect_ex((host, port))
return result == 0
target = '127.0.0.1'
common_ports = [22, 80, 443, 3306, 5432, 6379, 8080, 27017]
for port in common_ports:
if scan_port(target, port):
print(f'Port {port}: ACIK')
Burada dikkat edilecek nokta connect_ex kullanımı. Normal connect hata fırlatıyor, biz her seferinde try/except yazmak istemiyoruz. connect_ex başarıda 0 dönüyor, başarısızlıkta hata kodu; biz de bunu sade bir bool'a çeviriyoruz. settimeout(1.0) da kritik - vermezsek bir filtreli port'ta thread saatlerce bekleyebilir.
Thread'lerle hızlandırma
Sıralı tarama 1024 port için bile sıkıcı yavaş. Network I/O olduğu için GIL bizi yormuyor; thread'ler burada gerçekten işe yarıyor.
import socket
import threading
from queue import Queue
def safe_worker(host: str, port_queue: Queue, open_ports: list,
lock: threading.Lock, timeout: float) -> None:
while True:
port = port_queue.get()
if port is None:
port_queue.task_done()
break
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.settimeout(timeout)
if sock.connect_ex((host, port)) == 0:
with lock:
open_ports.append(port)
except OSError:
pass
finally:
port_queue.task_done()
Buradaki klasik desen Queue + 'poison pill'. Worker'lar kuyruktan port çekiyor, None görünce çıkıyor. Liste paylaşımlı olduğu için lock ile koruyoruz. Thread sayısı bence 200 civarı tatlı bir nokta - daha fazlası dosya descriptor limitine takılmaya başlar, daha azı ise yavaş kalır.
Banner okuma (banner grabbing)
Açık port'u bulmak hoş, ama orada ne çalışıyor onu da merak ediyoruz. Bazı servisler bağlanınca kendiliğinden bir karşılama satırı (banner) gönderiyor:
def grab_banner(host: str, port: int, timeout: float = 2.0) -> str:
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.settimeout(timeout)
sock.connect((host, port))
sock.sendall(b'\r\n')
data = sock.recv(1024)
return data.decode('utf-8', errors='replace').strip()
except (socket.timeout, OSError):
return ''
SSH, FTP, SMTP gibi protokollerde işe yarar; HTTP'de pek konuşkan değildir, oraya GET / HTTP/1.0 istemek gerekir.
Sık karşılaşılan tuzaklar
- Timeout vermemek:
settimeoutçağırmadanconnect_exyazarsanız filtreli port'larda thread'leriniz dakikalarca asılı kalır. Hemen her örnekte timeout var, sebebi bu. - Çok agresif paralellik: 5000 thread ile tarama açmak hem yerel makinanızı hem de hedefi rahatsız eder; Linux'ta
ulimit -nile dosya descriptor limitine de takılırsınız. 100-300 arası genelde yeter. - Loopback'i 'gerçek' sanmak:
127.0.0.1üzerinde her şey hızlı ve temiz görünür. Gerçek bir LAN host'unda gecikmeler, retransmit'ler çok farklıdır; timeout'unuzu ona göre ayarlayın. - İzinsiz tarama: Kendi sunucunuzu veya yazılı izniniz olan sistemleri taramak sorun değil, ama rastgele bir host'u taramak birçok ülkede suçtur. Bunu hafife almayın.
Kapanış
Bu yazıda Python'un socket modülü ile basit bir TCP port tarayıcı yazıp Queue + thread'lerle hızlandırdık, üstüne küçük bir banner okuyucu ekledik. Bence öğrenmek ve kendi makinanızı denetlemek için bu kadarı gayet yeterli; ciddi güvenlik işi yapacaksanız tekerleği yeniden icat etmek yerine nmap kullanın - SYN tarama, OS parmak izi gibi özellikleri zaten var. Umarım faydalı olur, bir sonraki yazıda görüşmek üzere.
