diff --git a/src/main.rs b/src/main.rs index 704387f..aa683e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,9 @@ use simple_endian::BigEndian; /// [RFC 8200 ยง 2]: https://www.rfc-editor.org/rfc/rfc791#section-3.2 pub const ADDR_SIZE: usize = 4; +pub const DHCP_SERVER_PORT: u16 = 67; +pub const DHCP_CLIENT_PORT: u16 = 68; + #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)] pub struct Ipv4Addr(pub [u8; ADDR_SIZE]); @@ -59,7 +62,6 @@ enum HType { Ethernet = 1u8.swap_bytes(), } -#[derive(Debug, Clone)] #[repr(C, packed)] struct Header { op: DhcpType, @@ -368,13 +370,26 @@ pub fn cvt(t: i32) -> io::Result { } } +fn get_nicname<'a>() -> &'a str { + static CACHED: Once = Once::new(); + + CACHED.call_once(|| { + let nic_name = std::env::args().nth(1).unwrap_or(DEFAULT_NIC.to_string()); + + get_index(&nic_name) + .unwrap_or_else(|nic_name| panic!("[ DHCPD ] (EE) invalid NIC name {}", nic_name)); + + nic_name + }) +} + fn get_macaddress<'a>() -> &'a [u8; 6] { static CACHED: Once<[u8; 6]> = Once::new(); CACHED .try_call_once(|| unsafe { let fd = cvt(libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0))?; - let macaddr = IfReq::new(DEFAULT_NIC); + let macaddr = IfReq::new(get_nicname()); cvt(libc::ioctl(fd, libc::SIOCGIFHWADDR, &macaddr))?; Ok::<[u8; 6], io::Error>(macaddr.macaddr()) @@ -467,9 +482,16 @@ fn configure(interface: &str, ip: Ipv4Addr, subnet_mask: Ipv4Addr) -> io::Result const DEFAULT_NIC: &str = "eth0"; // FIXME: retrieve the default NIC from the kernel +fn get_index(nic: &str) -> io::Result { + let ifname = std::ffi::CString::new(nic)?; + match unsafe { libc::if_nametoindex(ifname.as_ptr()) } { + 0 => Err(io::Error::last_os_error()), + index => Ok(index), + } +} + pub fn main() -> Result<(), Box> { - let socket = UdpSocket::bind(("0.0.0.0", 68))?; - socket.connect(("255.255.255.255", 67))?; + let socket = UdpSocket::bind(("0.0.0.0", DHCP_CLIENT_PORT))?; let mut discover_header = Header::new(HType::Ethernet); discover_header @@ -479,7 +501,7 @@ pub fn main() -> Result<(), Box> { .set_host_name("Aero") .set_parameter_request_list(); - socket.send(discover_header.as_slice())?; + socket.send_to(discover_header.as_slice(), "255.255.255.255:67")?; let mut offer = Header::new(HType::Ethernet); socket.recv(offer.as_slice_mut())?; @@ -495,7 +517,7 @@ pub fn main() -> Result<(), Box> { .set_host_name("Aero") .set_parameter_request_list(); - socket.send(request_header.as_slice())?; + socket.send_to(request_header.as_slice(), "255.255.255.255:67")?; let mut ack = Header::new(HType::Ethernet); socket.recv(ack.as_slice_mut())?; @@ -519,7 +541,7 @@ pub fn main() -> Result<(), Box> { let subnet_mask = subnet_mask.unwrap(); let dns = dns.unwrap(); - configure(DEFAULT_NIC, ack.your_ip, subnet_mask)?; + configure(get_nicname(), ack.your_ip, subnet_mask)?; println!("[ DHCPD ] (!!) Configured:"); println!("[ DHCPD ] (!!) IP: {}", ack.your_ip);