#![allow(clippy::option_map_unit_fn)] mod utils; use log::*; use std::collections::BTreeMap; use std::os::unix::io::AsRawFd; use smoltcp::iface::{Interface, InterfaceBuilder, NeighborCache, Routes}; use smoltcp::socket::{Dhcpv4Event, Dhcpv4Socket}; use smoltcp::time::Instant; use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address, Ipv4Cidr}; use smoltcp::{ phy::{wait as phy_wait, Device, Medium}, time::Duration, }; fn main() { #[cfg(feature = "log")] utils::setup_logging(""); let (mut opts, mut free) = utils::create_options(); utils::add_tuntap_options(&mut opts, &mut free); utils::add_middleware_options(&mut opts, &mut free); let mut matches = utils::parse_options(&opts, free); let device = utils::parse_tuntap_options(&mut matches); let fd = device.as_raw_fd(); let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false); let neighbor_cache = NeighborCache::new(BTreeMap::new()); let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); let ip_addrs = [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0)]; let mut routes_storage = [None; 1]; let routes = Routes::new(&mut routes_storage[..]); let medium = device.capabilities().medium; let mut builder = InterfaceBuilder::new(device, vec![]) .ip_addrs(ip_addrs) .routes(routes); if medium == Medium::Ethernet { builder = builder .hardware_addr(ethernet_addr.into()) .neighbor_cache(neighbor_cache); } let mut iface = builder.finalize(); let mut dhcp_socket = Dhcpv4Socket::new(); // Set a ridiculously short max lease time to show DHCP renews work properly. // This will cause the DHCP client to start renewing after 5 seconds, and give up the // lease after 10 seconds if renew hasn't succeeded. // IMPORTANT: This should be removed in production. dhcp_socket.set_max_lease_duration(Some(Duration::from_secs(10))); let dhcp_handle = iface.add_socket(dhcp_socket); loop { let timestamp = Instant::now(); if let Err(e) = iface.poll(timestamp) { debug!("poll error: {}", e); } let event = iface.get_socket::(dhcp_handle).poll(); match event { None => {} Some(Dhcpv4Event::Configured(config)) => { debug!("DHCP config acquired!"); debug!("IP address: {}", config.address); set_ipv4_addr(&mut iface, config.address); if let Some(router) = config.router { debug!("Default gateway: {}", router); iface.routes_mut().add_default_ipv4_route(router).unwrap(); } else { debug!("Default gateway: None"); iface.routes_mut().remove_default_ipv4_route(); } for (i, s) in config.dns_servers.iter().enumerate() { if let Some(s) = s { debug!("DNS server {}: {}", i, s); } } } Some(Dhcpv4Event::Deconfigured) => { debug!("DHCP lost config!"); set_ipv4_addr(&mut iface, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0)); iface.routes_mut().remove_default_ipv4_route(); } } phy_wait(fd, iface.poll_delay(timestamp)).expect("wait error"); } } fn set_ipv4_addr(iface: &mut Interface<'_, DeviceT>, cidr: Ipv4Cidr) where DeviceT: for<'d> Device<'d>, { iface.update_ip_addrs(|addrs| { let dest = addrs.iter_mut().next().unwrap(); *dest = IpCidr::Ipv4(cidr); }); }