Makale Özeti

Günümüzde kullandığımız pek çok anakart ve ağ arayüzü uzaktan uyandırılmayı desteklemekte. Bu sayede bilgisayarın başına dahi gitmeden intranet/internet üzerinden bilgisayarımızı başlatabilmemiz mümkün. Bu makalemde sizlere bilgisayarların ağ üzerinden uyandırılmasını sağlayan Wake-On-Lan standardından ve C# ile bu standarda uygun network paketlerini nasıl gönderebileceğinizden bahsedeceğim.

Makale

   Günümüzde kullandığımız pek çok anakart ve ağ arayüzü (network kartı) uzaktan uyandırılmayı desteklemekte. Bu sayede bilgisayarın başına dahi gitmeden intranet ya da internet üzerinden bilgisayarımızı başlatabilmemiz mümkün. Bu makalemde sizlere bilgisayarların ağ üzerinden uyandırılmasını sağlayan Wake-On-Lan standardından ve C# ile bu standarda uygun network paketlerini nasıl gönderebileceğinizden bahsedeceğim.

   C# uygulamamızı yazmaya geçmeden önce isterseniz Wake-On-Lan (diğer isimleri ile Wake On WAN, Remote Wake-up, Power On By LAN, Power Up By LAN, Resume by LAN, Resume on LAN, Wake Up On LAN) nedir birlikte görelim.

   Wake-On-Lan, en kaba anlatımıyla, network üzerinden gönderilen bir paket ile bir bilgisayarın çalışması için geliştirilmiş bir Ethernet bilgisayar ağ standardıdır. İşletim sisteminden bağımsız olarak, donanım seviyesinde desteklenen Wake-On-Lan standardında, anakartın ve ağ ara yüzünün (network kartı) bu özelliği destekliyor ve aktive edilmiş olması gerekmektedir. Çalışma prensibi olarak, biraz önce de belirttiğim gibi, ağ üzerinden gönderilen bir paket sonucunda sistem çalışır duruma geçmektedir. Tamamen kapalı durumdaki bir sistemin ağ üzerinden gelen paketleri işlemesinin mümkün olmadığı düşünecek olursak bilgisayarınızı öncelikle elektriğe bağlı ve düşük güç tüketiminde, bir nevi uyku modunda,  çalışıyor olması gerekmekte. Sistemin gelen her ağ paketi ile çalışır duruma gelmesini önlemek adına standartta özel/sihirli paket (magic packet) tanımlanmıştır. Ağ  ara yüzü sistem kapalı durumda iken teslim aldığı her bir paketi inceleyerek bu sihirli paketin ulaşıp ulaşmadığını kontrol etmekte ve uygun paket ulaştığında sistemi  çalıştırmaktadır. OSI modelinde 2. katmana yerleştirebileceğimiz Wake-On-Lan standardı bu özelliği nedeniyle OSI modelinde 3. katmanda yer alan IP adresi üzerinden çalışmamaktadır. İşletim sisteminin dahi devrede olmadığı ve sistemin neredeyse kapalı olduğu uyku halinde zaten bir IP adresinin kullanılabilir olması da pek mümkün değildir.

   Peki sisteme sihirli paketi IP adresini kullanarak ulaştıramıyorsam nasıl ulaştırabilirim? Yapılması gereken, sihirli paketin ağ üzerinde yer alan tüm bilgisayarlara iletilerek doğru bilgisayarın bu paketi kabul ederek çalışır duruma geçmesidir. Ağ üzerinde yer alan tüm bilgisayarlara bir paket göndermek, bir paketin yayınını yapmak dediğimde zaten pek çoğunuz kullanılması gereken yöntemin Broadcast olduğunu fark edecektir. Sistem hemen çalışır duruma gelerek pakete yanıt veremiyor olması nedeniyle TCP üzerinden göndermek yerine yanıt beklemediğimiz UDP tercih edilmesi oldukça normaldir. Tüm resmi bir araya getirdiğimizde sihirli paketimizi hedef bilgisayara iletmek için yapılması gereken ağ üzerinden bir UDP broadcast'i gönderilmesidir. Wake-On-Lan konusunda sıklıkla hataya düşülen nokta, sistemin tamamen broadcast üzerinden çalışabiliyor olduğunun düşünülmesidir. Yapılan broadcast sadece sihirli paketi hedef makineye ulaştırmak için bir araçtır. Örneğin; internete bağlı bir modem üzerinden yapılacak bir yönlendirme sonrasında dış ip adresinize yapacağını bir sihirli paket gönderimi de işe yarayacaktır. Ağ ara yüzü herhangi bir port üzerinden gelecek olan sihirli paket ile sistemi çalışır duruma getireceğinden broadcast için kullanacağınız portun bir önemi bulunmamaktadır, herhangi bir port tercih edilebilir.

   Teorik olarak sistemin nasıl işlediğini gördükten sonra bunu C# ile hayata geçirmek için yayını yapılan sihirli paketin içeriğini bilmemiz gerekli. Sihirli paketin ilk 6  byte'ı 255 (yani hexedecimal FF) olmalıdır. 6 byte’lık 255'in devamında hedef bilgisayarın 48-bitlik MAC adresi (olasılığı düşürmek adına) 16 kez tekrar ediliyor olmalıdır. Ağ ara yüzü, gönderim protokolünden bağımsız olarak, teslim aldığı paketleri kontrol ederek paket içerisindeki herhangi bir noktada bu kombinasyonu bulması halinde sistemi başlatacaktır.

