From 554eb2d72fd3b2c5f37fa8462b6a7bd9edb2da5d Mon Sep 17 00:00:00 2001 From: ache Date: Wed, 25 Sep 2019 13:46:09 +0200 Subject: Understand the DHCP request --- src/main.rs | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 160 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 712b2d9..eeaaedd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,9 @@ use std::net; use std::str; use std::fmt; use std::mem; +use std::net::Ipv4Addr; + +use std::io::ErrorKind; const BUFFER_SIZE: usize = 5000; const SERVER_PORT: u16 = 67; @@ -19,6 +22,37 @@ enum DhcpMessageType { DHCPRELEASE, // Send by client DHCPINFORM // Not send } +impl fmt::Display for DhcpMessageType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self { + DhcpMessageType::DHCPDISCOVER => "DHCPDISCOVER", + DhcpMessageType::DHCPOFFER => "DHCPOFFER", + DhcpMessageType::DHCPREQUEST => "DHCPREQUEST", + DhcpMessageType::DHCPNAK => "DHCPNAK", + DhcpMessageType::DHCPDECLINE => "DHCPDECLINE", + DhcpMessageType::DHCPPACK => "DHCPPACK", + DhcpMessageType::DHCPRELEASE => "DHCPRELEASE", + DhcpMessageType::DHCPINFORM => "DHCPINFORM" + }; + write!(f, "{}", s) + } +} + +impl DhcpMessageType { + fn into( i: u8 ) -> DhcpMessageType { + match(i) { + 1 => DhcpMessageType::DHCPDISCOVER, + 2 => DhcpMessageType::DHCPOFFER, + 3 => DhcpMessageType::DHCPREQUEST, + _ => DhcpMessageType::DHCPNAK, + } + } +} + +struct Config { + ranges: Vec<(Ipv4Addr, Ipv4Addr)>, + name: String, +} const OPTIONS_NAME : [&str;77] = ["Pad", // 0 "Subnet mask", @@ -117,6 +151,27 @@ struct DhcpMessage { options: [u8; 312] } impl DhcpMessage { + fn get_option_data( &self, opt: u8) -> Option<&[u8]> { + if opt == 0 || opt == 255 { + return None; + } + let mut i = 4; // Magic cookie ! 🍪 + loop { + if i >= 312 { + return None; + } + let i_tmp : usize = usize::from(i); + if self.options[i_tmp] == opt { + return Some(&self.options[i_tmp..(self.options[i_tmp+1] as usize + 2 + i_tmp)]); + } else if self.options[i_tmp] == 0 || self.options[i_tmp] == 255 { + i += 1 + } else if self.options[i_tmp] < 77 { + i += u16::from(self.options[i_tmp+1]) + 2; + } else { + return None; + } + } + } fn request_type( &self ) -> Option { let mut i = 4; // Magic cookie ! 🍪 loop { @@ -126,7 +181,6 @@ impl DhcpMessage { let i_tmp : usize = usize::from(i); if self.options[i_tmp] == 53 { if self.options[i_tmp+2] > 0 && self.options[i_tmp+2] < 9 { - print!("Type: {}\n", self.options[i_tmp+2]); return Some(unsafe { mem::transmute(self.options[i_tmp+2]) }); } else { return None @@ -134,12 +188,26 @@ impl DhcpMessage { } else if self.options[i_tmp] == 0 || self.options[i_tmp] == 255 { i += 1 } else if self.options[i_tmp] < 77 { - i += u16::from(self.options[i_tmp+1]); + i += u16::from(self.options[i_tmp+1]) + 2; } else { return None; } } } + fn to_bytes( &self ) -> Vec { + let mut ret = Vec::new(); + ret + } + /* + * + *use std::net::UdpSocket; + +let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); +socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data"); + * + * + * + */ } impl fmt::Display for DhcpMessage { @@ -208,7 +276,7 @@ impl fmt::Display for DhcpMessage { i += times; } else if self.options[i_tmp] < 77 { write!(f, " {} Option({:02x})\n", OPTIONS_NAME[usize::from(self.options[i_tmp])], self.options[i_tmp])?; - i += u16::from(self.options[i_tmp+1]); + i += u16::from(self.options[i_tmp+1]) + 2; } else { write!(f, " Unknow Option({:02x})\n", self.options[i_tmp])?; break; @@ -267,8 +335,84 @@ fn fill_dhcp_message( dhcp_message: &mut DhcpMessage, buf : &[u8; BUFFER_SIZE], true } +fn deal_discovery(dhcp_message: &mut DhcpMessage, conf: &Config) -> Result { + println!("Discovery ! 🦊"); + Err(ErrorKind::NotFound) +} + +fn is_in_range(ip: Ipv4Addr, range: &Vec<(Ipv4Addr,Ipv4Addr)>) -> bool { + for (min, max) in range { + if ip >= *min && ip <= *max { + return true + } + } + return false +} + +fn deal_request(dhcp_message: &DhcpMessage, conf: &Config, leases: &Vec) -> Result { + println!("Request ! 🦊"); + let request_opt = dhcp_message.get_option_data(50); + + let mut ret: DhcpMessage = DhcpMessage { + op: dhcp_message.op, + htype: dhcp_message.op, + hlen: dhcp_message.hlen, + hops: dhcp_message.hops, + xid: dhcp_message.xid, + secs: 0, + flags: dhcp_message.flags, + ciaddr: 0, + siaddr: 0, + giaddr: 0, + yiaddr: 0, + chaddr: dhcp_message.chaddr, + sname: [0; 64], + file: dhcp_message.file, + options: dhcp_message.options, + }; + + let request_opt = if let Some(request_opt) = request_opt { + if request_opt.len() < 6 { + println!("Too short {:?}", request_opt); + return Err(ErrorKind::InvalidData); + } + request_opt + } else { + println!("Didn't get anything 🤷"); + return Err(ErrorKind::InvalidData); + }; + let requested_addr = net::Ipv4Addr::new(request_opt[2], request_opt[3], request_opt[4], request_opt[5]); + println!("Want: {}", requested_addr); + + if leases.contains(&requested_addr) { + // Send DHCPNAK + return Err(ErrorKind::AddrInUse); + } + + if !is_in_range(requested_addr, &conf.ranges) { + // Send DHCPDECLINE + return Err(ErrorKind::AddrNotAvailable); + } + + ret.yiaddr = u32::from(requested_addr); + // Send DHCPPACK + Err(ErrorKind::NotFound) +} + + fn main() -> std::io::Result<()> { + + let mut available_ips = Vec::new(); + available_ips.push((Ipv4Addr::new(10, 0, 0, 0), Ipv4Addr::new(11, 0, 0, 0))); + + let config = Config { + ranges: available_ips, + name: "Unibit".to_string(), + }; + + let mut leases: Vec = Vec::new(); + { let addrs = [ net::SocketAddr::from(([0, 0, 0, 0], SERVER_PORT)), @@ -290,17 +434,23 @@ fn main() -> std::io::Result<()> { print!("{:02x}", buf[i]) } fill_dhcp_message(&mut dhcp_message, &buf, amt); - print!("\n"); - print!("{}\n", dhcp_message); + println!(""); + println!("{}", dhcp_message); if dhcp_message.xid == 42 { break } - if let Some(DhcpMessageType::DHCPDISCOVER) = dhcp_message.request_type() { - print!("It's a discovery !\n"); - } else { - print!("It's not a discovery !\n"); - } + let r = match dhcp_message.request_type() { + Some(DhcpMessageType::DHCPDISCOVER) => deal_discovery(&mut dhcp_message, &config), + Some(DhcpMessageType::DHCPREQUEST) => deal_request(&mut dhcp_message, &config, &leases), + Some(DhcpMessageType::DHCPOFFER) => Err(ErrorKind::PermissionDenied), + Some(e) => { + println!("Its {} !", e); + Err(ErrorKind::InvalidData) + }, + _ => Err(ErrorKind::InvalidData) + }; } } // the socket is closed here + Ok(()) } -- cgit v1.2.3