Search code examples
csocketstcp

do TCP warning means packet ignored,"Wireshark (Warning/Malformed):Short segment.Segment/fragment does not contain a full TCP header (might be NMAP )"


I am simulating TCP for example any received tcp packet so there should be a response, And for that I have coded my server program in C and created TUN interface so clients packet read my code, The problem with my code is simply that I am getting SYN packets, And I am responding to it with SYN + ACK packet. sequence numebers and ports are correct. in wire shark I am see my SYN + ACK reponses but my client keep sending SYN packets and in middle router solicitation messages, In wire shark its says

Expert Info (Warning/Malformed): Short segment. Segment/fragment does not contain a full TCP header (might be NMAP or someone else deliberately sending unusual packets)

What this mean, I am kind of sure I am including all the valid fields as values but why am I keep getting this warning and my client is seems like ignoring my SYN +ACK packet. can anyone please take a look at this code

This is my main function

int main(int argc, char **argv)
{
    const char *tun_ip = NULL;    /*virtual*/
    const char *remote_ip = NULL; /*physical*/
    ip4_addr_t local_ip4 = 0L;
    pthread_t tid_recv;//, tid_trans;
        void *thread_ret = NULL;
        

    _progname = argv[0];
    if (argc != 3) 
    {
        usage();
        exit(EXIT_FAILURE);
    }

    tun_ip = argv[1];
    remote_ip = argv[2];
       if (0 >= inet_pton(AF_INET, tun_ip, &local_ip4)) 
       {
        debug("%s: invalid IP address %s\n", _progname, tun_ip);
        exit(EXIT_FAILURE);
        }
    
    set_signal(SIGINT,  sigexit);
    set_signal(SIGQUIT, sigexit);

    
    _tun_fd = open_tun_iface(local_ip4);
    if (_tun_fd < 0 ) 
    {
        exit(EXIT_FAILURE);
    }
     


    _udp_fd = open_udp_socket();
    if (_udp_fd < 0 ) 
    {
        exit(EXIT_FAILURE);
    }
    
    
    if (0 >= inet_pton(AF_INET, remote_ip, &_remote_ip)) 
    {
        debug("%s: invalid IP address %s\n", _progname, remote_ip);
        exit(EXIT_FAILURE);
    }
    
    pthread_create(&tid_recv,  NULL, receiver,    NULL);
    
     while (!_do_exit)
        sleep(1);

    debug("** Shutting down...\n");
    close_tun_iface();
    shutdown(_udp_fd, 2); _udp_fd = -1;
    pthread_join(tid_recv,  &thread_ret);

    return 0;
}

This is my receiver and responder TCP thread

