C Socket Programlama! (Rootkit Eğitimi #2) (Linux)

Bunjo

Uzman üye
14 Ara 2020
1,581
1,875
HTTParty
oqk18ir.png


lbn20fm.png
2q250vr.png


Merhabalar ben saldırı timlerinden Bunjo. Rootkit eğitiminde ihtiyaç duyacağımız socket programlama için bu konuyu hazırladım.
Bu konu daha önce programlama bilgisine sahip olanlar için açılmıştır.
Socket ile alakalı daha önce bir anlatımım olduğu için tekrardan bahsetmiyorum. Konu İçin Tıkla!




C Kodu Linux Sistemlerde Nasıl Derlenir?

Windows için Visual Studio kurarak kod yazmak için gerekli ortamı sağlayabilirsiniz.

İlk olarak C için derleyici yüklü değilse aşağıda verdiğim kodu terminal içerisinde çalıştırın, eğer root kullanıcısı değilseniz komutun başına "sudo" ekleyebilirsiniz.

Bash:
apt install gcc

89wgvdr.png


Derleyici aşaması hallolduğuna göre şimdi de örnek bir C programlama dili dosyası içeriğine sahip bir dosya oluşturalım.

23mri4h.png


Oluşturmuş bulunduğumuz bu dosyayı yüklediğimiz derleyici ile -o parametresi kullanıp derleme sonucunda oluşacak dosya ismini verdikten sonra derleyip çalıştıralım.

49cizpr.png




Socket Programlama Aşaması

Bu aşama size kolay gelmeyeceği için basit örneklerle anlatımıma devam edeceğim. Bu konu dahilinde ilk olarak "TCP" protokülünü kullanan bir sunucu kodlayacağız.
Anlamda bir eksiklik olmaması için kullanılan aynı kodları bir önce geçtiği yazıdan kopyalayarak tekrardan bir ekleme yaptım.


C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#include <stdio.h>: Standart giriş/çıkış işlevleri için gerekli olan tanımlamaları ve prototipleri içerir. printf, scanf, fprintf gibi standart giriş/çıkış işlevlerini kullanabilmek için dahil edilir

#include <stdlib.h>: Genel amaçlı işlevlerin (malloc, free, exit gibi) tanımlamalarını ve prototiplerini içerir. Bellek yönetimi ve program sonlandırma işlemleri gibi genel işlevleri kullanmak için dahil edilir.

#include <string.h>: Karakter dizileri ile çalışan işlevlerin (strlen, strcpy, strcmp gibi) tanımlamalarını ve prototiplerini içerir. Karakter dizileri üzerinde işlemler yapabilmek için dahil edilir.

#include <unistd.h>: UNIX sistem çağrıları ve genel sistem fonksiyonlarının tanımlamalarını ve prototiplerini içerir. Özellikle dosya işlemleri, çeşitli I/O işlemleri ve sistem çağrıları gibi işlevleri kullanmak için dahil edilir.

#include <arpa/inet.h>: Ağ programlamasıyla ilgili olan tanımlamaları ve prototipleri içerir.

Socket için kullanılacak port ve alınabilecek maksimum verinin byte olarak karşılığını sabitler kullanarak tanımlayalım.


C:
#define PORT 7575
#define MAX_BUFFER_SIZE 1024

#define PORT 7575: Bu sabit, PORT adında bir sembolik ad (symbolic name) tanımlar ve ona 7575 değerini atar. Bu durumda, program içinde PORT kullanıldığında, bu sembolik ad 7575 ile değiştirilecektir. Genellikle, bu tür sembolik adlar, program içinde sabit bir değeri ifade etmek için kullanılır. Bu örnekte, PORT sembolik adı, kullanılan port numarasını temsil eder.

#define MAX_BUFFER_SIZE 1024: Bu sabit, MAX_BUFFER_SIZE adında bir sembolik ad tanımlar ve ona 1024 değerini atar. Bu durumda, program içinde MAX_BUFFER_SIZE kullanıldığında, bu sembolik ad 1024 ile değiştirilecektir. Bu sembolik ad, genellikle programda kullanılacak bir tamponun maksimum boyutunu temsil eder. Bu örnekte, MAX_BUFFER_SIZE, 1024 bayt (veya karakter) büyüklüğündeki bir tamponu ifade eder.

Şimdi ise socket oluşturma kısmı için main fonksiyonunu oluşturalım.


C:
int main() {
    
}

Kodlarımızı bu oluşturmuş olduğumuz main fonksiyonu içerisine yazacağız.

C:
 int server_socket, client_socket;

Socket versinin saklanacağı değişkenleri oluşturduk.



C:
struct sockaddr_in server_address, client_address;
socklen_t client_address_len = sizeof(client_address);
char buffer[MAX_BUFFER_SIZE];


"struct sockaddr_in server_address, client_address;": İki adet adres yapısı tanımlar. server_address, sunucunun dinlediği adres ve portu içerir. client_address, istemcinin bağlanacağı adres ve portu içerir.


"socklen_t client_address_len = sizeof(client_address);" İstemciden alınacak adres bilgisinin boyutunu belirleyen bir değişken tanımlar.


C:
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket oluşturulamadı");
        exit(EXIT_FAILURE);
}


