wireforge_app/dhcp/
builder.rs1use super::parser::DHCP_MIN_LEN;
4use super::types::DhcpOption;
5
6const DHCP_MAGIC_COOKIE: u32 = 0x63825363;
7
8pub struct DhcpPacketBuilder {
9 buf: Vec<u8>,
10 options: Vec<u8>,
11}
12
13impl Default for DhcpPacketBuilder {
14 fn default() -> Self { Self::new() }
15}
16
17impl DhcpPacketBuilder {
18 pub fn new() -> Self {
19 let mut buf = vec![0u8; DHCP_MIN_LEN];
20 buf[0] = 1; buf[1] = 1; buf[2] = 6; buf[236..240].copy_from_slice(&DHCP_MAGIC_COOKIE.to_be_bytes());
24 Self { buf, options: Vec::new() }
25 }
26
27 pub fn discover() -> Self { let mut s = Self::new(); s.options.push(53); s.options.push(1); s.options.push(1); s }
28 pub fn request() -> Self { let mut s = Self::new(); s.options.push(53); s.options.push(1); s.options.push(3); s }
29 pub fn offer() -> Self { let mut s = Self::new(); s.buf[0] = 2; s.options.push(53); s.options.push(1); s.options.push(2); s }
30 pub fn ack() -> Self { let mut s = Self::new(); s.buf[0] = 2; s.options.push(53); s.options.push(1); s.options.push(5); s }
31
32 pub fn op(mut self, v: u8) -> Self { self.buf[0] = v; self }
33 pub fn htype(mut self, v: u8) -> Self { self.buf[1] = v; self }
34 pub fn hlen(mut self, v: u8) -> Self { self.buf[2] = v; self }
35 pub fn hops(mut self, v: u8) -> Self { self.buf[3] = v; self }
36 pub fn xid(mut self, v: u32) -> Self { self.buf[4..8].copy_from_slice(&v.to_be_bytes()); self }
37 pub fn secs(mut self, v: u16) -> Self { self.buf[8..10].copy_from_slice(&v.to_be_bytes()); self }
38 pub fn flags(mut self, v: u16) -> Self { self.buf[10..12].copy_from_slice(&v.to_be_bytes()); self }
39 pub fn yiaddr(mut self, ip: [u8; 4]) -> Self { self.buf[16..20].copy_from_slice(&ip); self }
40 pub fn siaddr(mut self, ip: [u8; 4]) -> Self { self.buf[20..24].copy_from_slice(&ip); self }
41 pub fn giaddr(mut self, ip: [u8; 4]) -> Self { self.buf[24..28].copy_from_slice(&ip); self }
42 pub fn chaddr(mut self, mac: &[u8; 6]) -> Self { self.buf[28..34].copy_from_slice(mac); self }
43
44 pub fn add_option(mut self, opt: &DhcpOption) -> Self {
45 match opt {
46 DhcpOption::SubnetMask(ip) => { self.options.push(1); self.options.push(4); self.options.extend_from_slice(&ip.octets()); }
47 DhcpOption::Router(ips) => { self.options.push(3); self.options.push((ips.len() * 4) as u8); for ip in ips { self.options.extend_from_slice(&ip.octets()); } }
48 DhcpOption::DnsServer(ips) => { self.options.push(6); self.options.push((ips.len() * 4) as u8); for ip in ips { self.options.extend_from_slice(&ip.octets()); } }
49 DhcpOption::HostName(s) => { self.options.push(12); self.options.push(s.len() as u8); self.options.extend_from_slice(s.as_bytes()); }
50 DhcpOption::DomainName(s) => { self.options.push(15); self.options.push(s.len() as u8); self.options.extend_from_slice(s.as_bytes()); }
51 DhcpOption::BroadcastAddr(ip) => { self.options.push(28); self.options.push(4); self.options.extend_from_slice(&ip.octets()); }
52 DhcpOption::RequestedIp(ip) => { self.options.push(50); self.options.push(4); self.options.extend_from_slice(&ip.octets()); }
53 DhcpOption::LeaseTime(t) => { self.options.push(51); self.options.push(4); self.options.extend_from_slice(&t.to_be_bytes()); }
54 DhcpOption::ServerId(ip) => { self.options.push(54); self.options.push(4); self.options.extend_from_slice(&ip.octets()); }
55 DhcpOption::ParameterList(params) => { self.options.push(55); self.options.push(params.len() as u8); self.options.extend_from_slice(params); }
56 DhcpOption::End => {}
57 _ => {}
58 }
59 self
60 }
61
62 pub fn build(mut self) -> Vec<u8> {
63 self.options.push(0xff); self.buf.extend_from_slice(&self.options);
65 self.buf
66 }
67}