2
votes

we are building a NAT program,we change each packet that comes from our internal subnet, change it's source IP address by libnet functions.( catch the packet with libpcap, put it sniff structures and build the new packet with libnet)

over TCP, the syn/ack packets are good after the change, and when a HTTP-GET request is coming, we can see by wireshark that there is an error on the checksum field.. all the other fields are exactly the same as the original packet.

Is anyone knows what can cause this problem? the new checksum in other packets is calculated as it should be.. but in the HTTP packet it doesn't..

3
Is this homework? or 'Plz send teh codez'... can you at least enclose some code for us as we're not mind readers...t0mm13b
if(ip->ip_p==IP_TYPE_TCP ) { protocol = 0; payload_s = ntohs(ip->ip_len) - TH_OFF(tcp)*4 - IP_HL(ip)*4; if (payload_s) payload = (char* )(packet + SIZE_ETHERNET + TH_OFF(tcp)*4 + IP_HL(ip)*4); else payload = NULL; }Hila
l = libnet_init(LIBNET_RAW4,config.extNIC, errbuf); if(protocol == 0)//TCP { if(TH_OFF(tcp)*4 > TCP_HEADER_SIZE) { options = (char*)packet + 54; options_s = TH_OFF(tcp)*4 - TCP_HEADER_SIZE; popt = libnet_build_tcp_options((u_int8_t*)options,options_s, l,0); } ptag = libnet_build_tcp( srcPort, // source port ntohs(tcp->th_dport), // dest port htonl(tcp->th_seq), // sequence number ntohl(tcp->th_ack), // ack number tcp->th_flags, // flagsHila
ntohs(tcp->th_win), // window size 0, // checksum ntohs(tcp->th_urp), // urg ptr TH_OFF(tcp)*4, // total length of the TCP packet (u_int8_t*)payload, // response payload_s, // response_length l, // libnet_t pointer ptag // ptag );Hila
Uhhh Hila, for the benefit of the SO Community, please re-edit your question and enclose the code properly instead of junking up the comment boxes...as that is unreadable...t0mm13b

3 Answers

2
votes

Modern ethernet cards can compute the checksum in hardware, so TCP stacks tend to offload the job to the card. As a result, it is quite common for the checksum to be invalid in Wireshark.

Side note: There is an option in Wireshark to validate the checksum:

Edit
  Preferences
    Protocols
      TCP
        Validate the TCP checksum if possible

Turn this off to stop Wireshark nagging you about the checksum.

0
votes

Is this actually causing a problem - i.e. does the packet with "bad checksum" get dropped or processed incorrectly? Or are you just worried about the "bad checksum" notification? If the packets are processed OK, this may be just checksum offloading and it's nothing to worry about.

Wireshark documentation says:

If the received checksum is wrong, Wireshark won't even see the packet, as the Ethernet hardware internally throws away the packet.

0
votes

Hey, answering in her name. The GET and ACK are separated, and yes the GET request is sent completely, this being said based on the fact that the packets are sent by Firefox or Wget. we do not create the packets, nor the responses of the server (which is an Apache).

Our code just runs in the middle. we have a 3rd machine besides the Client and the Server, and all of the three are Virtual Machines (in VMWare Server [NAT, Client = Ubuntu; Server = Fedora]). it has 2 NIC's (each one connected to each subnet accordingly) and it's goal is to change the Source IP and Source Port fields (in both directions of network traffic).

Thanks for the explanation about TCP checksum offload, which is guessed to happen by wireshark, but in my opinion is not the case because the error appears in the server side too (not 100% sure if that rules out the possibility, thoughts?). If I'm right, what could be the reason for the checksum's incorrectness?

Here is a link to the current code: http://rapidshare.com/files/393704745/13.5.10.tar.gz

Thanks a lot, Aviv.

If it's better as a code in here, there you go:






#include "./main.h"


