2012-12-30 4 views
8

Haben Sie Probleme beim Empfangen von Paketen. Ich kann eingehende Pakete empfangen und lesen, aber ich denke, dass ich keinen Handschlag mit irgendeinem Host bekomme. Ich möchte nur ein Paket an einen Remote-Computer mit einem offenen Port senden, um eine Antwort zu erhalten, um die TTL (time to live) und die Fenstergröße zu sehen. Hat jemand eine Idee, wo die Fehler sind? (ich habe nicht sehr tiefes Wissen in C-Programmierung) Raw Socket Linux senden/empfangen ein Paket

Code:

#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/socket.h> 
#include <errno.h> 
#include <unistd.h> 
#include <arpa/inet.h> 
#include <net/ethernet.h> 
#include <netinet/in.h> 
#include <netinet/ip.h> 
#include <netinet/tcp.h> 

struct pseudohdr { 
    u_int32_t src_addr; 
    u_int32_t dst_addr; 
    u_int8_t padding; 
    u_int8_t proto; 
    u_int16_t length; 
}; 

struct data_4_checksum { 
    struct pseudohdr pshd; 
    struct tcphdr tcphdr; 
    char payload[1024]; 
}; 
unsigned short comp_chksum(unsigned short *addr, int len) { 
    long sum = 0; 

    while (len > 1) { 
     sum += *(addr++); 
     len -= 2; 
    } 

    if (len > 0) 
     sum += *addr; 

    while (sum >> 16) 
     sum = ((sum & 0xffff) + (sum >> 16)); 

    sum = ~sum; 

    return ((u_short) sum); 

} 

int main(int argc, char *argv[]) { 

    int sock, bytes, on = 1; 
    char buffer[1024]; 
    struct iphdr *ip; 
    struct tcphdr *tcp; 
    struct sockaddr_in to; 
    struct pseudohdr pseudoheader; 
    struct data_4_checksum tcp_chk_construct; 

    if (argc != 2) { 
     fprintf(stderr, "Usage: %s ", argv[0]); 
     fprintf(stderr, "<dest-addr>\n"); 
     return 1; 
    } 

    sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); 
    if (sock == -1) { 
     perror("socket() failed"); 
     return 1; 
    }else{ 
     printf("socket() ok\n"); 
    } 

    if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) == -1) { 
     perror("setsockopt() failed"); 
     return 2; 
    }else{ 
     printf("setsockopt() ok\n"); 
    } 

    ip = (struct iphdr*) buffer; 
    tcp = (struct tcphdr*) (buffer + sizeof(struct tcphdr)); 

    int iphdrlen = sizeof(struct iphdr); 
    int tcphdrlen = sizeof(struct tcphdr); 
    int datalen = 0; 
    printf("Typecasting ok\n"); 

    ip->frag_off = 0; 
    ip->version = 4; 
    ip->ihl = 5; 
    ip->tot_len = htons(iphdrlen + tcphdrlen); 
    ip->id = 0; 
    ip->ttl = 40; 
    ip->protocol = IPPROTO_TCP; 
    ip->saddr = inet_addr("192.168.165.135"); 
    ip->daddr = inet_addr(argv[1]); 
    ip->check = 0; 

    tcp->source  = htons(12345); 
    tcp->dest  = htons(80); 
    tcp->seq  = random(); 
    tcp->doff  = 5; 
    tcp->ack  = 0; 
    tcp->psh  = 0; 
    tcp->rst  = 0; 
    tcp->urg  = 0; 
    tcp->syn  = 1; 
    tcp->fin  = 0; 
    tcp->window  = htons(65535); 

    pseudoheader.src_addr = ip->saddr; 
    pseudoheader.dst_addr = ip->daddr; 
    pseudoheader.padding = 0; 
    pseudoheader.proto = ip->protocol; 
    pseudoheader.length = htons(tcphdrlen + datalen); 

    tcp_chk_construct.pshd = pseudoheader; 
    tcp_chk_construct.tcphdr = *tcp; 

    int checksum = comp_chksum((unsigned short*) &tcp_chk_construct, 
      sizeof(struct pseudohdr) + tcphdrlen + datalen); 

    tcp->check = checksum; 

    printf("TCP Checksum: %i\n", checksum); 
    printf("Destination : %i\n", ntohs(tcp->dest)); 
    printf("Source: %i\n", ntohs(tcp->source)); 

    to.sin_addr.s_addr = ip->daddr; 
    to.sin_family = AF_INET; 
    to.sin_port = tcp->dest; 

    bytes = sendto(sock, buffer, ntohs(ip->tot_len), 0, (struct sockaddr*) &to, 
      sizeof(to)); 

    if (bytes == -1) { 
     perror("sendto() failed"); 
     return 1; 
    } 

    recv(sock, buffer, sizeof(buffer), 0); 
    printf("TTL= %d\n", ip->ttl); 
    printf("Window= %d\n", tcp->window); 
    printf("ACK= %d\n", tcp->ack); 
    printf("%s:%d\t --> \t%s:%d \tSeq: %d \tAck: %d\n", 
        inet_ntoa(*(struct in_addr*) &ip->saddr), ntohs(tcp->source), 
        inet_ntoa(*(struct in_addr *) &ip->daddr), ntohs(tcp->dest), 
        ntohl(tcp->seq), ntohl(tcp->ack_seq)); 

    return 0; 
} 
+0