Wake-On-Lan Sihirli Paket yapısı

   Sistemin işleyişini ve sihirli paketin yapısını öğrendikten sonra bu işi yapacak olan C# kodunu yazmak aslında oldukça kolay. Öncelikle byte dizisi olarak MAC adresini bir değişkende saklamalıyız. Örnek olması adına sanal bir MAC adresi olarak 1A-4F-F5-4F-98-AA değerini kullanıyorum. Gerçek sistemlerde kullanmanız gereken MAC adresini hedef bilgisayarda komut satırından çalıştıracağınız ipconfig /all komutu ile öğrenebilirsiniz.

var bitMacAdresi = new byte[] { 0x1A, 0x4F, 0xF5, 0x4F, 0x98, 0xAA };

   Ardından yayınlanacak olan paketin içeriğini tutacak ikinci bir byte dizi oluşturarak ilk 6 byte'ını 0xFF ile doldurmalıyız;

var sihirliPaket = new List<byte>(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });

   paketimizin kalan kısmına ise 16'lık bir döngü ile MAC adresini eklemeliyiz;

for (int i = 0; i < 16; i++) {
    sihirliPaket.AddRange(bitMacAdresi);
}

   Son adımda ise, oluşturduğumuz sihirli paketi ağ üzerinden yayınlamalıyız. Yayınlama için System.Net.Sockets isim uzayında yer alan UDPClient sınıfı kullanılabilir;

var istemci = new UdpClient();
istemci.Connect(IPAddress.Broadcast, 80);
istemci.Send(sihirliPaket.ToArray(), sihirliPaket.Count);

   Her ne kadar örneğimde UDP yayınını 80. port üzerinden yapıyor olsam da, siz herhangi başka bir portu kullanmakta serbestsiniz.

   Yukarıdaki örnek hedef bilgisayarın uygulamanın çalışacağı makine ile aynı alt ağ'da (subnet) olduğunu varsayarak, bu alt ağa yayın yapmaktadır. Bazı senaryolarda hedef bilgisayarın uygulamanın çalışacağı alt ağdan farklı bir alt ağ'da bulunuyor olması söz konusudur. Bu gibi durumlarda ilgili alt ağ'a ait yayın adresi hesaplanarak sihirli paket bu adrese gönderilmelidir. Aşağıda sizlerle paylaştığım static YayinAdresiniHesapla fonksiyonu hedef makinenin ip adresi ve alt ağ maskesi verilerek yayının yapılacağı ip adresini hesaplamaktadır;

