From c76f32fa6c8034c3fc181965380ffa369156946e Mon Sep 17 00:00:00 2001 From: Thibaut Vandervelden Date: Wed, 11 Sep 2024 11:08:14 +0200 Subject: [PATCH] Use own src address for ARP and NDISC Solicits When looking up the destination link-layer address for a given destination address, we need to send an ARP or ICMPv6 Neighbor Solicitation if the destination link-layer address is not in the cache. When transmitting an ARP or ICMPv6 Neighbor Solicitation packet, use the source address of the interface instead of the source address of the packet that is tried to be sent. By using the source address of the interface, we are sure that a response will be received on the same interface. --- src/iface/interface/mod.rs | 30 ++++++++++-------------------- src/iface/interface/tests/ipv4.rs | 3 --- src/iface/interface/tests/ipv6.rs | 1 - 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/iface/interface/mod.rs b/src/iface/interface/mod.rs index 7eed974e8..47b2ae006 100644 --- a/src/iface/interface/mod.rs +++ b/src/iface/interface/mod.rs @@ -898,7 +898,6 @@ impl InterfaceInner { fn lookup_hardware_addr( &mut self, tx_token: Tx, - src_addr: &IpAddress, dst_addr: &IpAddress, fragmenter: &mut Fragmenter, ) -> Result<(HardwareAddress, Tx), DispatchError> @@ -966,11 +965,9 @@ impl InterfaceInner { _ => (), // XXX } - match (src_addr, dst_addr) { + match dst_addr { #[cfg(all(feature = "medium-ethernet", feature = "proto-ipv4"))] - (&IpAddress::Ipv4(src_addr), IpAddress::Ipv4(dst_addr)) - if matches!(self.caps.medium, Medium::Ethernet) => - { + IpAddress::Ipv4(dst_addr) if matches!(self.caps.medium, Medium::Ethernet) => { net_debug!( "address {} not in neighbor cache, sending ARP request", dst_addr @@ -980,7 +977,9 @@ impl InterfaceInner { let arp_repr = ArpRepr::EthernetIpv4 { operation: ArpOperation::Request, source_hardware_addr: src_hardware_addr, - source_protocol_addr: src_addr, + source_protocol_addr: self + .get_source_address_ipv4(&dst_addr) + .ok_or(DispatchError::NoRoute)?, target_hardware_addr: EthernetAddress::BROADCAST, target_protocol_addr: dst_addr, }; @@ -999,7 +998,7 @@ impl InterfaceInner { } #[cfg(feature = "proto-ipv6")] - (&IpAddress::Ipv6(src_addr), IpAddress::Ipv6(dst_addr)) => { + IpAddress::Ipv6(dst_addr) => { net_debug!( "address {} not in neighbor cache, sending Neighbor Solicitation", dst_addr @@ -1012,7 +1011,7 @@ impl InterfaceInner { let packet = Packet::new_ipv6( Ipv6Repr { - src_addr, + src_addr: self.get_source_address_ipv6(&dst_addr), dst_addr: dst_addr.solicited_node(), next_header: IpProtocol::Icmpv6, payload_len: solicit.buffer_len(), @@ -1059,12 +1058,8 @@ impl InterfaceInner { #[cfg(feature = "medium-ieee802154")] if matches!(self.caps.medium, Medium::Ieee802154) { - let (addr, tx_token) = self.lookup_hardware_addr( - tx_token, - &ip_repr.src_addr(), - &ip_repr.dst_addr(), - frag, - )?; + let (addr, tx_token) = + self.lookup_hardware_addr(tx_token, &ip_repr.dst_addr(), frag)?; let addr = addr.ieee802154_or_panic(); self.dispatch_ieee802154(addr, tx_token, meta, packet, frag); @@ -1091,12 +1086,7 @@ impl InterfaceInner { #[cfg(feature = "medium-ethernet")] let (dst_hardware_addr, mut tx_token) = match self.caps.medium { Medium::Ethernet => { - match self.lookup_hardware_addr( - tx_token, - &ip_repr.src_addr(), - &ip_repr.dst_addr(), - frag, - )? { + match self.lookup_hardware_addr(tx_token, &ip_repr.dst_addr(), frag)? { (HardwareAddress::Ethernet(addr), tx_token) => (addr, tx_token), (_, _) => unreachable!(), } diff --git a/src/iface/interface/tests/ipv4.rs b/src/iface/interface/tests/ipv4.rs index 1c394f2a9..c2c8ce460 100644 --- a/src/iface/interface/tests/ipv4.rs +++ b/src/iface/interface/tests/ipv4.rs @@ -456,7 +456,6 @@ fn test_handle_valid_arp_request(#[case] medium: Medium) { assert_eq!( iface.inner.lookup_hardware_addr( MockTxToken, - &IpAddress::Ipv4(local_ip_addr), &IpAddress::Ipv4(remote_ip_addr), &mut iface.fragmenter, ), @@ -505,7 +504,6 @@ fn test_handle_other_arp_request(#[case] medium: Medium) { assert_eq!( iface.inner.lookup_hardware_addr( MockTxToken, - &IpAddress::Ipv4(Ipv4Address([0x7f, 0x00, 0x00, 0x01])), &IpAddress::Ipv4(remote_ip_addr), &mut iface.fragmenter, ), @@ -564,7 +562,6 @@ fn test_arp_flush_after_update_ip(#[case] medium: Medium) { assert_eq!( iface.inner.lookup_hardware_addr( MockTxToken, - &IpAddress::Ipv4(local_ip_addr), &IpAddress::Ipv4(remote_ip_addr), &mut iface.fragmenter, ), diff --git a/src/iface/interface/tests/ipv6.rs b/src/iface/interface/tests/ipv6.rs index 785daba11..f6e214e76 100644 --- a/src/iface/interface/tests/ipv6.rs +++ b/src/iface/interface/tests/ipv6.rs @@ -834,7 +834,6 @@ fn test_handle_valid_ndisc_request(#[case] medium: Medium) { assert_eq!( iface.inner.lookup_hardware_addr( MockTxToken, - &IpAddress::Ipv6(local_ip_addr), &IpAddress::Ipv6(remote_ip_addr), &mut iface.fragmenter, ),