Ana içeriğe geç

Bölüm 6: Port Numarası ve Soket

12 dakikalık okumaGüncelleme:

Ağlar'a “Sen”i Katmak kitabının bir bölümü: adres çubuğuna yazdığın tek bir isteğin peşinden bakırla fiberin fiziğine inip karşı taraftan geri dönen uzun bir teknik yolculuk.

Kısım 2: Bağlantı Kuruluyor (Bölüm 6-12)

Tüm bölümler
  1. Giriş
  2. Adres Çubuğundan İsteğe
  3. Paket Anahtarlamalı Yol
  4. İsimden Adrese
  5. DNS Kayıtları
  6. Önbellek, Tazelik ve Güven
  7. Port Numarası ve Soket
  8. Bağlantısız Taşıma: UDP
  9. Üç Adımlı El Sıkışma
  10. Simetrik Şifreleme
  11. Açık Anahtarlı Kriptografi
  12. TLS El Sıkışması
  13. Sertifika Zinciri
  14. HTTP Mesajının Anatomisi
  15. Durum, Çerez ve Oturum
  16. HTTP/2'den HTTP/3'e
  17. İçerik Dağıtım Ağları
  18. Diğer Uygulama Protokolleri
  19. Katmanlı Mimari
  20. Hizmet ve Protokol
  21. Encapsulation ve Başlıklar
  22. Paket Yakalama ve Çözümleme
  23. Ağ Interface Kartı
  24. Fiziksel Adresleme
  25. Hata Sezme ve CRC
  26. Adres Çözümleme: ARP
  27. Ortam Erişimi: CSMA/CD
  28. Switch'ler
  29. Ağ Topolojileri
  30. Sanal Yerel Ağlar
  31. Kablosuz Erişim: 802.11
  32. Radyo Kanalı ve Kapasite
  33. Kablosuz Ağ Güvenliği
  34. Hücresel Ağlar
  35. Spektrum ve Kuşaklar
  36. Hareketlilik ve Aktarma
  37. Adres Kiralama: DHCP
  38. Adresin Anatomisi
  39. Adres Tükenmesi ve IPv6
  40. Router Mimarisi
  41. Kuyruk Yönetimi
  42. Cihaz Yapılandırma
  43. Routing Protokolleri
  44. Kontrol Düzlemi ve SDN
  45. Ağ İzleme ve Yönetimi
  46. Alanlar Arası Routing
  47. Adres Çevirisi
  48. Ara Kutular
  49. Tünelleme ve IPsec
  50. Firewall'lar
  51. Ağ Saldırıları
  52. Operatör ve Metro Ağları
  53. Bitten Sinyale
  54. Sembol Hızı ve Kanal Kapasitesi
  55. Multiplexing Teknikleri
  56. İletim Ortamları
  57. Bakır Kablo Sonlandırma
  58. Fiber Sonlandırma
  59. Fiber Optik İletim
  60. Bakır Erişim Ağı: DSL
  61. DSL'de Hız ve Mesafe
  62. Pasif Optik Ağlar
  63. Kablo Erişim Ağları
  64. Kablo Modem ve CMTS
  65. Denizaltı Kabloları
  66. Veri Merkezi Ağları
  67. Encapsulation Çözme
  68. Güvenilir Aktarım
  69. Tıkanıklık Denetimi
  70. Trafik Çözümleme
  71. Gecikme Bütçesi
  72. Soket Programlama
  73. Eşten Eşe ve Protokol Tasarımı
  74. Uyarlanır Video Akışı
  75. Gerçek Zamanlı Ses ve Görüntü
  76. Kablosuz Sensör Ağlarının Mimarisi
  77. Sensör Ağlarında Ortam Erişimi
  78. Sensör Ağlarında Yönlendirme ve IP
  79. Zaman Eşitleme ve Konum Bulma
  80. Sensör Ağı Uygulamaları
  81. Mobil Kablosuz Sensör Ağları
  82. Son Söz

Adres elinde. Ama tek başına adres, karşındaki makinede kiminle konuşacağını söylemiyor.

