typedef struct iphdr 
{
    u_char  ip_hl:4,        /* header length */
            ip_v:4;         /* version */
    u_char  ip_tos;         /* type of service */
    short   ip_len;         /* total length */
    u_short ip_id;          /* identification */
    short   ip_off;         /* fragment offset field */
#define IP_DF 0x4000        /* dont fragment flag */
#define IP_MF 0x2000        /* more fragments flag */
    u_char  ip_ttl;         /* time to live */
    u_char  ip_p;           /* protocol */
    u_short ip_sum;         /* checksum */
    struct  in_addr ip_src,ip_dst;  /* source and dest address */
} iphdr, *iphdr_ptr;


VOID RecalculateIPChecksum (
        iphdr_ptr pIpHeader 
        )
{
    unsigned short word16;
    unsigned int sum = 0;
    unsigned int i = 0;
    PUCHAR buff;

    // Initialize checksum to zero
    pIpHeader->ip_sum = 0;
    buff = (PUCHAR)pIpHeader;

    // Calculate IP header checksum
    for (i = 0; i < pIpHeader->ip_hl*sizeof(DWORD); i=i+2)
    {
        word16 = ((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF);
        sum = sum+word16; 
    }

    // keep only the last 16 bits of the 32 bit calculated sum and add the carries
    while (sum>>16)
        sum = (sum & 0xFFFF)+(sum >> 16);

    // Take the one's complement of sum
    sum = ~sum;

    pIpHeader->ip_sum = htons((unsigned short) sum);
}

Edited 3 Years Ago by Reverend Jim: Fixed formatting

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:

  1. typedef unsigned char* PUCHAR;
  2. 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!

Thank you so much. This gives me a lot of help with other peaces of code.

Ray

This question has already been answered. Start a new discussion instead.