2009-12-26 125 views
2

我为自学Ruby项目滚动了我自己的IP数据包,并且需要计算IP标头校验和(如RFC 791第14页所述)。当我在这里输入我的问题时弹出的一个相关问题指向我在RFC 1071,所以我可能大部分是那里的方式,但只是添加到堆栈溢出,任何人(可能未来乔希)提供一些Ruby代码用于计算校验和,假设红宝石的以下位:如何计算RFC 791 IP标头校验和?

def build_ip_packet(tos, ttl, protocol, dst_addr, data) 
     len = (IP_HEADER_LEN * 4) + data.size 

     ip_header = %w{ #{IP_VERSION} #{IP_HEADER_LEN} #{tos} #{len} #{IP_IDENTIFICATION} #{IP_FLAGS_BIT_0} #{IP_FLAGS_BIT_1} #{IP_FLAGS_BIT_2} #{IP_FRAG_OFFSET} #{ttl} #{protocol} #{hdr_checksum} #{src_addr} #{dst_addr} } 

     [...] 
    end 

的常量在文件的顶部定义,但如果你正在寻找在RFC791 P.11他们应该是不言自明的。

回答

2

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 
+0

请注意,我的单元测试目前失败,所以我有一个错误的地方。我会更新答案并接受测试通过。 – 2009-12-28 10:21:38