65
65
DHCP_HLENETHERNET = const (0x06 )
66
66
DHCP_HOPS = const (0x00 )
67
67
68
- MAGIC_COOKIE = const ( 0x63825363 )
68
+ MAGIC_COOKIE = b"c \x82 Sc" # Four bytes 99.130.83.99
69
69
MAX_DHCP_OPT = const (0x10 )
70
70
71
71
# Default DHCP Server port
@@ -179,7 +179,7 @@ def send_dhcp_message(
179
179
# Transaction ID (xid)
180
180
self ._initial_xid = htonl (self ._transaction_id )
181
181
self ._initial_xid = self ._initial_xid .to_bytes (4 , "big" )
182
- _BUFF [4 :7 ] = self ._initial_xid
182
+ _BUFF [4 :8 ] = self ._initial_xid
183
183
184
184
# seconds elapsed
185
185
_BUFF [8 ] = (int (time_elapsed ) & 0xFF00 ) >> 8
@@ -195,18 +195,15 @@ def send_dhcp_message(
195
195
# as they're already set to 0.0.0.0
196
196
# Except when renewing, then fill in ciaddr
197
197
if renew :
198
- _BUFF [12 :15 ] = bytes (self .local_ip )
198
+ _BUFF [12 :16 ] = bytes (self .local_ip )
199
199
200
200
# chaddr
201
201
_BUFF [28 :34 ] = self ._mac_address
202
202
203
203
# NOTE: 192 octets of 0's, BOOTP legacy
204
204
205
205
# Magic Cookie
206
- _BUFF [236 ] = (MAGIC_COOKIE >> 24 ) & 0xFF
207
- _BUFF [237 ] = (MAGIC_COOKIE >> 16 ) & 0xFF
208
- _BUFF [238 ] = (MAGIC_COOKIE >> 8 ) & 0xFF
209
- _BUFF [239 ] = MAGIC_COOKIE & 0xFF
206
+ _BUFF [236 :240 ] = MAGIC_COOKIE
210
207
211
208
# Option - DHCP Message Type
212
209
_BUFF [240 ] = 53
@@ -262,10 +259,10 @@ def send_dhcp_message(
262
259
# pylint: disable=too-many-branches, too-many-statements
263
260
def parse_dhcp_response (
264
261
self ,
265
- ) -> Union [ Tuple [int , bytes ], Tuple [ int , int ] ]:
262
+ ) -> Tuple [int , bytearray ]:
266
263
"""Parse DHCP response from DHCP server.
267
264
268
- :return Union[ Tuple[int, bytes], Tuple[int, int]] : DHCP packet type.
265
+ :return Tuple[int, bytearray] : DHCP packet type and ID .
269
266
"""
270
267
# store packet in buffer
271
268
_BUFF = self ._sock .recv ()
@@ -274,22 +271,23 @@ def parse_dhcp_response(
274
271
275
272
# -- Parse Packet, FIXED -- #
276
273
# Validate OP
277
- assert (
278
- _BUFF [ 0 ] == DHCP_BOOT_REPLY
279
- ), "Malformed Packet - \
274
+ if _BUFF [ 0 ] != DHCP_BOOT_REPLY :
275
+ raise RuntimeError (
276
+ "Malformed Packet - \
280
277
DHCP message OP is not expected BOOT Reply."
278
+ )
281
279
282
280
xid = _BUFF [4 :8 ]
283
- if bytes (xid ) < self ._initial_xid :
284
- print ("f" )
285
- return 0 , 0
281
+ if bytes (xid ) != self ._initial_xid :
282
+ raise ValueError ("DHCP response ID mismatch." )
286
283
287
284
self .local_ip = tuple (_BUFF [16 :20 ])
288
- if _BUFF [28 :34 ] == 0 :
289
- return 0 , 0
285
+ # Check that there is a server ID.
286
+ if _BUFF [28 :34 ] == b"\x00 \x00 \x00 \x00 \x00 \x00 " :
287
+ raise ValueError ("No DHCP server ID in the response." )
290
288
291
- if int . from_bytes ( _BUFF [235 :240 ], "big" ) != MAGIC_COOKIE :
292
- return 0 , 0
289
+ if _BUFF [236 :240 ] != MAGIC_COOKIE :
290
+ raise ValueError ( "No DHCP Magic Cookie in the response." )
293
291
294
292
# -- Parse Packet, VARIABLE -- #
295
293
ptr = 240
@@ -322,8 +320,8 @@ def parse_dhcp_response(
322
320
ptr += 1
323
321
opt_len = _BUFF [ptr ]
324
322
ptr += 1
325
- self .gateway_ip = tuple (_BUFF [ptr : ptr + opt_len ])
326
- ptr += opt_len
323
+ self .gateway_ip = tuple (_BUFF [ptr : ptr + 4 ])
324
+ ptr += opt_len # still increment even though we only read 1 addr.
327
325
elif _BUFF [ptr ] == DNS_SERVERS :
328
326
ptr += 1
329
327
opt_len = _BUFF [ptr ]
@@ -426,65 +424,79 @@ def _dhcp_state_machine(self) -> None:
426
424
if self ._sock .available ():
427
425
if self ._debug :
428
426
print ("* DHCP: Parsing OFFER" )
429
- msg_type , xid = self .parse_dhcp_response ()
430
- if msg_type == DHCP_OFFER :
431
- # Check if transaction ID matches, otherwise it may be an offer
432
- # for another device
433
- if htonl (self ._transaction_id ) == int .from_bytes (xid , "big" ):
434
- if self ._debug :
435
- print (
436
- "* DHCP: Send request to {}" .format (self .dhcp_server_ip )
427
+ try :
428
+ msg_type , xid = self .parse_dhcp_response ()
429
+ except ValueError as error :
430
+ if self ._debug :
431
+ print (error )
432
+ else :
433
+ if msg_type == DHCP_OFFER :
434
+ # Check if transaction ID matches, otherwise it may be an offer
435
+ # for another device
436
+ if htonl (self ._transaction_id ) == int .from_bytes (xid , "big" ):
437
+ if self ._debug :
438
+ print (
439
+ "* DHCP: Send request to {}" .format (
440
+ self .dhcp_server_ip
441
+ )
442
+ )
443
+ self ._transaction_id = (
444
+ self ._transaction_id + 1
445
+ ) & 0x7FFFFFFF
446
+ self .send_dhcp_message (
447
+ DHCP_REQUEST , (time .monotonic () - self ._start_time )
437
448
)
438
- self ._transaction_id = (self ._transaction_id + 1 ) & 0x7FFFFFFF
439
- self .send_dhcp_message (
440
- DHCP_REQUEST , (time .monotonic () - self ._start_time )
441
- )
442
- self ._dhcp_state = STATE_DHCP_REQUEST
449
+ self ._dhcp_state = STATE_DHCP_REQUEST
450
+ else :
451
+ if self ._debug :
452
+ print ("* DHCP: Received OFFER with non-matching xid" )
443
453
else :
444
454
if self ._debug :
445
- print ("* DHCP: Received OFFER with non-matching xid" )
446
- else :
447
- if self ._debug :
448
- print ("* DHCP: Received DHCP Message is not OFFER" )
455
+ print ("* DHCP: Received DHCP Message is not OFFER" )
449
456
450
457
elif self ._dhcp_state == STATE_DHCP_REQUEST :
451
458
if self ._sock .available ():
452
459
if self ._debug :
453
460
print ("* DHCP: Parsing ACK" )
454
- msg_type , xid = self .parse_dhcp_response ()
455
- # Check if transaction ID matches, otherwise it may be
456
- # for another device
457
- if htonl (self ._transaction_id ) == int .from_bytes (xid , "big" ):
458
- if msg_type == DHCP_ACK :
459
- if self ._debug :
460
- print ("* DHCP: Successful lease" )
461
- self ._sock .close ()
462
- self ._sock = None
463
- self ._dhcp_state = STATE_DHCP_LEASED
464
- self ._last_lease_time = self ._start_time
465
- if self ._lease_time == 0 :
466
- self ._lease_time = DEFAULT_LEASE_TIME
467
- if self ._t1 == 0 :
468
- # T1 is 50% of _lease_time
469
- self ._t1 = self ._lease_time >> 1
470
- if self ._t2 == 0 :
471
- # T2 is 87.5% of _lease_time
472
- self ._t2 = self ._lease_time - (self ._lease_time >> 3 )
473
- self ._renew_in_sec = self ._t1
474
- self ._rebind_in_sec = self ._t2
475
- self ._eth .ifconfig = (
476
- self .local_ip ,
477
- self .subnet_mask ,
478
- self .gateway_ip ,
479
- self .dns_server_ip ,
480
- )
481
- gc .collect ()
461
+ try :
462
+ msg_type , xid = self .parse_dhcp_response ()
463
+ except ValueError as error :
464
+ if self ._debug :
465
+ print (error )
466
+ else :
467
+ # Check if transaction ID matches, otherwise it may be
468
+ # for another device
469
+ if htonl (self ._transaction_id ) == int .from_bytes (xid , "big" ):
470
+ if msg_type == DHCP_ACK :
471
+ if self ._debug :
472
+ print ("* DHCP: Successful lease" )
473
+ self ._sock .close ()
474
+ self ._sock = None
475
+ self ._dhcp_state = STATE_DHCP_LEASED
476
+ self ._last_lease_time = self ._start_time
477
+ if self ._lease_time == 0 :
478
+ self ._lease_time = DEFAULT_LEASE_TIME
479
+ if self ._t1 == 0 :
480
+ # T1 is 50% of _lease_time
481
+ self ._t1 = self ._lease_time >> 1
482
+ if self ._t2 == 0 :
483
+ # T2 is 87.5% of _lease_time
484
+ self ._t2 = self ._lease_time - (self ._lease_time >> 3 )
485
+ self ._renew_in_sec = self ._t1
486
+ self ._rebind_in_sec = self ._t2
487
+ self ._eth .ifconfig = (
488
+ self .local_ip ,
489
+ self .subnet_mask ,
490
+ self .gateway_ip ,
491
+ self .dns_server_ip ,
492
+ )
493
+ gc .collect ()
494
+ else :
495
+ if self ._debug :
496
+ print ("* DHCP: Received DHCP Message is not ACK" )
482
497
else :
483
498
if self ._debug :
484
- print ("* DHCP: Received DHCP Message is not ACK" )
485
- else :
486
- if self ._debug :
487
- print ("* DHCP: Received non-matching xid" )
499
+ print ("* DHCP: Received non-matching xid" )
488
500
489
501
elif self ._dhcp_state == STATE_DHCP_WAIT :
490
502
if time .monotonic () > (self ._start_time + DHCP_WAIT_TIME ):
0 commit comments