Burada da socketin oluşturulup oluşturulmadığı kontrol ediliyor ve eğer hata varsa gerekli çıktı ekrana bastırılıp program kapatılıyor, eğer socket oluşturulamazsa -1 değeri döner.


C:
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(PORT);


"server_address.sin_family = AF_INET;": server_address yapısını sin_family üyesine, soket adresinin ailesini belirten değeri atar. AF_INET sabiti, IPv4 adresleme ailesini temsil eder. Yani, bu sunucu IPv4 adresleme ailesini kullanacaktır.

"server_address.sin_addr.s_addr = INADDR_ANY;": server_address yapısını sin_addr.s_addr üyesine, sunucunun dinleme yapacağı IP adresini atar. INADDR_ANY sabiti, sunucunun tüm mevcut ağ arabirimleri üzerinden gelen bağlantıları dinlemesini ifade eder. Yani, sunucu tüm mevcut IP adresleri üzerinden bağlantıları kabul eder.

"server_address.sin_port = htons(PORT);": Bu satır, server_address yapısını sin_port üyesine, sunucunun hangi port numarasını dinleyeceğini atar. htons fonksiyonu, host byte order'ı (endianness uyumlu sıralama) network byte order'a dönüştürür. PORT değişkeni, sunucunun dinleyeceği port numarasını içerir.

Oluşturmuş olduğumuz socket değerini bir adres ile ilişkilendirelim.


C:
if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {
        perror("Bind hatası");
        exit(EXIT_FAILURE);
}

bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)): Bahsettiğim adres ilişkilendirmesi için bind fonksiyonu çağrılır. Bu fonksiyon, üç parametre alır:

server_socket: Bind işleminin gerçekleştirileceği soketin dosya tanımlayıcısı.
(struct sockaddr *)&server_address: Bağlantı kurulacak adres bilgisini içeren bir struct sockaddr tipinden tür dönüşümü ile ifade edilen bir işaretçi.
sizeof(server_address): server_address yapısının boyutu.

== -1: Eşitlik karşılaştırması ile kontrol edilir. Eğer bind fonksiyonu başarısız olursa, -1 değeri döner.

perror("Bind hatası");: Eğer bind fonksiyonu başarısız olursa, perror fonksiyonu, bir hata mesajı ve errno değerini (hata numarası) standart hata akışına yazar. Bu durumda, "Bind hatası" mesajı ve ilgili hata mesajı ekrana yazılır.

exit(EXIT_FAILURE);: Program, bind işlemi başarısız olursa, EXIT_FAILURE sabit değeri ile birlikte sonlandırılır. EXIT_FAILURE genellikle stdlib.h başlığında tanımlanmış bir sabittir ve programın başarısız bir şekilde sonlandığını belirtir.


C:
if (listen(server_socket, 5) == -1) {
        perror("Listen hatası");
        exit(EXIT_FAILURE);
}

printf("Sunucu başlatıldı. Bağlantı bekleniyor...\n");

if (listen(server_socket, 5) == -1): Bu satırda, listen fonksiyonu çağrılır ve bağlantıları dinlemeye başlaması için sunucu soketi ile ilişkilendirilir. listen fonksiyonunun iki parametresi:
server_socket: Bağlantıları dinlemeye başlamak istediğimiz soketin dosya tanımlayıcısı.

