aboutsummaryrefslogtreecommitdiffstats
path: root/junos-bootstrap/dhcpd/server_dhcp.py
diff options
context:
space:
mode:
Diffstat (limited to 'junos-bootstrap/dhcpd/server_dhcp.py')
-rw-r--r--junos-bootstrap/dhcpd/server_dhcp.py433
1 files changed, 235 insertions, 198 deletions
diff --git a/junos-bootstrap/dhcpd/server_dhcp.py b/junos-bootstrap/dhcpd/server_dhcp.py
index 7d7bfc0..8681a18 100644
--- a/junos-bootstrap/dhcpd/server_dhcp.py
+++ b/junos-bootstrap/dhcpd/server_dhcp.py
@@ -1,141 +1,228 @@
-#!/usr/bin/env python
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
-#dhcpd.py pure python dhcp server pxe capable
-#psychomario - https://github.com/psychomario
+# server_dhcp.py by Jonas "j" Lindstad for The Gathering tech:server 2015
+# Used to configure the Juniper EX2200 edge switches with Zero Touch Protocol
+# License: GPLv2
+# Copyed/influcenced by the work of psychomario - https://github.com/psychomario
import socket,binascii,time,IN
from sys import exit
from optparse import OptionParser
+
if not hasattr(IN,"SO_BINDTODEVICE"):
IN.SO_BINDTODEVICE = 25 #http://stackoverflow.com/a/8437870/541038
+
+options_raw = {}
+
+# Length of DHCP fields in octets, and their placement in packet.
+# Ref: http://4.bp.blogspot.com/-IyYoFjAC4l8/UXuo16a3sII/AAAAAAAAAXQ/b6BojbYXoXg/s1600/DHCPTitle.JPG
+# 0 OP - 1
+# 1 HTYPE - 1
+# 2 HLEN - 1
+# 3 HOPS - 1
+# 4 XID - 4
+# 5 SECS - 2
+# 6 FLAGS - 2
+# 7 CIADDR - 4
+# 8 YIADDR - 4
+# 9 SIADDR - 4
+# 10 GIADDR - 4
+# 11 CHADDR - 6
+# 12 MAGIC COOKIE - 10
+# 13 PADDING - 192 octets of 0's
+# 14 MAGIC COOKIE - 4
+# 15 OPTIONS - variable length
+
+#############
+# FUNCTIONS #
+#############
+
def slicendice(msg,slices): #generator for each of the dhcp fields
+ # slicendice(message,dhcpfields)
for x in slices:
- if str(type(x)) == "<type 'str'>": x=eval(x) #really dirty, deals with variable length options
+ # if str(type(x)) == "<type 'str'>": x=eval(x) #really dirty, deals with variable length options
+ # print(x)
+ # print(msg)
yield msg[:x]
msg = msg[x:]
-# Convert hex IP to string with formated decimal IP
+# Splits a chunk of hex into a list of hex. (0123456789abcdef => ['01', '23', '45', '67', '89', 'ab', 'cd', 'ef'])
+def chunk_hex(hex):
+ # return [hex[i:i+2].decode('utf-8') for i in range(0, len(hex), 2)]
+ return [hex[i:i+2] for i in range(0, len(hex), 2)]
+
+# Convert hex IP to string with formated decimal IP. (0a0000ff => 10.0.0.255)
def hex_ip_to_str(hex_ip):
- hex_pieces = [hex_ip[i:i+2] for i in range(0, len(hex_ip), 2)] # split hex string into hex chunks
- bin_pieces = map(lambda x: int(x, 16), hex_pieces) # convert from hex to dec
- return '.'.join(str(y) for y in bin_pieces) # cast int to str for join
+ return '.'.join(str(y) for y in map(lambda x: int(x, 16), chunk_hex(hex_ip))) # cast int to str for join
+# formats a MAC address in the format "b827eb9a520f" to "b8:27:eb:9a:52:0f"
def format_hex_mac(hex_mac):
- hex_pieces = [hex_mac[i:i+2] for i in range(0, len(hex_mac), 2)]
- return ':'.join(str(x) for x in hex_pieces)
-
-# Splits a chunk of hex into a list of hex. e.g. 0123456789abcdef = ['01', '23', '45', '67', '89', 'ab', 'cd', 'ef']
-def chunk_hex(hex):
- return [hex[i:i+2] for i in range(0, len(hex), 2)]
+ return ':'.join(str(x) for x in chunk_hex(hex_mac))
+
+# Parses DHCP options - raw = hex options
def parse_options(raw):
print(' --> processing DHCP options')
- raw = '3501013d13ffeb9a520f000100011c1b8324b827eb9a520f5000390205dc3c306468637063642d362e362e373a4c696e75782d332e31322e33352d312d415243483a61726d76366c3a42434d323730380c07616c61726d7069910101370e01792103060c0f1c2a33363a3b775223012164697374726f2d746573743a67652d302f302f31322e303a626f6f747374726170'
- raw = '3501013c3c4a756e697065722d6578323230302d632d3132742d3267000000000000000000000000000000000000000000000000000000000000000000000000005222012064697374726f2d746573743a67652d302f302f302e303a626f6f747374726170ff'
+ # print(type(raw))
+ # raw = '3501013c3c4a756e697065722d6578323230302d632d3132742d3267000000000000000000000000000000000000000000000000000000000000000000000000005222012064697374726f2d746573743a67652d302f302f302e303a626f6f747374726170ff'
chunked = chunk_hex(raw)
+ print(chunked)
chunked_length = len(chunked)
- next = 0 # counter - next option start
+ pointer = 0 # counter - next option start
options = {} # options dataset
- while True:
- option = int(chunked[next], 16) # convert to dec
- length = int(chunked[next+1], 16) # convert to dec
-
- options[option] = raw[((next+2)*2):((next+length+2)*2)].decode("hex") # getting the options
-
- next = next + length + 2 # length of option + length field (1 chunk) + option ID (1 chunk)
- print(' --> option: %s (length: %s) (next option starting on chunk %s)' % (option, length, next))
+ global options_raw
+ options_raw = {}
+ special_options = [53, 82]
- if option is 82:
- parse_option_82(binascii.hexlify(options[option])) # TODO: "ugly as fuck want to go to bed-hax" must be fixed before 02:21 AM
-
- if int(chunked[next], 16) == 255:
- print(' --> finished processing options')
+ while True:
+ # print(chunked[pointer])
+ option = int(chunked[pointer], 16) # option ID (0 => 255)
+ code = int(chunked[pointer], 16) # option code (0 => 255)
+ length = int(chunked[pointer+1], 16) # option length
+ option_payload = raw[((pointer+2)*2):((pointer+length+2)*2)] # Contains the payload of the option - without option ID and length
+ options_raw[code] = option_payload
+ '''
+ # converts payload to ASCII and strips spaces in both ends, and removes repeating 0000s in the end of the string.
+ asciivalue = binascii.hexlify(option_payload.decode("hex").strip()).rstrip('0')
+ if len(asciivalue) % 2 == 1:
+ asciivalue = asciivalue + "0"
+ asciivalue = binascii.unhexlify(asciivalue)
+ '''
+ asciivalue = binascii.unhexlify(option_payload) # should not contain unreadable characters
+ # print('option_payload:')
+ # print(option_payload)
+ # print('asciivalue:')
+ # print(asciivalue)
+
+ if option in special_options:
+ if option is 82:
+ global option82_raw
+ option82_raw = option_payload
+ options[option] = parse_suboptions(option, option_payload)
+ elif option is 53:
+ # options[option] = 1 # Not adding DHCP DISCOVER to the options list, becouse it will not be used further on
+ if int(chunked[pointer+2], 16) is 1:
+ print(' --> option: %s: %s' % (option, 'DHCP Discover (will not be used in reply)'))
+ else:
+ print(' --> option: %s: %s' % (option, asciivalue))
+
+ else:
+ options[option] = asciivalue
+ print(' --> option: %s: "%s"' % (option, asciivalue))
+
+ pointer = pointer + length + 2 # length of option + length field (1 chunk) + option ID (1 chunk)
+ if int(chunked[pointer], 16) is 255: # end of DHCP options
+ print(' --> finished processing options')
break
return options
-def parse_option_82(raw):
- print(' --> processing hook for option 82')
- # print('RAW:', raw)
+def parse_suboptions(option, raw):
+ print(' --> processing hook for option %s' % option)
chunked = chunk_hex(raw)
chunked_length = len(chunked)
- if int(chunked[0], 16) is 1: # suboption 1
- subopt_1_length = int(chunked[2], 16)
- print(' --> suboption 1 found - value: "%s"' % raw[2:(subopt_1_length+2)].decode("hex"))
+ dataset = {}
+ if int(chunked[0], 16) is 1: # suboption 1 - loop over suboptions
+ while True:
+ subopt_length = int(chunked[2], 16)
+ value = raw[2:(subopt_length+2)].strip()
+ print(' --> suboption 1 found - value: "%s"' % value)
+ dataset[int(chunked[0], 16)] = value
+ break;
+ return dataset
def reqparse(message): #handles either DHCPDiscover or DHCPRequest
- #using info from http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol
- #the tables titled DHCPDISCOVER and DHCPOFFER
-
data=None
- # Length of DHCP fields in octets, and their placement in packet.
- # Ref: http://4.bp.blogspot.com/-IyYoFjAC4l8/UXuo16a3sII/AAAAAAAAAXQ/b6BojbYXoXg/s1600/DHCPTitle.JPG
- # OP - 1
- # HTYPE - 1
- # HLEN - 1
- # HOPS - 1
- # XID - 4
- # SECS - 2
- # FLAGS - 2
- # CIADDR - 4
- # YIADDR - 4
- # SIADDR - 4
- # GIADDR - 4
- # CHADDR - ?????
- # PADDING - 192 octets of 0's
- # MAGIC COOKIE - 4
- # OPTIONS - Magic goes here
-
-
- dhcpfields=[1,1,1,1,4,2,2,4,4,4,4,6,10,192,4,"msg.rfind('\xff')",1,None]
+ # dhcp_option_length = message.rfind(b'\xff')
+ # dhcpfields=[1,1,1,1,4,2,2,4,4,4,4,6,10,192,4,"msg.rfind('\xff')",1,None]
+ dhcpfields=[1,1,1,1,4,2,2,4,4,4,4,6,10,192,4,message.rfind(b'\xff'),1]
#send: boolean as to whether to send data back, and data: data to send, if any
#print len(message)
hexmessage=binascii.hexlify(message)
messagesplit=[binascii.hexlify(x) for x in slicendice(message,dhcpfields)]
+ print(messagesplit)
# print(messagesplit)
- dhcpopt=messagesplit[15][:6] #hope DHCP type is first. Should be.
- if dhcpopt == '350101': # option 53 - identifies DHCP packet type - discover/request/offer/ack++
- print('DHCP Discover')
- if(int(dhcpfields[10]) is not 0):
+ # dhcpopt=messagesplit[15][:6] # Checs first option, which should be DHCP type
+ if messagesplit[15][:6] == b'350101': # option 53 - identifies DHCP packet type - discover/request/offer/ack++
+ print('\n\nDHCP DISCOVER - client MAC %s' % format_hex_mac(messagesplit[11]))
+ if int(messagesplit[10]) is not 0:
print(' --> Relay: %s' % hex_ip_to_str(messagesplit[10]))
- print(' --> Client MAC: %s' % format_hex_mac(messagesplit[11]))
- # print('DHCP Options: ', messagesplit[15])
- options = parse_options('x')
+ else:
+ print(' --> Relay: none - direct request')
+ # options = parse_options('x')
+ options = parse_options(messagesplit[15])
# print(options)
- print(' --> crafting response')
- # print('parse_options: ', parse_options('x'))
- #DHCPDiscover
- #craft DHCPOffer
- #DHCPOFFER creation:
+
+ option43 = {
+ 'length': hex(30),
+ 'value': '01162f746731352d656467652f746573742e636f6e6669670304687474709'
+ }
+
+ #
+ # Crafting DHCP OFFER
+ #
+ # {82: {1: 'distro-test:ge-0/0/0.0:bootstrap'}, 60: 'Juniper-ex2200-c-12t-2g', 53: 1}
#options = \xcode \xlength \xdata
- lease=getlease(messagesplit[11])
- print 'Leased:',lease
- data='\x02\x01\x06\x00'+binascii.unhexlify(messagesplit[4])+'\x00\x04'
- data+='\x80\x00'+'\x00'*4+socket.inet_aton(lease)
- data+=socket.inet_aton(address)+'\x00'*4
- data+=binascii.unhexlify(messagesplit[11])+'\x00'*10+'\x00'*192
- data+='\x63\x82\x53\x63'+'\x35\x01\x02'+'\x01\x04'
- data+=socket.inet_aton(netmask)+'\x36\x04'+socket.inet_aton(address)
- data+='\x1c\x04'+socket.inet_aton(broadcast)+'\x03\x04'
- data+=socket.inet_aton(gateway)+'\x06\x04'+socket.inet_aton(dns)
- data+='\x33\x04'+binascii.unhexlify(hex(leasetime)[2:].rjust(8,'0'))
- data+='\x42'+binascii.unhexlify(hex(len(tftp))[2:].rjust(2,'0'))+tftp
- data+='\x43'+binascii.unhexlify(hex(len(pxefilename)+1)[2:].rjust(2,'0'))
- data+=pxefilename+'\x00\xff'
- elif dhcpopt == '350103':
- print('DHCP ACK')
- #DHCPRequest
- #craft DHCPACK
- data='\x02\x01\x06\x00'+binascii.unhexlify(messagesplit[4])+'\x00'*8
- data+=binascii.unhexlify(messagesplit[15][messagesplit[15].find('3204')+4:messagesplit[15].find('3204')+12])
- data+=socket.inet_aton(address)+'\x00'*4
- data+=binascii.unhexlify(messagesplit[11])+'\x00'*202
- data+='\x63\x82\x53\x63'+'\x35\x01\05'+'\x36\x04'+socket.inet_aton(address)
- data+='\x01\x04'+socket.inet_aton(netmask)+'\x03\x04'
- data+=socket.inet_aton(address)+'\x33\x04'
- data+=binascii.unhexlify(hex(leasetime)[2:].rjust(8,'0'))
- data+='\x42'+binascii.unhexlify(hex(len(tftp))[2:].rjust(2,'0'))
- data+=tftp+'\x43'+binascii.unhexlify(hex(len(pxefilename)+1)[2:].rjust(2,'0'))
- data+=pxefilename+'\x00\xff'
+ print(' --> crafting response')
+ lease=getlease(messagesplit[11].decode()) # Decodes MAC address
+ # print(binascii.unhexlify(messagesplit[4]))
+ # print('length: ' + str(len(binascii.unhexlify(messagesplit[4]))));
+
+ # DHCP OFFER details - Options
+ data = b'\x02' # Message type - boot reply
+ data += b'\x01' # Hardware type - ethernet
+ data += b'\x06' # Hardware address length - 6 octets for MAC
+ data += b'\x00' # Hops
+ data += binascii.unhexlify(messagesplit[4]) # XID / Transaction ID
+ data += b'\x00\x01' # seconds elapsed - 1 second
+ data += b'\x80\x00' # BOOTP flags - broadcast (unicast: 0x0000)
+ data += b'\x00'*4 # Client IP address
+ data += socket.inet_aton(lease) # New IP to client
+ data += socket.inet_aton(address) # Next server IP addres - self
+ data += binascii.unhexlify(messagesplit[10]) # Relay agent IP - DHCP forwarder
+ data += binascii.unhexlify(messagesplit[11]) # Client MAC
+ data += b'\x00'*202 # Client hardware address padding (10) + Server hostname (64) + Boot file name (128)
+ data += b'\x63\x82\x53\x63' # Magic cookie
+
+ # DHCP Options - ordered by pcapng "proof of concept" file
+ data += b'\x35\x01\x02' # Option 53 - DHCP OFFER
+ data += b'\x36\x04' + socket.inet_aton(address) # Option 54 - DHCP server identifier
+ data += b'\x33\x04' + binascii.unhexlify(b'00012340') # Option 51 - Lease time left padded with "0"
+ data += b'\x01\x04' + socket.inet_aton(netmask) # Option 1 - Subnet mask
+ data += b'\x03\x04' + binascii.unhexlify(messagesplit[10]) # Option 3 - Router (set to DHCP forwarders IP)
+ data += b'\x96\x04' + socket.inet_aton(address) # Option 150 - TFTP Server
+ # data += '\x2b' + option43['length'] + option43['value'] # Option 43 - Magic ZTP stuff
+ # data += '\x03\x04' + option82_raw # Option 82 - with suboptions
+ data += b'\xff'
+
+ elif messagesplit[15][:6] == b'350103':
+ print('\n\nDHCP REQUEST - client MAC %s' % format_hex_mac(messagesplit[11]))
+ print(' --> crafting response')
+
+ data = b'\x02' # Message type - boot reply
+ data += b'\x01' # Hardware type - ethernet
+ data += b'\x06' # Hardware address length - 6 octets for MAC
+ data += b'\x00' # Hops
+ data += binascii.unhexlify(messagesplit[4]) # XID / Transaction ID
+ data += b'\x00\x01' # seconds elapsed - 1 second
+ data += b'\x80\x00' # BOOTP flags - broadcast (unicast: 0x0000)
+ data += b'\x00'*4 # Client IP address
+ # data += binascii.unhexlify(messagesplit[15][messagesplit[15].find('3204')+4:messagesplit[15].find('3204')+12])
+ data += binascii.unhexlify(messagesplit[8]) # New IP to client
+ data += socket.inet_aton(address) # Next server IP addres - self
+ data += binascii.unhexlify(messagesplit[10]) # Relay agent IP - DHCP forwarder
+ data += binascii.unhexlify(messagesplit[11]) # Client MAC
+ data += b'\x00'*202 # Client hardware address padding (10) + Server hostname (64) + Boot file name (128)
+ data += b'\x63\x82\x53\x63' # Magic cookie
+
+ # DHCP Options - ordered by pcapng "proof of concept" file
+ data += b'\x35\x01\05' # Option 53 - DHCP ACK
+ data += b'\x36\x04' + socket.inet_aton(address) # Option 54 - DHCP server identifier
+ data += b'\x33\x04' + binascii.unhexlify(b'00012340') # Option 51 - Lease time left padded with "0"
+ data += b'\x01\x04' + socket.inet_aton(netmask) # Option 1 - Subnet mask
+ data += b'\x03\x04' + binascii.unhexlify(messagesplit[10]) # Option 3 - Router (set to DHCP forwarders IP)
+ data += b'\x96\x04' + socket.inet_aton(address) # Option 150 - TFTP Server
+ data += b'\xff'
return data
def release(): #release a lease after timelimit has expired
@@ -144,7 +231,7 @@ def release(): #release a lease after timelimit has expired
if time.time()+leasetime == leasetime:
continue
if lease[-1] > time.time()+leasetime:
- print "Released",lease[0]
+ print("Released" + lease[0])
lease[1]=False
lease[2]='000000000000'
lease[3]=0
@@ -162,111 +249,61 @@ def getlease(hwaddr): #return the lease of mac address, or create if doesn't exi
return lease[0]
if __name__ == "__main__":
- parser = OptionParser(description='%prog - a simple DHCP server', usage='%prog [options]')
- parser.add_option("-a", "--address", dest="address", action="store", help='server ip address (required).')
- parser.add_option("-i", "--interface", dest="interface", action="store", help='network interface to use (default all interfaces).')
- parser.add_option("-p", "--port", dest="port", action="store", help='server port to bind (default 67).')
- parser.add_option("-f", "--from", dest="offerfrom", action="store", help='ip pool from (default x.x.x.100).')
- parser.add_option("-t", "--to", dest="offerto", action="store", help='ip pool to (default x.x.x.150).')
- parser.add_option("-b", "--broadcast", dest="broadcast", action="store", help='broadcast ip to reply (x.x.x.254).')
- parser.add_option("-n", "--netmask", dest="netmask", action="store", help='netmask (default 255.255.255.0).')
- parser.add_option("-s", "--tftp", dest="tftp", action="store", help='tftp ip address (default ip address provided).')
- parser.add_option("-d", "--dns", dest="dns", action="store", help='dns ip address (default 8.8.8.8).')
- parser.add_option("-g", "--gateway", dest="gateway", action="store", help='gateway ip address (default ip address provided).')
- parser.add_option("-x", "--pxefilename", dest="pxefilename", action="store", help='pxe filename (default pxelinux.0).')
-
- (options, args) = parser.parse_args()
-
- if not (args or options.address):
- parser.print_help()
- exit(1)
-
- if options.interface:
- interface = options.interface
- else:
- interface = '' # Symbolic name meaning all available interfaces
-
- if options.port:
- port = options.port
- else:
- port = '67'
- port = int(port)
-
- if options.address:
- address = options.address
- elements_in_address = address.split('.')
- if len(elements_in_address) != 4:
- sys.exit(os.path.basename(__file__) + ": invalid ip address")
- else:
- exit(1)
-
- if options.offerfrom:
- offerfrom = options.offerfrom
- else:
- offerfrom = '.'.join(elements_in_address[0:3])
- offerfrom = offerfrom + '.100'
-
- if options.offerto:
- offerto = options.offerto
- else:
- offerto = '.'.join(elements_in_address[0:3])
- offerto = offerto + '.150'
-
- if options.broadcast:
- broadcast = options.broadcast
- else:
- broadcast = '.'.join(elements_in_address[0:3])
- broadcast = broadcast + '.254'
-
- if options.netmask:
- netmask = options.netmask
- else:
- netmask = '255.255.255.0'
-
- if options.tftp:
- tftp = options.tftp
- else:
- tftp = address
-
- if options.dns:
- dns = options.dns
- else:
- dns = '8.8.8.8'
-
- if options.gateway:
- gateway = options.gateway
- else:
- gateway = address
-
- if options.pxefilename:
- pxefilename = options.pxefilename
- else:
- pxefilename = 'pxelinux.0'
-
+ interface = 'eth0'
+ port = 67
+ address = '10.0.100.2'
+ offerfrom = '10.0.0.100'
+ offerto = '10.0.0.150'
+ broadcast = '10.0.0.255'
+ netmask = '255.255.255.0'
+ tftp = address
+ dns = '8.8.8.8'
+ gateway = address
+ pxefilename = 'pxelinux.0'
leasetime=86400 #int
- leases=[]
+ leases=[] # leases database
#next line creates the (blank) leases table. This probably isn't necessary.
- for ip in ['.'.join(elements_in_address[0:3])+'.'+str(x) for x in range(int(offerfrom[offerfrom.rfind('.')+1:]),int(offerto[offerto.rfind('.')+1:])+1)]:
- leases.append([ip,False,'000000000000',0])
-
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- s.setsockopt(socket.SOL_SOCKET,IN.SO_BINDTODEVICE,interface+'\0') #experimental
+ # for ip in ['.'.join(elements_in_address[0:3])+'.'+str(x) for x in range(int(offerfrom[offerfrom.rfind('.')+1:]),int(offerto[offerto.rfind('.')+1:])+1)]:
+ for octet in range(50):
+ leases.append(['10.0.0.' + str(octet), False, '000000000000', 0])
+ # leases.append([ip,False,'000000000000',0])
+
+ # TODO: Support for binding to interface / IP
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # IPv4 UDP socket
+ # python 2.7: s.setsockopt(socket.SOL_SOCKET,IN.SO_BINDTODEVICE,interface+'\0') #experimental
+ # s.setsockopt(socket.SOL_SOCKET, IN.SO_BINDTODEVICE, interface+'\0') #experimental
+ # s.bind(address)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
- s.bind(('',port))
- #s.sendto(data,(ip,port))
+ s.setsockopt(socket.SOL_SOCKET, 25, b'eth0')
+ s.bind(('', 67))
+ print('starting main loop')
while 1: #main loop
try:
message, addressf = s.recvfrom(8192)
- if not message.startswith('\x01') and not addressf[0] == '0.0.0.0':
- continue #only serve if a dhcp request
- data=reqparse(message) #handle request
- if data:
- s.sendto(data,('<broadcast>',68)) #reply
- release() #update releases table
+ print('received something!')
+ print(message)
+
+ if message.startswith(b'\x01'): # UDP payload is DHCP request (discover, request, release)
+ if addressf[0] == '0.0.0.0':
+ print('DHCP broadcast')
+ reply_to = '<broadcast>'
+ else:
+ print('DHCP unicast - DHCP forwarding')
+ reply_to = addressf[0]
+ # print(message.decode('ISO-8859-1'))
+ data=reqparse(message) # Parse the DHCP request
+ if data:
+ # print(options_raw)
+ # data = str.encode(data)
+ print(' -- > replying to %s' % reply_to)
+ print(b'replying with UDP payload: ' + data)
+ s.sendto(data, ('<broadcast>', 68)) # Sends reply
+ # s.sendto(data,(reply_to,68)) # Sends reply
+ release() #update releases table
+ else:
+ print('not DHCP')
except KeyboardInterrupt:
exit()
- # except:
- # continue