int main(int argc, char **argv)
{
    pcap_t *pcapInt, *pcapExt;                      /* pcap descriptor */
    u_char *intPacket, *extPacket;
    int i;
    struct pcap_pkthdr intPkthdr, extPkthdr;
    char errbuf[PCAP_ERRBUF_SIZE];
    struct bpf_program filter_code;
    bpf_u_int32 intLocalNet, intNetmask, extLocalNet;

    for(i=0;i to quit\n");

    /* read the configuration file and store it's data in an array */
    LIBXML_TEST_VERSION
    xmlNode *cur_node = xmlDocGetRootElement(xmlReadFile(((argv[1]) != NULL ? argv[1] : "conf.xml"), NULL, 0));
    strcpy(config.filter, "");

    XMLtoConf(cur_node);
    strcat(config.filter, " and not src host 192.168.191.137");
    printf("FILTER: %s\n", config.filter);


    /* get network number and mask associated with the internal capture device */
    if (pcap_lookupnet(config.intNIC, &intLocalNet, &intNetmask, errbuf) == -1) {
        fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
            config.intNIC, errbuf);
        intLocalNet = 0;
        intNetmask = 0;
    }

    /* open internal capture device */
    pcapInt = pcap_open_live(config.intNIC, SNAP_LEN, 1, 1000, errbuf);
    if (pcapInt == NULL) {
        fprintf(stderr, "Couldn't open device %s: %s\n", config.intNIC, errbuf);
        exit(EXIT_FAILURE);
    }
    /* open external capture device */
    pcapExt = pcap_open_live(config.extNIC, SNAP_LEN, 1, 1000, errbuf);
    if (pcapExt == NULL) {
        fprintf(stderr, "Couldn't open device %s: %s\n", config.extNIC, errbuf);
        exit(EXIT_FAILURE);
    }

    /* make sure we're capturing on an Ethernet device [2] */
    if (pcap_datalink(pcapInt) != DLT_EN10MB) {
        fprintf(stderr, "%s is not an Ethernet\n", config.intNIC);
        exit(EXIT_FAILURE);
    }
    if (pcap_datalink(pcapExt) != DLT_EN10MB) {
        fprintf(stderr, "%s is not an Ethernet\n", config.extNIC);
        exit(EXIT_FAILURE);
    }

    /* compile the internal filter expression */
    if (pcap_compile(pcapInt, &filter_code, config.filter, 1, intLocalNet) == -1) { //adsvfhakdhvkahdvkadh
        fprintf(stderr, "Couldn't parse filter %s: %s\n",
            argv[1], pcap_geterr(pcapInt));
        exit(EXIT_FAILURE);
    }
    /* compile the external filter expression */
    if (pcap_compile(pcapExt, &filter_code, NULL, 1, extLocalNet) == -1) { //adsvfhakdhvkahdvkadh
        fprintf(stderr, "Couldn't parse filter %s: %s\n",
            argv[1], pcap_geterr(pcapExt));
        exit(EXIT_FAILURE);
    }

    /* apply the compiled internal filter */
    if (pcap_setfilter(pcapInt, &filter_code) == -1) {
        fprintf(stderr, "Couldn't install filter %s: %s\n",
            argv[1], pcap_geterr(pcapInt));
        exit(EXIT_FAILURE);
    }
     //apply the compiled external filter 
    if (pcap_setfilter(pcapExt, &filter_code) == -1) {
        fprintf(stderr, "Couldn't install filter %s: %s\n",
            argv[1], pcap_geterr(pcapExt));
        exit(EXIT_FAILURE);
    }
    while (1 == 1)
    {     
        intPacket = (u_char*)pcap_next(pcapInt, &intPkthdr);
        extPacket = (u_char*)pcap_next(pcapExt, &extPkthdr);
        if (intPacket != NULL)
        {
            sniff(intPacket,0);
        } 
        if (extPacket != NULL)
        {
            sniff(extPacket,1);
        } 
    }

    printf("\nCapture complete.\n");
    /* cleanup */
    pcap_freecode(&filter_code);
    pcap_close(pcapInt);
    return (EXIT_SUCCESS);
}