5: Bağlantı sırasını (backlog) belirten bir sayıdır. Bu sayı, eğer sunucu aynı anda çok sayıda istemciden bağlantı kabul edemezse bekleyen bağlantıların sayısını temsil eder.

Eğer listen fonksiyonu başarısız olursa (-1 dönerse), perror fonksiyonu ile bir hata mesajı ve errno değeri (hata numarası) ekrana yazılır. Daha sonra exit(EXIT_FAILURE) fonksiyonu çağrılarak program başarısız bir şekilde sonlandırılır.

printf("Sunucu başlatıldı. Bağlantı bekleniyor...\n");: Eğer listen fonksiyonu başarılı bir şekilde çalışırsa, bu satırda ekrana bir bilgi mesajı yazılır. Mesaj, "Sunucu başlatıldı. Bağlantı bekleniyor..." şeklinde sunucunun başlatıldığını ve bağlantılar beklemeye başlandığını bildirir.


C:
while (1) {
        if ((client_socket = accept(server_socket, (struct sockaddr *)&client_address, &client_address_len)) == -1) {
            perror("Bağlantı kabul edilemedi");
            continue;
        }

        printf("Bağlantı kabul edildi: %s\n", inet_ntoa(client_address.sin_addr));

        ssize_t bytes_received;
        while ((bytes_received = recv(client_socket, buffer, MAX_BUFFER_SIZE - 1, 0)) > 0) {
            buffer[bytes_received] = '\0';
            printf("Gelen veri: %s\n", buffer);
            send(client_socket, buffer, strlen(buffer), 0);
        }

        close(client_socket);
        printf("Bağlantı kapatıldı\n");
    }

    close(server_socket);

    return 0;
}


while (1): Bu, sonsuz bir döngüyü temsil eder. Sunucu, bağlantıları sürekli olarak dinlemeye ve işlemeye devam eder.

if ((client_socket = accept(server_socket, (struct sockaddr *)&client_address, &client_address_len)) == -1): accept fonksiyonu kullanılarak yeni bir istemci bağlantısı kabul edilir. İstemci bağlantısı başarılı bir şekilde kabul edilirse, client_socket değişkenine atanır. Eğer bağlantı kabul işlemi başarısız olursa (dönen değer -1 ise), perror fonksiyonu ile bir hata mesajı ve errno değeri (hata numarası) ekrana yazılır. Daha sonra continue; ifadesi ile döngünün başına gidilir ve bir sonraki bağlantı beklendiğinde bu işlemler tekrarlanır.

printf("Bağlantı kabul edildi: %s\n", inet_ntoa(client_address.sin_addr));: Eğer bağlantı kabul işlemi başarılı olursa, istemcinin IP adresi ekrana yazılır. inet_ntoa fonksiyonu, struct in_addr türündeki bir IP adresini insan tarafından okunabilir bir formata dönüştürür.

ssize_t bytes_received;: Bu satırda, alınan verinin boyutunu saklamak için bir değişken tanımlanır.

while ((bytes_received = recv(client_socket, buffer, MAX_BUFFER_SIZE - 1, 0)) > 0): Bu iç içe geçmiş while döngüsü, istemciden gelen verileri sürekli olarak alır. recv fonksiyonu ile veri alındıkça, bu veri buffer dizisine yerleştirilir. Alınan veri boyutu bytes_received değişkenine atanır. Eğer recv fonksiyonu 0'dan büyük bir değer dönerse (istemci tarafından bağlantı kapatılmamışsa), içerdeki döngü devam eder.

buffer[bytes_received] = '\0';: Alınan veriyi bir C-string haline getirmek için, '\0' (null) karakteri ile bitirilir.

printf("Gelen veri: %s\n", buffer);: Alınan veri ekrana yazılır.

send(client_socket, buffer, strlen(buffer), 0);: Alınan veriyi geri göndermek için send fonksiyonu kullanılır.

close(client_socket);: İstemci bağlantısı kapatılır.

printf("Bağlantı kapatıldı\n");: İstemci bağlantısının kapatıldığını bildiren bir mesaj ekrana yazılır.

close(server_socket);: Ana döngüden çıkıldığında, sunucu soketi de kapatılır.

return 0;: Program normal bir şekilde sonlanır.