void * receiver(void *data)
{

    //struct sockaddr_in cliaddr = {0};
    int recvlen = -1;
    int writelen = -1;
    //socklen_t clilen = sizeof(cliaddr);

    while (!_do_exit)
    {
        //recvlen = rrecvfrom(_udp_fd, buf, sizeof(buf), 0, (struct sockaddr*)&cliaddr, &clilen);
        char buf[VPN_MAX_MTU] = {0};
        char buf_1[VPN_MAX_MTU] = {0};
        memset(buf,0,VPN_MAX_MTU);
        memset(buf_1,0,VPN_MAX_MTU);
        memset(buf,0,VPN_MAX_MTU);
        memset(buf_1,0,VPN_MAX_MTU);
        

        char *str_source=malloc(18);
        char *str_dest=malloc(18);
        memset(str_source,0,18);
        memset(str_dest,0,18);
        recvlen=read(_tun_fd,buf,VPN_MAX_MTU);
        if(recvlen>0)
        {

    //BUFFER received here        
        struct iphdr *iph=(struct iphdr *)buf;  
        struct iphdr *ip=(struct iphdr *)buf_1;
        int y=0;
        for(int b=0;b<(sizeof(struct iphdr)+sizeof(struct tcphdr));b++)
        {
            if(y==20)
            {
                y=0;
                //printf("\n");
            }
            
            //printf("%x ",buf[b]<<24);
            
            
            y++;
        
        }
    //      tcph->check=(tcp_chksum(iph,tcph));
        //iph->check = csum(iph, sizeof(*iph));
        char str_src[18]={0};
        char str_dest_t[18]={0};
           
           
        //printf("IN %s %s\n",get_ip_str_1(iph->saddr,str_src),get_ip_str_1(iph->daddr,str_dest_t));
        memcpy(&ip->daddr,&iph->saddr,sizeof(uint32_t));
        memcpy(&ip->saddr,&iph->daddr,sizeof(uint32_t));
        //printf("OUT %s %s\n",get_ip_str_1(ip->saddr,str_src),get_ip_str_1(ip->daddr,str_dest_t));
        //Create ip
        
        //DOUBLE CHECK FOR BYTE ORDER
        
        //ip->tot_len=iph->tot_len;
        populate_ip_some(iph,ip);
        ip->tos=0;
        ip->tos=iph->tos;
        ip->ihl         = 5;
        ip->version     = 4;
        ip->tot_len     = sizeof(struct iphdr) + sizeof(struct tcphdr);
        ip->protocol    = 6;
        ip->check=0; 
        //DOUBLE CHECK FOR BYTE ORDER
            ip->check = csum(ip, sizeof(*ip));
        ip->id=htons(100);

        //printf("before %d \n",htons(iph->check));
        iph->check=0; 
        //printf("middle %d\n",iph->check);
        //DOUBLE CHECK FOR BYTE ORDER
            iph->check = csum(iph, sizeof(*iph));

        int i=iph->ihl*4;
        struct tcphdr *tcph=(struct tcphdr *)(buf+i);
        //printf("tcp before %x\n",htons(tcph->check));
        tcph->check=0;
        printf("TCP START\n");
        tcph->check=(tcp_chksum(iph,tcph));
            printf("TCP END\n");
        //printf("tcp after %d\n",(tcph->check));
        //printf("i == %d\n",i);
        //POSSIBLY PRINT IPH for fun
        //for(int a=0;a<recvlen;a++)
            //printf("%x\n",buf[a]);
        //GET ihl SEND --  tcp
        int j=(ip->ihl*4);
        //printf("j == %d\n",j);
        int x=0;
        
        //SEEK filling
        struct tcphdr *tcp=(struct tcphdr *)(buf_1+20);
        populate_tcp_some(tcph,tcp);//Do LOOK AT THIS FUNCTION TO [SEE/CORRECT IT] >:)
        if(tcph->syn==1)
        {
               printf("syn\n");
               populate_tcp_some(tcph,tcp);
               tcp->seq=htons(1);
               tcp->ack_seq=1;
               tcp->syn=1;
               tcp->ack=1;

               tcp->source=htons(80);
    //         printf("received tcp syn = %d\n",tcph->syn);
        }
        else
        {
               populate_tcp_some(tcph,tcp);
               tcp->syn=0;
               tcp->ack=1;
    //         printf("sending tcp syn = %d ack = %d\n",tcp->syn,tcp->ack);
           
        }
        populate_tcp_some(tcph,tcp);
        tcp->dest=tcph->source;
        //printf("%d %d SOURCE PORT \n",ntohs(tcph->source),ntohs(tcp->dest));
        
        tcp->source=htons(80);
        printf("%d %d PORTS \n",ntohs(tcp->source),ntohs(tcp->dest));
        tcp->check=0;
        //TCP CHECKSUM ABOUT TRIPPLE WOW
        tcp->check=tcp_chksum(ip,tcp);
        
        //printf("tcpH = %d |  tcp = %d\n",tcph->check,htons(tcp->check));
        //IF needed make payload data
        //WRITE
        if (recvlen > 0) 
        {
            writelen = write(_tun_fd, buf_1, sizeof(struct iphdr)+sizeof(struct tcphdr));
            //debug("SR:%04d\n", recvlen);
            //debug("TW:%04d\n", writelen);
            
            if (writelen < 0) 
            {
            //debug("%s: rwrite() %s [%d]\n", _progname, strerror(errno), errno);
               //break;//NO NEED
            }
        }
        else if (recvlen < 0) 
        {
            //debug("%s: rrecvfrom() %s\n", _progname, strerror(errno));
               //break;//NO NEED
        }
        else if (recvlen == 0) 
        {
            //why
        }
    //FINALLY THEN SEND || DO WIRE SHARK 
        }
        
        // ...:)__ :) __:) ___:)___ (: __(:__ (;...  

    }

    debug("** Receiver ending.\n");
    pthread_exit(NULL);
}

and this is my how I set up tun interface

int open_tun_iface(ip4_addr_t local_ip4)
{
    struct ifreq ifr_tun;
    int fd = -1;
    sock = -1;
  //  int mtu = VPN_PATH_MTU;

    if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
        debug("%s: Cannot open /dev/net/tun: %s. Do modprobe tun; lsmod\n", _progname, strerror(errno));
        return -1;
    }

    memset( &ifr_tun, 0, sizeof(ifr_tun) );
    ifr_tun.ifr_flags = IFF_TUN | IFF_NO_PI;// | IFF_NO_PI;
    if ((ioctl(fd, TUNSETIFF, (void *)&ifr_tun)) < 0) {
        debug("%s: TUNSETIFF error: %s\n", _progname, strerror(errno));
        close(fd);
        return -1;
    }

