lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 26 Oct 2007 21:33:07 +0530
From:	"Gaurav Aggarwal" <grv.aggarwal@...il.com>
To:	linux-net-owner@...r.kernel.org
Cc:	netfilter-devel@...r.kernel.org, netdev@...r.kernel.org,
	linux-net@...r.kernel.org, linux-kernel@...r.kernel.org,
	davidsen@....com, "Gaurav Aggarwal" <grv.aggarwal@...il.com>
Subject: Re: Bad TCP checksum error

Hi All,

I have dome some changes in the code. Now instead of calculating the
TCP checksum from scratch, I was just recalculating it by incremental
update as mentioned in RFC 1624. Good thing is that now I was able to
get the correct IP header checksum but still TCP checksum value is
corrupted. Interesting thing is, this time the difference in checksum
is exactly the same as that of difference in original and modified
packet header. What I mean to say is that I was changing the
destination IP from "10.102.35.22" to "10.102.35.24" and the
difference in tcp checksum (expected and computed) is coming as 0x02.
Attached is the modified source code and tcpdump. Any help will be
really appreciated.

On 10/26/07, Gaurav Aggarwal <grv.aggarwal@...il.com> wrote:
> Hi,
>
> I wrote a program where I am using the nfnetlink and netfilter_queue
> model to capture the packet. After that I just change the destination
> address of the packet and insert it back into the ip stack. But after
> inserting the packet I am getting a bad TCP checksum error. Even I am
> getting the same error for IP header checksum. Attached is the source
> code and tcpdump on host machine.
>
> /* Source Code */
> /* Compile with gcc -lnfnetlink -lnetfilter_queue  */
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> #include <netinet/in.h>
> #include <netinet/ip.h>
> #include <netinet/tcp.h>
> #include <linux/netfilter.h>            /* for NF_ACCEPT */
> #include <arpa/inet.h>
>
> #include <libnetfilter_queue/libnetfilter_queue.h>
>
> #define  BUFSIZE  2048
>
> struct in_addr foreign;
> struct in_addr local;
>
> struct queued_pckt {
>         char *payload;
>         int payload_len;
> };
>
> struct pseudohdr
> {
>         unsigned long ip_src ;
>         unsigned long ip_dst ;
>         unsigned char reserve ;
>         unsigned char type ;
>         unsigned short length;
> } ;
>
> unsigned short checksum(unsigned short *addr, unsigned int count) {
>         /* Compute Internet Checksum for "count" bytes beginning at location "addr".
>          * Algorithm is simple, using a 32-bit accumulator (sum),
>          * we add sequential 16-bit words to it, and at the end, fold back
>          * all the carry bits from the top 16 bits into the lower 16 bits.
>         */
>        register long sum = 0;
>        unsigned short result;
>
>         while (count > 1)  {
>            /*  This is the inner loop */
>                sum += * addr++;
>                count -= 2;
>        }
>            /*  Add left-over byte, if any */
>        if (count == 1)
>        {
>                 result = 0;     //make sure top half is zero
>                 * (unsigned char *) (&result) = *(unsigned char *)addr;
>                 sum += result;
>         }
>
>         /*
>          * Add back carry outs from top 16 bits to low 16 bits.
>          * Fold 32-bit sum to 16 bits
>         */
>
>        sum = (sum >> 16) + (sum & 0xffff);      /* add high-16 to low-16 */
>        sum += (sum >> 16);                      /* add carry */
>
>        result = ~sum;                   /* ones-complement, then truncate to 16 bits */
>        return (result);
> }
>
>
> unsigned short get_tcp_chksum (struct tcphdr *orig_tcphdr, struct
> iphdr *orig_iphdr )
> {
>         struct pseudohdr pseudoh ;
>
>         unsigned int total_len = ntohs(orig_iphdr->tot_len);
>         int tcpopt_len = (orig_tcphdr->doff * 4) - 20;
>         int tcpdata_len = total_len - (orig_tcphdr->doff * 4) - (orig_iphdr->ihl * 4);
>
>         pseudoh.ip_src = orig_iphdr->saddr ;
>         pseudoh.ip_dst = orig_iphdr->daddr ;
>         pseudoh.reserve = 0 ;
>         pseudoh.type = orig_iphdr->protocol ;
>         pseudoh.length = htons (sizeof (struct tcphdr) + tcpopt_len + tcpdata_len) ;
>
>         int totaltcp_len = sizeof(struct pseudohdr) + sizeof(struct tcphdr) +
> tcpopt_len + tcpdata_len;
>
>         unsigned short *tcp = (unsigned short *)malloc (totaltcp_len);
>
>         memcpy ((unsigned char *)tcp, &pseudoh, sizeof(struct pseudohdr));
>         memcpy ((unsigned char *)tcp + sizeof(struct pseudohdr), (unsigned
> char *)orig_tcphdr, sizeof(struct tcphdr));
>         if (tcpopt_len > 0)
>                 memcpy ((unsigned char *)tcp + sizeof(struct pseudohdr) +
> sizeof(struct tcphdr), (unsigned char *)orig_iphdr + (orig_iphdr->ihl
> * 4) + sizeof(struct tcphdr), tcpopt_len);
>
>         if (tcpdata_len > 0)
>                 memcpy ((unsigned char *)tcp + sizeof(struct pseudohdr) +
> sizeof(struct tcphdr) + tcpopt_len, (unsigned char *)orig_tcphdr +
> (orig_tcphdr->doff * 4), tcpdata_len);
>
> #if 0
>         printf("pseudo length: %d\n",pseudoh.length);
>         printf("tcp hdr length: %d\n",orig_tcphdr->doff*4);
>         printf("tcp hdr struct length: %d\n",sizeof(struct tcphdr));
>         printf("tcphdr->doff = %d, tcp opt length:
> %d\n",orig_tcphdr->doff,tcpopt_len);
>         printf("tcp total+psuedo length: %d\n",totaltcp_len);
>
>         fflush(stdout);
>
>         printf("tcp data len: %d, data start %u\n",
> tcpdata_len,orig_tcphdr + (orig_tcphdr->doff*4));
> #endif
>
>         return (checksum (tcp, totaltcp_len)) ;
> }
>
> static void filter(
>         unsigned char *packet, unsigned int payload_len)
> {
>         struct iphdr *iphdr;
>         struct tcphdr *tcphdr;
>
>         printf ("in filter function\n");
>
>         iphdr = (struct iphdr *)packet;
>         /* check need some datas */
>         if (payload_len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
>                 return;
>         }
>         /* check IP version */
>         if (iphdr->protocol == IPPROTO_TCP)
>         {
>                 tcphdr = (struct tcphdr *)(((u_int32_t *)packet) + 4 * iphdr->ihl);
>
>                 if (iphdr->daddr == foreign.s_addr)
>                 {
>                         printf ("packet DEST addr = %s\n",inet_ntoa(foreign));
>                         fprintf (stderr, "changing pkt's DEST addr from FOREIGN to LOCAL\n");
>                         iphdr->daddr = local.s_addr;
>                         tcphdr->check = 0 ; // checksum will be calculated later
>                         iphdr->check = checksum(
>                                 (unsigned short *)iphdr,
>                                 sizeof(struct iphdr));
>                         tcphdr->check = get_tcp_chksum(
>                                 tcphdr,
>                                 iphdr);
>                 }
>         }
>
> }
>
> static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
>               struct nfq_data *nfa, void *data)
> {
>         int id = 0;
>         struct nfqnl_msg_packet_hdr *ph;
>         struct queued_pckt q_pckt;
>         u_int32_t mark,ifi;
>         int ret;
>         char *payload;
>
>         printf("entering callback\n");
>         ph = nfq_get_msg_packet_hdr(nfa);
>         if (ph){
>                 id = ntohl(ph->packet_id);
>                 printf("hw_protocol=0x%04x hook=%u id=%u ",
>                         ntohs(ph->hw_protocol), ph->hook, id);
>         }
>
>         mark = nfq_get_nfmark(nfa);
>         if (mark)
>                 printf("mark=%u ", mark);
>
>         ifi = nfq_get_indev(nfa);
>         if (ifi)
>                 printf("indev=%u ", ifi);
>
>         ifi = nfq_get_outdev(nfa);
>         if (ifi)
>                 printf("outdev=%u ", ifi);
>
>         q_pckt.payload_len = nfq_get_payload(nfa, &(q_pckt.payload));
>         if (q_pckt.payload_len >= 0)
>         {
>                 printf("payload_len=%d ", q_pckt.payload_len);
>                 fputc('\n', stdout);
>                 filter((unsigned char *)q_pckt.payload, q_pckt.payload_len);
>         }
>
>         printf("setting verdict of packet id %d\n",id);
>         return nfq_set_verdict(qh, id, NF_ACCEPT, q_pckt.payload_len, q_pckt.payload);
> }
>
> int main(int argc, char **argv)
> {
>         struct nfq_handle *h;
>         struct nfq_q_handle *qh;
>         struct nfnl_handle *nh;
>         int fd;
>         int rv;
>         unsigned char buf[BUFSIZE];
>
>         if (argc == 1)
>         {
>                 inet_aton("10.102.130.222", &(foreign));
>                 inet_aton("10.102.130.105", &(local));
>         } else if (argc == 3)
>         {
>                 inet_aton(argv[1], &(foreign));
>                 inet_aton(argv[2], &(local));
>         }
>         else
>         {
>                 printf("Usage: argv[0] [foreign_addr local_addr]\n");
>                 return 0;
>         }
>
>         printf("opening library handle\n");
>         h = nfq_open();
>         if (!h) {
>                 fprintf(stderr, "error during nfq_open()\n");
>                 return 0;
>         }
>
>         printf("unbinding existing nf_queue handler for AF_INET (if any)\n");
>         if (nfq_unbind_pf(h, AF_INET) < 0) {
>                 fprintf(stderr, "error during nfq_unbind_pf()\n");
>                 exit(1);
>         }
>
>         printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
>         if (nfq_bind_pf(h, AF_INET) < 0) {
>                 fprintf(stderr, "error during nfq_bind_pf()\n");
>                 exit(1);
>         }
>
>         printf("binding this socket to queue '0'\n");
>         qh = nfq_create_queue(h,  0, &cb, NULL);
>         if (!qh) {
>                 fprintf(stderr, "error during nfq_create_queue()\n");
>                 exit(1);
>         }
>
>         printf("setting copy_packet mode\n");
>         if (nfq_set_mode(qh, NFQNL_COPY_PACKET, BUFSIZE) < 0) {
>                 fprintf(stderr, "can't set packet_copy mode\n");
>                 exit(1);
>         }
>
>         nh = nfq_nfnlh(h);
>         fd = nfnl_fd(nh);
>
>         while ((rv = recv(fd, buf, BUFSIZE, 0)) && rv >= 0) {
>                 printf("pkt received\n");
>                 nfq_handle_packet(h, buf, rv);
>                 printf("pkt handled\n");
>         }
>
>         printf("unbinding from queue 0\n");
>         nfq_destroy_queue(qh);
>
>         printf("closing library handle\n");
>         nfq_close(h);
>
>         exit(0);
> }
> /* end - Source Code */
>
> /* TCP dump */
> tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
> 12:59:36.706161 IP (tos 0x0, ttl  64, id 61974, offset 0, flags [DF],
> proto: TCP (6), length: 60, bad cksum 75 (->8e24)!) 10.102.35.76.36898
> > 10.102.130.105.colubris: S, cksum 0xc6d5 (incorrect (-> 0xc74a),
> 366446207:366446207(0) win 5840 <mss 1460,sackOK,timestamp 14775401
> 0,nop,wscale 6>
>         0x0000:  0012 010a 5f4c 000b cd3a 5bfb 0800 4500
>         0x0010:  003c f216 4000 4006 0075 0a66 234c 0a66
>         0x0020:  8269 9022 0da2 15d7 867f 0000 0000 a002
>         0x0030:  16d0 c6d5 0000 0204 05b4 0402 080a 00e1
>         0x0040:  7469 0000 0000 0103 0306
> 12:59:39.708619 IP (tos 0x0, ttl  64, id 61975, offset 0, flags [DF],
> proto: TCP (6), length: 60, bad cksum 75 (->8e23)!) 10.102.35.76.36898
> > 10.102.130.105.colubris: S, cksum 0xc3e7 (incorrect (-> 0xc45c),
> 366446207:366446207(0) win 5840 <mss 1460,sackOK,timestamp 14776151
> 0,nop,wscale 6>
>         0x0000:  0012 010a 5f4c 000b cd3a 5bfb 0800 4500
>         0x0010:  003c f217 4000 4006 0075 0a66 234c 0a66
>         0x0020:  8269 9022 0da2 15d7 867f 0000 0000 a002
>         0x0030:  16d0 c3e7 0000 0204 05b4 0402 080a 00e1
>         0x0040:  7757 0000 0000 0103 0306
>
> 2 packets captured
> 4 packets received by filter
> 0 packets dropped by kernel
> /* End - TCP dump */
>
> Attached is the dump for ethreal also.
>
> --
> Regards,
> Gaurav Aggarwal
>
>


-- 
Regards,
Gaurav Aggarwal

Download attachment "nfq_test_modified.c" of type "application/octet-stream" (4157 bytes)

View attachment "tcpdump.txt" of type "text/plain" (1136 bytes)

Download attachment "ethreal_dump.pcap" of type "application/octet-stream" (338 bytes)

Powered by blists - more mailing lists