C - Raw Sockets

Hallo zusammen,
ich habe mal ein wenig die Suchfunktion genutzt, aber nichts gefunden, was mir weiterhelfen konnte.
Sollte ich was übersehen haben, schlagt mich und gebt mir bitte den Link ;)

Ich dachte mir, nachdem ich mich ein wenig mit Sockets in Python und Java rumgeschlagen habe, schaue ich mir mal die Sockets in C an.

Dabei wollte ich mich erstmal auf die Raw Sockets konzentrieren.
OK, für einen Anfänger vielleicht nicht so gut (?), aber ich dachte mir: "nur wer wagt, gewinnt".
Außerdem sind die "normalen" Sockets vermutlich viel einfacher zu verstehen, wenn ich erstmal die Raw Sockets verstanden habe.

Ich guckte also ein wenig in "C von A bis Z" und fand eigentlich nichts.
Also bemühte ich Google und fand ein paar Beispielcodes, aber irgendwie sagte mir Xcode immer, dass irgendwas nicht richtig sei.

Nun habe ich versucht einen dieser Beispielcodes zu verstehen und so zu ändern, dass er hoffentlich läuft.
Ich habe dafür den Code hier verwendet von dieser Seite: LINK

Code:
// Includes
#include <stdio.h> // Standard I/O Funktionen wie printf()
#include <stdlib.h> // Standard Funktionen wie exit() und malloc()
#include <string.h> // String und Memory Funktionen wie strcmp() und memset()
#include <unistd.h> // System Calls wie open(), read() und write()
#include <errno.h> // Detailliertere Fehlermeldungen
#include <sys/socket.h> // Socket Funktionen wie socket(), bind() und listen()
#include <arpa/inet.h> // Funktionen wie inet_addr()
#include <netinet/in.h> // IP Protokolle, sockaddr_in Struktur und Funktionen wie htons()
#include <netinet/ip.h> // IP Header Struktur
#include <netinet/tcp.h> // TCP Header Struktur
// Main part
int main(void)
{
int rawsock, uid;
struct sockaddr_in addr;
unsigned int packetsize = sizeof(struct iphdr) + sizeof(struct tcphdr);
unsigned char packet[packetsize];
struct iphdr *ip = (struct iphdr *)packet;
struct tcphdr *tcp = (struct tcphdr *)(packet + sizeof(struct iphdr));
int one = 1;
// Are you root?
uid = getuid();
if(uid != 0) { printf("You must have UID 0 instead of %d.\n",uid); exit(1); }
// Packet Buffer initialisieren
memset(packet,0,packetsize);
// Erstelle einen IP RAW Socket Deskriptor
if( (rawsock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) == -1 ) { perror("socket"); exit(1); }
// IP_HDRINCL muss eingeschaltet sein, um sicher zu stellen, dass uns der Kernel nicht
// in den Headern rum fummelt
if( setsockopt(rawsock, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) == -1 ) { perror("setsockopt"); exit(1); }
// IP Header zusammen basteln
ip->version = 4; // IP Version
ip->ihl = 5; // Internet Header Length
ip->id = htonl(random()); // IP ID
ip->saddr = inet_addr("127.0.0.1"); // Source IP
ip->daddr = inet_addr("127.0.0.1"); // Destination IP
ip->ttl = 123; // Time to live
ip->protocol = IPPROTO_TCP; // Transport Protokoll TCP (6)
ip->tot_len = packetsize; // Groesse des IP Pakets
ip->check = 0; // IP Checksum (Wenn die Checksumme 0 ist, wird sie
// vom Kernel berechnet)
// TCP Header zusammen basteln
tcp->source = htons(1234); // Source Port
tcp->dest = htons(23); // Destination Port
tcp->seq = htonl(1000000000); // Sequence number
tcp->ack_seq = htonl(1000000000); // Acknowledgement number
tcp->ack = 1; // TCP Flags
tcp->syn = 1;
tcp->window = htons(1024); // Window size
tcp->check = 0; // TCP Checksum
// Schicke das Paket auf die Reise
addr.sin_family = AF_INET;
addr.sin_port = tcp->source;
addr.sin_addr.s_addr = ip->saddr;
if( (sendto(rawsock,packet,packetsize,0,(struct sockaddr*)&addr,sizeof(struct sockaddr_in))) == -1 )
{
perror("send");
exit(1);
}
// Raw Socket Deskriptor schliessen
close(rawsock);
return 0;
}

