2

Over the last few days, I am passionate about the ICMP protocol and I found a python function that calculates its checksum:

def carry_around_add(a, b):
    c = a + b
    return (c & 0xffff) + (c >> 16)

def checksum(msg):
   s = 0
   for i in range(0, len(msg), 2):
       w = ord(msg[i]) + (ord(msg[i+1]) << 8)
       s = carry_around_add(s, w)
   return ~s & 0xffff

print checksum("abcdefghijklmnopqrst")

In this picture of a wireshark capture: http://memory00stack.files.wordpress.com/2013/12/resultat.png

The checksum is "0xcfcb" but the function in my test returns "55 245 -> 0xd7cd". Why ?

Thanks so much =)

Brian Cain
  • 14,403
  • 3
  • 50
  • 88
newuser
  • 67
  • 3
  • 8

1 Answers1

3

Your wireshark dump shows the ICMP checksum, but (wikipedia):

The third and fourth bytes are a checksum of the entire ICMP message.

...

Checksum – Error checking data, calculated from the ICMP header and data, with value 0 substituted for this field. The Internet Checksum is used, specified in RFC 1071.

Your input to the checksum routine in your test is only the ASCII payload portion. You must provide the entire ICMP input.


For example:

def carry_around_add(a, b):
    c = a + b
    return (c & 0xffff) + (c >> 16)

def checksum(msg):
   s = 0
   for i in range(0, len(msg), 2):
       w = ord(msg[i]) + (ord(msg[i+1]) << 8)
       s = carry_around_add(s, w)
   return ~s & 0xffff

payload_body = "abcdefghijklmnopqrst"
chk = checksum(payload_body)
print chk, '{:x}'.format(chk), '(host byte order)'

msg_type = '\x08' # ICMP Echo Request
msg_code = '\x00' # must be zero
msg_checksum_padding = '\x00\x00' # "...with value 0 substituted for this field..."
rest_header = '\x00\x01\x00\x01' # from pcap
entire_message = msg_type + msg_code + msg_checksum_padding + rest_header + payload_body
entire_chk = checksum(entire_message)
print entire_chk, '{:x}'.format(entire_chk), '(host byte order)'

When I run this on my (little endian) machine, I get:

$ ./icmp_checksum_test.py 
52695 cdd7 (host byte order)
52175 cbcf (host byte order)
Brian Cain
  • 14,403
  • 3
  • 50
  • 88
  • You talk datagram icmp ? Type(8bits), Code(8bits), Checksum(16bits) and message. But how to do this in Python ?? Thanks !! – newuser Jan 03 '14 at 14:38
  • @newuser, I've extended the answer to include more details. It's just a matter of including the other fields as input. – Brian Cain Jan 03 '14 at 14:52
  • thanks you so much. I understood everything !! I could have some details on "msg_checksum_padding" and "rest_header" ? – newuser Jan 03 '14 at 15:02
  • I got those values from your wireshark capture. Are you merely experimenting with ICMP or are you integrating the code described in the question above with something that actually does packet captures (like scapy)? – Brian Cain Jan 03 '14 at 15:06
  • I think if you asked more detailed questions regarding what you're really trying to do you might get better results. Take note: your `checksum` routine functions as designed, but the problem seems to lie in the integration between the checksum and the rest of the work you're doing. Please describe the problem in its entire context. – Brian Cain Jan 03 '14 at 15:06
  • 1
    I am french thus i try to understand, sorry for my response time. I wanted simply create a ping request with icmp protocol. But it is not easy and i just start learning the protocols – newuser Jan 03 '14 at 15:13