13 Nisan 2013 Cumartesi

Bir başka PIC #2


Geçtiğimiz hafta müsvedde kağıtlarımın arasında "PNP kağıdıyla baskı devre yapımı" başlıklı yazıda yaptığım devrenin şemasını buldum ve oturup yaptığım devrede arızanın nerede olduğuna bakmaya başladım. Buna en son değinirim. Önce asıl yazacağım konuyu ele alayım.

Yazı esas olarak Temmuz 2012'deki PIC yazımın devamı gibi olacak. Temmuz ayında kendi programlayıcımı yaptıktan sonraki aşamalara kısaca değineceğim.

Temmuzda yaptığım programlayıcı seri arabirimi kullanıyordu. Maalesef artık masaüstü makinalarda bile seri arabirim kalmadı. Seri arabirimi, yönlendirici (router), switch ve disk denetleyici ayarlarken hala kullanıyorum ama acil bir durumda bile kendi dizüstü bilgisayarıma USB-Seri çevirici takıp onu kullanmam gerekiyor. Bu çevirici için ayrıca bir sürücü gerekli. Ve sürücü programlayıcı için bilgisayar tarafında kullanan programla (IC-Prog gibi) uyumlu çalışmadığından, seri PIC programlayıcıyı kullanabilmek için Windows 98'i olan ayrı bir makina bulmak gerekiyordu. Bu da hiç pratik değil.

Yazıcıoğlunda gezerken BioPIC USB Programlayıcı'yı daha önce görmüştüm. 


USB kullandığından programlaması pratik. Üstelik programlayıcının üzerindeki USB iletişimi sağlayan bir PIC18F2550. Artısı seri programlayıcıya göre pratik olması, dış güç kaynağına gerek olmaması ve onlarca PIC serisi denetleyiciyi desteklemesi. Eksisi diyemeyeceğim ancak çeviriciler gibi bilgisayara bir sürücü kurmak gerekiyor. Satın aldıktan sonra CD'de Usburn yazılımıyla geliyor.

Programlayıcıyı bilgisayara takınca ışıklar kısa bir yanıp sönecek. Usburn'u çalıştırınca "Detect Programmer" yazıyorsa sürücülerde bir sorun vardır. "Identify PIC programmer" düğmesi çıkmalı. Buna tıklayınca artık .hex dosyaları okumak ve yazmak olanaklı. Internette bulunabilecek örnek bir .hex dosyayla denemeler yapılabilir. Daha önce denediğim arabirim programlarına göre üstün bir özelliği disassembler ve hex dump'ı da göstermesi. Programlayıcı bazen bilgisayara takıldığında ışıkları yanmadığında yada .hex dosya yazılıp doğrulaması bittikten hemen sonra sürekli ışığı yanıyorsa artık bilgisayar onu görmüyor. USB'yi çıkarıp tekrar takınca sorun düzeliyor.

Elbette ki bir derleyici olmadan sadece başkalarının .hex dosyalarını yazmak bir yerden sonra anlamsız. Benim amacım yaktığım PIC'deki kodu sıfırdan yazmaktı. Bu arada PIC assembly'si oldukça basit. Kendim anlatacak kadar değil ancak idare edecek kadar biliyordum, onu da kullanmaya kullanmaya çoğunu unuttum. O nedenle burada anlatamam ancak piyasada bunu anlatan kitaplar var. Sadece komut seti ve iç yapısı microchip firmasının sayfasındaki "datasheet"inden bulunabilir. O güne kadar PIC doğru düzgün Assembly kodu yazmamıştım. Gidip microchip'in sayfasından MPLAB IDE'yi indirdim. Bu bir IDE ancak içinde hazır bazı derleyici modüllerle geliyor ve bunları seçebiliyorsunuz. Üstelik ICE denen "In Circuit Emulation" özelliğiyle programlayıcıyı tanıyorsa ve destekleniyorsa IDE'den doğrudan programlayıcıya hex kodu aktarmak ve emülasyonunu yapmak olanaklı. Ben bu kadar gelişmiş özelliklerini ne biliyorum ne de kullanabiliyorum. Zaten bildiğim kadarıyla BioPIC'in böyle bir desteği de yok. 