int isStrBlank(unsigned char *s)
{
  if (!s || strcmp((char *)s, "") == 0) return 1;

  while(*s) {
    if ( (' ' != *s) && ('\n' != *s) && ('\r' != *s) && ('\t' != *s)) return 0;
    ++s;
  }
  return 1;
}

static void XMLtoConf(xmlNode* node)
{
     /*
     * this initialize the library and check potential ABI mismatches
     * between the version it was compiled for and the actual shared
     * library used.
     */
    LIBXML_TEST_VERSION
    xmlNode *cur_node = node;
    int i,flag=0;
    for (; cur_node; cur_node = cur_node->next) {
        if (cur_node->type == XML_ELEMENT_NODE) {
                //if (isStrBlank(cur_node->children->content) == 1) continue;

                if (strcmp((char *)cur_node->name, "subnet_address") == 0){
                    strcat(config.filter, "src net ");
                    strcat(config.filter,(char *)cur_node->children->content);
                }
                //printf("1: %s", config.filter);
                if (strcmp((char *)cur_node->name, "NIC") == 0){
                    if (strcmp((char *)cur_node->parent->name, "internal") == 0){
                        config.intNIC = strdup((char *)cur_node->children->content);
                    }
                    else{
                        config.extNIC = strdup((char *)cur_node->children->content);
                    }
                }
                for (i = 0; strncmp((char *)cur_node->name, "machine_", 8) == 0; i++){

                    strcat(config.filter, " and not");
                    strcat(config.filter, " src host ");
                    flag=1;
                    strcat(config.filter, (char *)cur_node->children->content);
                    cur_node = cur_node->next;
                }


        }
        XMLtoConf(cur_node->children);
    }
    /*
     *Free the global variables that may
     *have been allocated by the parser.
     */
    xmlCleanupParser();
    /*
     *  If device is NULL, that means the user did not specify one and is
     *  leaving it up libpcap to find one.
     */
}


