Browse Source

`IpRepr::lower` replaces unspecified src_addr in Ipv4Repr as well.

Egor Karavaev 7 years ago
parent
commit
42ca732ce3
1 changed files with 112 additions and 2 deletions
  1. 112 2
      src/wire/ip.rs

+ 112 - 2
src/wire/ip.rs

@@ -123,7 +123,7 @@ impl<T: Into<Address>> From<(T, u16)> for Endpoint {
 /// This enum abstracts the various versions of IP packets. It either contains a concrete
 /// high-level representation for some IP protocol version, or an unspecified representation,
 /// which permits the `IpAddress::Unspecified` addresses.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub enum IpRepr {
     Unspecified {
         src_addr:    Address,
@@ -219,10 +219,27 @@ impl IpRepr {
 
             &IpRepr::Unspecified { dst_addr: Address::Unspecified, .. } =>
                 panic!("unspecified destination IP address"),
+
             // &IpRepr::Unspecified { .. } =>
             //     panic!("source and destination IP address families do not match"),
 
-            repr @ &IpRepr::Ipv4(_) => Ok(repr.clone()),
+            &IpRepr::Ipv4(mut repr) => {
+                if repr.src_addr.is_unspecified() {
+                    for addr in fallback_src_addrs {
+                        match addr {
+                            &Address::Ipv4(addr) => {
+                                repr.src_addr = addr;
+                                return Ok(IpRepr::Ipv4(repr));
+                            }
+                            _ => ()
+                        }
+                    }
+                    Err(Error::Unaddressable)
+                } else {
+                    Ok(IpRepr::Ipv4(repr))
+                }
+            },
+
             &IpRepr::__Nonexhaustive => unreachable!()
         }
     }
@@ -311,3 +328,96 @@ pub mod checksum {
         }
     }
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use wire::{Ipv4Address, IpProtocol, IpAddress, Ipv4Repr};
+    #[test]
+    fn ip_repr_lower() {
+        let ip_addr_a = Ipv4Address::new(1, 2, 3, 4);
+        let ip_addr_b = Ipv4Address::new(5, 6, 7, 8);
+        let proto = IpProtocol::Icmp;
+        let payload_len = 10;
+
+        assert_eq!(
+            IpRepr::Unspecified{
+                src_addr: IpAddress::Ipv4(ip_addr_a),
+                dst_addr: IpAddress::Ipv4(ip_addr_b),
+                protocol: proto,
+                payload_len
+            }.lower(&[]),
+            Ok(IpRepr::Ipv4(Ipv4Repr{
+                src_addr: ip_addr_a,
+                dst_addr: ip_addr_b,
+                protocol: proto,
+                payload_len
+            }))
+        );
+
+        assert_eq!(
+            IpRepr::Unspecified{
+                src_addr: IpAddress::Unspecified,
+                dst_addr: IpAddress::Ipv4(ip_addr_b),
+                protocol: proto,
+                payload_len
+            }.lower(&[]),
+            Err(Error::Unaddressable)
+        );
+
+        assert_eq!(
+            IpRepr::Unspecified{
+                src_addr: IpAddress::Unspecified,
+                dst_addr: IpAddress::Ipv4(ip_addr_b),
+                protocol: proto,
+                payload_len
+            }.lower(&[IpAddress::Ipv4(ip_addr_a)]),
+            Ok(IpRepr::Ipv4(Ipv4Repr{
+                src_addr: ip_addr_a,
+                dst_addr: ip_addr_b,
+                protocol: proto,
+                payload_len
+            }))
+        );
+
+        assert_eq!(
+            IpRepr::Ipv4(Ipv4Repr{
+                src_addr: ip_addr_a,
+                dst_addr: ip_addr_b,
+                protocol: proto,
+                payload_len
+            }).lower(&[]),
+            Ok(IpRepr::Ipv4(Ipv4Repr{
+                src_addr: ip_addr_a,
+                dst_addr: ip_addr_b,
+                protocol: proto,
+                payload_len
+            }))
+        );
+
+        assert_eq!(
+            IpRepr::Ipv4(Ipv4Repr{
+                src_addr: Ipv4Address::new(0, 0, 0, 0),
+                dst_addr: ip_addr_b,
+                protocol: proto,
+                payload_len
+            }).lower(&[]),
+            Err(Error::Unaddressable)
+        );
+
+        assert_eq!(
+            IpRepr::Ipv4(Ipv4Repr{
+                src_addr: Ipv4Address::new(0, 0, 0, 0),
+                dst_addr: ip_addr_b,
+                protocol: proto,
+                payload_len
+            }).lower(&[IpAddress::Ipv4(ip_addr_a)]),
+            Ok(IpRepr::Ipv4(Ipv4Repr{
+                src_addr: ip_addr_a,
+                dst_addr: ip_addr_b,
+                protocol: proto,
+                payload_len
+            }))
+        );
+    }
+}