Bu programı kullanılabilir hale getirmek biraz karışık olduğundan ayrıntılı anlatma ihtiyacı duyuyorum. MPLAB'ı kurup IDE'yi açtım. IDE'de doğrudan dosya seçmek yerine önce bir proje oluşturmak gerekiyor. Project -> New diyip proje için bir ad bir de dizin seçiyorum. Karışıklık olmasın diye bütün kodları bu dizinde tutacağım ama bu zorunlu değil. Tamam'a tıkladıktan sonra proje ve çıktı pencereleri çıkması lazım. Çıkmıyorsa View'dan gösterilmesi sağlanabilir. Proje penceresinde 'Source Files'a sağ tıklayıp 'Add Files' kaynak kodu seçip eklemek gerekiyor. Ekledikten sonra proje penceresinde dosya görünecek. Kaynak kod penceresi çıkmıyorsa dosyaya çift tıklayınca çıkacaktır. 

Burada Make yada Build demeden önce yapılması gereken önemli işler var. Birisi Project menüsü altında 'Select Language Toolsuite'den "Microchip MPASM Toolsuite" seçili olmalı ve elbetteki yüklü olmalı. Bu araç MPLAB IDE ile geliyor diye hatırlıyorum ama yüklü değilse yüklemek gerekir. Yüklüyse derleyici, linkleyici gibi ıvır zıvırların yollarının doğru bir biçimde belirtilmesi lazım, yani 'Toolsuite Contents' altında bunların karşısında kırmızı bir çarpı bulunmamalı. Resimde, benim bilgisayarımda MPASM kitinin varsayılan kurulumda nerede bulunduğu görülüyor. Bu ayarlar sanıyorum Project -> Set Language Tool Locations altında da bulunabilir. Uygun derleyiciyi seçtikten sonra Ctrl + F10 ile yada Project -> Build All diyerek kodu derliyorum. Kodun tamamını vermek gereksiz olacak ancak kodun başlığı şu şekilde:

;*************************************************************
    title    "zamanlayici"
;*************************************************************
    list    p=16F84A
    #include    <p16F84A.inc>
    __CONFIG    _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
    ERRORLEVEL -302

SaH        equ        0x10
SaL        equ        0x11
;*************************************************************
        org        0x0000
        goto    BASLA
...


Buradaki #include<p16F84A.inc> ifadesi önemli. Kullanılan sabitlerin birçoğu bu dosya eklendikten sonra tanımlanıyor. Diğer önemli bir ifadeyse __CONFIG makrosu. Bu, programlama sırasında denetleyicinin ayar yazmacına yazılacak olan 'word'u belirtiyor. Buradaki örnekte CP (Code Protection) kapalı, WDT (Watchdog Timer) kapalı, PWRTE (Power-Up Timer) açık ve kristal osilatör seçili. Kodda ve donanımda herşey doğru olsa bile buradaki bitlerden herhangi biri yanlışsa devre hiç çalışmayabilir. Bütün bu tanımlar ve daha bir çoğu (STATUS, PORTA, PORTB, TRISA, TRISB, ...) 16F84A'ya özgü olacak şekilde p16F84a.inc dosyasında bulunur. 

Eğer kodda bir hata yoksa sorunsuz derlenmesi ve .hex dosyanın oluşması gerekiyor. Eğer oluştuysa bundan sonrası .hex dosyayı Usburn'da açıp ROM'a yazdırmak oluyor. Elbette geliştirme aşamasında her seferinde kodda ufak hataları düzeltmek, sonrasında ROM'a yeni kodu yazıp mikrodenetleyiciyi programlayıcıdan sökmek ve devre kartına takıp devre kartında test etmek ve her hatada bunu tekrarlamak bir yerden sonra işkenceye dönüşebilir. ICE'nin avantajı burada devreye giriyor.

Herşey buraya kadar iyiydi. Kodun başındaki ayarları yapıp belleği ayarladım. Kodun altmış küsuruncu satırında bir kere daha hatırladım ki 16F84A komut setinde bölme komutu yok. Benim hem saniyeler için 60'a bölme ve kalan (modulo) hem de basamaklar için 10'a bölme ve kalan koduna ihtiyacım vardı ve açıkçası bölme kodunu ayrı ayrı yazmak istemiyordum. Tek bir bölme fonksiyonuysa beni daha da uğraştıracak gibi görünüyordu. Üstelik yığın (stack) yoktu, fonksiyona argüman göndermek ayrı bir sıkıntıydı. Bu nedenle kodu PIC C'de yazmaya karar verdim çünkü PIC C gibi bir araç varken Assembly'de uğraşmak kılıç kalkanla tanklara saldırmak gibi olacaktı.