void sniff(const u_char *packet , int flag)
{
    int i,x,tcpOpen=0;
    int protocol=-1; // 0- tcp, 1- udp, 2 -icmp
    tcp = (struct sniff_tcp*)(packet + 34); //skipping the ethernet and IP layers
    udp = (struct sniff_udp *)(packet + 34); //skipping the ethernet and IP layers
    ip = (struct sniff_ip *)(packet + SIZE_ETHERNET);
    icmp = (struct sniff_icmp *)(packet+ 34);
    ether = (struct sniff_ethernet *)(packet);

    printf("/n1--%d/n",IP_HL(ip)*4);
    //if(ntohs(tcp->th_sport) == 80 || ntohs(tcp->th_dport) == 80)
        //{

        if(ip->ip_p==IP_TYPE_TCP )
        {
            protocol = 0;
            payload_s = ntohs(ip->ip_len) - TH_OFF(tcp)*4 - IP_HL(ip)*4;

            if (payload_s)
                payload = (char* )(packet + SIZE_ETHERNET + TH_OFF(tcp)*4 + IP_HL(ip)*4);
            else
                payload = NULL;

        }
        else if(ip->ip_p == IP_TYPE_UDP){
            protocol = 1;
            payload_s = ntohs(ip->ip_len) - ntohs(udp->udp_len) - IP_HL(ip)*4;

            if (payload_s)
                payload = (char* )(packet + SIZE_ETHERNET + ntohs(udp->udp_len) + IP_HL(ip)*4);
            else
                payload = NULL;
        }
        else if(ip->ip_p == IP_TYPE_ICMP)
        {
            protocol = 2;
            payload_s = ntohs(ip->ip_len) - 8 - IP_HL(ip)*4;

            if (payload_s)
                payload = (char* )(packet + SIZE_ETHERNET + 8 + IP_HL(ip)*4);
            else
                payload = NULL;
        }   


            if(flag == 0)// we got a packet from the internal
            {
                if( ip->ip_p == IP_TYPE_TCP)
                {
                    for(i=0;iip_p)
                                if(nTable[i].ip_src.s_addr == ip->ip_src.s_addr)
                                    if(nTable[i].ip_dst.s_addr == ip->ip_dst.s_addr)
                                        if(ntohs(nTable[i].srcPort) == ntohs(tcp->th_sport))
                                            if(ntohs(nTable[i].dstPort) == ntohs(tcp->th_dport))
                                            {
                                                printf("we are in an open connection \n");
                                                changeSrcPacket(packet ,(i+2000)%8000 ,protocol);
                                                tcpOpen = 1;
                                                break;
                                            }
                    }           
                }
                if(tcpOpen == 0)
                {
                    for(i=0;iip_p == IP_TYPE_UDP ||ip->ip_p == IP_TYPE_TCP    )
                        {
                            if(nTable[i].free==0)
                            {
                                nTable[i].free=1;
                                nTable[i].ip_src = ip->ip_src;
                                nTable[i].ip_dst = ip->ip_dst;
                                nTable[i].srcPort = tcp->th_sport;
                                nTable[i].dstPort = tcp->th_dport;
                                nTable[i].protocol = ip->ip_p;
                                //printf("index : %d  ipsrc : %s  srcport : %d\n",i,inet_ntoa(nTable[i].ip_src),ntohs(nTable[i].srcPort));
                                ////////////change packet and send it with the src ip of the nat machine 
                                ///////////and the src port is (i+2000)%8000
                                changeSrcPacket(packet ,(i+2000)%8000 ,protocol);
                                break;
                            }
                        }
                        else
                        {
                            if(icmpTable[i].free == 0)
                            {
                                icmpTable[i].free=1;
                                icmpTable[i].ip_src = ip->ip_src;
                                icmpTable[i].ip_dst = ip->ip_dst;
                                icmpTable[i].protocol = ip->ip_p;
                                icmpTable[i].icmp_type = icmp->icmp_type;
                                icmpTable[i].icmp_id1 = icmp->icmp_id1;
                                changeSrcPacket(packet ,-1 ,protocol);
                                break;
                            }
                        }
                    }
                }
            }
            else // flag = 1
            {
            // we got a packet from the external. we want to send it to the right 
            // place in the internal

            //nTable[(tcp->th_dport-2000)%8000];

            //printf("dst: %d , src: %d \n",ntohs(tcp->th_dport),ntohs(tcp->th_sport));

                if(ip->ip_p== IP_TYPE_ICMP)
                {
                    changeDstPacket (packet,-1,protocol);
                }
                else
                {
                    for(x=0;xip_p == IP_TYPE_TCP)
                        {
                            if(((int)(ntohs(tcp->th_dport))-2000)%8000 == x && nTable[x].free == 1)
                            {
                                changeDstPacket (packet,x,protocol);
                                break;
                            }
                        }
                        else
                        {
                            if(((int)(ntohs(udp->udp_destport))-2000)%8000 == x && nTable[x].free == 1)
                            {
                                changeDstPacket (packet,x,protocol);
                                break;
                            }

                        }
                    }   
                }       
            // we create a packet with thw same src ip and port as we got
            // and only the dst port and ip will be the ones that are 
            //saved in nTable[(tcp->th_dport-2000)%8000]
            // now if it is in udp we will put 0 in nTable[(tcp->th_dport-2000)%8000].free


            }

}

