2009-12-26 61 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