Tek Port Üzerinden HTTPS, SSH, OpenVPN Servislerinin Hizmet Vermesi

Elinizde kullanılabilir tek bir ip adresi var ve bu ip adresi üzerinde aynı portu kullanan birden fazla uygulama kullanmak istiyorsanız tek portta protokol başlık bilgisine göre paketleri ayırtedebilen bir yazılım kullanmak sorunu çözecektir. SSHL bu amaçla geliştirilmiş bir yazılımdır.  SSHL belittiğiniz bir portu dinler  ve bu porta gelen bağlantı isteklerini inceleyerek isteğin hangi protokole ait olduğunu tespit ettikten sonra bağlantıyı ilgili servise yönlendirme işlemini gerçekleştirir.
Bu şekilde örneğin tcp 443 üzerinden HTTPS, OpenVPN ve SSH himetlerini aynı anda sunabilirsiniz. Bu yazı özellikle bazı durumlar için gayet kullanışlı bir araç olan sslh ile ilgili kurulum, yapılandırma ve testleri içerecek şekilde detaylı bilgi içermektedir.

SSHL Nedir ?

Default olarak HTTP, SSL, SSH, OpenVPN, tinc, XMP protokollerini tespit edebilen ve farklı protokoller için de kendi regex pattern’lerinizi yazmanıza da izin veren sslh’ın yukarıda belirtildiği  gibi tcp 443 üzerinde hem HTTPS hem de SSH servisi vermek gibi yaygın bir kullanım şekli var. Bu şekilde örneğin firewall üzerinden sadece tcp 80 ve 443 geçişi olan bir sunucuya SSH üzerinden erişmek üzere sslh kullanılabilir. Bir başka deyişle firewall arkasında bulunan ve SSH portuna erişim olmayan bir sisteme, 443 gibi (muhtemelen) firewall tarafından engelli olmayan bir port üzerinden erişmek için sslh kullanabilirsiniz.

Çalışma Prensibi

Verdiğimiz örneğe bağlı kalarak sslh’ı 443 üzerinden çalıştıracağımızı ve HTTPS ile SSH hizmeti vereceğimizi düşünelim. Bu senaryoda, -detaylarını yapılandırma kısmında anlatacağım üzere – sslh’ı kullanmak istediğimiz ağ arayüzününün  443. portunu dinleyecek şekilde yapılandırıyoruz. Sonrasında HTTPS servisini localhost:443 ve SSH servisini localhost:22′yi dinlemeleri üzere ayarlayıp, sslh’a HTTPS’in 127.0.0.1 443′de, SSH’ın da 127.0.0.1 22′de olduğunu söyleyerek uygulamayı çalıştırıyoruz.

Bu şekilde ilgili hosta gelen SSH bağlantıları 22. porta yönlendirilirken HTTPS bağlantıları localhost 443. porta yönlendiriliyor. Yani sslh proxy görevi görevi görüyor. Uygulamanın servisleri nasıl ayırt ettiği konusu ise şu şekilde cereyan ediyor:
Protokol Tespiti
sslh temel olarak gelen bağlantı isteklerinin ilk bir kaç byte’ını okuyarak bağlantı protokolünü tespit etmeye çalışıyor. Örnek olarak SSH bağlantılarında sunucu ile client arasında gerçekleşen ilk iş iki ucun birbirine ssh versiyonlarını plain-text olarak ‘SSH-x.0′ şeklinde bildirmelerinden ibarettir. İşte sslh da bağlantının SSH olup olmadığını anlamak için ilk paketlerin içerisinde “SSH-” stringini arıyor ve bulması durumunda bağlantıyı ilgili servisin portuna yönlendiriyor. HTTPS trafiği için ise benzer bir şeklilde trafik başlangıcında ClientHello (0×16) ve TLS versiyon bilgisinin (0×0301) olup olmadığına bakıyor.
Diğer protokoller için örneğin XMPP testinde “jabber” ibaresi, HTTP trafiği için “HTTP” ibaresi ya da versiyon belirtilmemişse OPTIONS, GET vs. gibi methodların olup olmadığına bakarak yönlendirmeyi yapıyor.
sslh trafik tespiti için öntanımlı 2 saniye timeout süresi kullanır bu süre zarfında protokol tespit edilemezse trafik, yapılandırma dosyasında belirlenen ilk protokole (default kurulumda SSH’a ) yönlendirilir. Örnek olarak  versiyon bilgisini sunucuya bildirmeyen bir client üzerinden gelen SSH bağlantısı sslh tarafından tespit edilemeyeceği için bu timeout mekanizması önemlidir.
Kurulum ve Yapılandırma
sslh’ın RHEL, Debian ve FreeBSD tabanlı sistemler için önceden derlenmiş paketleri bulunuyor ve ilgili sistemlerin paket yöneticileri üzerinden kurulabiliyor. Ancak kaynak koddan derleyerek kurmak da çok kolay olduğu için burada bu şekilde kurulumun nasıl yapılabileceğinden bahsedeceğim.