Tüm Kod:


C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 7575
#define MAX_BUFFER_SIZE 1024

int main() {
    int server_socket, client_socket;
    struct sockaddr_in server_address, client_address;
    socklen_t client_address_len = sizeof(client_address);
    char buffer[MAX_BUFFER_SIZE];

    if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket oluşturulamadı");
        exit(EXIT_FAILURE);
    }

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = INADDR_ANY;
    server_address.sin_port = htons(PORT);

    if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {
        perror("Bind hatası");
        exit(EXIT_FAILURE);
    }

    if (listen(server_socket, 5) == -1) {
        perror("Listen hatası");
        exit(EXIT_FAILURE);
    }

    printf("Sunucu başlatıldı. Bağlantı bekleniyor...\n");

    while (1) {
        if ((client_socket = accept(server_socket, (struct sockaddr *)&client_address, &client_address_len)) == -1) {
            perror("Bağlantı kabul edilemedi");
            continue;
        }

        printf("Bağlantı kabul edildi: %s\n", inet_ntoa(client_address.sin_addr));

        ssize_t bytes_received;
        while ((bytes_received = recv(client_socket, buffer, MAX_BUFFER_SIZE - 1, 0)) > 0) {
            buffer[bytes_received] = '\0';
            printf("Gelen veri: %s\n", buffer);
            send(client_socket, buffer, strlen(buffer), 0);
        }

        close(client_socket);
        printf("Bağlantı kapatıldı\n");
    }

    close(server_socket);

    return 0;
}

Belki size karışık gelmiş olabilir ama anlatabileceğim en iyi anlatım şeklinde anlatmaya çalıştım.


Sunucunun Başlatılması

Yazmış olduğumuz sunucu kodlarını bir dosya halinde toplayıp kayıt edelim.

chcsgjm.png



Yeni konularda daha fazla detaylara değineceğim

Konuyu okuyan herkese teşekkür ederim.
 

Butcherb3y

Uzman üye
1 Eyl 2022
1,533
1,140
Anıtkabir
oqk18ir.png


lbn20fm.png
2q250vr.png


Merhabalar ben saldırı timlerinden Bunjo. Rootkit eğitiminde ihtiyaç duyacağımız socket programlama için bu konuyu hazırladım.
Bu konu daha önce programlama bilgisine sahip olanlar için açılmıştır.
Socket ile alakalı daha önce bir anlatımım olduğu için tekrardan bahsetmiyorum. Konu İçin Tıkla!




C Kodu Linux Sistemlerde Nasıl Derlenir?

Windows için Visual Studio kurarak kod yazmak için gerekli ortamı sağlayabilirsiniz.

İlk olarak C için derleyici yüklü değilse aşağıda verdiğim kodu terminal içerisinde çalıştırın, eğer root kullanıcısı değilseniz komutun başına "sudo" ekleyebilirsiniz.

Bash:
apt install gcc

89wgvdr.png


Derleyici aşaması hallolduğuna göre şimdi de örnek bir C programlama dili dosyası içeriğine sahip bir dosya oluşturalım.

23mri4h.png


Oluşturmuş bulunduğumuz bu dosyayı yüklediğimiz derleyici ile -o parametresi kullanıp derleme sonucunda oluşacak dosya ismini verdikten sonra derleyip çalıştıralım.

49cizpr.png




Socket Programlama Aşaması

Bu aşama size kolay gelmeyeceği için basit örneklerle anlatımıma devam edeceğim. Bu konu dahilinde ilk olarak "TCP" protokülünü kullanan bir sunucu kodlayacağız.
Anlamda bir eksiklik olmaması için kullanılan aynı kodları bir önce geçtiği yazıdan kopyalayarak tekrardan bir ekleme yaptım.


C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#include <stdio.h>: Standart giriş/çıkış işlevleri için gerekli olan tanımlamaları ve prototipleri içerir. printf, scanf, fprintf gibi standart giriş/çıkış işlevlerini kullanabilmek için dahil edilir

#include <stdlib.h>: Genel amaçlı işlevlerin (malloc, free, exit gibi) tanımlamalarını ve prototiplerini içerir. Bellek yönetimi ve program sonlandırma işlemleri gibi genel işlevleri kullanmak için dahil edilir.