Yine hatırladığım kadarıyla MPLAB'le birlikte bir C derleyicisi gelmiyor ama varolan C derleyicilerine destek veriyor. Zaten 'Select Language Toolsuite' altında bir çok C derleyicisi için ayar var. Yalnız varolan C derleyicileri paralı veya bedava ama kısıtlı özellikleri var. Ben iki tane C derleyicisi tavsiye edeceğim. Birisi MPLAB'ın XC8 derleyicisi, diğeri de HI-TECH C derleyicisi. Derleyicileri kurmadan önce hangi mikrodenetleyiciler için olduklarına dikkat edilmeli. Ben bu derleyiciler için bir gecemi ayırdığımdan yarı uykulu halde 16 bit, 32 bit ne varsa kurup çok sonradan aslında 8 bitlik derleyiciye ihtiyacım olduğunu anlamıştım. Hi-Tech C için yazılan C kodlarında Assembly'de eklenen dosya gibi htc.h adında bir başlık dosyası var. Nasıl ki neredeyse bütün C kodlarının başında #include<stdio.h> varsa Hi-Tech C'de de #include<htc.h> bulunuyor. __CONFIG makrosu yine var ama kullanımı Assembly'dekinden biraz daha farklı. Bir de #define _XTAL_FREQ 4000000 demek gerekiyor ki, zamanlamayla ilgili komutlar (__delay_ms() gibi) doğru çalışabilirsin. Elbetteki o sayı yerine devredeki kristal osilatör frekansı neyse o yazılmalı. Ben çoğunlukla Hi-Tech C'yi tercih ediyorum. Burada yine C kodlamayı yada PIC C'nin gündelik hayatta kullandığımız C'den farkını anlatamayacağım ancak bunun için 320volt.com'daki bir yazıyı önereceğim. Önbilgiye sahip okuycular yazının sonunda ek olarak verdiğim örnek kodu da inceleyebilirler. Devre kartının ayrıntısını vermeyeceğimi söylemiştim ancak kodun tamamını kendim yazdığımdan bunu yayınlayacağım.

Herhangi bir C derleyicisi kurup 'Set Language Tool Locations' altında gerekli çalıştırılabilir dosyaları gösterdikten sonra yapılacaklar aslında Assembly kodu derlerken yapılanlarla aynı. Elbette ki farklı derleyicilerin çıktıları farklı olacak. Ben aşağıdaki çıktıya dikkat çekmek istiyorum. 


Bu çıktı devresini kurduğum sayaç kodunun derleyici çıktısı. Gerçekten de derleyici sorununu halledip internetteki örneklere bakarak PIC C'yi çözdüm, kodu yazmaya başladım ve bir kaç saat sonra kodu bitirdim. O gece sabah ezanından sonrasına kadar çalıştım, sorunun çoğunu halletmiştim. İş yerine o gün gelemeyeceğimi e-postayla bildirip yattım. 4-5sa uykudan sonra kodun geri kalanını da bitirdim, denemeleri gerçekleştirdim ve herşey hazırdı.

Çıktıya geri dönersek; anlaşılacağı üzere derleme tamamlanmış ve şöyle birşey demiş: "The HI-TECH C PRO compiler output for this code could be 362 words smaller.". Yani derleyicinin paralı sürümü optimize kod üretiyor ve 906 word'de 362 word'luk bir küçülme aslında hiç de azımsanamayacak bir oran.

Önceki yazıda devreye oldukça hakim olduğumu belirtmiştim. Sayıcıyla ilgili herşeyi bitirip tekrar devreyi incelemeye geri dönünce aslında devreyi sadece sayıcı olarak kullanmanın haksızlık olacağını gördüm. Devre 3 tane giriş (klavye), bir tane gösterici dekoderi (ekran kartı) üzerinden sürülen 4 basamak 8 segment gösterici çıktısı (monitor), bir tane de röle çıktısı (port) olarak düşünüldüğünde aslında küçük bir bilgisayar olarak görülebilir. O halde devre kartı bir toplama bilgisayarı olarak yeniden programlanabilirdi. Şöyle ki iki düğme 00..99 arası sayıları arttıracak, bu sayılar göstericinin sağ iki ve sol iki basamağında gösterilecek ve üçüncü düğmeye basıldığında bu sayıların toplamı göstericide gösterilecek. Günün geri kalanında bu kodu da yazıp bitirdim ki aslında bu kodu yazmak sayıcının kodunu yazmaktan daha kolaydı. Göstericiyle ilgili kodlar zaten hazırdı. Bunun kodunu da yazının sonunda ek olarak vereceğim. Elbette ki basit bir sayıcı devresi, yeni birşeyler geliştirmek için çok da uygun değil. Bunun yerine daha genel amaçlı, geliştirmeye çok daha fazla açık PIC geliştirme kartları da elektronikçilerde bulunuyor. Örneğin aşağıdaki gibi:

Toplayıcıyı da bitirdikten sonra sayıcının kodunu biraz daha geliştireyim, örneğin dakika ve saniye ayarlama modundayken dakika ve saniyeler yanıp sönsün, fırın saati gibi görünsün istedimse de yukarıdaki çıktıda da görüldüğü üzere program ROM'unda 118 word kalmıştı. Dolayısıyla ikinci sürüm kodun bir kısmını tamamladım ama ROM'a sığmadı. Oysa PRO sürümünde optimizasyonlar açık olsaydı en az 362 word daha olacaktı ve çok rahatlıkla gelişmiş sürümü de bitirebilecektim. Bundan sonra da bu devreyle ilgili geliştirmeyi sonlandırdım.

Yazının en başında geçen ay yaptığım çift taraflı baskı devrede arızanın nerede olduğuna bakmaya başladığımı yazmıştım. Bir yandan bu böyle olmaz diyerek UT603 Sığa - Bobin Ölçme cihazını da sipariş ettim, yeni oyuncağım da kargoda. Devre kartında bir tanesi soğuk lehim kaynaklı ve 3 tanesi tasarım hatası kaynaklı arıza buldum. Tasarımda iki tane veri yolunu unutmuştum. Lehimleri tazeleyip iki tane veri yolunu dışarıdan tel lehimleyerek hallettim. Son olarak röle atmıyordu. Röleyi süren transistörü de söktüm ancak onu sökünce sadece kapasite modunda çalışan devre yeniden çalışmamaya başladı. Transistör bozuk değilmiş ancak sökerken büyük olasılıkla bozdum. En son durumda en azından kendisini açılışta kalibre etmeye çalışıyordu:


Ekler:


/*    16F84A entegreli zamanlayici devresi icin PIC C kod dokumu
    19.06.2012   */

#include 
#define _XTAL_FREQ 4000000

__CONFIG(CP_OFF & WDTE_OFF & PWRTE_ON & FOSC_XT);

int counter = 0;
int onesec = 0;        // bir saniye flag
char sayimda = 0;      // gerisayim flag
char cursec = 0;
char curmin = 0;
char digit1, digit2, digit3, digit4;

void guncelle();

void interrupt isr()    {       // kesme hizmet programi
    if(T0IF == 1)    {          // zamanlayici kesmesi mi?
        counter++;
        if(counter >= 1953)  {  // 4Mhz icin 1953 kesme 1sn olur.
            onesec = 1;
            counter = 0;
        }
        if(onesec == 1)    {
            onesec = 0;         // reset flag
            if(cursec == 0)  {  // saniye tasmasi
                if(curmin > 0)    {
                    cursec = 59;
                    curmin--;
                }
                else    {
                    sayimda = 0; // sayimi durdur
                    T0IE = 0;    // kesme'yi kapat
                }
            }
            else    {
                cursec--;
            }
            guncelle();          // basamaklari guncelle
        }
        T0IF = 0;
    }
}

void guncelle()    {
    digit4 = curmin / 10;        // en soldaki basamak
    digit3 = curmin % 10;
    digit2 = cursec / 10;
    digit1 = cursec % 10;        // en sagdaki basamak
}

void goster()    {
    char temp = PORTA & 0x10;
    /* PortA'nin 4. bitinde role bagli. 0-1-2-3'de 7 segment

       LED'leri adresliyor. Role'nin durumunu degistirmeden

       LED'leri taramak icin temp'de onceki PortA degerini

       yedekle. */

    PORTB = digit1;
    PORTA = temp | 0x01;
    __delay_ms(2);
    PORTA = temp;
   
    PORTB = digit2;
    PORTA = temp | 0x02;
    __delay_ms(2);
    PORTA = temp;

    if(counter < 976)   PORTB = digit3;
    else                PORTB = digit3 | 0x10;
    /* PortB'nin 4. bitine 7 segment'in noktalari bagli. Eger

       saniyenin ilk yarisiysa tam ortadaki 3. noktayi yakma ama

       ikinci yarisiysa yak. boylece saniyede bir kere yanip 

       sonecek. */ 


    PORTA = temp | 0x04;
    __delay_ms(2);
    PORTA = temp;

    PORTB = digit4;
    PORTA = temp | 0x08;
    __delay_ms(2);
    PORTA = temp;
}