void changeSrcPacket(const u_char *packet , int srcPort, int protocol)
{
    libnet_t *l;
    libnet_ptag_t ipv, ptag, popt,icmp;
    char errbuf[LIBNET_ERRBUF_SIZE];
    uint32_t nat_adder;

     size_t ip_hlen=IP_HL(ip)*4;
     size_t ip_len=ntohs(ip->ip_len);

    size_t tcp_len = ip_len - ip_hlen;

    printf("\n%d %d %d %d",IP_HL(ip),ip_hlen,ip_len,tcp_len);


    icmp = ptag = ipv = LIBNET_PTAG_INITIALIZER;


     nat_adder = libnet_name2addr4(l,"192.168.191.137",LIBNET_DONT_RESOLVE);

     l = libnet_init(LIBNET_RAW4,config.extNIC, errbuf);

     if(protocol == 0)//TCP
     {

         if(TH_OFF(tcp)*4 > TCP_HEADER_SIZE)
         {
                options = (char*)packet + 54;
                options_s = TH_OFF(tcp)*4 - TCP_HEADER_SIZE;
                popt = libnet_build_tcp_options((u_int8_t*)options,options_s, l,0);     
         }

         ptag = libnet_build_tcp(
          srcPort, // source port
          ntohs(tcp->th_dport), // dest port
          htonl(tcp->th_seq), // sequence number
          ntohl(tcp->th_ack), // ack number
          tcp->th_flags, // flags
          ntohs(tcp->th_win), // window size
          0, // checksum
          ntohs(tcp->th_urp), // urg ptr
          TH_OFF(tcp)*4, // total length of the TCP packet
          (u_int8_t*)payload, // response
          payload_s, // response_length
          l, // libnet_t pointer
          ptag // ptag
          );


          printf("%d, %d, %d, %d, %d\n", TH_OFF(tcp)*4, IP_HL(ip)*4, payload_s, ntohs(ip->ip_len),TH_OFF(tcp)*4);
            if(ptag==-1)
             {
                fprintf(stderr, "Error building TCP header: %s\n",libnet_geterror(l));
                exit(1);
             }

    if (libnet_do_checksum(l, (u_int8_t*)ip,IPPROTO_TCP, TH_OFF(tcp)*4) udp_destport), /* destination port */
                udp->udp_len, /* packet length */
                0, /* checksum */
                (u_int8_t*)payload, /* payload */
                payload_s, /* payload size */
                l, /* libnet handle */
                ptag); /* libnet id */

          if(ptag==-1)
          {
             fprintf(stderr, "Error building UDP header: %s\n",libnet_geterror(l));
             exit(1);
          }

     }

   // if(protocol == 2)//ICMP
     //{
        ///add functions of icmp
     // icmp = libnet_build_icmpv4_echo(
        //ICMP_ECHO, /* type */
        //0, /* code */
        //0, /* checksum */
        //icmp->icmp_id1, /* id */
        //icmp->icmp_seq1, /* sequence number */
        //payload, /* payload */
        //payload_s, /* payload size */
        //l, /* libnet context */
        //icmp); /* ptag */

        //if (icmp == -1)
        //{
        //  fprintf(stderr, "Can't build ICMP header: %s\n",
        //  libnet_geterror(l));

        //}
    // }


       ipv = libnet_build_ipv4(
                                                /* total length */
                   ntohs(ip->ip_len),
                    ip->ip_tos,                          /* type of service */
                    ntohs(ip->ip_id),                        /* identification */
                    ntohs(ip->ip_off),                          /* fragmentation */
                    ip->ip_ttl,                         /* time to live */
                    ip->ip_p,                /* protocol */
                    0,                          /* checksum */
                    nat_adder,                     /* (Nat) source */
                    ip->ip_dst.s_addr,                     /* destination */
                   NULL,                       /* payload */
                   0,                          /* payload size */
                    l,                          /* libnet handle */
                    0);                         /* ptag */

        if(ipv == -1)
        {
            fprintf(stderr,"Error building IP header: %s\n", libnet_geterror(l));
            exit(1);
        }

        /*if (libnet_do_checksum(l, (u_int8_t*)l, IPPROTO_IP, ntohs(ip->ip_len) + payload_s) th_flags == 0x01)
            {
                nTable[index].fin++;
            }
            if(tcp->th_flags == 0x11 && nTable[index].fin == 1)
            {
                nTable[index].fin++;
            }
            if(tcp->th_flags == 0x10 && nTable[index].fin == 2)
            {
                nTable[index].free = 0; 
                nTable[index].fin = 0;
            }
        }


         // Fix IP header checksum
  //  ip->ip_sum = 0;
    if (libnet_do_checksum(l, (u_int8_t*)ip,IPPROTO_IP, IP_HL(ip)*4) th_sport),ntohs(nTable[index].srcPort));
    printf("src ip : %s    dst ip: %s\n",inet_ntoa(ip->ip_src), inet_ntoa(nTable[index].ip_src));

    ptag = ipv = LIBNET_PTAG_INITIALIZER;

    if(protocol == 0 || protocol == 1) // udp or tcp
    {

        if(nTable[index].free == 1)
        {
            l = libnet_init(LIBNET_RAW4,config.intNIC, errbuf);

            if(protocol == 0 ) //TCP
            {

                if(TH_OFF(tcp)*4 > TCP_HEADER_SIZE)
                {
                     options = (char*)packet + 54;
                     options_s = TH_OFF(tcp)*4 - TCP_HEADER_SIZE;
                     popt = libnet_build_tcp_options((u_int8_t*)options,options_s, l,0);

                }

                  ptag = libnet_build_tcp(
                  ntohs(tcp->th_sport), // source port
                  ntohs(nTable[index].srcPort), // dest port
                  ntohl(tcp->th_seq), // sequence number
                  ntohl(tcp->th_ack), // ack number
                  tcp->th_flags, // flags
                  ntohs(tcp->th_win), // window size
                  0, // checksum
                  ntohs(tcp->th_urp), // urg ptr
                  TH_OFF(tcp)*4, // total length of the TCP packet
                  (u_int8_t*)payload, // response
                  payload_s, // response_length
                  l, // libnet_t pointer
                  ptag // ptag
                  );

                  if(ptag==-1)
                  {
                    fprintf(stderr, "Error building TCP header: %s\n",libnet_geterror(l));
                    exit(1);
                  }
            }

            if(protocol == 1)// UDP
            {
                ptag = libnet_build_udp(
                    ntohs(udp->udp_srcport), /* source port */
                    ntohs(nTable[index].srcPort), /* destination port */
                    udp->udp_len, /* packet length */
                    0, /* checksum */
                    (u_int8_t*)payload, /* payload */
                    payload_s, /* payload size */
                    l, /* libnet handle */
                    ptag); /* libnet id */

                if(ptag==-1)
                {
                    fprintf(stderr, "Error building UDP header: %s\n",libnet_geterror(l));
                    exit(1);
                }
            }
        }
    }
    if(protocol == 2) // ICMP
    {
        for(i=0;i icmp_type)
                    if(icmpTable[i].ip_dst.s_addr == ip->ip_src.s_addr)
                        if(icmpTable[i].icmp_id1 == icmp->icmp_id1)
                        {
                            index = i;
                            break;
                        }

        }

        ///add functions of icmp

    }

              ipv = libnet_build_ipv4(
                                                        /* total length */
                            ntohs(ip->ip_len),
                            ip->ip_tos,                          /* type of service */
                            ntohs(ip->ip_id),                        /* identification */
                            ntohs(ip->ip_off),                          /* fragmentation */
                            ip->ip_ttl,                         /* time to live */
                            ip->ip_p,                /* protocol */
                           0,                           /* checksum */
                            ip->ip_src.s_addr,                     /* (Nat) source */
                            nTable[index].ip_src.s_addr,                     /* destination */
                            NULL,                       /* payload */
                            0,                          /* payload size */
                            l,                          /* libnet handle */
                            0);                          /* ptag */
               if(ipv == -1)
              {
                fprintf(stderr,"Error building IP header: %s\n", libnet_geterror(l));
                exit(1);
              }   

            /*if (libnet_do_checksum(l, (u_int8_t*)l, IPPROTO_IP, ntohs(ip->ip_len) + payload_s) th_flags == 0x01)
                    {
                        nTable[index].fin++;
                    }
                    if(tcp->th_flags == 0x11 && nTable[index].fin == 1)
                    {
                        nTable[index].fin++;
                    }
                    if(tcp->th_flags == 0x10 && nTable[index].fin == 2)
                    {
                        nTable[index].free = 0; 
                        nTable[index].fin = 0;
                    }
                }
                else
                {
                    nTable[index].free = 0; 
                    nTable[index].fin = 0;
                }
            }


            if ( libnet_write(l) == -1 )
                      fprintf(stderr, "Error writing packet: %s\n",libnet_geterror(l));
            libnet_destroy(l);

}