5 Eylül 2012 Çarşamba

OSI TCP/IP

Normalde bu yazıda TCP/IP'nin katmanlı yapısından bahsetmeyecektim. Çok daha ilgisiz birşeylerden bahsedecektim ki işler her bakımdan tam anlamıyla sarpasardı. Kafamda olan PCB yapımıyla ilgili birşeylerden bahsetmekti ancak bunu anlatmak için kullanacağım devre doğru düzgün çalışmadı; diğer taraftan aynı devreyi kendim SMT elemanlarla kurup SMT lehimlemeye giriş yapacaktım hatta bir zaman sonra belki buradan kendim de anlatabilirdim. Tabi devre çalışmayınca olmadı, devreyi düzeltmek için simülatörde yada Protoboard'da zaman da ayıramadım. Diğer taraftan da ağ işlerine bulaşmak zorunda kaldım. Dolayısıyla hazır kafamdaki bilgiler tazeyken bununla ilgili yazacağım. Bu kısım aslında düşük seviye olduğu kadar yüksek seviye programlama ve API'leri de içeren bir bölüm olacak. Hadi bakalım.

TCP/IP yada şu an adı bile kalmamış IPX/SPX gibi hangi protokolü kullanıyor olursanız olun yaptığınız işler en yüksek seviyede kullanıcı etkileşiminden en düşük seviye bit kodlamasına ve ortama yayımlanmasına kadar bir çok ara işlem geçirir. Yani Facebook'ta birine "merhaba" şeklinde mesaj yazdıktan sonra o "merhaba" karakter katarının doğrudan bakır kablo üzerinden ASCII kodlanmış şekliyle gitmesini kimse beklemesin. Kullanıcının gönderdiği ve aldığı veriler birden çok defa işlemden geçirilir ve her işlem adımına katman denir. Daha önce duymuş olanlar için OSI katmanları yada TCP/IP katmanları aslında işlem adımlarını sanallaştıran katmanlar. Ben IPX/SPX yada NetBEUI gibi kullanımdan kalkmış protokoller yerine daha kolay kafada canlandırılması açısından TCP/IP üzerinden örnekler vereceğim.

Klavyeden girilen "merhaba" karakterinin bakır kabloya ulaşmasına kadar bir çok aşama olduğuna değindim. Eski (hatta ilk) TCP/IP yapısına göre bu katmanlar dört tane. Hatta daha heyecan verici olan aslında bu dört katmanlı modele "DoD model" yani "Department of Defense Model" deniyor. Savunma Bakanlığı modeli. Internetin ilk geliştirildiği zamanlarda adının ARPANET ve geliştiricisinin de DARPA olduğunu hatırlatayım. Açılımları Advanced Research Projects Agency Network ve Defense Advanced Research Projects Agency. Bilenler zaten biliyor ama kısaca; ABD savunma bakanlığı bir haberleşme düğümü çökse dahi veri iletimine devam edebilecek bir sistem kurma işini DARPA'ya veriyor. DARPA, Internet'in atası ARPANET'i geliştiriyor ve sistem sonradan zamanın büyük bilgisayar şirketleri (Hey gidi Digital Equipment) ve üniversitelerin kullanımına açılıp sivilleştiriliyor. DARPA'nın ilk zamanlarda yaptığı dört katmanlı dökümantasyon bu nedenle DoD model olarak biliniyor.

Nedir bu dört katman:
  1. Physical
  2. Internet
  3. Transport
  4. Application
Bunların ne işe yaradıklarını OSI katmanlarına değindikten sonra anlatacağım. OSI zamanla bu dört katmanı yetersiz görüyor ki dördüncü katmanı üç alt katmana ve birinci katmanı da iki ayrı katmana daha ayırıyor. Adlar biraz değişiyor:
  1. Physical
  2. Data Link
  3. Network
  4. Transport
  5. Session
  6. Presentation
  7. Application
Baş harflerini terstern sıralarsak "All Programmers Seems To Need Data Processing". (Bu arada Data Link katmanı da kendi içinde 2 alt katmana ayrılıyor ancak orjinal OSI dökümantasyonu yedi katman olduğundan böyle bırakılmış.)

Kullanıcı verisi en alt katmanda başlıyor. Her katmanda bir üst katmana geçerken belli veriler ekleniyor. Application'a daha yakın olan katmanları kullanıcı programları üstlenirken, orta katmanlarda işleri işletim sistemi devralıyor ve physical'a yaklaştıkça işletim sistemi de bayrağı donanıma devrediyor. Her bir katmandan diğerine geçişe paketlenme (encapsulation) yada direk türkçeye yamultulmuş şekliyle enkapsülasyon adı veriliyor.

