6565DHCP_HLENETHERNET = const (0x06 )
6666DHCP_HOPS = const (0x00 )
6767
68- MAGIC_COOKIE = const ( 0x63825363 )
68+ MAGIC_COOKIE = b"c \x82 Sc" # Four bytes 99.130.83.99
6969MAX_DHCP_OPT = const (0x10 )
7070
7171# Default DHCP Server port
@@ -179,7 +179,7 @@ def send_dhcp_message(
179179 # Transaction ID (xid)
180180 self ._initial_xid = htonl (self ._transaction_id )
181181 self ._initial_xid = self ._initial_xid .to_bytes (4 , "big" )
182- _BUFF [4 :7 ] = self ._initial_xid
182+ _BUFF [4 :8 ] = self ._initial_xid
183183
184184 # seconds elapsed
185185 _BUFF [8 ] = (int (time_elapsed ) & 0xFF00 ) >> 8
@@ -195,18 +195,15 @@ def send_dhcp_message(
195195 # as they're already set to 0.0.0.0
196196 # Except when renewing, then fill in ciaddr
197197 if renew :
198- _BUFF [12 :15 ] = bytes (self .local_ip )
198+ _BUFF [12 :16 ] = bytes (self .local_ip )
199199
200200 # chaddr
201201 _BUFF [28 :34 ] = self ._mac_address
202202
203203 # NOTE: 192 octets of 0's, BOOTP legacy
204204
205205 # 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
210207
211208 # Option - DHCP Message Type
212209 _BUFF [240 ] = 53
@@ -262,10 +259,10 @@ def send_dhcp_message(
262259 # pylint: disable=too-many-branches, too-many-statements
263260 def parse_dhcp_response (
264261 self ,
265- ) -> Union [ Tuple [int , bytes ], Tuple [ int , int ] ]:
262+ ) -> Tuple [int , bytearray ]:
266263 """Parse DHCP response from DHCP server.
267264
268- :return Union[ Tuple[int, bytes], Tuple[int, int]] : DHCP packet type.
265+ :return Tuple[int, bytearray] : DHCP packet type and ID .
269266 """
270267 # store packet in buffer
271268 _BUFF = self ._sock .recv ()
@@ -281,16 +278,16 @@ def parse_dhcp_response(
281278 )
282279
283280 xid = _BUFF [4 :8 ]
284- if bytes (xid ) < self ._initial_xid :
285- print ("f" )
286- return 0 , 0
281+ if bytes (xid ) != self ._initial_xid :
282+ raise ValueError ("DHCP response ID mismatch." )
287283
288284 self .local_ip = tuple (_BUFF [16 :20 ])
289- if _BUFF [28 :34 ] == 0 :
290- 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." )
291288
292- if int . from_bytes ( _BUFF [235 :240 ], "big" ) != MAGIC_COOKIE :
293- return 0 , 0
289+ if _BUFF [236 :240 ] != MAGIC_COOKIE :
290+ raise ValueError ( "No DHCP Magic Cookie in the response." )
294291
295292 # -- Parse Packet, VARIABLE -- #
296293 ptr = 240
@@ -323,8 +320,8 @@ def parse_dhcp_response(
323320 ptr += 1
324321 opt_len = _BUFF [ptr ]
325322 ptr += 1
326- self .gateway_ip = tuple (_BUFF [ptr : ptr + opt_len ])
327- 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.
328325 elif _BUFF [ptr ] == DNS_SERVERS :
329326 ptr += 1
330327 opt_len = _BUFF [ptr ]
@@ -427,65 +424,79 @@ def _dhcp_state_machine(self) -> None:
427424 if self ._sock .available ():
428425 if self ._debug :
429426 print ("* DHCP: Parsing OFFER" )
430- msg_type , xid = self .parse_dhcp_response ()
431- if msg_type == DHCP_OFFER :
432- # Check if transaction ID matches, otherwise it may be an offer
433- # for another device
434- if htonl (self ._transaction_id ) == int .from_bytes (xid , "big" ):
435- if self ._debug :
436- print (
437- "* 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 )
438448 )
439- self ._transaction_id = (self ._transaction_id + 1 ) & 0x7FFFFFFF
440- self .send_dhcp_message (
441- DHCP_REQUEST , (time .monotonic () - self ._start_time )
442- )
443- 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" )
444453 else :
445454 if self ._debug :
446- print ("* DHCP: Received OFFER with non-matching xid" )
447- else :
448- if self ._debug :
449- print ("* DHCP: Received DHCP Message is not OFFER" )
455+ print ("* DHCP: Received DHCP Message is not OFFER" )
450456
451457 elif self ._dhcp_state == STATE_DHCP_REQUEST :
452458 if self ._sock .available ():
453459 if self ._debug :
454460 print ("* DHCP: Parsing ACK" )
455- msg_type , xid = self .parse_dhcp_response ()
456- # Check if transaction ID matches, otherwise it may be
457- # for another device
458- if htonl (self ._transaction_id ) == int .from_bytes (xid , "big" ):
459- if msg_type == DHCP_ACK :
460- if self ._debug :
461- print ("* DHCP: Successful lease" )
462- self ._sock .close ()
463- self ._sock = None
464- self ._dhcp_state = STATE_DHCP_LEASED
465- self ._last_lease_time = self ._start_time
466- if self ._lease_time == 0 :
467- self ._lease_time = DEFAULT_LEASE_TIME
468- if self ._t1 == 0 :
469- # T1 is 50% of _lease_time
470- self ._t1 = self ._lease_time >> 1
471- if self ._t2 == 0 :
472- # T2 is 87.5% of _lease_time
473- self ._t2 = self ._lease_time - (self ._lease_time >> 3 )
474- self ._renew_in_sec = self ._t1
475- self ._rebind_in_sec = self ._t2
476- self ._eth .ifconfig = (
477- self .local_ip ,
478- self .subnet_mask ,
479- self .gateway_ip ,
480- self .dns_server_ip ,
481- )
482- 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" )
483497 else :
484498 if self ._debug :
485- print ("* DHCP: Received DHCP Message is not ACK" )
486- else :
487- if self ._debug :
488- print ("* DHCP: Received non-matching xid" )
499+ print ("* DHCP: Received non-matching xid" )
489500
490501 elif self ._dhcp_state == STATE_DHCP_WAIT :
491502 if time .monotonic () > (self ._start_time + DHCP_WAIT_TIME ):
0 commit comments