From 8ad6494a252b9121c47198bd13d010890f78436c Mon Sep 17 00:00:00 2001 From: ache Date: Mon, 26 Aug 2019 00:24:48 +0200 Subject: Init commit --- Cargo.lock | 6 ++ Cargo.toml | 7 ++ src/main.rs | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e7e6991 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "pinkydhcpd" +version = "0.1.0" + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..729bb12 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "pinkydhcpd" +version = "0.1.0" +authors = ["ache "] +edition = "2018" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..f514adf --- /dev/null +++ b/src/main.rs @@ -0,0 +1,258 @@ +use std::net::UdpSocket; +use std::net; +use std::str; +use std::fmt; + +const BUFFER_SIZE: usize = 5000; +const SERVER_PORT: u16 = 67; + +enum DHCP_MESSAGE_TYPE { + DHCPDISCOVER = 1, + DHCPOFFER = 2, + DHCPREQUEST = 3, + DHCPDECLINE, + DHCPPACK, + DHCPNAK, + DHCPRELEASE, + DHCPINFORM +} + +const OPTIONS_NAME : [&str;77] = ["Pad", // 0 + "Subnet mask", + "Time offset", + "Router option", + "Time server", + "Name server", // 5 + "Domain name server", + "Log server", + "Cookie server 🍪", + "LPR server", + "Impress server", // 10 + "Ressource location server", + "Host name", + "Boot file size", + "Merit dump file", + "Domain name", // 15 + "Swap server", + "Root path", + "Extensions path", + "IP Forwarding", + "Non-local source routing", // 20 + "Policy filter", + "Maximum datagram", + "Default TTL", + "Path MTU again", + "Path MTU plateau", // 25 + "Interface MTU", + "All subnets are local", + "Broadcast address", + "Perform mask discovery", + "Mask supplier", // 30 + "Perform router discovery", + "Router solicitation address", + "Static route", + "Trailer Encapsulation", + "ARP cache timeout", // 35 + "Ethernet encapsulation", + "TCP Default TTL", + "TCP Keepalive interval", + "TCP Keepalive garbage", + "Network information service domain", // 40 + "Network information servers", + "Network time protocol servers", + "Vendor specific information", + "NetBIOS over TCP/IP Name server", + "NetBIOS over TCP/IP Datagram disctribution server", // 45 + "NetBIOS over TCP/IP Node type", + "NetBIOS over TCP/IP Scope", + "X Window System Font Server", + "X Window System Display Manager", + "Requested IP Address", // 50 + "IP Address Lease Time", + "Option Overload", + "DHCP Message Type", + "Server Identifier", + "Parameter Request List", // 55 + "Message", + "Maximum DHCP Message Size", + "Renewal T1 Time Value", + "Rebindin T2 Time Value", + "Vendor class identifier", // 60 + "Client-identifier", + "62 - Unused", + "63 - Unused", + "Network Information Service+ Domain", + "Network Information Service+ Servers", // 65 + "TFTP Server Option", + "Bootfile name", + "Mobile IP Home Agent", + "SMTP Server", + "POP3 Server", // 70 + "NNTP Server", + "WWW Server", + "Finger Server", + "IRC Server", + "StreetTalk Server", // 75 + "STDA Server", +]; + +struct DhcpMessage { + op: u8, + htype: u8, + hlen: u8, + hops: u8, + xid: u32, + secs: u16, + flags: u16, + ciaddr: u32, + yiaddr: u32, + siaddr: u32, + giaddr: u32, + chaddr: [u8; 6], + sname: [u8; 64], + file: [u8; 128], + options: [u8; 312] +} + +impl fmt::Display for DhcpMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut name: &str = "Undef"; + let mut is_file_empty = true; + for o in &self.file[..] { + if *o != 0 { + is_file_empty = false; + } + }; + let is_file_empty = is_file_empty; + + if let Ok(s) = std::str::from_utf8(&self.sname[..]) { + name = s; + } + + write!(f, "( + op: {:02X} + htype: {:02X} + hlen: {:02X} + hops: {:02X} + xid: {} + secs: {:04X} + flags: {:04X} + ciaddr: {:#08X} + yiaddr: {:#08X} + siaddr: {:#08X} + giaddr: {:#08X} + chaddr: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X} + sname: [{}] + file: {} +", self.op, self.htype, + self.hlen, self.hops, self.xid, self.secs, + self.flags, self.ciaddr, self.yiaddr, + self.siaddr, self.giaddr, self.chaddr[0], + self.chaddr[1], self.chaddr[2], self.chaddr[3], + self.chaddr[4], self.chaddr[5], name, + if is_file_empty { "empty" } else {"not empty"}); + write!(f, "options :\n"); + let mut i: u16 = 0; + loop { + if i >= 312 { + break; + } + let I : usize = usize::from(i); + if self.options[I] == 0xFF { + write!(f, " End Option(0xFF)"); + break; + } else if self.options[I] == 0 { + write!(f, " Pad Option(0x00)"); + i += 1; + } else if self.options[I] < 77 { + write!(f, " {} Option({:02x})\n", OPTIONS_NAME[usize::from(self.options[I])], self.options[I]); + i += u16::from(self.options[I+1]); + } else { + write!(f, " Unknow Option({:02x})", self.options[I]); + break; + } + } + write!(f, ")\n") + } +} +impl DhcpMessage { + pub fn new() -> DhcpMessage { + DhcpMessage { + op: 0, + htype: 0, + hlen: 0, + hops: 0, + xid: 0, + secs: 0, + flags: 0, + ciaddr: 0, + yiaddr: 0, + siaddr: 0, + giaddr: 0, + chaddr: [0; 6], + sname: [0; 64], + file: [0; 128], + options: [0; 312], + } + } +} +fn fill_dhcp_message( dhcp_message: &mut DhcpMessage, buf : &[u8; BUFFER_SIZE], size: usize) -> bool { + dhcp_message.op = buf[0]; + dhcp_message.htype = buf[1]; + dhcp_message.hlen = buf[2]; + dhcp_message.hops = buf[3]; + dhcp_message.xid = u32::from_be_bytes([buf[4], buf[5], buf[ 6], buf[ 7]]); + dhcp_message.secs = u16::from_be_bytes([buf[ 8], buf[ 9]]); + dhcp_message.flags = u16::from_be_bytes([buf[10], buf[11]]); + + dhcp_message.ciaddr = u32::from_be_bytes([buf[12], buf[13], buf[14], buf[15]]); + dhcp_message.yiaddr = u32::from_be_bytes([buf[16], buf[17], buf[18], buf[19]]); + dhcp_message.siaddr = u32::from_be_bytes([buf[20], buf[21], buf[22], buf[23]]); + dhcp_message.giaddr = u32::from_be_bytes([buf[24], buf[25], buf[26], buf[27]]); + dhcp_message.chaddr = [buf[28], buf[29], buf[30], buf[31], buf[32], buf[33]]; + for i in 0..64 { + dhcp_message.sname[i] = buf[i+34] + } + for i in 0..128 { + dhcp_message.file[i] = buf[i+98] + } + let size = if size > 226 + 538 { 538 } else { size }; + for i in 226..size { + dhcp_message.options[i-226] = buf[i+98] + } + + + + true +} + +fn main() -> std::io::Result<()> { + { + let addrs = [ + net::SocketAddr::from(([0, 0, 0, 0], SERVER_PORT)), + ]; + let socket = UdpSocket::bind(&addrs[..])?; + + loop { + // Receives a single datagram message on the socket. If `buf` is too small to hold + // the message, it will be cut off. + let mut buf = [0; BUFFER_SIZE]; + let mut dhcp_message: DhcpMessage = DhcpMessage::new(); + let (amt, _) = socket.recv_from(&mut buf)?; + print!("Receive {} bytes\n", amt); + for i in 0..amt { + if i % 16 == 0 { + print!("\n"); + } + print!("{:02x}", buf[i]) + } + fill_dhcp_message(&mut dhcp_message, &buf, amt); + print!("\n"); + print!("{}\n", dhcp_message); + if dhcp_message.xid == 42 { + break + } + } + } // the socket is closed here + Ok(()) +} -- cgit v1.2.3