Python 3.x 在Python中计算ICMP回显请求的校验和

Python 3.x 在Python中计算ICMP回显请求的校验和,python-3.x,checksum,icmp,Python 3.x,Checksum,Icmp,我正在尝试用Python实现ping服务器,我将阅读Pyping的源代码作为参考: 我无法理解为计算ICMP回显请求的校验和而实现的计算\u校验和功能。已按以下方式实施: def calculate_checksum(source_string): countTo = (int(len(source_string) / 2)) * 2 sum = 0 count = 0 # Handle bytes in pairs (decoding as short in

我正在尝试用Python实现ping服务器,我将阅读Pyping的源代码作为参考:

我无法理解为计算ICMP回显请求的校验和而实现的计算\u校验和功能。已按以下方式实施:

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
def计算校验和(源字符串):
countTo=(int(len(源字符串)/2))*2
总和=0
计数=0
#成对处理字节(解码为短整数)
loByte=0
hiByte=0
当count>16)+(总和&0xffff)#将高16位与低16位相加
sum+=(sum>>16)#从上面加进位(如果有)
答案=~sum&0xffff#反转并截断为16位
答案=插座.htons(答案)
回覆
总和&=0xffffffff用于将总和截断为32位。但是,额外的位(第33位)会发生什么情况。那不应该作为进位加在总数上吗?此外,我无法理解这之后的代码

我阅读了RFC1071文档(),该文档解释了如何实现校验和,但我还不能理解太多


任何帮助都将不胜感激。谢谢

我终于能够弄清楚计算校验和函数的工作原理,我试着在下面解释它

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

  • 源_字符串中的相邻八位字节成对形成16位 整数,这些整数的 计算如果八位字节数为奇数,则从n-1个八位字节中创建对并相加,剩余的八位字节加到和中

  • 结果和被截断为16位(进位将被考虑),校验和通过取其1的补码来计算。最终校验和应为16位长

让我们举个例子

如果要在八位元[A,B,C,D,E]序列上计算校验和,则创建的对将是[A,B]和[C,D],剩余的八位元为E。对[A,B]可按如下方式计算:

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
a*256+b其中a和b是八位字节

假设a是11001010,b是00010011,a*256+b=1100101000010001,这样我们就得到了八位字节的串联结果

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

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=[A+B]+'[C+D]+'E,其中+'表示1的补码 加成

现在回到代码,行sum&=0xffffffffff之前的所有内容都计算我们之前计算过的1的补码和


总和&=0xffffffff

用于将和截断为32位,尽管在ping中不太可能超过和,因为源_字符串的大小不是很大

(源字符串=头(8字节)+有效负载(可变长度))


sum=(sum>>16)+(sum&0xffff)

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

(求和>>16):高阶16位

(总和&0xffff):低阶16位

然后把这两部分加起来。最终结果可能是16位大于16位


sum+=(sum>>16)

与前一行类似,该行用于前一计算的结果和大于16位的情况,并用于处理进位



最后,计算1的补码并将其截断为16位。该功能用于根据设备的体系结构(小端和大端)维护发送到网络的字节排列

我终于能够弄清楚计算校验和函数的工作原理,我试着在下面解释它

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

  • 源_字符串中的相邻八位字节成对形成16位 整数,这些整数的 计算如果八位字节数为奇数,则从n-1个八位字节中创建对并相加,剩余的八位字节加到和中

  • 结果和被截断为16位(进位将被考虑),校验和通过取其1的补码来计算。最终校验和应为16位长

让我们举个例子

如果要在八位元[A,B,C,D,E]序列上计算校验和,则创建的对将是[A,B]和[C,D],剩余的八位元为E。对[A,B]可按如下方式计算:

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
a*256+b其中a和b是八位字节

假设a是11001010,b是00010011,a*256+b=1100101000010001,这样我们就得到了八位字节的串联结果

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

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=[A+B]+'[C+D]+'E,其中+'表示1的补码 加成

现在回到代码,行sum&=0xffffffffff之前的所有内容都计算我们之前计算过的1的补码和


总和&=0xffffffff