Gereksinimler

sslh, libconfig ve libwrap paketlerine ihtiyaç duyuyor; bu nedenle öncesinde bu paketleri sisteminize kurmanız gerekiyor. Bu işlem için aşağıdaki adımları izleyin:
Debian/Ubuntu tabanlı sistemler:
# apt-get install libwrap0-dev libconfig8-dev
RHEL/CentOS tabanlı sistemler:
# yum install libconfig libconfig-devel
Böylece sistem sslh kurulumu için hazır hale geliyor.

Kaynak Kod’dan Kurulum

Şimdi, http://www.rutschle.net/tech/sslh.shtml adresinden sslh’ı indireceğiz. Şu anki son sürüm 1.16:
# wget http://www.rutschle.net/tech/sslh-v1.16.tar.gz
Sonrasında da paketi açarak kurulumu gerçekleştiriyoruz:
# tar xvfz sslh-v1.16.tar.gz
# cd sslh-v1.16
# make install
Make install dediğiniz zaman ilgili dizinde sslh-fork ve sslh-select isimli iki farklı sslh versiyonu oluşturulur.
İlk versiyon olan sslh-fork her yeni bir bağlantı isteği yeni bir sslh süreci oluşturur. Bu versiyon iyi test edildiğinden ve stabil olduğundan dolayı kurulum sırasında /usr/local/sbin/sslh ismi ile sisteme kopyalanır ve default olarak kullanılır. Ancak bu sürüm, çok fazla istek alan sunucular için çok sayıda süreç oluşmasına ve sistem kaynaklarının bu oranda kullanılmasına yol açmaktadır. Çok çok fazla sayıda bağlantı karşılamak için bu anlamda ideal olmayabilir.
İkinci versiyon olan sslh-select ise daha az test edilmiş ve yeni bir sslh versiyonudur ancak  tüm bağlantları tek bir süreç üzerinden handle eder ve her bir bağlantının sadece 16byte’lık bir sistem kaynağı maliyeti vardır. Fakat, sslh bir şekilde kapanırsa ve ssh için kullanıyorsanuz sunucuya uzaktan erişiminiz kesilebilir. Yine de bu sürümü kullanmak isterseniz kendisini /usr/local/sbin/ dizinine sslh ismi ile kopyalayabilirsiniz.

Yapılandırma

Şimdi ilk olarak scripts dizinindeki init scriptini sslh ismi ile init.d’nin altına kopyalayıp, sslh servisini startup’a ekleyeceğiz:
Debian/Ubuntu Sistemler:
# cp scripts/etc.init.d.sslh /etc/init.d/sslh
# update-rc.d sslh defaults
RHEL/CentOS Sistemler:
# cp scripts/etc.init.d.sslh /etc/init.d/sslh
# chkconfig sslh on
RHEL sistemlerde ayrıca, /etc/init.d/sslh dosyası içerisindeki “PREFIX=” satırını aşağıdaki şekilde güncelliyoruz:
PREFIX=/usr/local

Ana Yapılandırma

Şimdi ana yapılandırma ayarlarına geçeceğiz. Sslh’ın ana yapılandırma dosyası /etc/default/sslh’dır. Bu dosya Debian ve RHEL sistemlerde mantık aynı olsa da farklılık göstermektedir. Bu yüzden ikisinden ayrı ayrı bahsedeceğim.
Debian/Ubuntu Sistemler:
İlgili dosyanın içeriği aşağıdaki gibibir ve düzenlenmesi gereken alanlar bold ve kırmızı renk ile işaretlenmiştir:
# Default options for sslh initscript
# sourced by /etc/init.d/sslh

