Verständnisprobleme Strukturen und Raw Sockets
-
Hallo,
ich programmiere noch nicht sehr lange C unter Linux.
Seit kurzem beschäftige ich mich mit Sockets und Raw Sockets. Ich lese das Tutorial zu Raw Sockets von Mixter bzw.das Tutorial von zotteljedi.de .
Seht euch doch bitte mal folgenden Code an.#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>int main(int argc, char *argv[])
{
int s, bytes;
char buffer[1024], *data;
struct iphdr *ip;
// ^^^ Zeiger auf die Struktur iphdr, definiert in netinet/ip.h
struct udphdr *udp;
// ^^^ Zeiger auf die Struktur definiert in netinet/udp.h
struct in_addr addr;s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (s == -1)
{
perror("socket() failed");
return 1;
}if( (bytes = recv(s, buffer, sizeof(buffer), 0)) == -1)
{
perror("recv() failed");
return 2;
}ip = (struct iphdr*) buffer;
//Kann mir jemand die Zeile erklären?
//Normalerweise muss von iphdr eine Instanz erstellt werden
//auf die ip dann zeigt. Wird hier buffer als Instanz verwendet und
//liefert das einen Zeiger zurück der in ip gespeichert wird?udp = (struct udphdr*) (buffer + sizeof(struct iphdr));
// Das gleiche hier. Kann mir jemand diese Zeile erklären?data = buffer + sizeof(struct iphdr) + sizeof(struct udphdr);
//Und was soll diese Zeile?buffer[bytes] = '\0';
printf("%i Bytes empfangen\n", bytes);
printf("Time To Live: %i\n", ip->ttl);
addr.s_addr = ip->saddr;
printf("Absender: %s\n", inet_ntoa(addr));
addr.s_addr = ip->daddr;
printf("Empfanger: %s\n", inet_ntoa(addr));
printf("Quellport: %i\n", ntohs(udp->source));
printf("Zielport: %i\n", ntohs(udp->dest));
printf("Lange der Nutzlast: %i Bytes\n", ntohs(udp->len) - sizeof(struct udphdr));return 0;
}Danke für eure Hilfe,
an0nym
-
//Normalerweise muss von iphdr eine Instanz erstellt werden
//auf die ip dann zeigt. Wird hier buffer als Instanz verwendet und
//liefert das einen Zeiger zurück der in ip gespeichert wird?nein, buffer ist ja eigentlich ein Zeiger auf ein Speicherbereich von 1024 Byte. In dem Fall soll dieser Speicherbereich ja das Packet darstellen, was abgeschickt wird.
nun lässt man ip, also ein Zeiger auf eine IP Header Struktur auf den Anfang dieser 1024 Byte zeigen. Nun benutzt du die ersten bytes (entsprechend der größe von sturct iphdr) als struct iphdr und die bytes danach dann als UDP Header. Und den Rest danach für die Daten.
-
Ahh... jetzt hab ichs verstanden!
Besten Dank.
-
Hi
Ich hab mal ne ander Frage. Warum benutzt du recv bei UDP ?
-
Der code stammt aus dem Tutorial von zotteljedi.de.
Den Code selbst habe ich nicht ausprobiert. Ich wollte ihn nur
verstehen...
-
OK
-
Jetzt habe ich doch noch ein Problem.
Mein Programm sendet an eine bestimmte Addresse ein Packet und erwartet dann von dort eine Antwort. Ich benutze UDP auf dem Transport Layer.
Jetzt ergibt sich folgendes Problem:
Ich habe das Packet korrekt über Raw Sockets zusammengebaut, es wird korrekt
versandt und kommt an. Da ich aber UDP verwenden muss, ist das ganze natürlich nicht Verbindungsorientiert. Wie mache ich es aber, das ich etwas erhalten kann. Nachdem ich mit sendto etwas versandt habe, rufe ich sofort recvfrom auf.
Nur kommt nichts an! (...wahrscheinlich weil die Verbindung ja bereits beendet wurde....) Was kann ich tuen?
-
ich habe auch ewig gebraucht um die raw sockets zu verstehen.
bei mir war das problem(war aber bei tcp) das nich mit recv nichts auffangen konnte, weil meine checksum falsch war, jetzt würde mein packet verschmissen und ich konnte lange warten mit meinem recv;-).
hier sind super tutorials
[url]http://www.delikon.de/rawsock.html [/url](meine seite unter der c-section findest auch ein paar raw-sockets snipps)
das beste tutorial
http://packetstorm.widexs.nl/programming-tutorials/raw_socket.txtich weiß das das nicht gerade die antwort auf deine frage war aber, wenn du willst kannst mir ja mal deinen quellcode schicken(ich@delikon.de), vieleicht kann ich dir ja helfen.(p.s. check mal ethereal aus der überprüft die checksums zurlaufzeit das siehste kleich ob sie passen, viel glück)
-
Super ich schau mir mal die Links an. Das Tutorial von Mixter war auch sehr gut nur leider halt nur ein Beispiel.
Mit ethereal überprüfe ich das ja andauernd, komischerweise kommt da kein Packet zurück, aber irgendwas wird trotzdem in den Empfangsbuffer geschrieben...
Wie berechnest du bei UDP Packet die Checksumme? Die muss nicht unbedingt eingetragen werden, da ja der IP Header bereits eine Checksumme besitzt, deswegen
habe ich die nie eingetragen, also auf Null gesetzt.
Wie berechnet man die?[ Dieser Beitrag wurde am 08.06.2003 um 17:54 Uhr von an0nym editiert. ]
-
[url] http://neworder.box.sk/smsread.php?newsid=5903 [/url]
das ist zwar ein remote-bufferoverflow-exploit, aber ich finde daraus läßt sich die udp-packet erstellung sehr gut abschauen.
p.s. die checksums müssen im ip und udp header richtig sein!!! sonst wird dir jeder router das packet verwerfen
-
Mmmhhh... ich habe jetzt mal die UDP Checksum Errechnung mit implementiert.
//Checksummenberechnung unsigned short csum(unsigned short *addr, int len) { register int sum = 0; u_short answer = 0; register u_short *w = addr; register int nleft = len; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(u_char *) (&answer) = *(u_char *) w; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return (answer); }
...beziehungsweise...
[code]
struct pseudohdr
{
unsigned int saddr; //Source Addresse
unsigned int daddr; //Destination Addresse
unsigned char zero; //Platzhalter
unsigned char protocol; //Protokoll
unsigned short udp_len; //Gesamtlänge UDP Packetstruct udphdr phudp; //UDP Header
char *udpdata; //Funktioniert nicht ?};
struct pseudohdr *ph = (struct pseudohdr malloc(sizeof (struct pseudohdr));
ph->saddr=ip->saddr;
ph->daddr=ip->daddr;
ph->protocol=ip->protocol;
ph->udp_len=htons(sizeof(struct udphdr) + data_size);
ph->zero=0;
ph->phudp=*udp;
ph->udpdata=data; //Fehler?udp->check = csum((unsigned short ph, sizeof(struct pseudohdr));[/code]
So weit so gut. Nun gibt es aber ein Problem. Ich muss in den Pseudoheader nicht nur den UDP Header sondern auch den Body also die zu sendenden Daten übergeben. Aus all diesen Informationen wird dann über die Funktion csum (siehe oben) der Checksumme berechnet. Nur wie über gebe ich in meinem Beispiel denn die Daten?
struct iphdr *ip=(struct iphdr*) datagram; struct udphdr *udp = (struct udphdr*) (datagram + sizeof(struct iphdr)); char *data = datagram + sizeof(struct iphdr) +sizeof(struct udphdr);
Bei mir zeigt *data auf die Addresse des Speichers wo die Daten stehen. Unmittelbar davor stehen der UDP Header und davor der IP Header. Wie würde ich also meinem Pseudoheader sagen er soll bei *data die Daten suchen?
Wieso kann ich ph->udpdata nicht einfach *data übergeben? Dort steht doch die Addresse wo der Datenteil beginnt?![ Dieser Beitrag wurde am 13.06.2003 um 13:47 Uhr von an0nym editiert. ]