İlk katmanda kullanıcı verisi olduğu haliyle düşünülebilir yada tarayıcıya gelen HTML kodları, FTP komutları gibi pek az yabancı olunan yapılar ilk katmana ait bilgilerdir. Normal kullanıcı verisi HTML ile kodlanarak biçimlendirilir ve sunucu tarafından kullanıcıya gönderilir. HTML kodlarını doğrudan metin olarak göstermek yada biçimlendirmek tamamen kullanıcının programına kalmış bir seçenektir.

Kullanıcı verisine, Presentation katmanında verinin içeriği ve bu içeriğin nasıl gösterileceğiyle ilgili bilgiler eklenir. Bu bilgiler bir veri başlığı (header) ve gerekirse sona eklenen CRC gibi bir hata denetleme mekanizmasından oluşur. Bu katmanla ilgili en bilindik örnek e-posta içeriklerine ait MIME bilgileridir. Bu MIME bilgisi sayesinde e-postalarda resim yada sıkıştırılmış veri gönderilebilir ve karşı tarafa bunu şu programla aç şeklinde bildirilebilir. Büyük olasılıkla web sayfalarındaki resimler de bu şekilde bir bilgiyle karşı tarafa resim, MIDI vb. içerik; resmin biçimi (.gif, .jpg, .png) ile ilgili bilgiler gidiyordur. (Bu kısımdan tamamen emin değilim.) XML bu katmanda çalışan bir protokol.

Bundan sonra gönderilen veriler için bir oturum açılacaksa Session katmanına iş düşüyor. Bu kısım her zaman gerekli olmasa da bazı durumlarda, örneğin SSL ile şifrelenmiş veri alıp yollarken güvenli bir oturum açılması gerektiğinde kullanılıyor.

Yukarıdaki kısımlar genellikle kullanıcı programlarını ve seçimlik üst seviye işletim sistemi API'lerini kapsıyor. Ancak bundan sonra anlatacağım kısımlar daha önemli kısımlar.

Üç katman sonrasında veriye hala veri adı veriliyor. Başka ne olabilirdi diye sormayın çünkü zamanla verinin adı diğer katmanlarda değişecek. Internetteki port kavramı burada devreye giriyor. Aynı sunucuda bulunan bir web sayfası açıp bir de e-posta'larımı kontrol ettiğimi varsayalım. Bu durumda haberleşeceğim sunucu aynı ancak verilerin karışmaması için farklı haberleşme kanalları açılması gerekiyor. Benzer şekilde web sunucusunu açtım ama sonra aynı sitedeki bir linki farklı bir sekmede açarak incelemeye devam ettim. Gönderilen veri aynı ancak birden fazla kanaldan gönderilmesi gerekiyor yoksa diğer sekmeyle karışır. Bunun için sunucu bana bütün bu verileri farklı portlardan gönderiyor. Ben web sunucusuna 80'inci porttan ne istediğimi bildiryorum. HTTP1.0'in kendi 3 tane komutu var. GET, POST, HEAD. Örneğin bir web sunucusuna telnet programıyla 80. porttan bağlanıp GET yazarsanız sunucu size anasayfayı HTML kodlarıyla gönderir. Telnet programı HTML kodlarını yorumlayamadığından olduğu gibi gösterir. "GET deneme.html" yazarsanız bu sefer de deneme.html dosyasının kodlarını gösterecektir. Tabi sunucu tek bir porttan çalışır (HTTP için 80) ama istemci bunu farklı portlardan kabul eder. Yani web sunucusu 80. portundan anasayfayı istemcinin 12930. portuna yollarken, deneme.html dosyasının kodlarını yine 80. portundan ancak bu sefer istemcinin herhangi başka (mesela 22844 olsun) portuna yollar. Web tarayıcısı farklı portlardan gelen verileri farklı sayfalar olarak yorumlayabilir ve ayrı sekmelerde gösterebilir.

