title: Bogus TCP Header Length When Examining Packets in Tshark
body: <p>I was trying to send a TCP <code>SYN</code> packet to a server on my machine on port <code>8000</code>. Then, I wanted to check if the server responded with a <code>SYN ACK</code>. If this was the case, then I would send back a <code>RST</code> packet to abort the connection. However, when I sniff the <code>SYN</code> packet that I send out it tells me the TCP header has a bogus length of 0, which isn't the case. The sniffer I used was <code>tshark</code>, by the way. Here's my code: </p>
  
  <p>In the <code>main</code> function, I run this: </p>
  
  <pre><code>FLAGS f = SYN;
  
  tcp_scan("127.0.0.1",8000,f,0);
  </code></pre>
  
  <p>This function assembles the IP header:</p>
  
  <pre><code>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-&gt;version = 4; // the version
      iph-&gt;tos = 0; // type of services
      iph-&gt;ihl = 5; // internet header length
      iph-&gt;id = htons(rand() % 65536);  // random id
      iph-&gt;ttl = rand() % 257; // ttl
      iph-&gt;frag_off = 0; // fragment offset
  
      if (iph-&gt;ttl &lt; 64) iph-&gt;ttl += 64; // if TTL is not sufficient
  
      iph-&gt;tot_len = htons(iph-&gt;ihl*4); // the internet header length
  
      /* User defined values */
  
      iph-&gt;saddr = inet_addr(client); // source address
      iph-&gt;daddr = inet_addr(dest); // destination address
      iph-&gt;protocol = proto; // protocol
  
      iph-&gt;check = 0; // set to zero for later calculation
  
      return iph;
  
      }
  </code></pre>
  
  <p>This function assembles the TCP header:</p>
  
  <pre><code>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-&gt;seq = htonl(rand() % 65001); // generate random sequence number
      tcph-&gt;ack_seq = 0; // ack sequence should be 0
      tcph-&gt;doff = 5; // set data offset
      tcph-&gt;window = htons(rand() % 65536); // set window size
  
      /* Increase values by random value above 64 */
  
      if (ntohs(tcph-&gt;seq) &lt; 64) tcph-&gt;seq += (rand() % 101 + 64);
      if (ntohs(tcph-&gt;window) &lt; 64) tcph-&gt;window += (rand() % 101 + 64);
  
      /* User-defined values */
  
      tcph-&gt;source = htons(sport); // source port
      tcph-&gt;dest = htons(dport);  // destination port
      tcph = set_flags(tcph,f); // set the TCP flags
  
      /* Set urgent ptr if URG flag is set*/
  
      if (tcph-&gt;urg == 1) tcph-&gt;urg_ptr = 1;
      else tcph-&gt;urg_ptr = 0;
  
      tcph-&gt;check = 0; // set the checksum to 0 for other calculations
  
  
      return tcph;
  
      }
  </code></pre>
  
  <p>Also, I do compute the checksum of the headers. For my purposes, when calculating the checksum, the IP header is always 20 bytes long, since I'm not sending any data or options. That means that there are 10 16-bit words in the header. The TCP header is also going to be 20 bytes long since I didn't add any options or data. Here's the code: </p>
  
  <pre><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 -&gt; "..." represents more bits 
      1111111111111111 -&gt; this is 131071 in base 10 
      0000100101010110101 -&gt; 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 &lt; 10; i++) { // 20 bytes -&gt; 160 bits / 16 bits = 10 words
  
              sum += (hdr &amp; mask); // add to sum
  
              hdr &gt;&gt;= 16; // shift the next 16 bits
  
    }
  
    sum = ~sum; // inverse 
  
    return sum;
  
    }
  </code></pre>
  
  <p>TCP Checksum: </p>
  
  <pre><code>  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-&gt;saddr = (unsigned long)iph-&gt;saddr; // we add the  cast because the fields if of type u_int_32
            pseudo_hdr-&gt;daddr = (unsigned long)iph-&gt;daddr; // same reason for adding the cast as above
            memset(&amp;pseudo_hdr-&gt;reserved,0,8); // set these 8 bits to 0
            pseudo_hdr-&gt;proto = IPPROTO_TCP; // this will always be 6
            pseudo_hdr-&gt;len = htons(tcph-&gt;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 &lt; 16; i++) { // 32 bytes -&gt; 256 bits / 16 bits = 16 words
  
                 sum += (hdr &amp; mask); // apply mask to header and add to sum
  
                 hdr &gt;&gt;= 16;  // shift the next 16 bits
  
             }
  
  
             sum = ~sum; // bitwise NOT operation
  
             return sum;
  
             };
  </code></pre>
  
  <p>Here's all of the functions I stated above put together: </p>
  
  <pre><code>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-&gt;check = htons(ip_checksum(iph));
             tcph-&gt;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(&amp;sa,sizeof(struct sockaddr_in));
             bzero(&amp;recvstruct,sizeof(struct sockaddr_in));
             bzero(&amp;msg,sizeof(struct msghdr));
             bzero(&amp;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 = &amp;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,&amp;msg,0) == -1) {
  
                err();
                return -1;
  
            }
  
            printf("Sent\n");
  
            if (justsend) return 0; // exit cleanly
  
            bzero(&amp;recvstruct,sizeof(struct sockaddr_in)); // clear structure
  
            size = sizeof(struct sockaddr_in); // acquire size of recv structure
  
            for(int i = 0; i &lt; 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*)&amp;recvstruct,(socklen_t*)&amp;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;
  
  }
  </code></pre>
  
  <p>Alright, now that you've seen those, here's the 'tshark' command I used to sniff the packets: </p>
  
  <pre><code>sudo tshark -o tcp.check_checksum:TRUE # I also wanted to check the checksum value to make sure it was OK
  </code></pre>
  
  <p>Now here's the command to run the program: </p>
  
  <pre><code>sudo ./netmap enp0s3 # enp0s3 is the interface I'm sending packets on
  </code></pre>
  
  <p>After running both of these in separate terminals, <code>tshark</code> provides this output: </p>
  
  <pre><code>1    0.000000    10.0.2.15 -&gt; 127.0.0.1    TCP 74 31280-&gt;8000 [&lt;None&gt;] Seq=1 Win=0, bogus TCP header length (0, must be 20)
  </code></pre>
  
  <p>Please note that the declarations for <code>struct iphdr</code> and <code>struct tcphdr</code> are located in the system header files <code>&lt;netinet/ip.h&gt;</code> and <code>&lt;netinet/tcp.h&gt;</code>, respectively. </p>
  
  <p>I'm really lost as to how to solve this issue. In fact, I'm not certain what is causing the issue, in the first place. According to my knowledge there's no way to specify the length of the TCP header. Any help would be appreciated.</p>