Bir konuşmanın hangi programa ait olduğuna ne karar veriyor?

Adres binayı gösteriyor, daireyi değil

Zincirin sonunda aldığın şey bir makinenin adresiydi. O adres posta kutusuna değil, binaya kadar götürüyor.

Bir sunucu makinesinde aynı anda web sunucusu, posta sunucusu, veritabanı ve yönetim arayüzü çalışıyor olabilir. Dördü de aynı adresin arkasında. Gelen bir parçanın hangisine ait olduğunu adres söylemiyor.

Bu yüzden kimliğe ikinci bir parça eklendi: port numarası. Süreci belirleyen şey adres ile port numarasının ikisi birden.

Sokak adresi binayı buluyor, daire numarası ise binanın içinde kimi arayacağını söylüyor. Postacı binaya kadar geliyor, sonrasını numara belirliyor. Bina makinenin adresine, daire numarası porta, dairede oturan kişi ise o portu dinleyen sürece karşılık geliyor.

1919’da yapılmış bir New Orleans apartmanının girişinde sıra sıra posta kutuları; her kutunun yanında o daireye çıkan mekanik konuşma borusu var. Adres binaya kadar getiriyor, sonrasını numara belirliyor.

Benzetmenin nerede bittiğini söylemek gerekiyor. Apartmanda daireler sabittir ve boş daire de bir dairedir. Ağda ise dinleyen bir süreç yoksa o numara hiç yoktur; oraya gelen bir parça beklemeye alınmaz, geri çevrilir.

Port numarasını taşıyan katmanın adı transport layer (taşıma katmanı): veriyi bir makineden ötekine değil, bir programdan ötekine ulaştıran katman. Ağın bütün katmanlarını 18. bölümde sırayla göreceğiz; şimdilik adını bilmek yetiyor.

Programın bu katmana açılan ucuna soket deniyor: işletim sisteminin bir program için açtığı, adresi ve portu olan bir uç. Bir konuşmanın iki ucunda iki soket durur. Soket iki cihazı değil iki programı birbirine bağlar; uçlar çoğu zaman iki ayrı makinede olur, ama aynı makinedeki iki program da birbirine soketle bağlanabilir. 71. bölümde yazacağın örneklerin çoğu tam da böyle, tek bir makinenin içinde konuşuyor.

Numaranın kaç basamak olabileceği de bu katmanın başlığındaki alanın genişliğine bağlı. Her parçanın başında kaynak ve hedef için birer alan var ve her biri 16 bit. Yani numara sıfırdan başlıyor ve 65.535’te bitiyor: toplam 65.536 ayrı port.

Numaralar rastgele değil

Bir sunucuya bağlanırken numarayı sen uydurmuyorsun. Tarayıcı https gördüğünde 443’e, http gördüğünde 80’e bağlanıyor. Posta sunucuları 25’i, isim sunucuları 53’ü dinliyor.

Bu numaralar üç aralığa bölünmüş durumda ve ayrım standartla tanımlı:

AralıkAdıKim kullanıyor
0-1.023iyi bilinenyaygın hizmetler; çoğu sistemde yönetici yetkisi ister
1.024-49.151kayıtlıbelirli bir uygulama için kayıt ettirilmiş numaralar
49.152-65.535dinamikkimseye ait değil; kaynak portlar buradan seçilir

Birinci aralıktaki numaraların çoğunu tanımasan da işin bir yerinde karşına çıkıyorlar. Ezberlenecek liste değil ama okunacak listedir; hangi hizmetin hangi portta oturduğunu bilmek, bir firewall (güvenlik duvarı, 49. bölüm) kuralına ya da bir bağlantı hatasına bakarken tek başına yön verir.

