From: | gregoa [...] cpan.org |
Subject: | libnet-rawip-perl: miscalculates header checksums |
[ This bug has been forwarded from http://bugs.debian.org/623634 ]
From: "Steinar H. Gunderson" <sgunderson@bigfoot.com>
To: Debian Bug Tracking System <submit@bugs.debian.org>
Subject: Bug#623634: libnet-rawip-perl: miscalculates header checksums
Date: Fri, 22 Apr 2011 01:28:29 +0200
Reply-To: "Steinar H. Gunderson" <sgunderson@bigfoot.com>,
623634@bugs.debian.org
Hi,
It seems Net::RawIP, if you run a script using it long enough
(as in millions of generated UDP packets), eventually generates
bogus UDP checksums in the packets it's sending out (tcpdump
freaks out, the end hosts start ignoring them). I took a
look at the source, and it seems the following fragment from
RawIP.xs in the udp_pkt_creat() function is the culprit:
memcpy(ptr,(u_char*)&piu,20);
memcpy(ptr+20,SvPV(ip_opts,PL_na),SvCUR(ip_opts));
memcpy(ptr+20+SvCUR(ip_opts),(u_char*)&piu + 20,8);
((struct iphdr*)ptr)->check = in_cksum((unsigned short *)ptr,iplen);
RETVAL = newSVpv((char*)ptr, sizeof(IUPKT)+SvCUR(ip_opts));
You can't use cast-as-lvalue like this; it is an aliasing
violation, and with newer gcc seemingly something wrong happens
here. The easiest way to fix this is usually by using memcpy
(which has specific exceptions in POSIX from the aliasing rules),
like this:
unsigned short cksum;
[...]
cksum = in_cksum((unsigned short *)ptr,iplen);
memcpy(&((struct iphdr*)ptr)->check, &cksum, sizeof(cksum));
Adding this fragment seems to have fixed the issue for us;
at least it's running stable for a day or so. Granted, we also
run with noopt nostrip, so it _could_ be something else, but
it really sticks out as a sore thumb.
FWIW, there are similar fragments many other places in the code,
so you should probably fix all of them.