#include <string.h>: Karakter dizileri ile çalışan işlevlerin (strlen, strcpy, strcmp gibi) tanımlamalarını ve prototiplerini içerir. Karakter dizileri üzerinde işlemler yapabilmek için dahil edilir.

#include <unistd.h>: UNIX sistem çağrıları ve genel sistem fonksiyonlarının tanımlamalarını ve prototiplerini içerir. Özellikle dosya işlemleri, çeşitli I/O işlemleri ve sistem çağrıları gibi işlevleri kullanmak için dahil edilir.

#include <arpa/inet.h>: Ağ programlamasıyla ilgili olan tanımlamaları ve prototipleri içerir.

Socket için kullanılacak port ve alınabilecek maksimum verinin byte olarak karşılığını sabitler kullanarak tanımlayalım.


C:
#define PORT 7575
#define MAX_BUFFER_SIZE 1024

#define PORT 7575: Bu sabit, PORT adında bir sembolik ad (symbolic name) tanımlar ve ona 7575 değerini atar. Bu durumda, program içinde PORT kullanıldığında, bu sembolik ad 7575 ile değiştirilecektir. Genellikle, bu tür sembolik adlar, program içinde sabit bir değeri ifade etmek için kullanılır. Bu örnekte, PORT sembolik adı, kullanılan port numarasını temsil eder.

#define MAX_BUFFER_SIZE 1024: Bu sabit, MAX_BUFFER_SIZE adında bir sembolik ad tanımlar ve ona 1024 değerini atar. Bu durumda, program içinde MAX_BUFFER_SIZE kullanıldığında, bu sembolik ad 1024 ile değiştirilecektir. Bu sembolik ad, genellikle programda kullanılacak bir tamponun maksimum boyutunu temsil eder. Bu örnekte, MAX_BUFFER_SIZE, 1024 bayt (veya karakter) büyüklüğündeki bir tamponu ifade eder.

Şimdi ise socket oluşturma kısmı için main fonksiyonunu oluşturalım.


C:
int main() {
   
}

Kodlarımızı bu oluşturmuş olduğumuz main fonksiyonu içerisine yazacağız.

C:
 int server_socket, client_socket;

Socket versinin saklanacağı değişkenleri oluşturduk.



C:
struct sockaddr_in server_address, client_address;
socklen_t client_address_len = sizeof(client_address);
char buffer[MAX_BUFFER_SIZE];


"struct sockaddr_in server_address, client_address;": İki adet adres yapısı tanımlar. server_address, sunucunun dinlediği adres ve portu içerir. client_address, istemcinin bağlanacağı adres ve portu içerir.


"socklen_t client_address_len = sizeof(client_address);" İstemciden alınacak adres bilgisinin boyutunu belirleyen bir değişken tanımlar.


C:
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket oluşturulamadı");
        exit(EXIT_FAILURE);
}


Burada da socketin oluşturulup oluşturulmadığı kontrol ediliyor ve eğer hata varsa gerekli çıktı ekrana bastırılıp program kapatılıyor, eğer socket oluşturulamazsa -1 değeri döner.


C:
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(PORT);


"server_address.sin_family = AF_INET;": server_address yapısını sin_family üyesine, soket adresinin ailesini belirten değeri atar. AF_INET sabiti, IPv4 adresleme ailesini temsil eder. Yani, bu sunucu IPv4 adresleme ailesini kullanacaktır.

"server_address.sin_addr.s_addr = INADDR_ANY;": server_address yapısını sin_addr.s_addr üyesine, sunucunun dinleme yapacağı IP adresini atar. INADDR_ANY sabiti, sunucunun tüm mevcut ağ arabirimleri üzerinden gelen bağlantıları dinlemesini ifade eder. Yani, sunucu tüm mevcut IP adresleri üzerinden bağlantıları kabul eder.

"server_address.sin_port = htons(PORT);": Bu satır, server_address yapısını sin_port üyesine, sunucunun hangi port numarasını dinleyeceğini atar. htons fonksiyonu, host byte order'ı (endianness uyumlu sıralama) network byte order'a dönüştürür. PORT değişkeni, sunucunun dinleyeceği port numarasını içerir.

Oluşturmuş olduğumuz socket değerini bir adres ile ilişkilendirelim.