# Disabled by default, to force yourself
# to read the configuration:
# - /usr/share/doc/sslh/README.Debian (quick start)
# - /usr/share/doc/sslh/README, at "Configuration" section
# - sslh(8) via "man sslh" for more configuration details.
# Once configuration ready, you *must* set RUN to yes here
# and try to start sslh (standalone mode only)

RUN=no

# binary to use: forked (sslh) or single-thread (sslh-select) version
DAEMON=/usr/sbin/sslh

DAEMON_OPTS="--user sslh --listen 0.0.0.0:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:443 --pidfile /var/run/sslh/sslh.pid"
ilk olarak RUN bölümünü “yes” olarak düzenliyoruz.
RUN=yes
–listen 0.0.0.0:443 bölümü SSLH’ın hangi portu hangi ip üzerinden dinleyeceğinin belirleneceği yerdir. Biz burada sslh’i sistemimizin gerçek ipsine bind edeceğiz, örnek olarak ip adresiniz 1.1.1.1 ise bu alanı 1.1.1.1:443 olarak set ediyoruz:
Not: Bu noktada web sunucunuzu 443. port için sadece 127.0.0.1 üzerinden hizmet vermesi için yapılandırmayı unutmamanız gerekiyor. Aksi halde 443. port sslh tarafından kullanımda olduğu için web sunucunuz hata verecekir.
–ssh 127.0.0.1:22 ise 443 üzerinden gelen ssh isteklerinin 127.0.0.1:22′ye yönlendirilmesini söylüyor.
–ssl 127.0.0.1:443 ise aynı mantıkla SSL/TLS bağlantılarının 127.0.0.1:443′e atılmasını ifade ediyor.
Değişiklikleri tamamladıktan sonra, sslh’ı start ediyoruz:
# /etc/init.d/sslh start
RHEL/CentOS Sistemler
RHEL tabanlı sistemlerde ise mantık aynı olmakla birlikte yapılandırma dosyası aşağıdaki gibidir:
LISTEN=ifname:443
SSH=localhost:22
SSL=localhost:443
USER=nobody
PID=/var/run/sslh.pid
Bu dosya içerisinde en üstte, SSLH’ın hangi ip ve port üzerinden hizmet vereceğini belirtiyoruz ki yukarıda da bahsettiğim gibi bu alanı sistemimizin external ip’si olarak set ediyoruz. Örnek olarak ip adresiniz 1.1.1.1 ise bu alanı 1.1.1.1:443 olarak set ediyoruz:
LISTEN=1.1.1.1:443
Not: Bu noktada web sunucunuzu 443. port için sadece 127.0.0.1 üzerinden hizmet vermesi için yapılandırmayı unutmamanız gerekiyor. Aksi halde 443. port sslh tarafından kullanımda olduğu için web sunucunuz hata verecekir.
Sonrasında da debian sistemler kısmında detaylarına değinildiği şekilde ssh ve ssl servislerinin localhost 22 ve 443 üzerinden verilmesi için ilgili kısımları olduğu şekilde bırakıyoruz.
Son olarak servisi start edelim:
# /etc/init.d/sslh start
Evet, kurulum ve yapılandırma kısmı bu şekilde tamamlanıyor. Şimdi sistemi test edelim:

Test

Şu anda servis çalışıyor ve netstat ile baktığımız zaman aşağıdaki gibi bir çıktı alıyoruz:
# netstat -antp |grep LISTEN
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1522/sshd
tcp        0      0 127.0.0.1:443               0.0.0.0:*                   LISTEN      1794/httpd
tcp        0      0 1.1.1.1:443                 0.0.0.0:*                   LISTEN      1780/sslh
Görüldüğü gibi 1.1.1.1:443′i sslh dinlerken, 127.0.0.1:443′ü olması gerektiği gibi httpd dinliyor ve ssh da 0.0.0.0:22 üzerinden hizmet veriyor.
Şimdi dışarıdan 1.1.1.1′e ssh bağlantısı kurarsanız isteği sslh karşılayacak ve ssh servisine iletecektir.
Tüm detaylar için https://github.com/yrutschle/sslh adresine göz atabilirsiniz.
Cihat IŞIK < cihat.isik@bga.com.tr >