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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use crate::v4::UndecodedMessage;
use std::fmt::Debug;
/// A supertrait that defines everything a custom message
/// needs to be decoded after being received by a socket.
pub trait Decodable: DecodeMessage + Debug {}
/// Define how the bytes of a DHCP message's fields
/// decode into your custom Message's types.
///
/// ...or don't and use our homemade [Message](crate::v4::message::Message)
/// with this already implemented.
pub trait DecodeMessage {
/// The type your custom Message uses to represent the op field.
type Op;
/// The type your custom Message uses to represent the htype field.
type Htype;
/// The type your custom Message uses to represent the hlen field.
type Hlen;
/// The type your custom Message uses to represent the hops field.
type Hops;
/// The type your custom Message uses to represent the xid field.
type Xid;
/// The type your custom Message uses to represent the secs field.
type Secs;
/// The type your custom Message uses to represent the flags field.
type Flags;
/// The type your custom Message uses to represent the ciaddr field.
type Ciaddr;
/// The type your custom Message uses to represent the yiaddr field.
type Yiaddr;
/// The type your custom Message uses to represent the siaddr field.
type Siaddr;
/// The type your custom Message uses to represent the giaddr field.
type Giaddr;
/// The type your custom Message uses to represent the chaddr field.
type Chaddr;
/// The type your custom Message uses to represent the sname field.
type Sname;
/// The type your custom Message uses to represent the file field.
type File;
/// The type your custom Message uses to represent the magic field.
type Magic;
/// The type your custom Message uses to represent the options field.
type Options;
/// Your custom Message.
type Output;
/// Convert an op field's byte into your custom Message's type.
fn decode_op(op: &UndecodedMessage) -> Self::Op;
/// Convert an htype field's byte into your custom Message's type.
fn decode_htype(htype: &UndecodedMessage) -> Self::Htype;
/// Convert an hlen field's byte into your custom Message's type.
fn decode_hlen(hlen: &UndecodedMessage) -> Self::Hlen;
/// Convert an hops field's byte into your custom Message's type.
fn decode_hops(hops: &UndecodedMessage) -> Self::Hops;
/// Convert an xid field's bytes into your custom Message's type.
fn decode_xid(xid: &UndecodedMessage) -> Self::Xid;
/// Convert an secs field's bytes into your custom Message's type.
fn decode_secs(secs: &UndecodedMessage) -> Self::Secs;
/// Convert an flags field's bytes into your custom Message's type.
fn decode_flags(flags: &UndecodedMessage) -> Self::Flags;
/// Convert an ciaddr field's bytes into your custom Message's type.
fn decode_ciaddr(ciaddr: &UndecodedMessage) -> Self::Ciaddr;
/// Convert an yiaddr field's bytes into your custom Message's type.
fn decode_yiaddr(yiaddr: &UndecodedMessage) -> Self::Yiaddr;
/// Convert an siaddr field's bytes into your custom Message's type.
fn decode_siaddr(siaddr: &UndecodedMessage) -> Self::Siaddr;
/// Convert an giaddr field's bytes into your custom Message's type.
fn decode_giaddr(giaddr: &UndecodedMessage) -> Self::Giaddr;
/// Convert an chaddr field's bytes into your custom Message's type.
fn decode_chaddr(chaddr: &UndecodedMessage) -> Self::Chaddr;
/// Convert an sname field's bytes into your custom Message's type.
fn decode_sname(sname: &UndecodedMessage) -> Self::Sname;
/// Convert an file field's bytes into your custom Message's type.
fn decode_file(file: &UndecodedMessage) -> Self::File;
/// Convert an magic field's bytes into your custom Message's type.
fn decode_magic(magic: &UndecodedMessage) -> Self::Magic;
/// Convert an options field's bytes into your custom Message's type.
fn decode_options(options: &UndecodedMessage) -> Self::Options;
/// decodes a byte array into a [Message](crate::v4::Message) or other type that implements decodeMessage.
fn from_bytes(undecoded: &UndecodedMessage) -> Self::Output;
}
// ------------------------------------------------
#[cfg(test)]
mod tests {
use std::net::Ipv4Addr;
use super::*;
use crate::v4::*;
// Output additional debug info with
// RUST_LOG=debug cargo test test_from_bytes -- --show-output
fn init_logger() {
let _ = env_logger::builder().is_test(true).try_init();
}
#[test]
fn test_from_bytes() {
init_logger();
let bytes = Socket::receive_mock(&[
1, 1, 6, 1, 0, 0, 0, 4, 0, 2, 128, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 0, 99, 130, 83, 99, 0, 53, 1, 1, 255,
]);
let test: Message = Message::from_bytes(&bytes);
let expected = Message {
op: Ops::Request,
htype: HTypes::Ethernet,
hlen: 6,
hops: 1,
xid: 4,
secs: 2,
flags: Flags { broadcast: true },
ciaddr: Ipv4Addr::new(1, 1, 1, 1),
yiaddr: Ipv4Addr::new(1, 1, 1, 1),
siaddr: Ipv4Addr::new(1, 1, 1, 1),
giaddr: Ipv4Addr::new(1, 1, 1, 1),
chaddr: [3; 16],
sname: SName::new(c"000000000000000000000000000000000000000000000000000000000000000")
.unwrap(),
file: File::new(c"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@").unwrap(),
magic: [99, 130, 83, 99],
options: vec![
MessageOptions::MessageType(MessageTypes::Discover),
].into(),
};
assert_eq!(expected, test);
}
}