вычислить контрольную сумму IP в Python - PullRequest
1 голос
/ 16 октября 2010

Мне нужно вычислить контрольную сумму IP-пакета, как описано в http://www.faqs.org/rfcs/rfc1071.html.

У меня уже есть следующий код:

#!/usr/bin/python
import struct

data = "45 00 00 47 73 88 40 00 40 06 a2 c4 83 9f 0e 85 83 9f 0e a1"

# a test for the checksum calculation

def _checksum(data):
    #calculate the header sum
    ip_header_sum = sum(struct.unpack_from("6H", data))
    #add the carry
    ip_header_sum = (ip_header_sum & 0xFFFF) + (ip_header_sum >> 16 & 0xFFFF)
    #invert the sum, python does not support inversion (~a is -a + 1) so we have to do
    #little trick: ~a is the same as 0xFFFF & ~a
    ip_header_sum = ~ip_header_sum & 0xFFFF

    return ip_header_sum #should return 0 if correct

data = data.split()
data = map(lambda x: int(x,16), data)
data = struct.pack("%dB" % len(data), *data)

print " ".join(map(lambda x: "0x%02x" % ord(x), data))
print "Checksum: 0x%04x" % _checksum(data)

Он работает с захваченным пакетомс wireshark, который должен иметь правильную контрольную сумму и поэтому должен иметь значение 0

К сожалению, результат равен 0x6524.Также интересно, что результат всегда равен 0x6524 для каждого правильного пакета ...

Кто обнаружит ошибку?

Отредактировано, чтобы ошибка стала более понятной * Отредактировановторой раз *

Ответы [ 2 ]

8 голосов
/ 17 октября 2010

Вы можете использовать решение непосредственно из Python для вычисления контрольной суммы udp , в результате чего ожидаемое значение контрольной суммы равно нулю.

import struct

data = "45 00 00 47 73 88 40 00 40 06 a2 c4 83 9f 0e 85 83 9f 0e a1"

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

data = data.split()
data = map(lambda x: int(x,16), data)
data = struct.pack("%dB" % len(data), *data)

print ' '.join('%02X' % ord(x) for x in data)
print "Checksum: 0x%04x" % checksum(data)

Результаты:

45 00 00 47 73 88 40 00 40 06 A2 C4 83 9F 0E 85 83 9F 0E A1
Checksum: 0x0000
6 голосов
/ 16 октября 2010

У вас здесь два вопроса.

Во-первых, ваш вызов struct.unpack_from распаковывает только 4 16-битных значения (то есть 8 байтов) из буфера. Если вы хотите распаковать весь заголовок, вам нужно сделать что-то вроде struct.unpack_from("!nH"), где n - это количество шорт, которые вы хотите распаковать. Вы можете сгенерировать соответствующую строку формата с помощью struct.unpack_from("!%dH"%(len(data)/2), data), предполагая, что data не содержит ничего, кроме заголовка IP.

Во-вторых, как только вы это сделаете, вы обнаружите, что контрольная сумма теперь работает до 0. Это правильный результат для пакета, для которого уже установлена ​​контрольная сумма, как этот. (Вы выделили байты A2 и C4 в пакете выше.) Чтобы вычислить правильную контрольную сумму для пакета с нуля, необходимо установить байты контрольной суммы равными 0. (См. Начало шага 2 в RFC1071: Для создания контрольной суммы само поле контрольной суммы очищается ".)

...