2017-08-16 5 views
2

J'essayais d'envoyer un paquet TCP SYN à un serveur sur ma machine sur le port 8000. Ensuite, je voulais vérifier si le serveur a répondu avec un SYN ACK. Si tel était le cas, alors je renverrais un paquet RST pour annuler la connexion. Cependant, quand je renifle le paquet SYN que j'envoie, il me dit que l'en-tête TCP a une longueur fictive de 0, ce qui n'est pas le cas. Le sniffer que j'ai utilisé était tshark, au fait. Voici mon code:Bogus longueur d'en-tête TCP lors de l'examen des paquets dans Tshark

Dans la fonction main, je lance ceci:

FLAGS f = SYN; 

tcp_scan("127.0.0.1",8000,f,0); 

Cette fonction assemble l'en-tête IP:

struct iphdr* assemble_ip(char* dest,unsigned int proto) { 

    /* Assemble IP Layer */ 

    struct iphdr* iph; 

    iph = malloc(sizeof(struct iphdr)); // allocate memory 

    if (iph == NULL) { // if the ip header is NULL 

     err(); 
     return NULL; 

    } 

    srand((unsigned int)time(NULL)); // seed random number generator 

    /* Hardcoded values */ 

    iph->version = 4; // the version 
    iph->tos = 0; // type of services 
    iph->ihl = 5; // internet header length 
    iph->id = htons(rand() % 65536); // random id 
    iph->ttl = rand() % 257; // ttl 
    iph->frag_off = 0; // fragment offset 

    if (iph->ttl < 64) iph->ttl += 64; // if TTL is not sufficient 

    iph->tot_len = htons(iph->ihl*4); // the internet header length 

    /* User defined values */ 

    iph->saddr = inet_addr(client); // source address 
    iph->daddr = inet_addr(dest); // destination address 
    iph->protocol = proto; // protocol 

    iph->check = 0; // set to zero for later calculation 

    return iph; 

    } 

Cette fonction assemble l'en-tête TCP:

struct tcphdr* assemble_tcp(unsigned int sport,unsigned int dport,FLAGS f) { 

    /* Assemble TCP layer */ 

    struct tcphdr* tcph; 

    tcph = malloc(sizeof(struct tcphdr)); // allocate tcp header 

    if (tcph == NULL) { // if tcp is NULL 

     err(); 
     return NULL; 

    } 


    bzero(tcph,sizeof(struct tcphdr)); 

    srand((unsigned int)time(NULL)); // seed random number generator 

    /* Hardcoded values */ 

    tcph->seq = htonl(rand() % 65001); // generate random sequence number 
    tcph->ack_seq = 0; // ack sequence should be 0 
    tcph->doff = 5; // set data offset 
    tcph->window = htons(rand() % 65536); // set window size 

    /* Increase values by random value above 64 */ 

    if (ntohs(tcph->seq) < 64) tcph->seq += (rand() % 101 + 64); 
    if (ntohs(tcph->window) < 64) tcph->window += (rand() % 101 + 64); 

    /* User-defined values */ 

    tcph->source = htons(sport); // source port 
    tcph->dest = htons(dport); // destination port 
    tcph = set_flags(tcph,f); // set the TCP flags 

    /* Set urgent ptr if URG flag is set*/ 

    if (tcph->urg == 1) tcph->urg_ptr = 1; 
    else tcph->urg_ptr = 0; 

    tcph->check = 0; // set the checksum to 0 for other calculations 


    return tcph; 

    } 

En outre, je calcule la somme de contrôle des en-têtes. Pour mes besoins, lors du calcul de la somme de contrôle, l'en-tête IP est toujours long de 20 octets, puisque je n'envoie aucune donnée ou option. Cela signifie qu'il y a 10 mots de 16 bits dans l'en-tête. L'en-tête TCP va aussi être de 20 octets depuis que je n'ai pas ajouté d'options ou de données. Voici le code:

unsigned short ip_checksum(struct iphdr* iph) { 

    /* Acquire IP checksum */ 

    /* 

    Checksum for Internet Protocol: 
    One's complement of the one's complement sum of the 16 bit words in the header. 
    So we get the first 16 bits of the header then add it to the sum, and then 
    we get the next 16 bits, and add it, and so on. 
    ...0100101010110101 -> "..." represents more bits 
    1111111111111111 -> this is 131071 in base 10 
    0000100101010110101 -> notice how the "..." bits are now 0's 

    */ 

    /* One's complement sum */ 

    unsigned long long* ptr; 
    unsigned long long hdr; 
    unsigned short sum = 0; 
    unsigned long mask = 131071; 

    ptr = (unsigned long long*)iph; // cast structure 
    hdr = *ptr; // get hdr 

    for (int i = 0; i < 10; i++) { // 20 bytes -> 160 bits/16 bits = 10 words 

      sum += (hdr & mask); // add to sum 

      hdr >>= 16; // shift the next 16 bits 

    } 

    sum = ~sum; // inverse 

    return sum; 

    } 

