C Paket aus Raw Socket lesen

Freezedevil

Lieutenant
Registriert
Mai 2011
Beiträge
640
Hi,
wie der Titel schon sagt habe ich ein kleines Problem beim lesen aus einem Raw Socket. Woher weiß ich denn wie groß das Paket ist, sodass ich weiß wie groß ich den Buffer wählen muss in den ich das Paket lese.
Ich hab mir das eigentlich so vorgestellt:
Ich lese den IP und und TCP Header ein. Dem IP Header kann ich dem tot_len Feld die Größe des Paket entnehmen. So weiß ich wie viel ich noch lesen muss.
Leider funktioniert das so nicht wie ich mir das vorstelle. Was muss ich denn ändern um das Paket korrekt einzulesen.

Beim Senden habe ich als Nutzlast einfach nen unsigned int drangehangen, weshalb ich hier einfach 4 Byte zusätzlich lese.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>


int main(void) {
    int sock, uid;
    unsigned int hdrsize = sizeof(struct iphdr) + sizeof(struct tcphdr);
    unsigned char packet[hdrsize+4];
    struct iphdr* ip = (struct iphdr*)packet;
    struct tcphdr* tcp = (struct tcphdr*)(packet + sizeof(struct iphdr));
    unsigned int* payload = (unsigned int*)(packet + hdrsize);
    int one = 1;
    
    uid = getuid();
    if (uid) {
        printf("You must be root!\n");
        exit(1);
    }
    
    if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1) {
        perror("socket");
        exit(1);
    }
    
    if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) == -1) {
        perror("setsockopt");
        exit(1);
    }
 
    while(1) {
        // Das funktioniert wunderbar, allerdings muss ich vorher wissen wie gross
        // das Paket ist
        /*
        read(sock,packet,hdrsize+4); 
        if (strcmp(inet_ntoa(*(struct in_addr *)&ip->daddr), "127.0.0.1")==0
            && ntohs(tcp->dest)==23) {
            printf("syn: %d\tack: %d\tpayload: %d\n", tcp->syn, tcp->ack, *payload);
        }
        */
        
        
        // Das funktioniert leider nicht. Wie muss ich den Code anpassen, damit das
        // so laeuft wie ich mir das vorstelle?
        read(sock,ip,hdrsize); 
        if (strcmp(inet_ntoa(*(struct in_addr *)&ip->daddr), "127.0.0.1")==0
            && ntohs(tcp->dest)==23) {
            printf("syn: %d\tack: %d\n", tcp->syn, tcp->ack);
            read(sock,payload,4);
            printf("payload:%u\n", *payload);
        }
    }
    
    return 0;
}

Kann man, wenn wir einmal dabei sind, die Überprüfung der IP Adresse noch etwas eleganter gestalten?

Edit: OS ist Ubuntu, falls das noch von Relevanz ist.
 
Zuletzt bearbeitet:
"So weiß ich wie viel ich noch lesen muss."
du musst im Grunde - so absurd es klingen mag - gar nicht wissen, wie viel du lesen musst. Der Längen-Parameter von read stellt ja nur den Maximalwert dar, der eingelesen wird.

Ich würde alles immer in einen Buffer lesen lassen, die Grüße wird ja über die MTU (die 1500 Bytes, wie Blitzermerker sagte) mehr oder weniger bestimmt, aber könntest ihn auch z.B 65536 Bytes groß machen um "sicher" zu gehen. In den Buffer liest du dann alles vom Socket, in dem du dann 65536 Bytes vom Socket liest... read sagt dann, wieviel gelesen wurde.

Danach kannst du den Buffer analyiseren, also IP-Header interpeteiren usw...
 
Wunderbar und vielen Dank. Probier ich gleich mal aus.

Edit:
Hat wie erwartet wunderbar funktioniert. Dankeschön Jungs.
 
Zurück
Oben