2012-12-30 9 views
8

Hanno alcuni problemi nella ricezione dei pacchetti. Posso ricevere e leggere i pacchetti in arrivo, ma penso di non avere una stretta di mano con nessun host. Voglio solo inviare un pacchetto a un computer remoto con una porta aperta alla ricezione di una risposta per vedere il TTL (tempo di vita) e le dimensioni della finestra. Qualcuno ha un'idea di dove sono gli errori? (non ho molto profonda conoscenza di programmazione C) Raw Socket Linux invia/riceve un pacchetto

CODICE:

#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

con i pacchetti in entrata Voglio dire, ci sono altri in arrivo da tutto il mondo, ma non ho bisogno di – x4k3p

+0

perché per analizzare il pacchetto? Stavo cercando di ottenere una risposta su una macchina unix pulita sotto vmware. quando ho inviato manualmente un pacchetto, ho ottenuto quello di cui avevo bisogno. ma se semplicemente aspetto non succede nulla. sotto il sistema reale ci sono pacchetti in arrivo, ma questi sono da qualche altra parte. – x4k3p

+0

Ho appena ripubblicato i miei commenti come una risposta reale. Spero non ti dispiaccia. – jweyrich

risposta

10
  1. Stai ricevere e memorizzare i pacchetti in buffer, ma si sta stampando i dati da ip e tcp senza analizzare questo buffer. È necessario analizzare il pacchetto da bufferdopo aver ricevuto e prima di stampare.
  2. Il tuo codice presuppone che tutti i pacchetti siano TCP, il che non è il caso. I socket RAW supportano solo i protocolli Layer 3 (IP, ICMP, ecc.). In altre parole, l'utilizzo di IPPROTO_TCP è fuorviante quando si crea un socket RAW. Passa a IPPROTO_IP e aggiungi le condizioni necessarie al tuo codice per ogni protocollo che ti interessa (TCP, UDP, ecc.). Questo succede perché il kernel di Linux convalida il numero di protocollo e fallbacks su . Tuttavia, questo potrebbe non funzionare in altri sistemi.
  3. Verificare se la comunicazione di rete sta utilizzando l'ordine dei byte corretto. L'ordine dei byte di rete è Big-Endian, mentre l'ordine dei byte host dipende dall'architettura, quindi potrebbe essere necessario convertire i campi multi-byte avanti e indietro.
  4. Il tuo tcp->seq potrebbe avere un valore non valido, poiché TCP accetta solo valori fino a 65535, mentre random() restituisce valori da 0 a RAND_MAX (0x7fffffff). Prova tcp->seq = htonl(random() % 65535);
  5. Il calcolo dell'offset per l'intestazione TCP non è corretto. Dovrebbe essere sizeof(struct iphdr) anziché sizeof(struct tcphdr).
+0

È persino possibile ricevere pacchetti TCP o UDP con un socket raw? Pensavo che questi pacchetti in entrata fossero sempre passati ai driver TCP e UDP. – Barmar

+0

@Barmar è possibile. Il kernel fornisce una copia di ciascun datagramma ad ogni processo che ha creato un socket RAW che corrisponde al protocollo del datagramma. – jweyrich

+0

Trovato l'errore! È il buffer, perché stavo inviando alcuni rifiuti all'host remoto. Pertanto non ho potuto ricevere una risposta. Correzione: char buffer [1024] = {0}; – x4k3p

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

qui per ottenere indice di array di intestazione TCP nella buffer, è necessario aggiungere sizeof(struct iphdr)-buffer come indicato di seguito.

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