RFC 1071提供在C下面的示例實現:
in 6
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register long sum = 0;
while(count > 1) {
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* Add left-over byte, if any */
if(count > 0)
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
checksum = ~sum;
}
我寫了下面的C代碼進行單元測試:
#include <stdio.h>
#include <stdlib.h>
unsigned short checksum (int count, unsigned short * addr) {
unsigned long sum = 0;
while (count > 1) {
sum += *addr++;
count -= 2;
}
// Add left-over byte, if any
if (count > 0)
sum += * (unsigned char *) addr;
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return (unsigned short)sum;
}
void test (const unsigned short expected, const unsigned short got) {
printf(
"%s expected 0x%04x, got 0x%04x\n",
(expected == got ? "OK" : "NOK"),
expected,
got
);
}
int main(void) {
unsigned short *buf = calloc(1024, sizeof(unsigned short));
buf[0] = 0x0000;
test(
0x0,
checksum(2, buf)
);
buf[0] = 0x0001;
buf[1] = 0xf203;
buf[2] = 0xf4f5;
buf[3] = 0xf6f7;
test(
0xddf2,
checksum(8, buf)
);
return 0;
}
據稍微令人不安的是我的代碼在校驗和()函數的最後一行中不採用和的按位非NOT,如RFC impl ementation的確如此,但是增加了按位NOT NOT打破了我的單元測試。
運行代碼率:
: [email protected]; /tmp/rfc-1071-checksum
OK expected 0x0000, got 0x0000
OK expected 0xddf2, got 0xddf2
我移植這個紅寶石如下:
def rfc1071_checksum(header_fields)
checksum = 0
header_fields.each{|field| checksum += field}
while (checksum >> 16) != 0
checksum = (checksum & 0xffff) + (checksum >> 16)
end
return checksum
end
我把這樣的方法:
def build_ip_packet(tos, ttl, protocol, dst_addr, data)
len = (IP_HEADER_LEN * 4) + data.size
# Header checksum is set to 0 for computing the checksum; see RFC 791 p.14
hdr_checksum = 0
src_addr = IPAddr.new('127.0.0.1')
header_fields = [
(((IP_VERSION << 4) + IP_HEADER_LEN) << 8) + (tos ),
len,
IP_IDENTIFICATION,
((IP_FLAGS_BIT_0 << 15) + (IP_FLAGS_BIT_1 << 14) + (IP_FLAGS_BIT_2 << 13) + (IP_FRAG_OFFSET << 12)),
(ttl << 8) + (protocol),
hdr_checksum,
src_addr & 0xff00, # 16 most significant bits
src_addr & 0x00ff, # 16 least significant bits
dst_addr & 0xff00, # 16 most significant bits
dst_addr & 0x00ff, # 16 least significant bits
]
hdr_checksum = rfc1071_checksum(header_fields)
return nil
end
這裏是單位測試:
require 'test/unit'
require 'lib/traceroute'
class TestTraceroute < MiniTest::Unit::TestCase
def test_rfc1071_checksum
[
[ 0x0000, [ 0x0000 ] ],
[
0xddf2,
[
0x0001f203,
0xf4f5f6f7,
]
],
].each{|input_record|
got = Traceroute.new.rfc1071_checksum(input_record[1])
expected = input_record[0]
assert_equal(got, expected, "rfc1071_checksum: #{input_record[1].inspect}")
}
end
end
請注意,我的單元測試目前失敗,所以我有一個錯誤的地方。我會更新答案並接受測試通過。 – 2009-12-28 10:21:38