1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
use dhcp4d::lease::{Lease, LeaseDummyManager, LeaseManager};
use std::io;
use std::net::{SocketAddr, SocketAddrV4, UdpSocket};
use anyhow::{anyhow, bail};
use dhcproto::v4::{DhcpOption, Flags, Message, MessageType, Opcode, OptionCode};
use dhcproto::{Decodable, Decoder, Encodable, Encoder};
fn main() -> io::Result<()> {
let sock = UdpSocket::bind("0.0.0.0:67")?;
sock.set_broadcast(true)?;
loop {
let mut buf = [0; 1024];
let (n, remote) = sock.recv_from(&mut buf)?;
let buf = &buf[..n];
let remote = match remote {
SocketAddr::V4(addr) => addr,
_ => {
unreachable!();
}
};
match handle_request(&sock, buf, remote) {
Ok(_) => {}
Err(e) => eprintln!("erroneous request from {}: {}", remote, e),
}
}
}
fn handle_request(sock: &UdpSocket, buf: &[u8], remote: SocketAddrV4) -> anyhow::Result<()> {
let chaddr = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let lease_mgr = LeaseDummyManager::new(None);
let msg = Message::decode(&mut Decoder::new(buf))?;
let op = msg.opcode();
match op {
Opcode::BootRequest => {
let xid = msg.xid();
let opts = msg.opts();
let msg_type = opts.msg_type().ok_or(anyhow!("no message type given"))?;
match msg_type {
MessageType::Discover => {
let client_id = match opts
.get(OptionCode::ClientIdentifier)
.ok_or(anyhow!("no client id"))?
{
DhcpOption::ClientIdentifier(id) => id,
_ => bail!("expected ClientIdentifier"),
};
let lease = obtain_lease(lease_mgr, client_id)
.ok_or(anyhow!("no free addresses available"))?;
let mut resp = Message::default();
let opts = resp
.set_flags(Flags::default().set_broadcast())
.set_opcode(Opcode::BootReply)
.set_xid(xid)
.set_siaddr(lease.address)
.set_chaddr(chaddr)
.opts_mut();
opts.insert(DhcpOption::MessageType(MessageType::Offer));
let mut resp_buf = Vec::new();
resp.encode(&mut Encoder::new(&mut resp_buf))?;
let n = sock.send_to(&resp_buf, remote)?;
if n != resp_buf.len() {
Err(anyhow!("partial response"))
} else {
let cid = client_id
.iter()
.map(|octet| format!("{:x}", octet))
.reduce(|acc, octet| acc + &octet)
.ok_or(anyhow!("zero-length client id"))?;
println!(
"offering {} to client ID {} for {:?}",
lease.address, cid, lease.lease_time
);
Ok(())
}
}
_ => Err(anyhow!("invalid message type {:?}", msg_type,)),
}
}
_ => Err(anyhow!("invalid opcode {:?}", op)),
}
}
fn obtain_lease<T: LeaseManager>(lease_mgr: T, client_id: &[u8]) -> Option<Lease> {
lease_mgr.persistent_free_address(client_id)
}
|