在Python中计算ICMP echo请求的校验和

问题描述 投票:1回答:1

我试图在Python中实现ping服务器,我将通过Pyping的源代码作为参考:https://github.com/Akhavi/pyping/blob/master/pyping/core.py

我无法理解为计算ICMP回应请求的校验和而实现的calculate_checksum函数。它的实施如下:

def calculate_checksum(source_string):

    countTo = (int(len(source_string) / 2)) * 2
    sum = 0
    count = 0

    # Handle bytes in pairs (decoding as short ints)
    loByte = 0
    hiByte = 0
    while count < countTo:
        if (sys.byteorder == "little"):
            loByte = source_string[count]
            hiByte = source_string[count + 1]
        else:
            loByte = source_string[count + 1]
            hiByte = source_string[count]
        sum = sum + (ord(hiByte) * 256 + ord(loByte))
        count += 2

    # Handle last byte if applicable (odd-number of bytes)
    # Endianness should be irrelevant in this case
    if countTo < len(source_string): # Check for odd length
        loByte = source_string[len(source_string) - 1]
        sum += ord(loByte)

    sum &= 0xffffffff # Truncate sum to 32 bits (a variance from ping.c, which
                      # uses signed ints, but overflow is unlikely in ping)

    sum = (sum >> 16) + (sum & 0xffff)  # Add high 16 bits to low 16 bits
    sum += (sum >> 16)                  # Add carry from above (if any)
    answer = ~sum & 0xffff              # Invert and truncate to 16 bits
    answer = socket.htons(answer)

    return answer

sum&= 0xffffffff用于将总和截断为32位。但是,额外的位(第33位)会发生什么。不应该作为一个附加物加入总和吗?此外,我无法理解此后的代码。

我阅读了RFC1071文档(http://www.faqs.org/rfcs/rfc1071.html),该文档解释了如何实现校验和,但我无法理解。

任何帮助,将不胜感激。谢谢!

python-3.x checksum icmp
1个回答
0
投票

我终于能够弄清楚calculate_checksum函数的工作情况,我试图在下面解释它。

校验和计算如下(根据RFC1071):

  • source_string中的相邻八位字节配对形成16位整数,并计算这些整数的1's complement sum。在奇数个八位字节的情况下,从n-1个八位字节中创建对并添加,并将剩余的八位字节添加到总和中。
  • 产生的和被截断为16位(要处理进位),并通过取1的补码计算校验和。最终校验和应为16位长。

我们来举个例子吧。

如果要在八位字节序列[A,B,C,D,E]上计算校验和,则创建的对将是[A,B]和[C,D],其余的八位字节为E.对[ a,b]可以如下计算:

a * 256 + b其中a和b是八位字节

假如a是11001010且b是00010001,a * 256 + b = 1100101000010001,从而给出了八位组的连接结果。

因此,1的补数和计算如下:

sum = [A + B] +'[C + D] +'E其中+'表示1的补码加法

现在回到代码,行和&x 0xffffffff之前的所有内容计算我们之前计算的1的补码和。


我是&lt; 0&gt;

用于将总和截断为32位,尽管由于source_string的大小不是很大而在ping中不太可能超过总和

(source_string = header(8字节)+ payload(可变长度))。


am =(am >> 16)+(am&amp; fffffff)

这段代码是在总和大于16位的情况下实现的。总和分为两部分:

(sum >> 16):高阶16位

(sum&0xffff):低位16位

然后添加这两部分。最终结果可以是16位,而不是16位


我是+ =(I >> 16)

该行用于以前计算的结果总和超过16位并用于处理进位,类似于前一行。


最后,计算1的补码并截断为16位。 socket.htons()函数用于维护基于设备架构(Little endian和big endian)发送到网络的字节排列。

© www.soinside.com 2019 - 2024. All rights reserved.