Raw Socket Linux envoyer / recevoir un paquet

J’ai des problèmes pour recevoir des paquets. Je peux recevoir et lire les paquets entrants, mais je pense que je ne reçois aucune poignée de main avec aucun hôte. Je veux seulement envoyer un paquet à un ordinateur distant avec un port ouvert en recevant une réponse pour voir la durée de vie et la taille de la fenêtre Est-ce que quelqu’un a une idée des erreurs? (Je n’ai pas de connaissances approfondies en programmation C)

CODE:

#include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  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, "\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; } 

  1. Vous recevez et stockez des paquets dans la buffer , mais vous imprimez des données depuis ip et tcp sans parsingr cette mémoire tampon. Vous devez parsingr le paquet à partir de la buffer après l’avoir reçu et avant l’impression .
  2. Votre code suppose que tous les paquets sont en TCP, ce qui n’est pas le cas. Les sockets RAW ne prennent en charge que les protocoles de couche 3 (IP, ICMP, etc.). En d’autres termes, utiliser IPPROTO_TCP est trompeur lors de la création d’un socket RAW. Tenez-vous-en à IPPROTO_IP et ajoutez les conditions nécessaires à votre code pour chaque protocole qui vous IPPROTO_IP à IPPROTO_IP (TCP, UDP, etc.). Cela fonctionne car le kernel Linux valide le numéro de protocole et effectue des repliements sur IPPROTO_IP . Cependant, cela pourrait ne pas fonctionner dans d’autres systèmes.
  3. Vérifiez si votre communication réseau utilise l’ordre correct d’octets. L’ordre des octets du réseau est Big-Endian, tandis que l’ordre des octets de l’hôte dépend de votre architecture. Vous devrez donc peut-être convertir les champs de plusieurs octets dans les deux sens.
  4. Votre tcp->seq peut avoir une valeur non valide, car TCP accepte uniquement les valeurs inférieures à 65535, tandis que random() renvoie les valeurs de 0 à RAND_MAX (0x7fffffff). Essayez tcp->seq = htonl(random() % 65535);
  5. Votre calcul de décalage pour l’en-tête TCP est incorrect. Ce devrait être sizeof(struct iphdr) plutôt que sizeof(struct tcphdr) .
 ip = (struct iphdr*) buffer; tcp = (struct tcphdr*) (buffer + sizeof(struct tcphdr)); 

Ici, pour obtenir l’index de tableau de l’en-tête tcp dans le buffer , vous devez append sizeof(struct iphdr) au buffer comme indiqué ci-dessous.

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