That C code is a mess. And it is dangerous because it uses bitfields (which C++ does
not guarantee to be packed in any specific order -- so results vary by compiler!).
Alas, why don't programmers stp usng stpd shrt nonsns nms.
Anyway:
uses
SysUtils, // for PByteArray
Winsock; // for htons()
const
IP_DF = $4000; // don't fragment flag
IP_MF = $2000; // more fragments flag
type
in_addr = record ... end; // you must fill this in
iphdr_ptr = ^iphdr;
iphdr = packed record
ip_hl__ip_v: byte; // header length, version: four bits each
ip_tos: byte; // type of service
ip_len: shortint; // total length
ip_id: word; // identification
ip_off: shortint; // fragment offset field
ip_ttl: byte; // time to live
ip_p: byte; // protocol
ip_sum: word; // checksum
ip_src: in_addr; // source address
ip_dst: in_addr // destination address
end;
procedure RecalculateIPChecksum( pIpHeader: iphdr_ptr );
var
sum: longword;
i: longword;
buff: PByteArray; // see note 1
begin
sum := 0;
i := 0;
// Initialize checksum to zero
pIpHeader^.ip_sum := 0;
buff := pIpHeader;
// Calculate IP header checksum
while i < (pIpHeader^.ip_hl__ip_v and $F) *sizeof( longword ) do // see note 2
begin
inc( sum, (buff[ i ] shl 8) +buff[ i +1 ] );
inc( i, 2 )
end;
// Keep only the last 16 bits of the 32 bit calculated sum and add the carries
while (sum shr 16) <> 0 do
sum := (sum and $FFFF) +(sum shr 16);
// Take the one's complement of sum
sum := sum xor $FFFFFFFF;
// ...and store it in network order
pIpHeader^.ip_sum := htons( sum )
end;
The above code presumes the following:
typedef unsigned char* PUCHAR;- bitfields are packed in MS VC++ order [1], meaning that ip_hl is in the lower four bits and ip_v is in the upper four bits. If this is not the case you will need to change that
and $F to shr 4.
Enjoy!
Last edited by Duoas : May 16th, 2008 at 10:19 am.