#if 0
    if (ioctl(fd, TUNSETPERSIST, 1) < 0) {
        debug("%s: TUNSETPERSIST error: %s\n", _progname, strerror(errno));
        close(fd);
        return -1;
    }
#endif

 sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
            printf("interface socket error\n");
        debug("%s: Cannot open udp socket: %s\n", _progname, strerror(errno) );
        close(fd);
        return -1;
    }

    if (set_ip(&ifr_tun, sock, local_ip4) < 0) {
        close(fd);
        close(sock);
        return -1;
    }


    if (ioctl(sock, SIOCGIFFLAGS, &ifr_tun) < 0) {
        debug("%s: SIOCGIFFLAGS: %s\n", _progname, strerror(errno));
        printf("SIOCSIFFLAGS\n");
        close(fd);
        close(sock);
        
        return -1;
    }

    ifr_tun.ifr_flags |= IFF_UP;
    ifr_tun.ifr_flags |= IFF_RUNNING;

    if (ioctl(sock, SIOCSIFFLAGS, &ifr_tun) < 0)  {
        debug("%s: SIOCSIFFLAGS: %s\n", _progname, strerror(errno));
        printf("SIOCSIFFLAGS\n");
        exit(0);    
        close(fd);
        close(sock);
        return -1;
    }


    /*mtu = get_if_mtu("eth0", sock);*/
  /*  mtu = path_mtu_to_ip(_remote_ip, 32);
    if (mtu <= 0) {
        mtu = INTERNET_MTU;
    }

    if (mtu + VPN_OVERHEAD > VPN_MIN_MTU)
        mtu -= VPN_OVERHEAD;

    if (0 != set_mtu(&ifr_tun, sock, mtu)) {
        close(fd);
        close(sock);
        return -1;
    }
*/
    debug("** TUN opened: %s\n", ifr_tun.ifr_name);
    //close(sock);
    
    return fd;
}

and this is my checksum calculations

generic csum function

uint16_t csum(const void *data, const int length)
{
    uint16_t *accumalator = (uint16_t *)data;
    uint64_t sum = 0;

    /* Take care of the first 16-bit even blocks */
    for (int i = 0; i < length/2; ++i) {
        sum += *(accumalator+i);

        if (sum >= 0x10000) {
            sum -= 0xffff;
        }
    }

    /* Handle the ending partial block */
    if (length % 2 != 0) {
        accumalator = accumalator+ length/2; /* Point accumalator to the end block */
        uint16_t end_block = 0;
        memcpy(&end_block, accumalator, sizeof(length));
        sum += ntohs(end_block);
        if (sum >= 0x10000) {
            sum -= 0xffff;
        }
    }
  
    return htons(~sum);
}

and this is I calculate and handle TCP checksum calculation

uint16_t tcp_chksum(struct iphdr *snd_iph, struct tcphdr *snd_tcph)
{
    struct psuedo_header psh;

    psh.src_addr = snd_iph->saddr;
    psh.dst_addr = snd_iph->daddr;
    psh.rsvd = 0;
    psh.proto = IPPROTO_TCP;
    psh.len_tcp = htons(sizeof(struct tcphdr)); /* No options, and no data */

    int pseudogram_size = sizeof(struct tcphdr) + sizeof(struct psuedo_header);
    //int pseudogram_size = sizeof(*snd_tcph) + sizeof(psh);
    char *pseudogram = malloc(pseudogram_size);

    memcpy(pseudogram, (char *)&psh, sizeof(struct psuedo_header));
    memcpy(pseudogram + sizeof(struct psuedo_header), snd_tcph, sizeof(struct tcphdr));

    return((csum1(pseudogram, pseudogram_size)));
    //return (htons(csum(snd_tcph, sizeof(struct my_tcph)) + csum(&psh, sizeof(struct psuedo_header))));
}

int populate_ip_some(struct iphdr *o1,struct iphdr *o2) { o2->ihl=o1->ihl; //o2->version=o1->version; o2->id=htons(ntohs(o1->id)+1); o2->frag_off=o1->frag_off; o2->ttl=o1->ttl; o2->tos=0; //o2->protocol=o1->protocol; //o2->check=0; return 1;

}