Bu veriye port eklenmesi işini verileri paketleyerek yapar. Şekilde bunu nasıl yaptığı anlatılıyor. Application katmanından gelen kullanıcı verisi Transport katmanına geldiğinde başına bir başlık ekleniyor. Bu başlıkta port bilgileri var. Port bilgileri eklenen veri sonrasında bir alt katmana gidiyor, burada IP başlığı ekleniyor. Her katmanda eklenen bilgileri yeri geldikçe daha ayrıntılı açıklayacağım. Yalnız unutmadan şunu ekleyeyim, verilerin adlarının değiştiğinden bahsetmiştim. Kaynak ve hedef port bilgisi eklenerek paketlenmiş veriye artık Segment adı veriliyor.



Transport katmanın önemli bir özelliğide verinin doğru ulaşıp ulaşmadığını kontrol etmek. Yukarıdaki şekilde UDP anlatılıyor. UDP pek verinin doğru ulaşıp ulaşmadığıyla ilgilenmez. UDP'de veriyi yollarsınız, sonrasında başka veri yollarsınız, böylece sürer gider. Karşı tarafın veriyi alıp almadığıyla pek ilgilenmezsiniz. Ancak UDP'den başka bu katmanda çalışan diğer protokol olan TCP verinin alınıp alınmadığıyla ilgilidir. Bir kere TCP karşı tarafla bir oturum açar. Bu oturum açma işine "Three way handshake" deniyor. TCP başlığında sadece port bilgisi bulunmaz (UDP'de de bulunmaz ancak UDP başlığı her zaman TCP başlığından daha basittir.) bazı bayraklar ve sıra numaraları bulunur. Bu bayraklardan biri SYN diğeri de ACK'dir. Bir TCP oturumu açılacağı zaman istemci sunucuya SYN bayrağı set edilmiş bir paket yollar. Sunucu eğer karşılık verecekse ACK bayrağı set edilmiş bir paket bir de SYN bayrağı set edilmiş bir paket yollar. (Paketler iki ayrı paket olabileceği gibi tek bir paket de olabilir.) Sonra istemci de karşı tarafın SYN isteğini ACK ile onaylar ve komut satırında "netstat -a" yazdığımızda ESTABLISHED olarak görünen bağlantılar oluşur. Her bağlantı işletim sisteminde belli bir miktar kaynak kullanır. Eğer siz bir sunucuya farklı farklı yerlerden bir sürü SYN yollarsanız o zaman sunucunun bir yerden sonra kaynakları sadece SYN'lerden dolayı tükenebilir. Bu SYN FLOOD saldırısı olarak bilinir. Bu nedenle aynı anda açılabilecek en fazla SYN sayısı ve birim zamanda kabul edilecek SYN paketlerinin sayısı sınırlandırılır.

TCP paketinde bu bayraklardan başka sıra numarasını bildiren 32 bitlik bir alan daha vardır. Eğer farklı paketler sunucudan farklı yollar üzerinden gelirse, aslında sonradan gelmesi gereken bir paket önce gelebilir yada önce gelmesi gereken bir paket gecikebilir. Bu durumun önüne geçmek için paketler sıra numaralarıyla gönderilirler. Yine örneğin bir paket 01 sıra numarasıyla, ve hemen ardından paket 4196000 numarasıyla gönderilirse işletim sistemi bu paketi belleğe sığdırıcam diye çok fazla bellek ayırmaya kalkabilir. Ya bellek biter yada segmentation fault yada benzeri bir durum oluşabilir. Bu saldırının adı da Fragments Attack'tir.

Hem TCP hem de UDP'de segmentin doğru alınıp alınmadığıyla ilgili bir CRC bulunur. Hoş UDP ile yanlış segment alınsa yapılabilecek tek şey onu çöpe atmaktır ancak TCP'de bu segment'in yeniden gönderilmesi istenebilir. TCP'de bir de pencere büyüklüğü (Window Size) adında bir parametre bulunur. Bunun değerini çoğunlukla işletim sistemi belirler ancak oturum açılırken ortak bir pencere büyüklüğü kararlaştırılabilir. Yani işletim sisteminin belirlediği değeri karşı taraf beğenmeyebilir. TCP, Window Size ile belirlenen kadar veri alındığında veriyi alan "Tamam sorunsuz geldi sonrakileri de yolla" anlamında bir ACK paketi yollar. Eğer gönderici belirli bir zaman içerisinde ACK paketini almazsa önce gönderdiğini tekrar yollar. Eğer veriler yolda bozulmuşsa yolda bir sıkıntı var demektir ve yada belki sunucuda aşırı trafik olduğundan herkese 60KB yollamaktansa herkese 10KB'lik veriler yollamayı tercih ediyorsa, karşılıklı olarak bu pencere büyüklüğü veri iletişimi sırasında gerçek zamanlı olarak değiştirilebilir.

Port, bayraklar ve pencere büyüklüğü gibi parametreler eklendikten sonra segment network katmanına gelir. Bu katmanda IP adresleri ve bununla ilgili bilgiler eklenir. IP protokolü verilerin doğru iletilip iletilmediğiyle ilgilenmez. IP protokolü verileri gönderilmesi gereken yere yollar ancak verilerin doğru gidip gitmediği, ulaşıp ulaşmadığının kontrolü bir üst katman olan Transport katmanında yapılır. Bu bağlamda katmanlaşma verilerle ilgili işlerin bölüşülmesini kolaylaştırır. Eğer Network katmanı Transport katmanının denetleme yaptığından habersiz kendisi de bir denetleme yapmaya kalksaydı bu durumda performans düşecekti. Transport katmanında bir denetleme, bir de gerekiyorsa Session katmanında bir denetleme yeterli olmaktadır. Segment IP başlığı da eklenerek paketlendiğinde artık adı Paket olur. Yani adını sıkça duyduğumuz IP paketi.

Paket'ten sonraki durak Data Link katmanıdır. Data Link katmanının da ikiye bölündüğünden bahsetmiştim. Biri Logical Link Control (Mantıksal Bağlantı kontrolü - LLC) diğeri de Media Access Control (ortama erişim kontrolü - MAC) adını alır. LLC işletim sisteminin son durağı, MAC ise donanımın başladığı yerdir. Siz ethernet fişini taktığınızda kartın üzerinde yada modemde yanan yeşil ışık bu katmanda gerçekleşen bir "handshake" sonucunda yanar. Bu katmanda artık iş IP'den de çıkmaktadır. Bağlantı kablolu yada kablosuz Ethernet olabilir ancak Ethernet verileri ADSL modem'den PPP ile paketlenerek çıkıyor olabilir. ADSL modem, ADSL erişim merkezine bağlanırken artık Ethernet kurallarıyla değil PPP kurallarıyla konuşur. (ADSL aslında PPP paketlerini Ethernet ile paketleyerek yollar. ADSL modemde PPPoE'yi hatırlayın. Yani PPP over Ethernet) Bu farklı bir ortamdır dolayısıyla Ethernetten farklı protokolleri ve kuralları vardır. Telefonu kullanan modemler de PPP kullanırlar. Eğer modem harici modemse ve Seri porttan bağlanıyorsa araya SLIP protokolü girecektir. Eğer kiralık hat kullanıyorsanız (Leased Line) ATM yada Frame Relay gibi ikinci katman teknolojileri girecektir. Bunların hepsi içinde IP protokolünü paketleyerek iletebilir. Bu durumda örneğin IP paketi SLIP ile paketlenip modeme iletilir, modem SLIP katmanını atar IP paketini alır, PPP ile yeniden paketler ve servis sağlayıcıya yollar.