mit eingehenden Paketen ich meine, gibt es von überall her eingehenden andere aber nicht aus ich brauche – x4k3p

+0

warum das Paket zu analysieren? Ich habe versucht, eine Antwort auf einem sauberen Unix-Rechner unter VMware zu bekommen. Wenn ich ein Paket manuell gesendet habe, habe ich das, was ich brauche. aber wenn ich einfach warte, passiert nichts. unter echtem System kommen Pakete herein, aber diese kommen von woanders. – x4k3p

+0

Ich habe gerade meine Kommentare als tatsächliche Antwort neu gepostet. Ich hoffe, es macht dir nichts aus. – jweyrich

Antwort

10
  1. Sie erhalten und Speichern von Paketen in buffer, aber Sie drucken Daten von ip und tcp ohne diesen Puffer zu analysieren. Sie sollten das Paket von bufferanalysieren, nachdem Sie it und vor dem Drucken erhalten haben.
  2. Ihr Code geht davon aus, dass alle Pakete TCP sind, was nicht der Fall ist. RAW-Sockets unterstützen nur Layer-3-Protokolle (IP, ICMP usw.). Mit anderen Worten, die Verwendung von IPPROTO_TCP ist irreführend beim Erstellen eines RAW-Sockets. Bleiben Sie bei IPPROTO_IP, und fügen Sie Ihrem Code die notwendigen Bedingungen für jedes Protokoll hinzu, das Ihnen wichtig ist (TCP, UDP usw.). Dies funktioniert, weil der Linux-Kernel die Protokollnummer und Fallbacks auf IPPROTO_IP validiert. Dies funktioniert jedoch möglicherweise nicht in anderen Systemen.
  3. Überprüfen Sie, ob Ihre Netzwerkkommunikation die richtige Byte-Reihenfolge verwendet. Die Netzwerk-Byte-Reihenfolge ist Big-Endian, während die Host-Byte-Reihenfolge von Ihrer Architektur abhängt. Daher müssen Sie möglicherweise mehrere Byte-Felder vor und zurück konvertieren.
  4. Ihr tcp->seq hat möglicherweise einen ungültigen Wert, da TCP nur Werte bis zu 65535 akzeptiert, während random() Werte von 0 bis RAND_MAX (0x7fffffff) zurückgibt. Versuchen Sie tcp->seq = htonl(random() % 65535);
  5. Ihre Offset-Berechnung für den TCP-Header ist falsch. Es sollte sizeof(struct iphdr) statt sizeof(struct tcphdr) sein.
+0

Ist es überhaupt möglich, TCP- oder UDP-Pakete mit einem Raw-Socket zu empfangen? Ich dachte, diese eingehenden Pakete würden immer an die TCP- und UDP-Treiber weitergegeben. – Barmar

+0

@Barmar ist es möglich. Der Kernel liefert eine Kopie jedes Datagramms an jeden Prozess, der einen RAW-Socket erstellt hat, der dem Datagrammprotokoll entspricht. – jweyrich

+0

Fehler gefunden! Es ist der Puffer, weil ich etwas Müll zum entfernten Wirt schickte. Daher konnte ich keine Antwort erhalten. Korrektur: Zeichenpuffer [1024] = {0}; – x4k3p

-1
ip = (struct iphdr*) buffer; 
tcp = (struct tcphdr*) (buffer + sizeof(struct tcphdr)); 

Hier Array-Index von TCP-Header in buffer zu erhalten, müssen Sie sizeof(struct iphdr)-buffer hinzufügen wie unten erwähnt.

ip = (struct iphdr*) buffer; 
tcp = (struct tcphdr*) (buffer + sizeof(struct iphdr)); 
Verwandte Themen