TCP Checksum:

unsigned short tcp_checksum(struct tcphdr* tcph,struct iphdr* iph) { 

      /* Calculate TCP checksum */ 

      struct pseudo_hdr* pseudo_hdr; 
      u_char* buffer; 
      u_char* segment; 
      u_char* pseudo_segment; 
      unsigned short sum = 0; 
      unsigned long mask = 131071; 
      unsigned long long* ptr; 
      unsigned long long hdr; 

      pseudo_hdr = malloc(sizeof(struct pseudo_hdr)); // allocate memory 
      buffer = malloc(32); // allocate for 32 bytes of information 

      if (pseudo_hdr == NULL || buffer == NULL) { // if memory wasn't allocated properly 

       err(); 
       if (pseudo_hdr != NULL) free(pseudo_hdr); 
       if (buffer != NULL) free(buffer); 
       return 0; 

      } 

      pseudo_hdr->saddr = (unsigned long)iph->saddr; // we add the cast because the fields if of type u_int_32 
      pseudo_hdr->daddr = (unsigned long)iph->daddr; // same reason for adding the cast as above 
      memset(&pseudo_hdr->reserved,0,8); // set these 8 bits to 0 
      pseudo_hdr->proto = IPPROTO_TCP; // this will always be 6 
      pseudo_hdr->len = htons(tcph->doff*4); // length of tcp header 

      /* Place both headers into a buffer */ 

      segment = (u_char*)tcph; 
      pseudo_segment = (u_char*)pseudo_hdr; 

      /* Concactenate */ 

      strncat((char*)buffer,(char*)pseudo_segment,12); // first the pseudo header 
      strncat((char*)buffer,(char*)segment,20); // then the TCP segment 

      /* Calculate checksum just like IP checksum */ 

      ptr = (unsigned long long*)buffer; // convert buffer 

      hdr = *ptr; // dereference for clarity in following clode 

      for (int i = 0; i < 16; i++) { // 32 bytes -> 256 bits/16 bits = 16 words 

       sum += (hdr & mask); // apply mask to header and add to sum 

       hdr >>= 16; // shift the next 16 bits 

      } 


      sum = ~sum; // bitwise NOT operation 

      return sum; 

      }; 

est ici toutes les fonctions je l'ai dit ci-dessus mis en place:

int tcp_scan(char* ipaddr,unsigned int port,FLAGS f,unsigned int justsend) { 

    /* Do a TCP port scan */ 

    u_char* buffer; 
    u_char recvbuf[65535]; 
    u_char* ipbuf; 
    u_char* tcpbuf; 
    int s; 
    size_t bufsize; 
    size_t size; 
    struct sockaddr_in sa; 
    struct sockaddr_in recvstruct; 
    struct msghdr msg; 
    struct iovec iv[1]; 
    struct iphdr* iph; 
    struct tcphdr* tcph; 
    FLAGS rst = RST; 

    srand((unsigned int)time(NULL)); // seed random number generator 

    bufsize = sizeof(struct tcphdr) + sizeof(struct iphdr); // store size in variable 

    buffer = malloc(bufsize); // allocate memory to buffer 
    iph = assemble_ip(ipaddr,IPPROTO_TCP); // set the ip address to provided and protocol as TCP 
    tcph = assemble_tcp(rand() % 65536,port,f); // set flag, source port as rand, and dest port as supplied port num 

    if (iph == NULL || tcph == NULL || buffer == NULL) { // if error occurs 

      err(); 

      /* Deallocate memory to variables that still have it */ 

      if (iph != NULL) free(iph); 
      if (tcph != NULL) free(tcph); 
      if (buffer != NULL) free(buffer); 

      return -1; 

    } 

      /* Now compute checksum */ 

      iph->check = htons(ip_checksum(iph)); 
      tcph->check = htons(tcp_checksum(tcph,iph)); 

      /* Store headers in buffer */ 

      ipbuf = (u_char*)iph; 
      tcpbuf = (u_char*)tcph; 

      /* Concactenate to buffer */ 

      strncat((char*)buffer,(char*)tcpbuf,20); // copy only 20 bytes...this ensures that no extra bytes are catted 
      strncat((char*)buffer,(char*)ipbuf,20); // do same thing but with ip header 

      /* Create a socket */ 

      s = create_socket(); // create a raw socket 

      if (s == -1) return -1; // if the socket wasn't able to be created 


      /* Clear memory */ 

      bzero(&sa,sizeof(struct sockaddr_in)); 
      bzero(&recvstruct,sizeof(struct sockaddr_in)); 
      bzero(&msg,sizeof(struct msghdr)); 
      bzero(&iv,sizeof(struct iovec)); 

      /* For analyze_packet() */ 

      sa.sin_family = AF_INET; // address family 
      sa.sin_addr.s_addr = inet_addr(ipaddr); // convert ip address 
      sa.sin_port = htons(port); // port number 

      /* For sendmsg() */ 

      iv[0].iov_base = buffer; 
      iv[0].iov_len = bufsize; 

      msg.msg_name = &sa; // caller allocated buffer 
      msg.msg_namelen = sizeof(struct sockaddr_in); // specify size of buffer 
      msg.msg_iov = iv; // iov structure array 
      msg.msg_iovlen = 1; // the length of the array 
      msg.msg_control = NULL; // for ancillary data 
      msg.msg_controllen = 0; // sizeof ancillary data 


      if (sendmsg(s,&msg,0) == -1) { 

       err(); 
       return -1; 

      } 

      printf("Sent\n"); 

      if (justsend) return 0; // exit cleanly 

      bzero(&recvstruct,sizeof(struct sockaddr_in)); // clear structure 

      size = sizeof(struct sockaddr_in); // acquire size of recv structure 

      for(int i = 0; i < 100; i++) { // loop until we've received 100 packets 

       printf("Receiving\n"); 
       bzero(recvbuf,65535); // clear memory 

       if (recvfrom(s,recvbuf,sizeof(recvbuf),0,(struct sockaddr*)&recvstruct,(socklen_t*)&size) == -1) { // recv 

         err(); 
         return -1; 

       } 

       if (analyze_packet(recvbuf,sa,recvstruct) == 0) { // if packet is what we wanted 

         printf("\ttcp %d is open\n",port); // print out that port is opened 
         tcp_scan(ipaddr,port,rst,-1); // abort connection with RST flag 
         break; 

        } 


      } 

      return 0; 

} 