C:
if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {
        perror("Bind hatası");
        exit(EXIT_FAILURE);
}

bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)): Bahsettiğim adres ilişkilendirmesi için bind fonksiyonu çağrılır. Bu fonksiyon, üç parametre alır:

server_socket: Bind işleminin gerçekleştirileceği soketin dosya tanımlayıcısı.
(struct sockaddr *)&server_address: Bağlantı kurulacak adres bilgisini içeren bir struct sockaddr tipinden tür dönüşümü ile ifade edilen bir işaretçi.
sizeof(server_address): server_address yapısının boyutu.

== -1: Eşitlik karşılaştırması ile kontrol edilir. Eğer bind fonksiyonu başarısız olursa, -1 değeri döner.

perror("Bind hatası");: Eğer bind fonksiyonu başarısız olursa, perror fonksiyonu, bir hata mesajı ve errno değerini (hata numarası) standart hata akışına yazar. Bu durumda, "Bind hatası" mesajı ve ilgili hata mesajı ekrana yazılır.

exit(EXIT_FAILURE);: Program, bind işlemi başarısız olursa, EXIT_FAILURE sabit değeri ile birlikte sonlandırılır. EXIT_FAILURE genellikle stdlib.h başlığında tanımlanmış bir sabittir ve programın başarısız bir şekilde sonlandığını belirtir.


C:
if (listen(server_socket, 5) == -1) {
        perror("Listen hatası");
        exit(EXIT_FAILURE);
}

printf("Sunucu başlatıldı. Bağlantı bekleniyor...\n");

if (listen(server_socket, 5) == -1): Bu satırda, listen fonksiyonu çağrılır ve bağlantıları dinlemeye başlaması için sunucu soketi ile ilişkilendirilir. listen fonksiyonunun iki parametresi:
server_socket: Bağlantıları dinlemeye başlamak istediğimiz soketin dosya tanımlayıcısı.

5: Bağlantı sırasını (backlog) belirten bir sayıdır. Bu sayı, eğer sunucu aynı anda çok sayıda istemciden bağlantı kabul edemezse bekleyen bağlantıların sayısını temsil eder.

Eğer listen fonksiyonu başarısız olursa (-1 dönerse), perror fonksiyonu ile bir hata mesajı ve errno değeri (hata numarası) ekrana yazılır. Daha sonra exit(EXIT_FAILURE) fonksiyonu çağrılarak program başarısız bir şekilde sonlandırılır.


printf("Sunucu başlatıldı. Bağlantı bekleniyor...\n");: Eğer listen fonksiyonu başarılı bir şekilde çalışırsa, bu satırda ekrana bir bilgi mesajı yazılır. Mesaj, "Sunucu başlatıldı. Bağlantı bekleniyor..." şeklinde sunucunun başlatıldığını ve bağlantılar beklemeye başlandığını bildirir.


C:
while (1) {
        if ((client_socket = accept(server_socket, (struct sockaddr *)&client_address, &client_address_len)) == -1) {
            perror("Bağlantı kabul edilemedi");
            continue;
        }

        printf("Bağlantı kabul edildi: %s\n", inet_ntoa(client_address.sin_addr));

        ssize_t bytes_received;
        while ((bytes_received = recv(client_socket, buffer, MAX_BUFFER_SIZE - 1, 0)) > 0) {
            buffer[bytes_received] = '\0';
            printf("Gelen veri: %s\n", buffer);
            send(client_socket, buffer, strlen(buffer), 0);
        }

        close(client_socket);
        printf("Bağlantı kapatıldı\n");
    }

    close(server_socket);

    return 0;
}


while (1): Bu, sonsuz bir döngüyü temsil eder. Sunucu, bağlantıları sürekli olarak dinlemeye ve işlemeye devam eder.

if ((client_socket = accept(server_socket, (struct sockaddr *)&client_address, &client_address_len)) == -1): accept fonksiyonu kullanılarak yeni bir istemci bağlantısı kabul edilir. İstemci bağlantısı başarılı bir şekilde kabul edilirse, client_socket değişkenine atanır. Eğer bağlantı kabul işlemi başarısız olursa (dönen değer -1 ise), perror fonksiyonu ile bir hata mesajı ve errno değeri (hata numarası) ekrana yazılır. Daha sonra continue; ifadesi ile döngünün başına gidilir ve bir sonraki bağlantı beklendiğinde bu işlemler tekrarlanır.


