Browse Source

Simplify checksum computation.

whitequark 8 years ago
parent
commit
8a3dee0943
3 changed files with 17 additions and 21 deletions
  1. 9 11
      src/wire/icmpv4.rs
  2. 3 3
      src/wire/ip.rs
  3. 5 7
      src/wire/ipv4.rs

+ 9 - 11
src/wire/icmpv4.rs

@@ -2,7 +2,7 @@ use core::{cmp, fmt};
 use byteorder::{ByteOrder, NetworkEndian};
 use byteorder::{ByteOrder, NetworkEndian};
 
 
 use Error;
 use Error;
-use super::ip::rfc1071_checksum;
+use super::ip::checksum;
 
 
 enum_with_unknown! {
 enum_with_unknown! {
     /// Internet protocol control message type.
     /// Internet protocol control message type.
@@ -216,11 +216,8 @@ impl<T: AsRef<[u8]>> Packet<T> {
 
 
     /// Validate the header checksum.
     /// Validate the header checksum.
     pub fn verify_checksum(&self) -> bool {
     pub fn verify_checksum(&self) -> bool {
-        let checksum = {
-            let data = self.buffer.as_ref();
-            rfc1071_checksum(field::CHECKSUM.start, data)
-        };
-        self.checksum() == checksum
+        let data = self.buffer.as_ref();
+        checksum(data) == !0
     }
     }
 }
 }
 
 
@@ -285,9 +282,10 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
 
 
     /// Compute and fill in the header checksum.
     /// Compute and fill in the header checksum.
     pub fn fill_checksum(&mut self) {
     pub fn fill_checksum(&mut self) {
+        self.set_checksum(0);
         let checksum = {
         let checksum = {
             let data = self.buffer.as_ref();
             let data = self.buffer.as_ref();
-            rfc1071_checksum(field::CHECKSUM.start, data)
+            !checksum(data)
         };
         };
         self.set_checksum(checksum)
         self.set_checksum(checksum)
     }
     }
@@ -411,7 +409,7 @@ mod test {
     use super::*;
     use super::*;
 
 
     static ECHO_PACKET_BYTES: [u8; 12] =
     static ECHO_PACKET_BYTES: [u8; 12] =
-        [0x08, 0x00, 0x39, 0xfe,
+        [0x08, 0x00, 0x8e, 0xfe,
          0x12, 0x34, 0xab, 0xcd,
          0x12, 0x34, 0xab, 0xcd,
          0xaa, 0x00, 0x00, 0xff];
          0xaa, 0x00, 0x00, 0xff];
 
 
@@ -423,11 +421,11 @@ mod test {
         let packet = Packet::new(&ECHO_PACKET_BYTES[..]).unwrap();
         let packet = Packet::new(&ECHO_PACKET_BYTES[..]).unwrap();
         assert_eq!(packet.msg_type(), Type::EchoRequest);
         assert_eq!(packet.msg_type(), Type::EchoRequest);
         assert_eq!(packet.msg_code(), 0);
         assert_eq!(packet.msg_code(), 0);
-        assert_eq!(packet.checksum(), 0x39fe);
+        assert_eq!(packet.checksum(), 0x8efe);
         assert_eq!(packet.echo_ident(), 0x1234);
         assert_eq!(packet.echo_ident(), 0x1234);
         assert_eq!(packet.echo_seq_no(), 0xabcd);
         assert_eq!(packet.echo_seq_no(), 0xabcd);
-        assert_eq!(packet.verify_checksum(), true);
         assert_eq!(packet.data(), &ECHO_DATA_BYTES[..]);
         assert_eq!(packet.data(), &ECHO_DATA_BYTES[..]);
+        assert_eq!(packet.verify_checksum(), true);
     }
     }
 
 
     #[test]
     #[test]
@@ -438,8 +436,8 @@ mod test {
         packet.set_msg_code(0);
         packet.set_msg_code(0);
         packet.set_echo_ident(0x1234);
         packet.set_echo_ident(0x1234);
         packet.set_echo_seq_no(0xabcd);
         packet.set_echo_seq_no(0xabcd);
-        packet.fill_checksum();
         packet.data_mut().copy_from_slice(&ECHO_DATA_BYTES[..]);
         packet.data_mut().copy_from_slice(&ECHO_DATA_BYTES[..]);
+        packet.fill_checksum();
         assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
         assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
     }
     }
 
 

+ 3 - 3
src/wire/ip.rs

@@ -21,12 +21,12 @@ impl fmt::Display for ProtocolType {
     }
     }
 }
 }
 
 
-pub fn rfc1071_checksum(checksum_at: usize, data: &[u8]) -> u16 {
+/// Compute an RFC 1071 compliant checksum (without the final complement).
+pub fn checksum(data: &[u8]) -> u16 {
     let mut accum: u32 = 0;
     let mut accum: u32 = 0;
     for i in (0..data.len()).step_by(2) {
     for i in (0..data.len()).step_by(2) {
-        if i == checksum_at { continue }
         let word = NetworkEndian::read_u16(&data[i..i + 2]) as u32;
         let word = NetworkEndian::read_u16(&data[i..i + 2]) as u32;
         accum += word;
         accum += word;
     }
     }
-    !(((accum >> 16) as u16) + (accum as u16))
+    (((accum >> 16) as u16) + (accum as u16))
 }
 }

+ 5 - 7
src/wire/ipv4.rs

@@ -2,7 +2,7 @@ use core::fmt;
 use byteorder::{ByteOrder, NetworkEndian};
 use byteorder::{ByteOrder, NetworkEndian};
 
 
 use Error;
 use Error;
-use super::ip::rfc1071_checksum;
+use super::ip::checksum;
 
 
 pub use super::InternetProtocolType as ProtocolType;
 pub use super::InternetProtocolType as ProtocolType;
 
 
@@ -211,11 +211,8 @@ impl<T: AsRef<[u8]>> Packet<T> {
 
 
     /// Validate the header checksum.
     /// Validate the header checksum.
     pub fn verify_checksum(&self) -> bool {
     pub fn verify_checksum(&self) -> bool {
-        let checksum = {
-            let data = self.buffer.as_ref();
-            rfc1071_checksum(field::CHECKSUM.start, &data[..self.header_len() as usize])
-        };
-        self.checksum() == checksum
+        let data = self.buffer.as_ref();
+        checksum(&data[..self.header_len() as usize]) == !0
     }
     }
 }
 }
 
 
@@ -342,9 +339,10 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
 
 
     /// Compute and fill in the header checksum.
     /// Compute and fill in the header checksum.
     pub fn fill_checksum(&mut self) {
     pub fn fill_checksum(&mut self) {
+        self.set_checksum(0);
         let checksum = {
         let checksum = {
             let data = self.buffer.as_ref();
             let data = self.buffer.as_ref();
-            rfc1071_checksum(field::CHECKSUM.start, &data[..self.header_len() as usize])
+            !checksum(&data[..self.header_len() as usize])
         };
         };
         self.set_checksum(checksum)
         self.set_checksum(checksum)
     }
     }