LLC katmanında donanımsal yada yazılımsal hata kontrolü gerçekleşir. Seri iletişimi kullananlar bileceklerdir, Seri porttan bir veri yollandığı zaman asıl veriye başlama ve durma bitlerinin eklenmesiyle bir yapı elde edilir. 'A' karakteri yollanırken 6 bit de kullanılabilir 8 bit de. Başlama ve durma bitleri de eklendiğinde seri kabloya aktarılan veri 7 bitle 10 bit arasında farklılık gösterebilir. Buna bir Frame yada çerçeve adı verilir. Benzer şekilde IP paketi de ikinci katmana geçtiği zaman artık Frame adını alır. Frame olarak paketlenirken başına Ethernet için MAC adresleri sonuna da CRC eklenir. LLC katmanında gelen verinin CRC'si donanımsal yada yazılımsal olarak kontrol edilir. Doğruysa kabul edilir, değilse dikkate alınmaz. Elbette ki böyle bir durumda Transport katmanı gerekirse olaya müdahale edip hatayı düzeltecektir.

MAC katmanında donanım adreslemesi ve veri yollayacakların ortama ne şekilde erişeceklerinin kontrolü yapılır.

Son fiziksel katmana gelindiğinde artık Frame'ler bitlere dönüşür. Yine ortama salınacak bitler için belli dönüşümler yapılır. Frame'ler içerisindeki bitler olduğu gibi ASCII kodlarıyla salınmaz. Yani osiloskobu bağlayıp gidip gelen verileri kolaylıkla okuyamayız. Bitler dış ortamda ister istemez gürültüden etkilenir. CPU'ya iletilecek 5V sinyalde %1'lik bir düşüş kabul edilebilir ancak dış ortamda yeri geldiğinde sinyal gerilimi gürültüden %30-%40 kadar etkilenebilir. Sinyallerin nasıl modüle edildikleri de önemlidir. En basitinden 1'leri artı gerilim ve 0'ları toprakla gösterirsek Genlik modülasyonu yapmış oluruz. Sıfırları taşıyıcı sinyal üzerinde değişim olmaması, birleri de taşıyıcı sinyalde değişim olmasıyla gösterirsek Frekans modülasyonu yapmış oluruz. Bu kodlamaların her birinde sıkıntı saat sinyallemesinde kayma olursa ortaya çıkar. Yüksek bant genişliği, dolayısıyla yüksek frekans gereken yerlerde ardarda 111 mi yolladık yoksa 1111 mi yolladık tam olarak ayırt edilemeyebilir. Bununla başedebilmek için saat sinyali gönderici tarafından ayrıca yollanmalıdır ki bu da gereksiz kablo kalabalığı yaratır.