Da laut Xcode iphdr und tcphdr Probleme machten, habe ich mir netident/ip.h und netident/tcp.h angeschaut (ip.h & tcp.h) und den Code so umgeändert, wie ich die structs verstanden habe.
Dabei kam Folgendes raus:

Code:
#include <stdio.h> // Standard I/O Funktionen wie printf()
#include <stdlib.h> // Standard Funktionen wie exit() und malloc()
#include <string.h> // String und Memory Funktionen wie strcmp() und memset()
#include <unistd.h> // System Calls wie open(), read() und write()
#include <errno.h> // Detailliertere Fehlermeldungen
#include <sys/socket.h> // Socket Funktionen wie socket(), bind() und listen()
#include <arpa/inet.h> // Funktionen wie inet_addr()
#include <netinet/in.h> // IP Protokolle, sockaddr_in Struktur und Funktionen wie htons()
#include <netinet/ip.h> // IP Header Struktur
#include <netinet/tcp.h> // TCP Header Struktur
// Main part
int main(void)
{
    int rawsock, uid;
    struct sockaddr_in addr;
    unsigned int packetsize = sizeof(struct ip) + sizeof(struct tcphdr);
    unsigned char packet[packetsize];
    struct ip *ip = (struct ip *)packet;
    struct tcphdr *tcp = (struct tcphdr *)(packet + sizeof(struct ip));
    int one = 1;
    // Are you root?
    uid = getuid();
    if(uid != 0) { printf("You must have UID 0 instead of %d.\n",uid); exit(1); }
    // Packet Buffer initialisieren
    memset(packet,0,packetsize);
    // Erstelle einen IP RAW Socket Deskriptor
    if( (rawsock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) == -1 ) { perror("socket"); exit(1); }
    // IP_HDRINCL muss eingeschaltet sein, um sicher zu stellen, dass uns der Kernel nicht
    // in den Headern rum fummelt
    if( setsockopt(rawsock, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) == -1 ) { perror("setsockopt"); exit(1); }
    
    // IP Header zusammen basteln
    ip->ip_v = 4; // IP Version
    ip->ip_hl = 5; // Internet Header Length
    ip->ip_id = htonl(random()); // IP ID
    ip->ip_src = inet_addr("127.0.0.1"); // Source IP
    ip->ip_dst = inet_addr("127.0.0.1"); // Destination IP
    ip->ip_ttl = 123; // Time to live
    ip->ip_p = IPPROTO_TCP; // Transport Protokoll TCP (6)
    ip->ip_len = packetsize; // Groesse des IP Pakets
    ip->ip_sum = 0; // IP Checksum (Wenn die Checksumme 0 ist, wird sie
    // vom Kernel berechnet)
    // TCP Header zusammen basteln
    tcp->th_sport = htons(1234); // Source Port
    tcp->th_dport = htons(80); // Destination Port
    tcp->th_seq = htonl(1000000000); // Sequence number
    tcp->th_ack = htonl(1000000000); // Acknowledgement number
    tcp->th_flags = 0x02; // TCP Flags
    tcp->th_win = htons(1024); // Window size
    tcp->th_sum = 0; // TCP Checksum
    // Schicke das Paket auf die Reise
    addr.sin_family = AF_INET;
    addr.sin_port = tcp->th_sport;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    if( (sendto(rawsock,packet,packetsize,0,(struct sockaddr*)&addr,sizeof(struct sockaddr_in))) == -1 )
    {
        perror("send");
        exit(1);
    }
    // Raw Socket Deskriptor schliessen
    close(rawsock);
    return 0;
}

Probleme machen nun nur noch diese zwei Zeilen hier:
Code:
    ip->ip_src = inet_addr("127.0.0.1"); // Source IP
    ip->ip_dst = inet_addr("127.0.0.1"); // Destination IP

Wenn ich das Problem richtig verstehe erwartet ip->ip_src ein struct in_addr und inet_addr() liefert ein struct in_addr_t.

