From 5cec6633c5b7a154960e191a425e6f40490db2a3 Mon Sep 17 00:00:00 2001 From: Nikolay Edigaryev Date: Wed, 14 Jan 2026 18:12:05 +0100 Subject: [PATCH] Introduce uncertainty duration and subtract it from total lease time --- lib/dhcp_snooper.rs | 19 ++++++++++++++----- lib/poller.rs | 11 ++++++++--- lib/proxy/mod.rs | 6 ++++-- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/dhcp_snooper.rs b/lib/dhcp_snooper.rs index e40cdb2..0a31822 100644 --- a/lib/dhcp_snooper.rs +++ b/lib/dhcp_snooper.rs @@ -7,9 +7,17 @@ use std::time::Duration; #[derive(Default)] pub struct DhcpSnooper { vm_lease: Option, + uncertainty_duration: Duration, } impl DhcpSnooper { + pub fn new(uncertainty_duration: Duration) -> Self { + DhcpSnooper { + uncertainty_duration, + ..Default::default() + } + } + pub fn register_dhcp_reply(&mut self, dhcp_packet: &[u8]) { let mut decoder = dhcproto::v4::Decoder::new(dhcp_packet); @@ -32,11 +40,12 @@ impl DhcpSnooper { _ => HashSet::new(), }; - self.vm_lease = Some(Lease::new( - message.yiaddr(), - Duration::from_secs(*lease_time as u64), - dns_ips, - )) + let mut lease_duration = Duration::from_secs(*lease_time as u64); + + // Adjust for uncertainty caused by using a coarse clock + lease_duration = lease_duration.saturating_sub(self.uncertainty_duration); + + self.vm_lease = Some(Lease::new(message.yiaddr(), lease_duration, dns_ips)) } Some(MessageType::Nak) => { self.vm_lease = None; diff --git a/lib/poller.rs b/lib/poller.rs index 24a657d..27e38f4 100644 --- a/lib/poller.rs +++ b/lib/poller.rs @@ -9,6 +9,7 @@ use std::time::Duration; pub struct Poller<'poller> { poller: polling::Poller, events: polling::Events, + timeout: Duration, vm_fd: BorrowedFd<'poller>, host_fd: BorrowedFd<'poller>, } @@ -22,12 +23,17 @@ enum EventKey { } impl Poller<'_> { - pub fn new<'poller>(vm_fd: RawFd, host_fd: RawFd) -> Result> { + pub fn new<'poller>( + vm_fd: RawFd, + host_fd: RawFd, + timeout: Duration, + ) -> Result> { let poller = polling::Poller::new()?; Ok(Poller { poller, events: polling::Events::new(), + timeout, vm_fd: unsafe { BorrowedFd::borrow_raw(vm_fd) }, host_fd: unsafe { BorrowedFd::borrow_raw(host_fd) }, }) @@ -59,8 +65,7 @@ impl Poller<'_> { } pub fn wait(&mut self) -> Result<(bool, bool, bool)> { - self.poller - .wait(&mut self.events, Some(Duration::from_millis(100)))?; + self.poller.wait(&mut self.events, Some(self.timeout))?; let vm_readable = self .events diff --git a/lib/proxy/mod.rs b/lib/proxy/mod.rs index 6f61a52..1703c84 100644 --- a/lib/proxy/mod.rs +++ b/lib/proxy/mod.rs @@ -18,6 +18,7 @@ use prefix_trie::{Prefix, PrefixMap, PrefixSet}; use smoltcp::wire::EthernetFrame; use std::io::ErrorKind; use std::os::unix::io::{AsRawFd, RawFd}; +use std::time::Duration; use vmnet::Batch; pub struct Proxy<'proxy> { @@ -48,7 +49,8 @@ impl Proxy<'_> { ) -> Result> { let vm = VM::new(vm_fd)?; let host = Host::new(vm_net_type, !allow.contains(&Ipv4Net::zero()))?; - let poller = Poller::new(vm.as_raw_fd(), host.as_raw_fd())?; + let poller_timeout = Duration::from_millis(100); + let poller = Poller::new(vm.as_raw_fd(), host.as_raw_fd(), poller_timeout)?; // Craft packet filter rules // @@ -69,7 +71,7 @@ impl Proxy<'_> { host, poller, vm_mac_address: smoltcp::wire::EthernetAddress(vm_mac_address.bytes()), - dhcp_snooper: Default::default(), + dhcp_snooper: DhcpSnooper::new(poller_timeout), rules, enobufs_encountered: false, port_forwarder: PortForwarder::new(exposed_ports),