@@ -22,17 +22,20 @@ impl Ipv4Addr {
22
22
const MAC_ADDRESS : & [ u8 ] = & [ 52 , 54 , 0 , 12 , 34 , 56 ] ;
23
23
const DHCP_XID : u32 = 0x43424140 ;
24
24
25
+ #[ derive( Debug , Copy , Clone ) ]
25
26
#[ repr( u8 ) ]
26
27
enum DhcpType {
27
28
BootRequest = 1u8 . swap_bytes ( ) ,
28
29
// BootReply = 2u8.swap_bytes(),
29
30
}
30
31
32
+ #[ derive( Debug , Copy , Clone ) ]
31
33
#[ repr( u8 ) ]
32
34
enum HType {
33
35
Ethernet = 1u8 . swap_bytes ( ) ,
34
36
}
35
37
38
+ #[ derive( Debug , Clone ) ]
36
39
#[ repr( C , packed) ]
37
40
struct Header {
38
41
op : DhcpType ,
@@ -53,19 +56,62 @@ struct Header {
53
56
}
54
57
55
58
impl Header {
59
+ fn new ( htype : HType ) -> Self {
60
+ let mut client_hw_addr = [ 0 ; 16 ] ;
61
+ client_hw_addr[ 0 ..6 ] . copy_from_slice ( MAC_ADDRESS ) ;
62
+
63
+ Self {
64
+ htype,
65
+ hlen : BigEndian :: < u8 > :: from ( 6 ) ,
66
+ hops : BigEndian :: < u8 > :: from ( 0 ) ,
67
+ xid : BigEndian :: < u32 > :: from ( DHCP_XID ) ,
68
+ seconds : BigEndian :: < u16 > :: from ( 0 ) ,
69
+ client_hw_addr,
70
+ server_name : [ 0 ; 64 ] ,
71
+ file : [ 0 ; 128 ] ,
72
+ options : [ 0 ; 64 ] ,
73
+
74
+ // request info:
75
+ op : DhcpType :: BootRequest ,
76
+ flags : BigEndian :: from ( 0x8000 ) , // broadcast
77
+ client_ip : Ipv4Addr :: EMPTY ,
78
+ your_ip : Ipv4Addr :: EMPTY ,
79
+ server_ip : Ipv4Addr :: EMPTY ,
80
+ gateway_ip : Ipv4Addr :: EMPTY ,
81
+ }
82
+ }
83
+
56
84
fn options_mut ( & mut self ) -> OptionsWriter < ' _ > {
57
85
OptionsWriter :: new ( & mut self . options )
58
86
}
87
+
88
+ fn as_slice < ' a > ( & ' a self ) -> & ' a [ u8 ] {
89
+ unsafe {
90
+ core:: slice:: from_raw_parts (
91
+ ( self as * const Header ) as * const u8 ,
92
+ std:: mem:: size_of :: < Header > ( ) ,
93
+ )
94
+ }
95
+ }
59
96
}
60
97
61
98
#[ repr( u8 ) ]
62
99
enum MessageType {
100
+ /// Broadcast to locate available servers.
63
101
Discover = 1u8 . swap_bytes ( ) ,
102
+ /// Message to servers to either:
103
+ /// 1. Request the offered parameters from one server and implicitly
104
+ /// declining offers from all others.
105
+ /// 2. Confirm correctness of previously allocated address after,
106
+ /// (e.g., system reboot).
107
+ /// 3. Extend the lease on a particular network address.
108
+ Request = 3u8 . swap_bytes ( ) ,
64
109
}
65
110
66
111
#[ repr( u8 ) ]
67
112
enum DhcpOption {
68
113
HostName = 12 ,
114
+ RequestedIp = 50 ,
69
115
MessageType = 53 ,
70
116
ParameterRequestList = 55 ,
71
117
ClientIdentifier = 61 ,
@@ -146,6 +192,11 @@ impl<'a> OptionsWriter<'a> {
146
192
self . insert_padding ( 1 ) ; // null-terminator
147
193
self
148
194
}
195
+
196
+ fn set_requested_ip ( mut self , ip : Ipv4Addr ) -> Self {
197
+ self . insert ( DhcpOption :: RequestedIp , & ip. 0 ) ;
198
+ self
199
+ }
149
200
}
150
201
151
202
impl < ' a > Drop for OptionsWriter < ' a > {
@@ -158,43 +209,33 @@ pub fn main() -> Result<(), Box<dyn Error>> {
158
209
let socket = UdpSocket :: bind ( ( "0.0.0.0" , 68 ) ) ?;
159
210
socket. connect ( ( "255.255.255.255" , 67 ) ) ?;
160
211
161
- let mut client_hw_addr = [ 0 ; 16 ] ;
162
- client_hw_addr[ 0 ..6 ] . copy_from_slice ( MAC_ADDRESS ) ;
163
-
164
- let mut header = Header {
165
- htype : HType :: Ethernet ,
166
- hlen : BigEndian :: < u8 > :: from ( 6 ) ,
167
- hops : BigEndian :: < u8 > :: from ( 0 ) ,
168
- xid : BigEndian :: < u32 > :: from ( DHCP_XID ) ,
169
- seconds : BigEndian :: < u16 > :: from ( 0 ) ,
170
- client_hw_addr,
171
- server_name : [ 0 ; 64 ] ,
172
- file : [ 0 ; 128 ] ,
173
- options : [ 0 ; 64 ] ,
174
-
175
- // request info:
176
- op : DhcpType :: BootRequest ,
177
- flags : BigEndian :: from ( 0x8000 ) , // broadcast
178
- client_ip : Ipv4Addr :: EMPTY ,
179
- your_ip : Ipv4Addr :: EMPTY ,
180
- server_ip : Ipv4Addr :: EMPTY ,
181
- gateway_ip : Ipv4Addr :: EMPTY ,
182
- } ;
183
-
184
- let _ = header
212
+ let mut discover_header = Header :: new ( HType :: Ethernet ) ;
213
+ discover_header
185
214
. options_mut ( )
186
215
. set_message_type ( MessageType :: Discover )
187
216
. set_client_identifier ( )
188
217
. set_host_name ( "Aero" )
189
218
. set_parameter_request_list ( ) ;
190
219
191
- let header_bytes = unsafe {
192
- core:: slice:: from_raw_parts (
193
- ( & header as * const Header ) as * const u8 ,
194
- std:: mem:: size_of :: < Header > ( ) ,
195
- )
196
- } ;
220
+ socket. send ( discover_header. as_slice ( ) ) ?;
221
+
222
+ let mut offer_bytes = [ 0u8 ; core:: mem:: size_of :: < Header > ( ) ] ;
223
+ socket. recv ( & mut offer_bytes) ?;
224
+
225
+ // SAFETY: The array has the same size as of the DHCP header.
226
+ let offer = unsafe { & * ( offer_bytes. as_ptr ( ) as * const Header ) } ;
227
+ println ! ( "dhcpd: recieved offer {:?}" , offer. your_ip) ;
228
+
229
+ let mut request_header = Header :: new ( HType :: Ethernet ) ;
230
+ request_header
231
+ . options_mut ( )
232
+ . set_message_type ( MessageType :: Request )
233
+ . set_client_identifier ( )
234
+ . set_requested_ip ( offer. your_ip )
235
+ . set_host_name ( "Aero" )
236
+ . set_parameter_request_list ( ) ;
237
+
238
+ socket. send ( request_header. as_slice ( ) ) ?;
197
239
198
- socket. send ( & header_bytes) ?;
199
240
Ok ( ( ) )
200
241
}
0 commit comments