|laziness, impatience, and hubris|
Compensate for bad inet checksum routineby VinsWorldcom (Parson)
|on Mar 29, 2013 at 14:24 UTC||Need Help??|
VinsWorldcom has asked for the
wisdom of the Perl Monks concerning the following question:
I found the solution for my problem here http://fossies.org/dox/wireshark-1.9.1/packet-cdp_8c_source.html starting at line 230. Of course the solution is in C and I need it in Perl (obviously). I already did it and it's working (code below), but there HAS to be a better way than my hack job so if you have some time and want to show me a more elegant way, please proceed.
Cisco Discovery Protocol (CDP) uses the internet checksum routine to calculate it's packet checksum. Of course there's a bug (or perhaps proprietary glitch by design). In any case, the standard internet checksum sub (which I already have) will work, as long as you "massage" the input to compensate. A nice explanation and C code is provided in the link above.
Essentially, if the length of the CDP packet data is odd, internet checksum routine would add \x00 padding before calculating. The bug prevents this from working. Instead, because of an endian-ness assumption, I need to determine if the packet is odd length *BEFORE* sending to inet checksum. If so, instead of adding \x00 padding, we strip the last byte, add the \x00 padding and the re-add the stripped last byte. With an even packet length now, there's one more compensation.
If after the byte-swap, the last byte is now greater than \x80, we need to decrement the last two byes (the added \x00 padding and the re-added original last byte) each by 1.
I created a quick script to pass some data into the prepchksum() sub I wrote. The BEFORE represents the hex (unpack) versions of real CDP packet data payload (after the header) and the output I expect for each follows in the AFTER output:
And now, the code - 'sub prepchksum' - could use some attention if you'd like to educate me on a better way to do it: