lkml.org 
[lkml]   [2007]   [Oct]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectBad TCP checksum error
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
[unhandled content-type:application/octet-stream][unhandled content-type:application/octet-stream]
\
 
 \ /
  Last update: 2007-10-26 09:45    [W:0.099 / U:0.028 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site