void klavye()    {
    if(RB7 == 0)    {    // ucuncu dugmeye bagli.
        if(sayimda == 0)    {
            sayimda = 1;
            T0IE = 1;    // sayimda degilse kesmeyi ve sayimdayi 

                         // baslat
        }
        else    {
            sayimda = 0;
            T0IE = 0;    // sayimdaysa kesmeyi ve sayimdayi kapat
        }
        while(RB7 == 0)    goster();
        // basili tutuldugu sure icerisinde sadece ekrani tazele
    }
   
    if((RB6 == 0) && (sayimda == 0))    {
        // ikinci dugmeye bagli. sadece sayimda degilse aktif
        cursec++;          // saniyeyi arttir
        if(cursec == 60)   cursec = 0;        // saniye tasmasi
        guncelle();        // artmis saniyeyi guncelle
        while(RB6 == 0)    goster();
        // basili tutuldugu sure icerisinde sadece ekrani tazele
    }

    if((RB5 == 0) && (sayimda == 0))    {
        // birinci dugmeye bagli. sadece sayimda degilse aktif
        curmin++;          // dakikayi arttir
        if(curmin == 100)  curmin = 0;        // dakika tasmasi
        guncelle();        // artmis dakikayi guncelle
        while(RB5 == 0)    goster();
        // basili tutuldugu sure icerisinde sadece ekrani tazele
    }
}

void role()    {
    if((cursec == 0) && (curmin == 0))  RA4 = 1;
    // saniye ve dakika sifir oldugunda roleyi ac
    else                                RA4 = 0;
    // degilse roleyi kapat.
}

void main()    {

    TMR0 = 0;
    GIE = 1;           // kesmeleri aktiflestir
    T0IE = 0;          // zamanlayici kesmesini kapat
    OPTION_REG = 0;    /* PortB pull-up enable. Timer0 clock

                          source = CLKOUT. Prescaler to Timer0. 

                          Prescaler 1:2  */
    RBIF = 0;          // PortB kesmesini kapat

    PORTA = 0x10;      // Role bacagi haricindeki bacaklar sifir.
    PORTB = 0;
    TRISA = 0;         // Butun bacaklar cikti
    TRISB = 0xE0;      // ilk 3 bacak dugmelere bagli girdi
                       // geri kalan bacaklar cikti.

    guncelle();        // basamak degerlerini guncelle
    while(1)    {
        goster();      // degerleri goster
        klavye();      // dugmeleri oku
        role();
    }

}



/*    16F84A zamanlayici devre icin toplayici   
    19.06.2012    */

#include 
#define _XTAL_FREQ 4000000

__CONFIG(CP_OFF & WDTE_OFF & PWRTE_ON & FOSC_XT);

int sayi1 = 16;
int sayi2 =  9;
int toplam;
char basamak1, basamak2, basamak3, basamak4;

void interrupt isr()    {    // bos kesme hizmet programi
    #asm
        NOP
    #endasm
}

void guncelle()    {
    basamak1 = sayi1 % 10;        // en sagdaki basamak
    basamak2 = sayi1 / 10;
    basamak3 = sayi2 % 10;
    basamak4 = sayi2 / 10;        // en soldaki basamak
}

void goster()    {
    // basamaklari PortB'den gonder. PortA 7 segment'in basamaklarini tarar.
    PORTB = basamak1;
    PORTA = 0x01;
    __delay_ms(2);
   
    PORTB = basamak2;
    PORTA = 0x02;
    __delay_ms(2);

    PORTB = basamak3;
    PORTA = 0x04;
    __delay_ms(2);

    PORTB = basamak4;
    PORTA = 0x08;
    __delay_ms(2);

}

void klavye()    {
    if(RB7 == 0)    {
        toplam = sayi1 + sayi2;
        // ucuncu dugmeye basilinca iki sayiyi topla
        basamak4 = 0;
        basamak3 = toplam / 100;
        basamak2 = (toplam / 10) % 10;
        basamak1 = toplam % 10;
        // bu toplama icin kendi guncelleme rutini gerekli.
        while(RB7 == 0)    goster();
        // ucuncu dugme basili oldugu surece toplami ekranda goster
        guncelle();
        // sonra yine eski sayilarla ekrani guncelle
    }
   
    if(RB6 == 0)    {
        // ikinci dugme basiliysa birinci sayiyi arttir [0, 100]
        sayi1++;
        if(sayi1 == 100)    sayi1 = 0;
        guncelle();
        while(RB6 == 0)    goster();
    }

    if(RB5 == 0)    {
        // birinci dugme basiliysa ikinci sayiyi arttir [0, 100]
        sayi2++;
        if(sayi2 == 100)    sayi2 = 0;
        guncelle();
        while(RB5 == 0)    goster();
    }
}

