瀏覽代碼

Treat unspecified IPv4/IPv6 addresses as IpAddress::Unspecified in IpRepr::lower.

Closes #127.
Egor Karavaev 7 年之前
父節點
當前提交
283109caca
共有 1 個文件被更改,包括 87 次插入40 次删除
  1. 87 40
      src/wire/ip.rs

+ 87 - 40
src/wire/ip.rs

@@ -496,75 +496,88 @@ impl Repr {
         match self {
             #[cfg(feature = "proto-ipv4")]
             &Repr::Unspecified {
-                src_addr: Address::Ipv4(src_addr),
+                src_addr: src_addr @ Address::Unspecified,
                 dst_addr: Address::Ipv4(dst_addr),
                 protocol, payload_len, hop_limit
-            } => {
+            } |
+            &Repr::Unspecified {
+                src_addr: src_addr @ Address::Ipv4(_),
+                dst_addr: Address::Ipv4(dst_addr),
+                protocol, payload_len, hop_limit
+            } if src_addr.is_unspecified() => {
+                let mut src_addr = if let Address::Ipv4(src_ipv4_addr) = src_addr {
+                    Some(src_ipv4_addr)
+                } else {
+                    None
+                };
+                for cidr in fallback_src_addrs {
+                    if let Address::Ipv4(addr) = cidr.address() {
+                        src_addr = Some(addr);
+                        break;
+                    }
+                }
                 Ok(Repr::Ipv4(Ipv4Repr {
-                    src_addr:    src_addr,
-                    dst_addr:    dst_addr,
-                    protocol:    protocol,
-                    payload_len: payload_len, hop_limit
+                    src_addr:    src_addr.ok_or(Error::Unaddressable)?,
+                    dst_addr, protocol, payload_len, hop_limit
                 }))
             }
 
             #[cfg(feature = "proto-ipv6")]
             &Repr::Unspecified {
-                src_addr: Address::Ipv6(src_addr),
+                src_addr: src_addr @ Address::Unspecified,
                 dst_addr: Address::Ipv6(dst_addr),
                 protocol, payload_len, hop_limit
-            } => {
+            } |
+            &Repr::Unspecified {
+                src_addr: src_addr @ Address::Ipv6(_),
+                dst_addr: Address::Ipv6(dst_addr),
+                protocol, payload_len, hop_limit
+            } if src_addr.is_unspecified() => {
+                let mut src_addr = if let Address::Ipv6(src_ipv6_addr) = src_addr {
+                    Some(src_ipv6_addr)
+                } else {
+                    None
+                };
+                for cidr in fallback_src_addrs {
+                    if let Address::Ipv6(addr) = cidr.address() {
+                        src_addr = Some(addr);
+                        break;
+                    }
+                }
                 Ok(Repr::Ipv6(Ipv6Repr {
-                    src_addr:    src_addr,
-                    dst_addr:    dst_addr,
+                    src_addr:    src_addr.ok_or(Error::Unaddressable)?,
                     next_header: protocol,
-                    payload_len: payload_len,
-                    hop_limit:   hop_limit
+                    dst_addr, payload_len, hop_limit
                 }))
             }
 
             #[cfg(feature = "proto-ipv4")]
             &Repr::Unspecified {
-                src_addr: Address::Unspecified,
+                src_addr: Address::Ipv4(src_addr),
                 dst_addr: Address::Ipv4(dst_addr),
                 protocol, payload_len, hop_limit
             } => {
-                let mut src_addr = None;
-                for cidr in fallback_src_addrs {
-                    match cidr.address() {
-                        Address::Ipv4(addr) => {
-                            src_addr = Some(addr);
-                            break
-                        }
-                        _ => ()
-                    }
-                }
                 Ok(Repr::Ipv4(Ipv4Repr {
-                    src_addr:    src_addr.ok_or(Error::Unaddressable)?,
-                    dst_addr, protocol, payload_len, hop_limit
+                    src_addr:    src_addr,
+                    dst_addr:    dst_addr,
+                    protocol:    protocol,
+                    payload_len: payload_len, hop_limit
                 }))
             }
 
             #[cfg(feature = "proto-ipv6")]
             &Repr::Unspecified {
-                src_addr: Address::Unspecified,
+                src_addr: Address::Ipv6(src_addr),
                 dst_addr: Address::Ipv6(dst_addr),
                 protocol, payload_len, hop_limit
             } => {
-                // Find a fallback address to use
-                match fallback_src_addrs.iter().filter_map(|cidr| match cidr.address() {
-                    Address::Ipv6(addr) => Some(addr),
-                    _ => None
-                }).next() {
-                    Some(addr) =>
-                        Ok(Repr::Ipv6(Ipv6Repr {
-                            src_addr:    addr,
-                            next_header: protocol,
-                            hop_limit:   hop_limit,
-                            dst_addr, payload_len
-                        })),
-                    None => Err(Error::Unaddressable)
-                }
+                Ok(Repr::Ipv6(Ipv6Repr {
+                    src_addr:    src_addr,
+                    dst_addr:    dst_addr,
+                    next_header: protocol,
+                    payload_len: payload_len,
+                    hop_limit:   hop_limit
+                }))
             }
 
             #[cfg(feature = "proto-ipv4")]
@@ -875,6 +888,40 @@ pub(crate) mod test {
             }))
         );
 
+        assert_eq!(
+            Repr::Unspecified{
+                src_addr:  IpAddress::Ipv4(Ipv4Address::UNSPECIFIED),
+                dst_addr:  IpAddress::Ipv4(ip_addr_b),
+                protocol:  proto,
+                hop_limit: 64,
+                payload_len
+            }.lower(&[IpCidr::new(IpAddress::Ipv4(ip_addr_a), 24)]),
+            Ok(Repr::Ipv4(Ipv4Repr{
+                src_addr:  ip_addr_a,
+                dst_addr:  ip_addr_b,
+                protocol:  proto,
+                hop_limit: 64,
+                payload_len
+            }))
+        );
+
+        assert_eq!(
+            Repr::Unspecified{
+                src_addr:  IpAddress::Ipv4(Ipv4Address::UNSPECIFIED),
+                dst_addr:  IpAddress::Ipv4(ip_addr_b),
+                protocol:  proto,
+                hop_limit: 64,
+                payload_len
+            }.lower(&[]),
+            Ok(Repr::Ipv4(Ipv4Repr{
+                src_addr:  Ipv4Address::UNSPECIFIED,
+                dst_addr:  ip_addr_b,
+                protocol:  proto,
+                hop_limit: 64,
+                payload_len
+            }))
+        );
+
         assert_eq!(
             Repr::Ipv4(Ipv4Repr{
                 src_addr:  ip_addr_a,