1use super::config::*;
2use super::ip_pool::*;
3use crate::v4::error::Result;
4use crate::v4::message::*;
5use inherface::get_interfaces;
6use log::{debug, error, warn};
7use std::net::Ipv4Addr;
8
9pub struct Server {
16 pub socket: Socket,
18 pub ip: Ipv4Addr,
22 pub config: Config,
24 pub ip_pool: IpPool,
26}
27
28fn get_interface_broadcast(maybe_interface_name: Option<String>) -> Option<Ipv4Addr> {
29 let interface = maybe_interface_name?;
30 let interfaces = get_interfaces().ok()?;
31 let maybe_interface = interfaces.get(&interface);
32 let maybe_addr = maybe_interface?
33 .v4_addr
34 .iter()
35 .find(|address| address.broadcast.is_some());
36
37 debug!(
38 "found ipv4 broadcast address ({:?}) in list of addresses for interface",
39 maybe_addr
40 );
41
42 maybe_addr?.broadcast
43}
44
45impl Server {
46 pub fn new(config: Config) -> Self {
51 let broadcast = get_interface_broadcast(config.interface.clone());
52 let socket = Socket::new(config.listen_address, broadcast);
53 let ip = config.server_address.unwrap_or_else(|| socket.get_ip());
54 let ip_pool = IpPool::restore_or_new(&config);
55
56 Self {
57 socket,
58 ip,
59 config,
60 ip_pool,
61 }
62 }
63
64 pub fn listen_once(&mut self) {
68 let (decoded, src) = match self.socket.receive::<Message>() {
69 Ok(values) => values,
70 Err(error) => {
71 error!("{error}");
72 return;
73 }
74 };
75
76 let message_type = match decoded.find_option(53) {
77 Some(MessageOptions::MessageType(message_type)) => message_type,
78 _ => {
79 error!("Request does not have option 53");
80 return;
81 }
82 };
83
84 let response = match message_type {
85 MessageTypes::Discover => 'discover: {
86 debug!("Received Discover message");
87 if self.config.rapid_commit {
88 debug!("Rapid commit enabled on server");
89 match decoded.find_option(80) {
90 Some(MessageOptions::RapidCommit) => {
91 debug!("Discover message has rapid commit option");
92 let mac_address = decoded.get_mac_address();
93
94 let ip = match self.ip_pool.ack(mac_address) {
95 Ok(ip) => ip,
96 Err(error) => {
97 error!("{}", error);
98 return;
99 }
100 };
101 let mut message = self.ack(decoded, ip);
102 message.add_option(MessageOptions::RapidCommit);
103 break 'discover message;
104 }
105 _ => {
106 error!(
107 "Discover message has not sent a (valid) rapid commit option, will send Offer"
108 );
109 }
110 };
111 }
112
113 match self.offer(decoded) {
114 Ok(message) => message,
115 Err(error) => {
116 error!("{}", error);
117 return;
118 }
119 }
120 }
121 MessageTypes::Request => 'request: {
122 debug!("Received Request message");
123 let mac_address = decoded.get_mac_address();
124
125 match decoded.find_option(54) {
128 Some(MessageOptions::ServerIdentifier(address_option)) => {
129 let server_identifier = address_option.inner();
130 if server_identifier != self.ip {
131 debug!("Ignoring client broadcast of DHCP Request for {} which is not this server ({}).", server_identifier, self.ip);
132
133 match self.ip_pool.release(mac_address) {
134 Ok(_) => {
135 debug!("Removed IP address previously offered to this client")
136 }
137 Err(error) => error!("{}", error),
138 }
139
140 return;
141 }
142
143 debug!("client has selected this server for a lease");
144 let ip = match self.ip_pool.ack(mac_address) {
145 Ok(ip) => ip,
146 Err(error) => {
147 error!("{}", error);
148 return;
149 }
150 };
151 self.ack(decoded, ip)
152 }
153 _ => {
154 if decoded.ciaddr.is_unspecified() {
155 debug!("client is attempting to verify lease");
157
158 let ip = match decoded.find_option(50) {
159 Some(MessageOptions::RequestedIp(address_option)) => {
160 address_option.inner()
161 }
162 _ => {
163 break 'request self.nak(decoded, "Request does not have required option 50 (requested ip address)".to_string());
166 }
167 };
168
169 match self.ip_pool.verify_lease(mac_address, &ip) {
170 Ok(_) => self.ack(decoded, ip),
171 Err(error) => {
172 if error == "No IP address lease found with that owner" {
173 return;
176 } else {
177 self.nak(decoded, error.to_string())
179 }
180 }
181 }
182 } else {
183 debug!("client is attempting to renew/rebind lease");
185 match self.ip_pool.extend(mac_address) {
186 Ok(_) => {
187 let ip = decoded.ciaddr;
191 self.ack(decoded, ip)
192 }
193 Err(error) => self.nak(decoded, error.to_string()),
194 }
195 }
196 }
197 }
198 }
199 MessageTypes::Release => {
200 debug!("Received Release message");
201 if let Err(error) = self.ip_pool.release(decoded.get_mac_address()) {
202 error!("{}", error);
203 }
204 return;
205 }
206 MessageTypes::Decline => {
207 debug!("Received Decline message");
208
209 if let Err(error) = self.ip_pool.release(decoded.get_mac_address()) {
213 error!("{}", error);
214 }
215 return;
216 }
217 MessageTypes::Inform => {
218 debug!("Received Inform message");
219 self.ack_inform(decoded)
220 }
221 MessageTypes::LeaseQuery
222 | MessageTypes::BulkLeaseQuery
223 | MessageTypes::ActiveLeaseQuery
224 | MessageTypes::Tls => {
225 warn!("Client sent a message type that is known but not yet handled");
226 return;
227 }
228 _ => {
229 error!("Client sent unknown message type");
230 return;
231 }
232 };
233
234 match self.socket.broadcast(&response, src.port()) {
235 Ok(_) => {}
236 Err(error) => {
237 error!("{error}");
238 }
239 };
240 }
241
242 pub fn listen(&mut self) -> ! {
244 loop {
245 self.listen_once();
246 }
247 }
248
249 fn handle_parameter_requests(&self, request_message: &Message) -> Vec<MessageOptions> {
253 match request_message.find_option(55) {
254 Some(MessageOptions::RequestedOptions(list)) => {
255 list.iter()
257 .filter_map(|parameter_request| {
258 self.config
259 .parameters
260 .get(¶meter_request.to_string())
261 .cloned()
262 })
263 .collect()
264 }
265 _ => vec![],
266 }
267 }
268
269 pub fn offer(&mut self, message: Message) -> Result<Message> {
271 debug!("Sending Offer message");
272
273 let maybe_requested_ip = match message.find_option(50) {
278 Some(MessageOptions::RequestedIp(address_option)) => Some(address_option.inner()),
279 _ => None,
280 };
281 let mac_address = message.get_mac_address();
282 let yiaddr = self.ip_pool.offer(mac_address, maybe_requested_ip)?;
283
284 let mut parameters = self.handle_parameter_requests(&message);
285 parameters.push(MessageOptions::MessageType(MessageTypes::Offer)); parameters.push(MessageOptions::LeaseTime(TimeOption::new(
287 self.config.lease_time.as_client(),
288 ))); parameters.push(MessageOptions::ServerIdentifier(AddressOption::new(
290 self.ip,
291 ))); parameters.push(MessageOptions::End); Ok(Message {
295 op: Ops::Reply,
296 htype: HTypes::Ethernet,
297 hlen: 6,
298 hops: 0,
299 xid: message.xid,
300 secs: 0,
301 flags: message.flags,
302 ciaddr: Ipv4Addr::UNSPECIFIED, yiaddr,
304 siaddr: self.ip,
305 giaddr: message.giaddr,
306 chaddr: message.chaddr,
307 sname: SName::EMPTY,
308 file: File::EMPTY,
309 magic: MAGIC,
310 options: parameters,
311 })
312 }
313
314 pub fn ack(&mut self, message: Message, yiaddr: Ipv4Addr) -> Message {
323 debug!("Sending Ack message");
324
325 let mut parameters = self.handle_parameter_requests(&message);
326 parameters.push(MessageOptions::MessageType(MessageTypes::Ack)); parameters.push(MessageOptions::LeaseTime(TimeOption::new(
328 self.config.lease_time.as_client(),
329 ))); parameters.push(MessageOptions::ServerIdentifier(AddressOption::new(
331 self.ip,
332 ))); parameters.push(MessageOptions::End); Message {
336 op: Ops::Reply,
337 htype: HTypes::Ethernet,
338 hlen: 6,
339 hops: 0,
340 xid: message.xid,
341 secs: 0,
342 flags: message.flags,
343 ciaddr: message.ciaddr,
344 yiaddr,
345 siaddr: self.ip, giaddr: message.giaddr,
347 chaddr: message.chaddr,
348 sname: SName::EMPTY,
349 file: File::EMPTY,
350 magic: MAGIC,
351 options: parameters,
352 }
353 }
354
355 pub fn ack_inform(&self, message: Message) -> Message {
360 debug!("Sending Ack message (in response to an inform)");
361
362 let mut parameters = self.handle_parameter_requests(&message);
363 parameters.push(MessageOptions::MessageType(MessageTypes::Ack)); parameters.push(MessageOptions::ServerIdentifier(AddressOption::new(
365 self.ip,
366 ))); parameters.push(MessageOptions::End); Message {
370 op: Ops::Reply,
371 htype: HTypes::Ethernet,
372 hlen: 6,
373 hops: 0,
374 xid: message.xid,
375 secs: 0,
376 flags: message.flags,
377 ciaddr: message.ciaddr,
378 yiaddr: Ipv4Addr::UNSPECIFIED,
379 siaddr: self.ip, giaddr: message.giaddr,
381 chaddr: message.chaddr,
382 sname: SName::EMPTY,
383 file: File::EMPTY,
384 magic: MAGIC,
385 options: parameters,
386 }
387 }
388
389 pub fn nak(&self, message: Message, error: String) -> Message {
391 debug!("Sending Nak message");
392
393 let mut response = Message {
394 op: Ops::Reply,
395 htype: HTypes::Ethernet,
396 hlen: 6,
397 hops: 0,
398 xid: message.xid,
399 secs: 0,
400 flags: message.flags,
401 ciaddr: Ipv4Addr::UNSPECIFIED,
402 yiaddr: Ipv4Addr::UNSPECIFIED,
403 siaddr: Ipv4Addr::UNSPECIFIED,
404 giaddr: message.giaddr,
405 chaddr: message.chaddr,
406 sname: SName::EMPTY, file: File::EMPTY, magic: MAGIC,
409 options: vec![
410 MessageOptions::MessageType(MessageTypes::Nak), MessageOptions::ServerIdentifier(AddressOption::new(self.ip)), MessageOptions::End, ],
414 };
415
416 match StringOption::new(error) {
417 Ok(converted) => {
418 response.add_option(MessageOptions::Message(converted)); }
420 Err(_) => {
421 error!("Sending Nak without error message option because option's value is empty");
422 }
423 };
424
425 response
426 }
427}