1use std::cell::Cell;
2use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
3
4use crate::options;
5use crate::options::{DhcpOption, MessageType};
6use crate::packet::*;
7
8pub struct Server {
11 out_buf: Cell<[u8; 1500]>,
12 socket: UdpSocket,
13 src: SocketAddr,
14 server_ip: Ipv4Addr,
15}
16
17pub trait Handler {
18 fn handle_request(&mut self, server: &Server, in_packet: Packet);
19}
20
21pub fn filter_options_by_req(opts: &mut Vec<DhcpOption>, req_params: &[u8]) {
25 let mut pos = 0;
26 let h = &[
27 options::DHCP_MESSAGE_TYPE as u8,
28 options::SERVER_IDENTIFIER as u8,
29 options::IP_ADDRESS_LEASE_TIME as u8,
30 ] as &[u8];
31 for z in [h, req_params].iter() {
32 for r in z.iter() {
33 let mut found = false;
34 let mut at = 0;
35 for (i, o) in opts[pos..].iter().enumerate() {
36 if o.code() == *r {
37 found = true;
38 at = i + pos;
39 break;
40 }
41 }
42 if found {
43 opts.swap(pos, at);
44 pos += 1;
45 }
46 }
47 }
48 opts.truncate(pos);
49}
50
51impl Server {
52 pub fn serve<H: Handler>(
53 udp_soc: UdpSocket,
54 server_ip: Ipv4Addr,
55 mut handler: H,
56 ) -> std::io::Error {
57 let mut in_buf: [u8; 1500] = [0; 1500];
58 let mut s = Server {
59 out_buf: Cell::new([0; 1500]),
60 socket: udp_soc,
61 server_ip,
62 src: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0),
63 };
64 loop {
65 match s.socket.recv_from(&mut in_buf) {
66 Err(e) => return e,
67 Ok((l, src)) => {
68 if let Ok(p) = Packet::from(&in_buf[..l]) {
69 s.src = src;
70 handler.handle_request(&s, p);
71 }
72 }
73 }
74 }
75 }
76
77 pub fn reply(
81 &self,
82 msg_type: MessageType,
83 additional_options: Vec<DhcpOption>,
84 offer_ip: Ipv4Addr,
85 req_packet: Packet,
86 ) -> std::io::Result<usize> {
87 let ciaddr = match msg_type {
88 MessageType::Nak => Ipv4Addr::new(0, 0, 0, 0),
89 _ => req_packet.ciaddr,
90 };
91
92 let mut opts: Vec<DhcpOption> = Vec::with_capacity(additional_options.len() + 2);
95 opts.push(DhcpOption::DhcpMessageType(msg_type));
96 opts.push(DhcpOption::ServerIdentifier(self.server_ip));
97 opts.extend(additional_options);
106
107 if let Some(DhcpOption::ParameterRequestList(prl)) =
108 req_packet.option(options::PARAMETER_REQUEST_LIST)
109 {
110 filter_options_by_req(&mut opts, &prl);
111 }
112
113 self.send(Packet {
114 reply: true,
115 hops: 0,
116 xid: req_packet.xid,
117 secs: 0,
118 broadcast: req_packet.broadcast,
119 ciaddr,
120 yiaddr: offer_ip,
121 siaddr: Ipv4Addr::new(0, 0, 0, 0),
122 giaddr: req_packet.giaddr,
123 chaddr: req_packet.chaddr,
124 options: opts,
125 })
126 }
127
128 pub fn for_this_server(&self, packet: &Packet) -> bool {
130 match packet.option(options::SERVER_IDENTIFIER) {
131 Some(DhcpOption::ServerIdentifier(x)) => (x == &self.server_ip),
132 _ => false,
133 }
134 }
135
136 pub fn send(&self, p: Packet) -> std::io::Result<usize> {
138 let mut addr = self.src;
139 if p.broadcast || addr.ip() == IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)) {
140 addr.set_ip(IpAddr::V4(Ipv4Addr::new(255, 255, 255, 255)));
141 }
142 self.socket.send_to(p.encode(&mut self.out_buf.get()), addr)
143 }
144}