printf("Bağlantı kabul edildi: %s\n", inet_ntoa(client_address.sin_addr));: Eğer bağlantı kabul işlemi başarılı olursa, istemcinin IP adresi ekrana yazılır. inet_ntoa fonksiyonu, struct in_addr türündeki bir IP adresini insan tarafından okunabilir bir formata dönüştürür.

ssize_t bytes_received;: Bu satırda, alınan verinin boyutunu saklamak için bir değişken tanımlanır.

while ((bytes_received = recv(client_socket, buffer, MAX_BUFFER_SIZE - 1, 0)) > 0): Bu iç içe geçmiş while döngüsü, istemciden gelen verileri sürekli olarak alır. recv fonksiyonu ile veri alındıkça, bu veri buffer dizisine yerleştirilir. Alınan veri boyutu bytes_received değişkenine atanır. Eğer recv fonksiyonu 0'dan büyük bir değer dönerse (istemci tarafından bağlantı kapatılmamışsa), içerdeki döngü devam eder.

buffer[bytes_received] = '\0';: Alınan veriyi bir C-string haline getirmek için, '\0' (null) karakteri ile bitirilir.

printf("Gelen veri: %s\n", buffer);: Alınan veri ekrana yazılır.

send(client_socket, buffer, strlen(buffer), 0);: Alınan veriyi geri göndermek için send fonksiyonu kullanılır.

close(client_socket);: İstemci bağlantısı kapatılır.

printf("Bağlantı kapatıldı\n");: İstemci bağlantısının kapatıldığını bildiren bir mesaj ekrana yazılır.

close(server_socket);: Ana döngüden çıkıldığında, sunucu soketi de kapatılır.

return 0;: Program normal bir şekilde sonlanır.

Tüm Kod:


C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 7575
#define MAX_BUFFER_SIZE 1024

int main() {
    int server_socket, client_socket;
    struct sockaddr_in server_address, client_address;
    socklen_t client_address_len = sizeof(client_address);
    char buffer[MAX_BUFFER_SIZE];

    if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket oluşturulamadı");
        exit(EXIT_FAILURE);
    }

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = INADDR_ANY;
    server_address.sin_port = htons(PORT);

    if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {
        perror("Bind hatası");
        exit(EXIT_FAILURE);
    }

    if (listen(server_socket, 5) == -1) {
        perror("Listen hatası");
        exit(EXIT_FAILURE);
    }

    printf("Sunucu başlatıldı. Bağlantı bekleniyor...\n");

    while (1) {
        if ((client_socket = accept(server_socket, (struct sockaddr *)&client_address, &client_address_len)) == -1) {
            perror("Bağlantı kabul edilemedi");
            continue;
        }

        printf("Bağlantı kabul edildi: %s\n", inet_ntoa(client_address.sin_addr));

        ssize_t bytes_received;
        while ((bytes_received = recv(client_socket, buffer, MAX_BUFFER_SIZE - 1, 0)) > 0) {
            buffer[bytes_received] = '\0';
            printf("Gelen veri: %s\n", buffer);
            send(client_socket, buffer, strlen(buffer), 0);
        }

        close(client_socket);
        printf("Bağlantı kapatıldı\n");
    }

    close(server_socket);

    return 0;
}

Belki size karışık gelmiş olabilir ama anlatabileceğim en iyi anlatım şeklinde anlatmaya çalıştım.


Sunucunun Başlatılması

Yazmış olduğumuz sunucu kodlarını bir dosya halinde toplayıp kayıt edelim.

chcsgjm.png



Yeni konularda daha fazla detaylara değineceğim

Konuyu okuyan herkese teşekkür ederim.
Elinize sağlık bunjom süper içinden gecmissin
 

Bunjo

Uzman üye
14 Ara 2020
1,581
1,875
HTTParty

ZuL-RaA

Kadim Üye
9 Ara 2017
5,552
839
Semerkant
Konu gayet hoş görünümlü olmuş.
İçeriği de keza öyle.

Tek tek derlemek benim sevdiğim bir olay olmasa da biraz lazım gibi görünüyor. Açıklamalar da net olmuş. Elinize sağlık.
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.