Port Exhaustion problemi nasıl oluşur ve nasıl önlenir?

Bu flood’da Port Exhaustion olarak bilinen ve istemci üzerinde soket açacak uygun port kalmaması probleminin nasıl oluştuğunu ve önlenebileceğini anlatacağım.

TCP ve UDP header’larında kaynak ve hedef port numaraları için 16 bit ayrılmıştır. Bu 16 bit ile 2 ^ 16 = 65536 farklı port numarası ifade edilebilir. Dolayısıyla bir bilgisayardan yapılabilecek toplam TCP veya UDP bağlantı sayısı teorik olarak 65536 sayısı ile sınırlıdır.

Pratik durumda ise bir istemciden bir sunucuya yapılabilecek bağlantı sayısı daha düşüktür. Bilgisayarda bulunan portlardan bir kısmı Internet Corporation for Assigned Names and Numbers - ICANN (önceki adıyla IANA) kurumu tarafından bazı uygulamalara tahsis edilmiştir.

0 ile 1023 arasındaki portlar Well-known ports olarak adlandılır. İşletim sistemleri genel olarak uygulamaların bu portları kullanabilmesi için yönetici hesabı ile çalıştırılmalarını şart koşar. Bu sayede kullanıcı seviyesi proseslerin bu portları kullanması engellenir.

HTTP/S - 80, 443, SSH - 22, FTP - 20, 21 iyi bilinen port örnekleridir. İyi bilinen portları, 1024 ile 49151 arasındaki portlar ile Registered ports takip eder. Kayıtlı portlar ICANN tarafından kontrol edilmese de topluluk faydası için kayıt edilip yayınlanır.

Redis - 6379, MongoDB - 27017, Skype - 23399 kayıtlı port örnekleridir. 49152 ile 65535 arasındaki portlar Dynamic, Private veya en çok kullanıldığı şekli ile Ephemeral (kısa ömürlü, geçici) port olarak adlandırılırlar.

Anlaşılacağı üzere 0'dan başlayarak 49152'ye kadar portlar bilgisayarın ağ iletişiminin hedef yani sunucu rolünde yer aldığı bağlantı tiplerinde kullanılır. Ephemeral portlar ise bilgisayarın istemci rolü ile yer aldığı durumlarda kullanılmaktadır.

Daha önce de üzerinden geçtiğimiz üzere bilgisayarımız istemci olarak bir web sunucusunun 443 numaralı portu ile iletişim kuracağı zaman işletim sistemi tarafından ilgili uygulamaya (curl, tarayıcı, vb) Ephemeral port aralığından bir port tahsis edilir.

Bir ağ iletişimini kaynak ip/port ve hedef ip/port olmak üzere 4 değer tanımlar. Dolayısıyla yukarıda 65536 olarak verilen teorik sınır aslında istemcideki Ephemeral port sayısı kadardır. Ephemeral port aralığının 49152 - 65535 olduğu durumda limit 16384 olacaktır.

Linux işletim sisteminde Ephemeral port aralığı cat /proc/sys/net/ipv4/ip_local_port_range komutu ile görülebilir. Ubuntu dağıtımının sunucularında bu aralık 32768 - 60999 olarak belirlenerek tavsiye edilenden daha fazla Ephemeral port (28231) kullanıma sunulmuştur.

Şimdi gelelim Port Exhaustion problemine. Port Exhaustion bir cihazda başka bir cihaz ile iletişim kurmak üzere uygun durumda port bulunmadığı için soket oluşturulamaması problemine verilen isimdir. Anlaşılacağı üzere istemci ya da proxy'lerde görülen bir problemdir.

Port Exhaustion'ın sık görülmesinin sebebi TCP soketlerin kapatıldıktan sonra paket kaybı ve tekrar iletimi ihtimaline karşılık TIME_WAIT state'ine alınması, belirli süre (1-2 dakika) bu state'te tutulması ve bu state'te olduğu süre boyunca yeni bağlantıda kullanılamamasıdır.

Anlaşılacağı üzere kısa süreli çok fazla sayıda bağlantı açıp kapatan istemci, proxy (vekil) sunucular ve yük dağıtıcılarda fazla sayıda port TIME_WAIT state'inde kalabilir ve sistem Port Exhaustion durumuna gelebilir. Farklı bir şekilde istemci ve sunucu arasındaki TCP bağlantısının sürekli açık tutulması gereken websocket kullanımı gibi durumlarda portlar halihazırda kullanıldığı için soketler TIME_WAIT durumunda olmasa da kullanılabilir boş port eksikliğinden Port Exhaustion oluşabilir.

Linux’ta istemcideki bir ephemeral port aynı hedef sunucudaki farklı bir porta veya farklı hedef sunucudaki aynı porta erişmek için kullanılabilir. Örneğin, Linux istemci üzerindeki 52301 numaralı port, üç farklı hedef IP'deki 443 portuna erişmek için kullanılabilir.

Yukarıdaki bilgi ışığında bir istemciden sunucu sayısı sınırsız olmak üzere yapılabilecek bağlantı sayısı teorik olarak sınırsızdır (aslında istemcinin işlemci ve memory’si ile sınırlıdır). Linux çekirdeği bütün Ephemeral portlar tükenmeden bir portu tekrar kullanmayacaktır.

Özetle Port Exhaustion'ın oluşması için bir istemci ve az sayıda sunucu gerekir dolayısıyla bu problem ağırlıklı olarak Proxy ve yük dağıtıcılarda karşımıza çıkar. Problemi hafifletmek için dağıtım yapılan sunucu sayısı artırılabilir. Alternatif olarak aynı sunucu üzerinde aynı network interface üzerinde farklı sanal IP'ler oluşturulabilir ya da daha modern ve yönetilebilir şekilde yine aynı sunucu üzerinde birden fazla konteyner çalıştırılarak istemcinin fazla sayıda IP adresi ile iletişim kurması ve Port Exhaustion'dan kaçınması sağlanabilir.

Ek olarak istemci tarafındaki TIME_WAIT state'indeki bağlantıları azaltmak için HTTP protokolünde Keep-Alive'da olduğu gibi mevcut TCP bağlantısı kapatılmadan tekrar kullanılabilir.

Son olarak sonraki flood’larda Port Exhaustion problemini oluşturup semptomları gözlemleyip soket debug etme ile ilgili araçları tanıyacağız. Ek olarak yazıda geçen aynı network interface üzerinde farklı sanal IP'ler oluşturmayı ve kullanım alanlarını inceleyeceğiz.