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.unoffer(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 let ip = decoded.ciaddr;
186
187 match self.ip_pool.extend(mac_address, ip) {
188 Ok(_) => {
189 self.ack(decoded, ip)
193 }
194 Err(error) => self.nak(decoded, error.to_string()),
195 }
196 }
197 }
198 }
199 }
200 MessageTypes::Release => {
201 debug!("Received Release message");
202 if let Err(error) = self.ip_pool.release(decoded.get_mac_address()) {
203 error!("{}", error);
204 }
205 return;
206 }
207 MessageTypes::Decline => {
208 debug!("Received Decline message");
209
210 if let Err(error) = self.ip_pool.release(decoded.get_mac_address()) {
214 error!("{}", error);
215 }
216 return;
217 }
218 MessageTypes::Inform => {
219 debug!("Received Inform message");
220 self.ack_inform(decoded)
221 }
222 MessageTypes::LeaseQuery
223 | MessageTypes::BulkLeaseQuery
224 | MessageTypes::ActiveLeaseQuery
225 | MessageTypes::Tls => {
226 warn!("Client sent a message type that is known but not yet handled");
227 return;
228 }
229 _ => {
230 error!("Client sent unknown message type");
231 return;
232 }
233 };
234
235 match self.socket.broadcast(&response, src.port()) {
236 Ok(_) => {}
237 Err(error) => {
238 error!("{error}");
239 }
240 };
241 }
242
243 pub fn listen(&mut self) -> ! {
245 loop {
246 self.listen_once();
247 }
248 }
249
250 fn handle_parameter_requests(&self, request_message: &Message) -> Vec<MessageOptions> {
254 match request_message.find_option(55) {
255 Some(MessageOptions::RequestedOptions(list)) => {
256 list.iter()
258 .filter_map(|parameter_request| {
259 self.config
260 .parameters
261 .get(¶meter_request.to_string())
262 .cloned()
263 })
264 .collect()
265 }
266 _ => vec![],
267 }
268 }
269
270 pub fn offer(&mut self, message: Message) -> Result<Message> {
272 debug!("Sending Offer message");
273
274 let maybe_requested_ip = match message.find_option(50) {
279 Some(MessageOptions::RequestedIp(address_option)) => Some(address_option.inner()),
280 _ => None,
281 };
282 let mac_address = message.get_mac_address();
283 let yiaddr = self.ip_pool.offer(mac_address, maybe_requested_ip)?;
284
285 let mut parameters = self.handle_parameter_requests(&message);
286 parameters.push(MessageOptions::MessageType(MessageTypes::Offer)); parameters.push(MessageOptions::LeaseTime(TimeOption::new(
288 self.config.lease_time.as_client(),
289 ))); parameters.push(MessageOptions::ServerIdentifier(AddressOption::new(
291 self.ip,
292 ))); parameters.push(MessageOptions::End); Ok(Message {
296 op: Ops::Reply,
297 htype: HTypes::Ethernet,
298 hlen: 6,
299 hops: 0,
300 xid: message.xid,
301 secs: 0,
302 flags: message.flags,
303 ciaddr: Ipv4Addr::UNSPECIFIED, yiaddr,
305 siaddr: self.ip,
306 giaddr: message.giaddr,
307 chaddr: message.chaddr,
308 sname: SName::EMPTY,
309 file: File::EMPTY,
310 magic: MAGIC,
311 options: parameters,
312 })
313 }
314
315 pub fn ack(&mut self, message: Message, yiaddr: Ipv4Addr) -> Message {
324 debug!("Sending Ack message");
325
326 let mut parameters = self.handle_parameter_requests(&message);
329 parameters.push(MessageOptions::MessageType(MessageTypes::Ack)); parameters.push(MessageOptions::LeaseTime(TimeOption::new(
331 self.config.lease_time.as_client(),
332 ))); parameters.push(MessageOptions::ServerIdentifier(AddressOption::new(
334 self.ip,
335 ))); parameters.push(MessageOptions::End); Message {
339 op: Ops::Reply,
340 htype: HTypes::Ethernet,
341 hlen: 6,
342 hops: 0,
343 xid: message.xid,
344 secs: 0,
345 flags: message.flags,
346 ciaddr: message.ciaddr,
347 yiaddr,
348 siaddr: self.ip, giaddr: message.giaddr,
350 chaddr: message.chaddr,
351 sname: SName::EMPTY,
352 file: File::EMPTY,
353 magic: MAGIC,
354 options: parameters,
355 }
356 }
357
358 pub fn ack_inform(&self, message: Message) -> Message {
363 debug!("Sending Ack message (in response to an inform)");
364
365 let mut parameters = self.handle_parameter_requests(&message);
366 parameters.push(MessageOptions::MessageType(MessageTypes::Ack)); parameters.push(MessageOptions::ServerIdentifier(AddressOption::new(
368 self.ip,
369 ))); parameters.push(MessageOptions::End); Message {
373 op: Ops::Reply,
374 htype: HTypes::Ethernet,
375 hlen: 6,
376 hops: 0,
377 xid: message.xid,
378 secs: 0,
379 flags: message.flags,
380 ciaddr: message.ciaddr,
381 yiaddr: Ipv4Addr::UNSPECIFIED,
382 siaddr: self.ip, giaddr: message.giaddr,
384 chaddr: message.chaddr,
385 sname: SName::EMPTY,
386 file: File::EMPTY,
387 magic: MAGIC,
388 options: parameters,
389 }
390 }
391
392 pub fn nak(&self, message: Message, error: String) -> Message {
394 debug!("Sending Nak message");
395
396 let mut response = Message {
397 op: Ops::Reply,
398 htype: HTypes::Ethernet,
399 hlen: 6,
400 hops: 0,
401 xid: message.xid,
402 secs: 0,
403 flags: message.flags,
404 ciaddr: Ipv4Addr::UNSPECIFIED,
405 yiaddr: Ipv4Addr::UNSPECIFIED,
406 siaddr: Ipv4Addr::UNSPECIFIED,
407 giaddr: message.giaddr,
408 chaddr: message.chaddr,
409 sname: SName::EMPTY, file: File::EMPTY, magic: MAGIC,
412 options: vec![
413 MessageOptions::MessageType(MessageTypes::Nak), MessageOptions::ServerIdentifier(AddressOption::new(self.ip)), MessageOptions::End, ],
417 };
418
419 match StringOption::new(error) {
420 Ok(converted) => {
421 response.add_option(MessageOptions::Message(converted)); }
423 Err(_) => {
424 error!("Sending Nak without error message option because option's value is empty");
425 }
426 };
427
428 response
429 }
430}