Bon, maintenant que vous avez vu ceux-ci, voici la commande 'tshark' que j'utilisais pour renifler les paquets:

sudo tshark -o tcp.check_checksum:TRUE # I also wanted to check the checksum value to make sure it was OK 

Maintenant, voici la commande pour exécuter le programme:

sudo ./netmap enp0s3 # enp0s3 is the interface I'm sending packets on 

Après avoir exécuté ces deux bornes séparées, tshark fournit cette sortie:

1 0.000000 10.0.2.15 -> 127.0.0.1 TCP 74 31280->8000 [<None>] Seq=1 Win=0, bogus TCP header length (0, must be 20) 

S'il vous plaît noter que les déclarations de struct iphdr et struct tcphdr sont situés dans les fichiers d'en-tête système <netinet/ip.h> et <netinet/tcp.h>, respectivement.

Je suis vraiment perdu sur la façon de résoudre ce problème. En fait, je ne suis pas certain de ce qui cause le problème, en premier lieu. D'après mes connaissances, il n'y a aucun moyen de spécifier la longueur de l'en-tête TCP. Toute aide serait appréciée.

+0

Videz l'hexagone du paquet et montrez-nous cela. Cela pourrait être aussi simple qu'un problème endian. –

+1

strncat() ne copie pas les octets. –

+0

cette ligne: strncat ((char *) buffer, (char *) pseudo_segment, 12); a une probabilité d'échec de 254: 1 car le tableau buffer [], le premier octet n'a pas été précédemment défini sur 0x00 ET les données ne sont pas une chaîne char et peuvent contenir 0x00 octets. Suggérer l'utilisation de 'memcpy()' – user3629249

Répondre

3

Je pense que votre problème est ici

strncat((char*)buffer,(char*)tcpbuf,20); // copy only 20 bytes...this ensures that no extra bytes are catted 
strncat((char*)buffer,(char*)ipbuf,20); 

Les en-têtes ne sont pas des chaînes de sorte que vous ne pouvez copierez une partie de chaque en-tête. Essayez quelque chose comme ça;

memcpy((char*)buffer, (char*)tcpbuf, 20); 
memcpy((char*)buffer+20, (char*)ipbuf, 20); 
+0

Merci beaucoup! Je me cognais la tête contre le mur en essayant de comprendre cela. :) – ssharma

+0

@ssharma malheureusement, l'utilisation abusive de la bibliothèque C strxxx() appels dans le code réseau est légendaire. Tellement légendaire que c'était la première chose que je cherchais dans ton code. Vous devez être très prudent à chaque fois que vous vous trouvez en tapant 'str' :) –

+0

@ssharma Je l'ai regardé et éteint pendant un certain temps moi-même :-D – cleblanc