Python İle Çok İş Parçacıklı Bir Ağ Tarayıcısı Nasıl Yapılır?

Python İle Çok İş Parçacıklı Bir Ağ Tarayıcısı Nasıl Yapılır?
Python İle Çok İş Parçacıklı Bir Ağ Tarayıcısı Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Projemize başlamadan önce Python 3.12 veya daha güncel bir sürümün yüklü olduğundan emin olmalısınız. Ağ tarama işlemleri için Python'un standart kütüphaneleri olan socket, threading ve queue modüllerini kullanacağız. Harici bir bağımlılığa ihtiyaç duymadan, sistemin kendi kütüphaneleriyle yüksek performanslı bir araç geliştireceğiz.

Geliştirme ortamınızda şu komutla Python sürümünüzü kontrol edebilirsiniz:

python --version

Ağ tarama işlemleri sırasında işletim sisteminizin güvenlik duvarı (firewall) veya antivirüs yazılımları, gönderdiğiniz paketleri "şüpheli" olarak işaretleyebilir. Bu nedenle, kendi yerel ağınızda veya yetkili olduğunuz ortamlarda test yapmanız önerilir.

Temel Soket Programlama Mantığı

Bir ağ tarayıcısının kalbi "soket" yapısıdır. Soket, iki cihaz arasındaki veri alışverişini sağlayan uç noktadır. Python'da bir portun açık olup olmadığını anlamak için o porta bir bağlantı isteği göndeririz. Eğer bağlantı kabul edilirse port açıktır, reddedilirse kapalıdır.

Aşağıdaki örnek, tek bir IP ve port için basit bir bağlantı denemesini gösterir:

import socket