public static IPAddress YayinAdresiniHesapla(IPAddress hedefMakineIP, IPAddress altAgMaskesi) {
    var ipAdresBitleri = hedefMakineIP.GetAddressBytes();
    var altAgMaskesiBitleri = altAgMaskesi.GetAddressBytes();

    var yayinAdresi = new byte[ipAdresBitleri.Length];
    for (int i = 0; i < yayinAdresi.Length; i++) {
        yayinAdresi[i] = (byte)(ipAdresBitleri[i] | (altAgMaskesiBitleri[i] ^ 255));
    }

    return new IPAddress(yayinAdresi);
}

   Bu fonksiyon kullanılırken hedef makineni ip adresi bilinmiyorsa, ip adresi olarak hedef makine ile aynı ağ ayda bulunan bir başka makine ip'si verilerek de yayının yapılacağı adres bulunabilir. Aşağıda, şimdiye kadar sizlerle paylaştığım kodları toplu halde bulabilirsiniz;

class Program {
    static void Main(string[] args) {
        var hedefMakineIP = "192.168.2.12";
        var altAgMaskesi = "255.255.255.0";
        var macAdresi = "1A-4F-F5-4F-98-AA";

        var yayinAdresi = YayinAdresiniHesapla(IPAddress.Parse(hedefMakineIP), IPAddress.Parse(altAgMaskesi));

        #region Mac adresini parse et
        var hexMacAdresi = long.Parse(macAdresi.Replace("-", string.Empty), 
NumberStyles.HexNumber, CultureInfo.CurrentCulture.NumberFormat); var bitMacAdresi = BitConverter.GetBytes(hexMacAdresi); Array.Reverse(bitMacAdresi); #endregion #region Sihirli paketi oluştur var sihirliPaket = new List<byte>(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); for (int i = 0; i < 16; i++) { sihirliPaket.AddRange(bitMacAdresi); } #endregion #region Sihirli paketi yayınla var istemci = new UdpClient(); istemci.Connect(yayinAdresi, 80); istemci.Send(sihirliPaket.ToArray(), sihirliPaket.Count); #endregion } public static IPAddress YayinAdresiniHesapla(IPAddress hedefMakineIP, IPAddress altAgMaskesi) { var ipAdresBitleri = hedefMakineIP.GetAddressBytes(); var altAgMaskesiBitleri = altAgMaskesi.GetAddressBytes(); var yayinAdresi = new byte[ipAdresBitleri.Length]; for (int i = 0; i < yayinAdresi.Length; i++) { yayinAdresi[i] = (byte)(ipAdresBitleri[i] | (altAgMaskesiBitleri[i] ^ 255)); } return new IPAddress(yayinAdresi); } }

    Örneğimiz ip adresi ve alt ağ maskesi ikilisi verilerek intranet üzerinden çalıştırılabilir. Internet üzerinden bir bilgisayarı başlatmak istiyorsak ise öncelikli bu bilgisayarın bağlı olduğu modem üzerinden kullanılacak olarak port için NAT yönlendirmesi ve firewall ayarlarının yapılmış olması gereklidir. Bu ayarların yapılmasından sonra doğrudan ip adresine gönderim yapmak için ip adresi ile birlikte 255.255.255.255 alt ağ maskesi kullanılmalıdır.

    Konuyla ilgili olarak düşülmesi gereken son not ise; donanımsal olarak anakart ve ağ arayüzünüzün Wake-On-Lan özelliğinin aktif edilmiş olması gerektiğidir.

Ağ arayüzün özellikler ekranında Wake-On-Lan seçeneğinin aktif hale getirilmesi

   Windows yüklü sistemlerde bu ayar cihaz yöneticisi üzerinden ağ arayüzünüzün özellikleri diyaloguna gelerek bu diyalogda yer alan güç yönetimi sekmesinde "bu aygıt bilgisayarı başlatsın" seçeneği seçilerek yapılabilir.

Fatih Boy

http://www.enterprisecoding.com
http://twitter.com/fatihboy