numarahizmetne yapar
20 / 21FTPeski dosya aktarımı; veri ile denetim ayrı portlarda
22SSHşifreli uzak kabuk, dosya kopyalama ve tünel
23Telnetşifresiz uzak kabuk; bugün yalnızca eski cihazlarda
25SMTPposta sunucuları arası teslim
53DNSad çözme; hem UDP hem TCP
67 / 68DHCPadres kiralama; sunucu 67, istemci 68
80HTTPşifresiz web
110 / 143POP3 / IMAPposta kutusunu okuma
123NTPsaat eşitleme
161 / 162SNMPcihaz izleme ve tuzak bildirimi
389 / 636LDAP / LDAPSdizin sorgulama
443HTTPSşifreli web; QUIC de aynı numarayı UDP’de kullanır
445SMBWindows dosya paylaşımı
465 / 587SMTPS / gönderimistemcinin postayı sunucuya bırakması
3306MySQLveritabanı
3389RDPWindows uzak masaüstü
5432PostgreSQLveritabanı
6379Redisbellek içi veri deposu
8080HTTP (alternatif)yönetici yetkisi olmadan açılan web sunucuları

Son satır bir kuralı ele veriyor. 1.024’ün altındaki numaraları açmak çoğu sistemde yönetici yetkisi ister. Kural, ağın kendisinden değil işletim sisteminden gelir ve amacı basittir: sıradan bir kullanıcı 443’ü kapıp kendi sahte sunucusunu oraya oturtamasın. Yetkisi olmayan geliştiricinin 8080’e ya da 3000’e düşmesinin sebebi bu tek kısıttır.

Kural, çok kullanıcılı eski Unix makinelerinden kalma. O dönemde bazı hizmetler, düşük numaralı bir porttan gelen bağlantının karşı makinenin yöneticisi tarafından açıldığını varsayıp ona parola sormadan güveniyordu. O güven çoktan geçersiz; bugün sınır bir ayar hâline geldi. Linux’ta aşağı çekilebiliyor, macOS ise 2018’den beri çoğu durumda bu kısıtı uygulamıyor.

Ama burada altı çizilmesi gereken bir şey var. Numara ile hizmet arasındaki bağ gelenek, zorunluluk değil. 80’i dinleyen bir program web sunucusu olmak zorunda değil; istersen orada bambaşka bir protokol konuşabilirsin. Aynı şekilde web sunucunu 8080’de de çalıştırabilirsin, yalnızca adres çubuğunda numarayı yazmak zorunda kalırsın.

Bunu bilmek pratikte işe yarıyor. Bir portun açık olması orada beklediğin hizmetin çalıştığını kanıtlamıyor; yalnızca bir şeyin dinlediğini gösteriyor.

Aynı porttan yüz binlerce konuşma

Şimdi ilk bakışta çelişki gibi duran bir şey. Bir web sunucusu tek bir numarayı dinliyor, diyelim 443. Aynı anda yüz binlerce kişi ona bağlanıyor. Numara bir tane olduğuna göre sunucu bunları nasıl ayırıyor?

Önce bir ayrım. Yoldaki kutular paketin üstündeki hedefe bakıyordu; o hedef adres, port değil. Yoldaki hiçbir router port numarasına bakmak zorunda değil. Port, yalnızca iki uçta anlam taşıyor.

Cevap, transport layer’ının soketi tek bir sayıyla değil, dört sayıyla tanımlamasında. Kaynak adres, kaynak port, hedef adres, hedef port. Bu four-tuple’ın (dörtlü) tamamı aynı olan iki konuşma olamaz.

Aynı sunucuya bağlanmış üç istemciyi yan yana koyalım:

Kaynak adresKaynak portHedef adresHedef port
192.0.2.1451322203.0.113.9443
192.0.2.1451323203.0.113.9443
198.51.100.749930203.0.113.9443

Üçünün de hedefi aynı, hatta ilk ikisi aynı makineden geliyor. Ayrım tek bir sütunda: kaynak port. Üçüncüsü ise başka bir makineden, dolayısıyla kaynak portu aynı olsa da karışmazdı.

Gelen her parça için makine bu dört değere bakıyor ve parçayı doğru sokete bırakıyor. Bu ayıklama işine demultiplexing deniyor. Gönderen taraftaki karşılığı, pek çok soketin verisini aynı kablodan çıkarmak, yani multiplexing.