void main()    {
   
    TMR0 = 0;        // Timer0 sifirlama
    GIE = 0;         // Kesmeleri durdur
    T0IE = 0;        // Zamanlayici kesmesini durur
    OPTION_REG = 0;   
    RBIF = 0;        // PortB kesmelerini durdur

    PORTA = 0x10;    // Roleye dokunma diger bacaklari sifirla
    PORTB = 0;
    TRISA = 0;       // PortA cikis.
    TRISB = 0xE0;    // PortB ilk 3 pin giris, digerleri cikis.

    guncelle();
    while(1)    {
        goster();
        klavye();
    }
}

4 Nisan 2013 Perşembe

SSH Tunneling ve SSH Proxy

Artık Telnet protokolünün neredeyse tümüyle yerini alan SSH yani Secure Shell uzaktaki bir bilgisayarda bir UNIX kabuğu açıp sizin sanki o bilgisayardaymış gibi çalışmanıza olanak verir. Ben yazıyı okuyan kesimin SSH'yı az çok bildiğini varsayıp az bilinen yönlerinden bahsedeceğim. Bunlar başlıkta da yazdığım gibi tünelleme ve proxy özellikleri. Bunu yaparken sunucum yani sshd'nin çalıştığı makina Linux, istemci makinam Windows ve kullandığım istemci yazılımı PuTTY olacak.

Tünelleme Nedir?
Tünelleme bir firewall arkasındaki makinanın, firewall'da kapatılmış bir servisle iletişim kurmak istediğinde, firewall'daki açık portları kullanması ve bunu yaparken de giden gelen paketleri o hizmete aitmiş gibi göstermesi olarak anlatılabilir. ICQ zamanlarında bunu oldukça sık yapıyorduk. ICQ, yanlış hatırlamıyorsam TCP 5190 portunu kullanırdı. O zaman işyerlerinde bu port kapatıldığından ICQ ayarlarında HTTP Tunnelling seçeneğini seçince gidip gelen paketler TCP 80 portu aracılığıyla gidip gelir; firewall bu ağ trafiğini HTTP zannettiğinden izin verirdi. ICQ'da tünelleme kullanınca dosya gönderilemezdi. 

Tünellemede yapılan, ICQ'nun ürettiği veriler paketlenip (encapsulation) OSI 4. katmanda datagramlar haline getirildikten sonra (ayrıntılı bilgi için Eylül 2012'deki OSI TCP/IP yazısı) datagramlar veri olarak ele alınıp bir de HTTP olarak tekrar paketlenir, başlığa TCP 80 portu yazılır sonrasında, hedef IP olarak ICQ sunucusunun IP'si eklenip paketler internet ortamına salınırdı. Aslında denilebilir ki tünelleme veri olarak başka katmana ait veri yapılarını (datagram, paket, frame) veri olarak içeren paketlerin olduğu iletişimlere denir. ADSL'den internete bağlanırken seçilen PPPoE ayarının açılımı PPP over Ethernet anlamına gelir. PPP ve Ethernet her ikisi de bir ikinci katman protokolüdür. Günümüz altyapısı Ethernet olsa da PPP (Point to Point Protocol) doğrulama ve iletişim kalitesi açısından yada Ethernet'in kısıtlamalarından dolayı tercih edilebilir. Dolayısıyla Ethernet altyapısında PPP çerçeveleri taşımak için PPP'yi Ethernet çerçevelerinde paketlersiniz. 

Peki Proxy (Vekil Sunucu) Nedir?
Tam anlamıyla olmasa da bence her proxy bir tünellemedir denilebilir. Siz vekil sunucuya yine birden çok kere paketlemeden geçmiş verileri yollarsınız. Vekil sunucu bu paketleri açar, kendisine göre düzenler. Paketleri kendi üzerinden çıkıyormuş gibi IP başlığını değiştirir yada düzenler ve sizin asıl iletişim kurmak istediğiniz sunucuya gönderir. Sunucudan gelen cevabı yine kendisi alıp ve size iletir. Böylelikle siz bir firewall arkasındaysanız firewall'u "Hayır abi ben kesinlikle ICQ sunucusuyla haberleşmiyorum, Hindistan'daki bir sunucuyla haberleşiyorum." diyerek kandırabilir sizin yerinize Hindistan'daki sunucuyu ICQ sunucusuyla haberleştirebilir aynı zamanda da ICQ sunucusunu siz Hindistan'dan bağlanıyormuş gibi kekleyebilirsiniz.