def port_kontrol(ip, port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(1)
    sonuc = s.connect_ex((ip, port))
    s.close()
    return sonuc == 0

# Örnek kullanım: 192.168.1.1 IP'sinin 80. portunu kontrol et
print(f"Port açık mı: {port_kontrol('192.168.1.1', 80)}")

Burada connect_ex metodu, bağlantı başarılıysa 0 değerini döndürür. settimeout(1) kullanımı, yanıt vermeyen portlarda programın sonsuza kadar beklemesini engeller.

Çok İş Parçacıklı (Multi-Threading) Yapının Kurulması

Tek bir işlemle 1000 portu taramak dakikalar sürebilir. threading modülü ile bu işlemi paralel hale getirerek süreyi saniyelere indirebiliriz. İş parçacıkları, aynı bellek alanını paylaşarak CPU'nun boşta kalan zamanlarını değerlendirir.

İş parçacıklarını yönetmek için queue (kuyruk) yapısını kullanmak en güvenli yöntemdir. Bu sayede her bir iş parçacığı, kuyruktaki bir sonraki portu alıp işlemeye başlar.

import threading
from queue import Queue

kuyruk = Queue()

def tarayici():
    while not kuyruk.empty():
        port = kuyruk.get()
        if port_kontrol("127.0.0.1", port):
            print(f"Port {port} açık!")
        kuyruk.task_done()

# Kuyruğu doldur
for i in range(1, 1025):
    kuyruk.put(i)

# İş parçacıklarını başlat
for _ in range(100):
    thread = threading.Thread(target=tarayici)
    thread.start()

Bu kod bloğunda 100 farklı iş parçacığı aynı anda 1024 portu tarar. kuyruk.task_done() metodu, iş parçacığının görevi bitirdiğini sisteme bildirir.

Performans ve Yöntem Karşılaştırması

Ağ tarama işlemlerinde farklı yöntemler farklı ihtiyaçlara hitap eder. Aşağıdaki tablo, Python ile geliştirilen tarama yaklaşımlarını karşılaştırmaktadır.

Yöntem Hız Karmaşıklık Kullanım Alanı
Sıralı (Single-thread) Çok Düşük Düşük Hata ayıklama
Çok İş Parçacıklı (Threading) Yüksek Orta Yerel ağ/Sunucu tarama
Asenkron (Asyncio) Çok Yüksek Yüksek Geniş ölçekli ağlar

Güvenlik ve Etik Kullanım

Kritik Uyarı: Ağ tarama araçları, izinsiz kullanıldığında saldırı girişimi olarak algılanabilir. Yalnızca sahibi olduğunuz veya üzerinde yazılı izninizin bulunduğu ağlarda test yapın. Yasal sorumluluk tamamen kullanıcıya aittir.

Tarama yaparken ağ trafiğini aşırı yüklememek için "sleep" (bekleme) süreleri eklemek veya iş parçacığı sayısını ağın kapasitesine göre sınırlamak iyi bir pratiktir. Çok yüksek iş parçacığı sayısı, hedef cihazın servis dışı kalmasına (DoS) neden olabilir.

Gelişmiş Tarama: IP Aralığı ve Port Listesi

Şimdi kodumuzu daha modüler hale getirelim. Kullanıcıdan IP aralığı alan ve bu aralıktaki tüm cihazları tarayan bir yapı kuralım.

def ip_tarama(ip_listesi, portlar):
    for ip in ip_listesi:
        print(f"Hedef taranıyor: {ip}")
        for port in portlar:
            kuyruk.put((ip, port))
    
    # İş parçacıklarını başlatma mantığı buraya gelecek

Bu yapıda, kuyruk içerisinde artık sadece port değil, (ip, port) demeti (tuple) tutulmaktadır. Bu yöntem, geniş ağ yapılarında cihaz envanteri çıkarmak için oldukça etkilidir.

Sıkça Sorulan Sorular

Neden threading yerine multiprocessing kullanmıyoruz?

threading, I/O (Giriş/Çıkış) ağırlıklı işlemler için idealdir. Ağ tarama işlemi ağ soketlerine dayalı bir I/O işlemi olduğu için threading yeterlidir ve daha az bellek tüketir.

Programım neden bazı portları kaçırıyor?

Bunun nedeni genellikle ağ tıkanıklığıdır. Çok fazla iş parçacığı aynı anda ağa yüklendiğinde paket kayıpları oluşabilir. İş parçacığı sayısını azaltmayı deneyin.

Tarama hızını nasıl artırabilirim?

İş parçacığı sayısını artırabilirsiniz ancak bu, ağ cihazınızın (router/switch) limitlerine takılabilir. Daha hızlı bir tarama için asyncio kütüphanesini araştırmanızı öneririm.

Bu araçla hangi protokolleri tarayabilirim?

Bu temel kod TCP protokolünü tarar. UDP taraması yapmak isterseniz socket.SOCK_DGRAM kullanmanız gerekir, ancak UDP'nin doğası gereği yanıt almak daha zordur.

Sistem kaynaklarını nasıl korurum?

Tarama sırasında time.sleep(0.01) gibi kısa beklemeler ekleyerek işlemci üzerindeki yükü dengeleyebilirsiniz.

Tarama Sonuçlarını SQLite Veritabanında Saklama

Ağ tarayıcınızdan gelen verileri anlık olarak ekrana yazdırmak yerine, kalıcı bir veritabanında saklamak, ağınızdaki değişimleri zaman içinde izlemenize olanak tanır. Python'un yerleşik sqlite3 kütüphanesi, bu tür hafif ölçekli verileri yönetmek için idealdir. Aşağıdaki örnek, tarama sonuçlarını bir tabloya nasıl kaydedeceğinizi göstermektedir.

import sqlite3

def veritabani_kaydet(ip, port, durum):
    conn = sqlite3.connect('ag_tarama_sonuclari.db')
    cursor = conn.cursor()
    cursor.execute('''CREATE TABLE IF NOT EXISTS sonuclar 
                      (ip TEXT, port INTEGER, durum TEXT, zaman TIMESTAMP)''')
    cursor.execute("INSERT INTO sonuclar VALUES (?, ?, ?, CURRENT_TIMESTAMP)", (ip, port, durum))
    conn.commit()
    conn.close()

# Tarama fonksiyonunuz içinde kullanımı:
# if port_acik:
#     veritabani_kaydet(hedef_ip, port, "AÇIK")

Scapy ile Paket Analizi ve İleri Seviye Tarama

Standart socket kütüphanesi TCP bağlantısı kurarak "Connect Scan" yapar. Ancak, daha gizli ve hızlı bir tarama yöntemi olan "SYN Scan" (yarı açık tarama) gerçekleştirmek isterseniz, scapy kütüphanesini kullanmanız gerekir. scapy, ağ paketlerini düşük seviyede oluşturmanıza ve manipüle etmenize olanak tanır.

Dikkat: Scapy kullanımı için işletim sistemi düzeyinde yönetici (root/administrator) yetkilerine sahip olmanız gerekir.

from scapy.all import sr1, IP, TCP

def syn_tarama(hedef_ip, port):
    # SYN paketi oluştur
    paket = IP(dst=hedef_ip)/TCP(dport=port, flags="S")
    # Paketi gönder ve yanıtı bekle
    yanit = sr1(paket, timeout=1, verbose=0)
    
    if yanit is None:
        return "Filtrelenmiş veya Kapalı"
    elif yanit.haslayer(TCP):
        if yanit.getlayer(TCP).flags == 0x12: # SYN-ACK
            return "Açık"
        elif yanit.getlayer(TCP).flags == 0x14: # RST-ACK
            return "Kapalı"
    return "Bilinmiyor"

Performans Analizi ve İyileştirme Tablosu

Farklı tarama yöntemlerinin sistem üzerindeki etkilerini ve hızlarını aşağıdaki tabloda inceleyebilirsiniz:

Yöntem Hız Gizlilik Gereksinim
Socket (TCP Connect) Orta Düşük Standart Kullanıcı
Scapy (SYN Scan) Yüksek Yüksek Root/Admin
Scapy (UDP Scan) Düşük Orta Root/Admin

Dağıtık Tarama İçin İleri İpuçları

Büyük bir ağ altyapısını tararken, tek bir makine üzerindeki threading yapısı bir noktadan sonra darboğaz oluşturabilir. Bu durumda şu stratejileri izleyebilirsiniz:

  • İşlemci Bağlılığı (CPU Affinity): Çok çekirdekli sistemlerde iş parçacıklarını belirli çekirdeklere atayarak bağlam değiştirme (context switching) maliyetini azaltın.
  • Ağ Arayüzü Yönetimi: Eğer sisteminizde birden fazla ağ kartı varsa, tarama trafiğini bu kartlar arasında bölüştürerek bant genişliği limitlerini aşın.
  • Hata Yönetimi: socket.error istisnalarını yakalarken, "Too many open files" hatasına karşı ulimit değerlerinizi kontrol edin ve her tarama sonrası soketleri s.close() ile mutlaka kapatın.

Bu ileri seviye yaklaşımlar, basit bir port tarayıcısını kurumsal düzeyde bir ağ keşif aracına dönüştürmenize yardımcı olacaktır. Kodunuzu yazarken her zaman modüler bir yapı kurmaya ve fonksiyonlarınızı test edilebilir parçalara bölmeye özen gösterin.

Sonuç

Python ile çok iş parçacıklı bir ağ tarayıcısı geliştirmek, ağ programlama dünyasına giriş yapmak için mükemmel bir projedir. Bu makalede soketlerin nasıl çalıştığını, iş parçacıklarıyla performansı nasıl artıracağınızı ve kuyruk yapısını nasıl yöneteceğinizi öğrendiniz. Bir sonraki adım olarak, tarama sonuçlarını bir veritabanına (örneğin SQLite) kaydeden veya sonuçları görselleştiren bir arayüz ekleyerek projenizi daha profesyonel hale getirebilirsiniz.

Kod güvenliği sorumluluk reddi: Bu rehberdeki kodlar eğitim amaçlıdır. Üretim ortamlarında kullanmadan önce girdi doğrulama, hata yönetimi (try-except blokları) ve ağ trafiği limitlerini içeren profesyonel güvenlik katmanlarını eklediğinizden emin olun.

Bu yazıya tepkinizi paylaşın:
Selin Yılmaz

Zaman yönetimi ve üretkenlik ipuçları üzerine uzmanlaşmış bir içerik yazarıyım. Günlük yaşamı kolaylaştıran etkili yöntemleri okuyucularla paylaşarak hayat kalitesini artırmayı hedefliyorum.

Yorumlar (0)

Yorum Yaz