Dörtlü ayrım, bağlantı kuran taşımanın kuralı. Bağlantısız taşımada kernel, parçayı teslim edeceği soketi çoğu zaman yalnızca hedef adres ile hedef porta bakarak seçiyor; farklı istemcilerden gelen parçalar aynı sokete düşüyor ve kimden geldiklerini uygulama kendisi ayıklıyor. İki taşımanın farkını 7. bölümde açacağız.

Four-tuple’da görünmeyen gizli bir beşinci sütun daha var: protokol. Port numarası transport layer’a ait ve her taşıma protokolünün kendi numara uzayı var. Yani TCP’nin 443’ü ile UDP’nin 443’ü aynı port değil, birbirinden tamamen bağımsız iki port. Aynı makinede biri açık öbürü kapalı olabilir; ikisini iki ayrı süreç dinleyebilir. “53 açık” cümlesi bu yüzden eksik: hangi protokolde açık olduğunu söylemeden bir şey ifade etmiyor. HTTPS’in hem TCP hem UDP 443’te yaşayabilmesi de bu sayede mümkün; QUIC aynı numarayı öteki protokolde kullanıyor ve kimsenin ayağına basmıyor.

Bunun doğal sonucu şu: portu olmayan protokoller de var. IP başlığındaki protokol alanı ICMP diyorsa içeride port yoktur, çünkü ICMP bir taşıma protokolü değildir. Ping’in port numarası yoktur ve bir firewall’da ping’i “port kapatarak” engelleyemezsin; onu protokol düzeyinde ele almak zorundasın.

Sunucu tarafında olan biteni çağrı sırasıyla görmek daha da netleştiriyor:

1. tutamağı oluştur                    socket()
2. yerel adres ve porta bağla          bind()     -> 203.0.113.9:443
3. gelen bağlantıları beklemeye başla  listen()
4. bekleyeni kabul et                  accept()   -> YENİ bir soket doğar

Asıl nokta son adımda. Kabul etmek sana dinlediğin soketi vermiyor; o konuşmaya özel yeni bir soket veriyor. Dinleyen soket kapıda beklemeye devam ediyor. Yüz binlerce bağlantı yüz binlerce ayrı soket demek; port numarası ise hâlâ tek. Bu dört çağrıyı 71. bölümde kendi yazdığın bir sunucuda çalıştıracaksın.

Kendi makinende bu tabloyu görebilirsin. Linux’ta ss -tan, Windows’ta netstat -an dinleyen ve kurulu soketleri listeliyor:

Durum        Yerel adres:port        Uzak adres:port
LISTEN       0.0.0.0:443             0.0.0.0:*
ESTAB        203.0.113.9:443         192.0.2.14:51322
ESTAB        203.0.113.9:443         192.0.2.14:51323
ESTAB        203.0.113.9:443         198.51.100.7:49930
TIME-WAIT    203.0.113.9:443         192.0.2.14:51290

İlk satırda uzak uç boş. Dinleyen soketin karşı tarafı yok, çünkü henüz kimseyle konuşmuyor; yalnızca bekliyor. Yerel taraftaki 0.0.0.0 ise bir makineyi göstermiyor; “bu makinedeki bütün interface’ler (ağ arayüzleri)” anlamına geliyor.

Bu ayrıntı pratikte sık karşına çıkıyor. Bir süreç soketi 0.0.0.0 yerine 127.0.0.1 adresine bağlarsa yalnızca aynı makineden erişilebilir hâle geliyor; dışarıdan gelen paketler o sokete hiç düşmüyor. Veritabanları çoğu zaman böyle kurulu geliyor ve “servis çalışıyor ama uzaktan bağlanamıyorum” şikâyetinin en yaygın sebebi bu tek satır. Tersi de doğru: yanlışlıkla bütün interface’lere açılan bir yönetim paneli, olması gerekenden çok daha geniş bir kitleye görünür oluyor.

DerinleşmeAynı porta iki süreç birden nasıl bağlanabiliyor?

Kural olarak bir portu aynı anda tek bir soket dinler. İkinci bir süreç aynı numaraya bağlanmaya kalkarsa hata alır ve çoğu geliştirici bu hatayı tanır: adres zaten kullanımda.