Bunların yanısıra vekil sunucularda eğer aktifleştirilmişse sizin bağlandığınız sayfaları saklar ve gerektiğinde oraya bağlanmaksızın size daha hızlıca sakladığı kopyayı getirebilir. 

Gelelim bunların SSH ile nasıl yapılacağına. Öncelikle SSH neden Telnet'in yerini aldı? Çünkü SSH gidip gelen şifreleri ve kabuk komutlarını şifreleyerek gönderiyor ve sonuçları şifreleyerek iletiyor. Dolayısıyla siz bir tünelleme yada vekil sunucu olarak SSH kullanacaksanız bu durumun bir güzelliği de SSH sunucuyla bilgisayar arasındaki veriler de şifrelenerek gönderiliyor ve alınıyor. Diyelim ki bir internet kafedesiniz ve bir banka işlemi yapacaksınız. SSH makinanıza bağlanıp onu vekil sunucu olarak kullanarak işlemlerin internet kafenin switch ve yönlendiricisinden (router) şifrelenmiş olarak çıkmasını ve sizin sshd çalıştıran makinanıza kadar güvenli bir bağlantıyla (secure connection) iletilmesini sağlayabilirsiniz. 

İlk olarak PuTTY'i açıp bağlantı ayarlarını yapmak gerekli. Bize lazım olacak kısım Session ve Tunnels kısmı. Bağlanmaya çalışmadan önce sunucuya bağlanıp sshd'nin ayarlarını değiştirmek gerekli. Tunnels alanında birşey yapmadan önce Session alanında sshd'yi çalıştıran sunucunun adresinin veya IP'sinin girilmesi gerekiyor. IP'yi girip Open'a tıkladıktan sonra uzaktaki Linux bilgisayarda kullanıcı adı ve şifreyi soracak. Oradaki hesap bilgilerini girdikten sonra kabuk açılacak. Burada sshd'yi TCP paketlerini iletecek biçimde düzenlemek gerekiyor. O ayarlar da bende /etc/ssh/sshd_config dosyasında bulunuyor. (Dağıtıma göre farklılık gösterebilir.) Elbette üzerinde düzenlemeleri yalnızca root yapabilir. root ile dosyayı açıp, içerisinde AllowTcpForwarding değeri yoksa dosyaya ekleyip karşısına yes yazmak gerekiyor. Kurulumda normalde bu değer kapalıdır (comment out) ve varsayılan değeri de no'dur. Bu arada bu özellik bildiğim kadarıyla SSH'nin ikinci sürümünce destekleniyor. sshd kurulumunda yeni sürümler eğer istemci destekliyorsa v2 yoksa v1'den bağlanır. (Ayarlarda sadece v2 yada sadece v1 seçilebilir.). PuTTY de varsa v2 ile bağlanmayı tercih eder. Düşük bir olasılık ama bağlantı sorunu varsa bağlantı protokolünün sürümüne bir bakmakta yarar var.

no yerine yes olacak

Dosyayı kaydedip çıktıktan sonra Red Hat dağıtımlarında 'service sshd restart' yada '/etc/init.d/sshd restart' komutuyla daemon'u yeniden başlatınca artık Tcp paketleri iletilmeye hazır olacak. Bağlantıyı kapatmadan sol üst köşedeki PuTTY simgesinden Change Settings altında Tunnels'a ulaşılabilir ancak bağlantıyı kapatıp yeniden açmadan paketler gelmeyecektir.

Yukarıda banka örneğini vermiştim o nedenle buna benzer bir örnek vereyim. Session kısmında 'Hostname (or IP address)' yazan yere tekrar ssh sunucumun adını yazdım. Tunnels'a geldikten sonra Source Port kısmında çalıştığım (Windows) bilgisayarda açık olmayan bir port yazacağım. Örneğin httpd çalıştırıyorsam 80 yazamam. Açık olmayan herhangi bir port olabilir. Örneğin kaynak port 4567 ve erişmek istediğim sayfa www.google.com olacak. Destination bölümüne www.google.com:80 yazıp Add düğmesine tıklayınca 'Forwarded Ports' bölümüne L4567 ile başlayan bir kural eklendi. Open düğmesine basıp tekrar bağlandıktan sonra kabuk penceresi bir kenarda kalacak, tarayıcıyı açıp 127.0.0.1:4567 yazdığımda artık www.google.com'u görüyorum. 