int populate_tcp_flags(struct tcphdr *o1,struct tcphdr *o2) {

if(o1->syn==1 && o1->ack==0)
{

    printf("syn received\n\n");
    o2->syn=1;
    o2->ack=1;
    o2->rst=0;
    o2->fin=0;
    return 1;
}
if(o1->syn ==0 && o1->ack==1)
{
    printf("ack received\n\n");
    o2->syn=0;
    o2->ack=0;
    o2->rst=0;
    o2->fin=0;
    return 1;
}
if(o1->syn==0 && o1->fin==1)
{
    printf("fin received\n\n");
    o2->syn=0;
    o2->ack=1;
    o2->fin=0;
    o2->rst=0;
    return 1;
}

return 1;

}

uint32_t *ik;
int x=0;
int populate_tcp_some(struct tcphdr *o1,struct tcphdr *o2)
{
    if(x==0)
    {
        ik=malloc(sizeof(int)*100);
        if(ik==NULL)
        {printf("heap\n");exit(0);}
    }
    *(ik+x)=x;
    o2->seq=htons(*(ik+x));
    uint32_t host=ntohs(o1->seq);
    if(o1->syn==1)
    o2->ack_seq=1;
    else
    {
        //DOUBLE CHECK FOR TCP. ACK_SEQ SHOULD HAVE BEEN sizeof(OF TOTAL PACKET) + 1
        //DOUBLE CHECK MAY NEED TO PASS IPHDR ipH   
        o2->ack_seq=(htons(host+1));
    }   
    o2->doff=o1->doff;
    o2->res1=o1->res1;
    o2->window=o1->window;
    o2->check=0;
    o2->urg_ptr=o1->urg_ptr;
    x++;
    return 1;
}

this is my netinet/ip.h which has iphdr defination

struct iphdr
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ihl:4;
    unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
    unsigned int version:4;
    unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
    uint8_t tos;
    uint16_t tot_len;
    uint16_t id;
    uint16_t frag_off;
    uint8_t ttl;
    uint8_t protocol;
    uint16_t check;
    uint32_t saddr;
    uint32_t daddr;
    /*The options start here. */
  };

and this is netinet/tcp.h where my tcphdr struct can be found

struct tcphdr
  {
    __extension__ union
    {
      struct
      {
    uint16_t th_sport;  /* source port */
    uint16_t th_dport;  /* destination port */
    tcp_seq th_seq;     /* sequence number */
    tcp_seq th_ack;     /* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
    uint8_t th_x2:4;    /* (unused) */
    uint8_t th_off:4;   /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
    uint8_t th_off:4;   /* data offset */
    uint8_t th_x2:4;    /* (unused) */
# endif
    uint8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH    0x08
# define TH_ACK 0x10
# define TH_URG 0x20
    uint16_t th_win;    /* window */
    uint16_t th_sum;    /* checksum */
    uint16_t th_urp;    /* urgent pointer */
      };
      struct
      {
    uint16_t source;
    uint16_t dest;
    uint32_t seq;
    uint32_t ack_seq;
# if __BYTE_ORDER == __LITTLE_ENDIAN
    uint16_t res1:4;
    uint16_t doff:4;
    uint16_t fin:1;
    uint16_t syn:1;
    uint16_t rst:1;
    uint16_t psh:1;
    uint16_t ack:1;
    uint16_t urg:1;
    uint16_t res2:2;
# elif __BYTE_ORDER == __BIG_ENDIAN
    uint16_t doff:4;
    uint16_t res1:4;
    uint16_t res2:2;
    uint16_t urg:1;
    uint16_t ack:1;
    uint16_t psh:1;
    uint16_t rst:1;
    uint16_t syn:1;
    uint16_t fin:1;
# else
#  error "Adjust your <bits/endian.h> defines"
# endif
    uint16_t window;
    uint16_t check;
    uint16_t urg_ptr;
      };
    };
};

enter image description here


Solution

  • In order to have an answer to the question.

    OP is trying to create a SYNACK packet to answer incomming SYN packet. TCP SYN packet is generated from an OS stack, and uses Options.

    Wireshark complains that header is too short. It can be seen, that header length in the tcp header is set to 40 bytes, while the actual header present is only 20 bytes (the whole packet is 40 bytes: 20 bytes IP header and 20 bytes tcp header).

    The issue is that the field tcp->doff, which is tcp header, length is copied from the incomming SYN packet. Although not shown, incomming SYN packet presumably has TCP options in it, and thus its header is 40 bytes, not 20 bytes. Thus copying tcp->doff leads to the error message in quesition.

    For the reference, tcp header length field is tcp header length in multiples of 32 bits, or 4 bytes. Minimal tcp header is 20 bytes or 5 tcp header units. Alternatively tcp->doff = sizeof(struct tcphdr)/4 should work too.