Ama modern sistemlerde bu kuralı gevşeten bir seçenek var. Süreç soketi açarken “bu portu paylaşmaya razıyım” diyebiliyor; aynı şeyi söyleyen başka süreçler de aynı numaraya bağlanabiliyor. Kernel gelen bağlantıları bu süreçler arasında dağıtıyor. Seçeneğin Linux’taki adı SO_REUSEPORT.

Neden istenir? Çünkü tek iş parçacığıyla çalışan bir süreç, makinenin bütün çekirdeklerini kullanamıyor. Aynı portu dinleyen sekiz süreç açarsan, gelen bağlantılar sekize bölünüyor ve her biri ayrı bir çekirdekte çalışıyor. Aradaki dağıtımı uygulama değil kernel yapıyor, üstelik four-tuple’a bakarak: aynı konuşmanın bütün parçaları hep aynı sürece gidiyor.

İkinci faydası kesintisiz güncelleme. Yeni sürümü aynı portu dinleyerek başlatıyorsun, eski sürüm elindeki bağlantıları bitirip kapanıyor. Doğru yapıldığında arada hiçbir bağlantı reddedilmiyor; eski sürümün kabul sırasında bekleyen bağlantıları unutulursa ise onlar kopuyor.

Bedeli de var. Dağıtım bağlantı sayısına göre değil, four-tuple’ın karmasına göre yapılıyor; uzun ömürlü bağlantılarda yük eşit dağılmayabiliyor. Bir süreç yorulurken öteki boş durabiliyor.

Paylaşımı yasaklayan kuralların çoğu, tek çekirdekli bir dünyanın varsayımını taşıyor. Donanım değişince kural da gevşetiliyor ama kaldırılmıyor, çünkü kazayla aynı portu açmak hâlâ bir hata.

Bir port dışarıdan neye benziyor?

Portun ikinci bir yüzü daha var. Dinleyen her port, dışarıdan bakan biri için bir giriş denemesi noktasıdır; bir makinenin saldırı yüzeyi, kabaca açık portlarının toplamıdır.

Dışarıdan bakan biri üç yanıttan birini alır ve üçü üç ayrı şey söyler:

gördüğüne demeknasıl anlaşılıyor
açıkorada dinleyen bir süreç varbağlantı isteği kabul ediliyor
kapalımakine ayakta ama o portu dinleyen yokmakine “burada kimse yok” diye açıkça reddediyor
filtrelenmişarada bir firewall varhiç cevap gelmiyor, istek sessizce yutuluyor

Aradaki fark önemli. Kapalı bir port cevap verdiği için makinenin varlığını ele veriyor; filtrelenmiş bir port ise makinenin orada olup olmadığını bile söylemiyor. Firewall’ların varsayılan davranışının “reddet” değil “sessizce düşür” olmasının sebebi bu.

Buradan iki pratik sonuç çıkıyor. Birincisi, kapatılması gereken şey port değil süreçtir; kimsenin dinlemediği bir numara zaten kapalıdır. İkincisi, bir hizmeti standart dışı bir numaraya taşımak onu gizlemez. Numara değiştirmek yalnızca gelişigüzel taramaların gürültüsünü azaltır, hedefli bir taramayı hiç yavaşlatmaz.

Kendi numaranı sen seçmiyorsun

Four-tuple’ın üç değerini biliyorsun: hedef adres isim çözümlemesinden geldi, hedef port şemadan, kaynak adres de makinenin kendi adresi. Dördüncüsü nereden çıkıyor?

Onu işletim sistemi veriyor. Soket açılırken kaynak portu belirtmezsen kernel dinamik aralıktan boş bir numara seçip sana veriyor. Bu numaraya geçici port deniyor ve konuşma bitince havuza geri dönüyor.

Seçimin rastgele olması da önemli. İsim sorgusuna sahtecilik yapmak, kimlik numarasını ve kaynak portu tahmin etmeye dayanıyordu. Kaynak portu tahmin edilebilir olsaydı, araya girmek isteyen tarafın işi bir kat kolaylaşırdı.