Ethernet bunun yerine Manchester Encoding adı verilen, veriyi gönderirken aynı zamanda saat sinyalinin de gönderilebilmesine olanak sağlayan bir teknoloji kullanır. Bu kodlamada sıfırlar (+) sinyalden toprağa yada (-) sinyale geçiş, birlerse (-) sinyalden yada topraktan (+) sinyale geçiş olarak kodlanır. Üst üste üç sıfır yollanacaksa ilk sıfır için sinyalin tutulma zamanında bir gerilim düşmesi olur, sonraki tutulma zamanının tam arasında gerilim yukarı çıkar (bu aynı zamanda saat sinyali yerine de geçer) ve sonraki tutulma zamanında yine gerilim düşer (sıfır). Bir sonraki sıfır için aynı durum tekrarlanır. Bunun wikipedia'daki resim çok daha iyi anlatıyor. Bu kodlamanın dışında Ethernet bir de 4B/5B adı verilen bir kodlamayda dört bitlik veriyi beş bitlik veriye çıkarır. Genelde 11111 yada 00000 gibi veriler kullanılmaz. Bunun yerine 4 bitlik veriler bit geçişleri çok olan örn. 10010, 01010 gibi 5 bitlik verilerle eşleştirilir. Bundan başka bazı 5 bitlik sinyaller komut sinyalleridir.

Yedi katmanı da geçip bitlere dönüşen veri ortama (fiber kablo, bakır kablo, kablosuz ethernet için mikrodalga ışınımı vb.) salınır. Veriyi alan taraf bitleri frame'lere dönüştürür. Frame kendisine gelmişse ve hatasızsa frame'in başlığını atıp paketi işletim sistemine verir. İşletim sistemi paket doğru IP'ye gelmişse IP başlığını sıyırıp Segment'teki port bilgisine göre veriyi kullanıcı programına aktarır. Kullanıcı programı veriyi yorumlayarak olması gerektiği şekilde gösterir.

Son olarak yukarıda "frame kendisine gelmişse" gibi bir ifade kullandım. Normalde Ethernet ortamında özellikle kullanıcılar birbirlerine Hub ile bağlıysalar ortama gönderilen paketler bütün bilgisayarlara ulaşır. MAC adresi kullanıcının MAC adresine eşitse işletim sistemi bunu alır ancak işletim sistemini yerine kendi yazacağımız Ethernet kartı sürücüsü ve bunu kullanan bir kullanıcı programıyla gelen bütün frame'lerin kabul edilerek içeriğinin görüntülenmesi sağlanabilir. Piyasada Sniffer adıyla bu tür programlar bulunmaktadır. (Şu ana kadar gördüğüm en iyi Sniffer Wireshark adında bir program). Ancak Hub'ların zamanla ortadan kalkıp yerini Switch'lerin almasıyla bu programlar da gelen bütün paketleri alamamaktadırlar ancak kablosuz ortamlar için aynı durum geçerli değil. Wireshark kablolu ortamda bile gidip gelen Broadcast paketlerini gösterebiliyor. Diğer yandan amatörce ayarlanmış switchleri de belli saldırı araçlarıyla Hub gibi davrandırabilmek mümkündür. Bunun nasıl yapılacağı bu yazının konusunu aşacağından burada değinmeyeceğim.