Skip to content

Commit 0c68ef6

Browse files
dhcpd: parse the offer and send request
Signed-off-by: Andy-Python-Programmer <[email protected]>
1 parent d888f9d commit 0c68ef6

File tree

1 file changed

+72
-31
lines changed

1 file changed

+72
-31
lines changed

src/main.rs

Lines changed: 72 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,20 @@ impl Ipv4Addr {
2222
const MAC_ADDRESS: &[u8] = &[52, 54, 0, 12, 34, 56];
2323
const DHCP_XID: u32 = 0x43424140;
2424

25+
#[derive(Debug, Copy, Clone)]
2526
#[repr(u8)]
2627
enum DhcpType {
2728
BootRequest = 1u8.swap_bytes(),
2829
// BootReply = 2u8.swap_bytes(),
2930
}
3031

32+
#[derive(Debug, Copy, Clone)]
3133
#[repr(u8)]
3234
enum HType {
3335
Ethernet = 1u8.swap_bytes(),
3436
}
3537

38+
#[derive(Debug, Clone)]
3639
#[repr(C, packed)]
3740
struct Header {
3841
op: DhcpType,
@@ -53,19 +56,62 @@ struct Header {
5356
}
5457

5558
impl Header {
59+
fn new(htype: HType) -> Self {
60+
let mut client_hw_addr = [0; 16];
61+
client_hw_addr[0..6].copy_from_slice(MAC_ADDRESS);
62+
63+
Self {
64+
htype,
65+
hlen: BigEndian::<u8>::from(6),
66+
hops: BigEndian::<u8>::from(0),
67+
xid: BigEndian::<u32>::from(DHCP_XID),
68+
seconds: BigEndian::<u16>::from(0),
69+
client_hw_addr,
70+
server_name: [0; 64],
71+
file: [0; 128],
72+
options: [0; 64],
73+
74+
// request info:
75+
op: DhcpType::BootRequest,
76+
flags: BigEndian::from(0x8000), // broadcast
77+
client_ip: Ipv4Addr::EMPTY,
78+
your_ip: Ipv4Addr::EMPTY,
79+
server_ip: Ipv4Addr::EMPTY,
80+
gateway_ip: Ipv4Addr::EMPTY,
81+
}
82+
}
83+
5684
fn options_mut(&mut self) -> OptionsWriter<'_> {
5785
OptionsWriter::new(&mut self.options)
5886
}
87+
88+
fn as_slice<'a>(&'a self) -> &'a [u8] {
89+
unsafe {
90+
core::slice::from_raw_parts(
91+
(self as *const Header) as *const u8,
92+
std::mem::size_of::<Header>(),
93+
)
94+
}
95+
}
5996
}
6097

6198
#[repr(u8)]
6299
enum MessageType {
100+
/// Broadcast to locate available servers.
63101
Discover = 1u8.swap_bytes(),
102+
/// Message to servers to either:
103+
/// 1. Request the offered parameters from one server and implicitly
104+
/// declining offers from all others.
105+
/// 2. Confirm correctness of previously allocated address after,
106+
/// (e.g., system reboot).
107+
/// 3. Extend the lease on a particular network address.
108+
Request = 3u8.swap_bytes(),
64109
}
65110

66111
#[repr(u8)]
67112
enum DhcpOption {
68113
HostName = 12,
114+
RequestedIp = 50,
69115
MessageType = 53,
70116
ParameterRequestList = 55,
71117
ClientIdentifier = 61,
@@ -146,6 +192,11 @@ impl<'a> OptionsWriter<'a> {
146192
self.insert_padding(1); // null-terminator
147193
self
148194
}
195+
196+
fn set_requested_ip(mut self, ip: Ipv4Addr) -> Self {
197+
self.insert(DhcpOption::RequestedIp, &ip.0);
198+
self
199+
}
149200
}
150201

151202
impl<'a> Drop for OptionsWriter<'a> {
@@ -158,43 +209,33 @@ pub fn main() -> Result<(), Box<dyn Error>> {
158209
let socket = UdpSocket::bind(("0.0.0.0", 68))?;
159210
socket.connect(("255.255.255.255", 67))?;
160211

161-
let mut client_hw_addr = [0; 16];
162-
client_hw_addr[0..6].copy_from_slice(MAC_ADDRESS);
163-
164-
let mut header = Header {
165-
htype: HType::Ethernet,
166-
hlen: BigEndian::<u8>::from(6),
167-
hops: BigEndian::<u8>::from(0),
168-
xid: BigEndian::<u32>::from(DHCP_XID),
169-
seconds: BigEndian::<u16>::from(0),
170-
client_hw_addr,
171-
server_name: [0; 64],
172-
file: [0; 128],
173-
options: [0; 64],
174-
175-
// request info:
176-
op: DhcpType::BootRequest,
177-
flags: BigEndian::from(0x8000), // broadcast
178-
client_ip: Ipv4Addr::EMPTY,
179-
your_ip: Ipv4Addr::EMPTY,
180-
server_ip: Ipv4Addr::EMPTY,
181-
gateway_ip: Ipv4Addr::EMPTY,
182-
};
183-
184-
let _ = header
212+
let mut discover_header = Header::new(HType::Ethernet);
213+
discover_header
185214
.options_mut()
186215
.set_message_type(MessageType::Discover)
187216
.set_client_identifier()
188217
.set_host_name("Aero")
189218
.set_parameter_request_list();
190219

191-
let header_bytes = unsafe {
192-
core::slice::from_raw_parts(
193-
(&header as *const Header) as *const u8,
194-
std::mem::size_of::<Header>(),
195-
)
196-
};
220+
socket.send(discover_header.as_slice())?;
221+
222+
let mut offer_bytes = [0u8; core::mem::size_of::<Header>()];
223+
socket.recv(&mut offer_bytes)?;
224+
225+
// SAFETY: The array has the same size as of the DHCP header.
226+
let offer = unsafe { &*(offer_bytes.as_ptr() as *const Header) };
227+
println!("dhcpd: recieved offer {:?}", offer.your_ip);
228+
229+
let mut request_header = Header::new(HType::Ethernet);
230+
request_header
231+
.options_mut()
232+
.set_message_type(MessageType::Request)
233+
.set_client_identifier()
234+
.set_requested_ip(offer.your_ip)
235+
.set_host_name("Aero")
236+
.set_parameter_request_list();
237+
238+
socket.send(request_header.as_slice())?;
197239

198-
socket.send(&header_bytes)?;
199240
Ok(())
200241
}

0 commit comments

Comments
 (0)