Ungefähr eine Stunde googlen habe ich inzwischen fast alle Funktionen inet_* und andere ausprobiert und versucht irgendwie in_addr_t zu in_addr umzuwandeln. Wie dieser Thread beweist ohne Erfolg.

Was mache ich falsch?
Hat vielleicht jemand aus eigenen Spielereien und/oder Versuchen einen Beispielcode für Raw Sockets, den er oder sie mir zeigen könnte?
Mein Übungsziel war eigentlich das ganze so weit zu treiben, dass ich ein HTTP GET Request an meinen Webserver schicken und die Website empfangen kann.
Anscheinend bin ich davon wohl noch sehr, sehr weit entfernt.

Vielen Dank schonmal im Voraus und viele Grüße
Liaf

Update:
OK, ich muss ein kleines Update machen, da mich gerade jemand auf einen Fehler hingewiesen hat.

netinet/ip.h und netinet/tcp.h sind in Linux anders, als in BSD und OSX.
In Linux gibt es ein iphdr, welches bei BSD ip heißt usw.

Ich habe nun BSD-Beispiele gefunden, die beim ersten Kompilier-Versuch auch Fehler melden. Ich versuche das ganze mal weiter zu verstehen.
Sollte hier jemandem ein schönes Beispiel über den Weg laufen, oder jemand einen Hinweis haben, der mir helfen könnte, bin ich weiterhin für Meldungen dankbar
 
Zuletzt bearbeitet von einem Moderator:
Also erstmal sehe ich keinen Pseudoheader in deinem Code und afaik (ist ein paar Tage her) musst du auch die ip_Chksum korrekt bauen (bei nicht-raw socks uebernimmt das der kernel).

Dafür (checksum) findest Du im Netz reichlich beispiel code (ist immer das gleiche).

Hier gibts noch raw-sockets fuer BSDs: IP SPOOFING with BSD RAW SOCKETS INTERFACE

Und wenn Du nach socket Literatur für Männer suchst, dann kommst Du an _dem_ Stevens nicht vorbei ;)

Solltest vielleicht doch erst mit "normalen" sockets starten. Portscanner sind immer eine super Uebung. Und spiele mit den socket options rum und sniffe fleissig mit, damit du auch verstehst, was da eigentlich passiert.
 
Danke für Eure Antworten.

@Chromatin:
Den Link habe ich auch gefunden und mal geguckt, ob die Beispiele bei mir laufen.
ICMP meldet einen Error im sendto und zwar "Invalid argument".
Das UDP Beispiel funktioniert und konnte ich im Wireshark auch nochmals nachgucken.
Das TCP Beispiel schaue ich mir morgen nochmals an, da Xcode da einiges dran bemängelt und ich den Code ja auch erst mal oberflächlich verstehen möchte bevor ich den ausführe ;)

Ich stehe vermutlich etwas auf dem Schlauch, aber ich kann "_dem_ Stevens" gerade nicht zuordnen. Wen meinst Du?

@+++ATH0:
Zu in_addr habe ich spontan das hier gefunden: unsigned long

Zu in_addr_t: uint32_t

Ich gebe zu, ich habe mir nur die ersten Treffer bei Google angeguckt. Ich schau eventuell morgen nochmals genauer, aber wenn das schon der von Dir gemeinte Unterschied ist, dann sag mir doch bitte kurz Bescheid :)
 
Code:
typedef __uint32_t      in_addr_t; 

struct in_addr {
        in_addr_t s_addr;
};

Nun bin ich verwirrt.

Also, ich habe mir nun den Code zum TCP IP Spoofing angeschaut.
Ich denke mal die Funktionen für Syn und Ack, sowie run sind mehr oder weniger selbsterklärend
Allerdings wundert mich, dass z.B. send_syn das Socket sd übergeben wird, wenn send_syn keine Argumente erwartet.

raw_packet_receiver glaube ich auch zu verstehen.

Bei pth_capture_run hat Xcode abet eine ganze Menge zu bemängeln und irgendwie verstehe ich noch nicht, wie ich diese "Fehler" (?) beheben muss.
Hat den Code mal irgendwer hier getestet und kann mir sagen, ob ich einfach zu doof zum kompilieren bin?
 
Zurück
Oben