Burada www.google.com'un DNS çözümlemesini yapan yine karşıdaki (sshd çalıştıran) makina. Eğer istersem DNS çözümlemesini kendi makinamda yapıp PuTTY'de 'Destination' kısmına IP de girebilirim. Windows'un komut satırı DNS çözümleme aracı nslookup'la aşağıdaki komutlarla yapılabilir:



Server komutu kullanılan DNS sunucunu yerine sorgulamayı başka bir sunucuda yapmak için gerekiyor, eğer varolan sunucu kullanılacaksa gerek yok. TTnet DNS'lerinden www.google.com'un IP'sini doğrudan sayfanın adını yazarak buluyorum. Google'ın birden fazla sunucusu olduğundan bana birden fazla IP cevabı geliyor. Bu IP'lerin herhangi birini Destination kısmına girerek aynı yönlendirme yapılabilir. Banka gibi https kullanan bağlantılarda http portu yerine https portunun açılması gerekmektedir.

Karşılaşılabilecek bir sorun da sshd'nin boşta kalan bağlantıları kapatması. Bunu engellemek için PuTTY'nin ayarlarında (en başta açarken yada çalışma esnasında sol üst köşedeki simgeden) 'Connection' bölümüne gelip belli zaman aralıklarında Keepalive paketleri göndertirseniz sorun düzelecektir.

Bu şekilde tünellemeyle bir LAN içerisinde kendinize ait makinanız varsa LAN dışına kapalı makinalarda lokaldeymiş gibi çalışmak da olanaklı. Yalnız bir konu var. Büyük httpd'lerde aynı sunucuda birden fazla sayfa olabilir. DNS kayıtlarından kontrol edilirse en.wikipedia.org, www.wikipedia.org ve tr.wikipedia.org aynı IP'lere sahip. Böyle bir durumda sunucu yazılımı muhtemelen HTTP başlığında hangi domain'in istendiğini tutan bir alana bakıyor (ben böyle tahmin ediyorum). Dolayısıyla bazı sayfalarda bu özellik varsa http://IP_Adresi yazarak giremiyorsunuz. Wikipedia'da böyle bir site. Bu sitelere tünellemeyle girmek istediğiniz zaman da sorun çıkabiliyor.

Bu sorunu çözümü, yazının da diğer kısmını oluşturan SSH'yı vekil sunucu olarak kullanmaktan geçiyor. Bunun için sunucu tarafında yapılması gereken ayarlar tünellemeyle aynı: AllowTcpForwarding yes olmalı ve SSHv2 ile bağlantı sağlanmalı. PuTTY'i açıp Hostname'e bağlanılacak sunucunun adresi yazılır. SSH altındaki 'Tunnels''da kaynak port için bir değer girilir ancak tünellemeden farklı olarak bu sefer aşağıda Local seçeneği yerine Dynamic seçeneği işaretlenir. Destination bölümüne herhangi bir şey yazılmaz. Add düğmesine basarak yeni bir kural eklenir. Open diyip bağlantı kurulduktan sonra yine terminal penceresiyle başka işimiz olmaz. 

SSH Proxy için bağlantı ayarı

Sıra geldi Windows makinadaki tarayıcıyı vekil sunucu kullanarak internete bağlanacak biçimde ayarlamaya. Firefox v19.x serisinde bu ayar Tools -> Options -> Advanced -> Settings altında bulunuyor. Sonuçta herkes kendi tarayıcısında vekil sunucu ayarlamayı biliyordur. Ayarlarda SOCKS sunucu 127.0.0.1, portu PuTTY ile girdiğiniz port ve SOCKSv5 seçili olacak. Bu ayarları yapıp OK düğmesine tıkladıktan sonra artık tarayıcı SSH tarafından oluşturulan güvenli kanaldan vekil sunucu aracılığıyla istenen herhangi bir sayfayı açabilir. Ancak sayfaya paketleri gönderen ve alan hala UNIX makinadır. http://www.whatismyip.com/ dan bakınca Windows makinanın değil UNIX makinanın IP'si görülebilir.