Havuzun sınırları da yazılı. IANA dinamik aralığı 49152-65535 diye tanımlıyor, yani 16.384 numara. İşletim sistemleri bu öneriye tam uymuyor: Linux varsayılan olarak 32768-60999 aralığını kullanıyor ve 28.232 numara veriyor, Windows ise IANA aralığına sadık kalıyor. Kendi makinendeki değeri okuyabilirsin:

$ cat /proc/sys/net/ipv4/ip_local_port_range
32768   60999

Havuzun sonu da var. Aynı hedef adres ve porta doğru açabileceğin bağlantı sayısı, elindeki geçici numara kadar; four-tuple’ın öteki üç değeri sabitken ayrım yalnızca kaynak porttan gelebiliyor. Yani tek bir arka uca, tek bir porta doğru açabileceğin eşzamanlı bağlantı sayısının tavanı Linux’ta 28.232.

Tavan yalnızca açık bağlantıları saymıyor. Yukarıdaki çıktıda görünen TIME-WAIT durumu, kapanan bir bağlantının four-tuple’ının hemen serbest bırakılmadığını, bir süre beklemede tutulduğunu gösteriyor. Sebep şu: yolda gecikmiş eski bir paket, aynı four-tuple’la açılan yeni bir bağlantıya düşerse yeni konuşmanın içine eski veri karışır. Bekleme, o paketlerin ömrünün dolmasını garanti ediyor. Standardın öngördüğü sürenin neden dört dakika olduğunu 8. bölümde el sıkışmayı kurarken hesaplayacağız; Linux bu süreyi 60 saniyede tutuyor.

Sayı bol görünüyor ama tükendiği yerler var ve hep aynı desen: çok sayıda kısa ömürlü bağlantı, tek bir hedefe. Saniyede 500 bağlantı açıp kapatan bir proxy düşün. Linux’taki 60 saniyelik beklemeyle aynı anda beklemede duran four-tuple sayısı 500 × 60 = 30.000 eder; havuzda ise 28.232 numara var. Havuz bir dakika dolmadan tükenir ve yeni bağlantı açılamaz. Hata iletisi “Cannot assign requested address” olur, oysa hedef sunucu turp gibi ayaktadır. Sıradan bir kullanıcı bunu hiç görmez; tek bir arka uca saniyede yüzlerce bağlantı açan bir proxy görür.

Soketin kernel tarafını burada kapalı kutu bırakıyorum: tamponların nerede durduğunu ve kopyalamanın maliyetini 22. bölümde ağ kartına indiğimizde, gelen verinin hangi kuyruklardan geçip uygulamaya vardığını da 66. bölümde açacağız.

Özet

  • Adres binayı gösteriyor, süreci değil. Kimlik adres ile port numarasının ikisi birden; port alanı 16 bit olduğu için toplam 65.536 port var.
  • Numara ile hizmet arasındaki bağ gelenek. Standart üç aralık tanımlıyor ama açık bir port, orada beklediğin hizmetin çalıştığını kanıtlamıyor.
  • Soketi dört değer tanımlıyor: kaynak adres, kaynak port, hedef adres, hedef port. Tek bir dinleme portu bu sayede yüz binlerce ayrı konuşmayı taşıyabiliyor.
  • Kabul işlemi yeni bir soket doğuruyor; dinleyen soket kapıda kalıyor ve her konuşma kendi soketine düşüyor.
  • Kaynak portu sen değil kernel seçiyor, dinamik aralıktan ve tahmin edilemez biçimde; havuzun sonu, beklemedeki bağlantılar da sayıldığı için, tek bir hedefe açılan bağlantı sayısına sınır koyuyor.

Four-tuple tamam, port belli, soket açılmaya hazır. Ama şu ana kadar hep “transport layer” deyip geçtim; adını andım, ne vaat ettiğini hiç açmadım. Portu buldun; peki oradan geçen her şey aynı sözü mü veriyor?

7. bölüme devam et: Bağlantısız Taşıma: UDP