a simple python script that sends a dhcp discover packet and recieves the dhcp offer that contains a suggested ip address, gateway, dns servers and displays them.
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 | '''
Created on Mar 27, 2011
@author: hassane
'''
import socket
import struct
from uuid import getnode as get_mac
from random import randint
def getMacInBytes():
mac = str(hex(get_mac()))
mac = mac[2:]
while len(mac) < 12 :
mac = '0' + mac
macb = b''
for i in range(0, 12, 2) :
m = int(mac[i:i + 2], 16)
macb += struct.pack('!B', m)
return macb
class DHCPDiscover:
def __init__(self):
self.transactionID = b''
for i in range(4):
t = randint(0, 255)
self.transactionID += struct.pack('!B', t)
def buildPacket(self):
macb = getMacInBytes()
packet = b''
packet += b'\x01' #Message type: Boot Request (1)
packet += b'\x01' #Hardware type: Ethernet
packet += b'\x06' #Hardware address length: 6
packet += b'\x00' #Hops: 0
packet += self.transactionID #Transaction ID
packet += b'\x00\x00' #Seconds elapsed: 0
packet += b'\x80\x00' #Bootp flags: 0x8000 (Broadcast) + reserved flags
packet += b'\x00\x00\x00\x00' #Client IP address: 0.0.0.0
packet += b'\x00\x00\x00\x00' #Your (client) IP address: 0.0.0.0
packet += b'\x00\x00\x00\x00' #Next server IP address: 0.0.0.0
packet += b'\x00\x00\x00\x00' #Relay agent IP address: 0.0.0.0
#packet += b'\x00\x26\x9e\x04\x1e\x9b' #Client MAC address: 00:26:9e:04:1e:9b
packet += macb
packet += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' #Client hardware address padding: 00000000000000000000
packet += b'\x00' * 67 #Server host name not given
packet += b'\x00' * 125 #Boot file name not given
packet += b'\x63\x82\x53\x63' #Magic cookie: DHCP
packet += b'\x35\x01\x01' #Option: (t=53,l=1) DHCP Message Type = DHCP Discover
#packet += b'\x3d\x06\x00\x26\x9e\x04\x1e\x9b' #Option: (t=61,l=6) Client identifier
packet += b'\x3d\x06' + macb
packet += b'\x37\x03\x03\x01\x06' #Option: (t=55,l=3) Parameter Request List
packet += b'\xff' #End Option
return packet
class DHCPOffer:
def __init__(self, data, transID):
self.data = data
self.transID = transID
self.offerIP = ''
self.nextServerIP = ''
self.DHCPServerIdentifier = ''
self.leaseTime = ''
self.router = ''
self.subnetMask = ''
self.DNS = []
self.unpack()
def unpack(self):
if self.data[4:8] == self.transID :
self.offerIP = '.'.join(map(lambda x:str(x), data[16:20]))
self.nextServerIP = '.'.join(map(lambda x:str(x), data[20:24])) #c'est une option
self.DHCPServerIdentifier = '.'.join(map(lambda x:str(x), data[245:249]))
self.leaseTime = str(struct.unpack('!L', data[251:255])[0])
self.router = '.'.join(map(lambda x:str(x), data[257:261]))
self.subnetMask = '.'.join(map(lambda x:str(x), data[263:267]))
dnsNB = int(data[268]/4)
for i in range(0, 4 * dnsNB, 4):
self.DNS.append('.'.join(map(lambda x:str(x), data[269 + i :269 + i + 4])))
def printOffer(self):
key = ['DHCP Server', 'Offered IP address', 'subnet mask', 'lease time (s)' , 'default gateway']
val = [self.DHCPServerIdentifier, self.offerIP, self.subnetMask, self.leaseTime, self.router]
for i in range(4):
print('{0:20s} : {1:15s}'.format(key[i], val[i]))
print('{0:20s}'.format('DNS Servers') + ' : ', end='')
if self.DNS:
print('{0:15s}'.format(self.DNS[0]))
if len(self.DNS) > 1:
for i in range(1, len(self.DNS)):
print('{0:22s} {1:15s}'.format(' ', self.DNS[i]))
if __name__ == '__main__':
#defining the socket
dhcps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #internet, UDP
dhcps.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #broadcast
try:
dhcps.bind(('', 68)) #we want to send from port 68
except Exception as e:
print('port 68 in use...')
dhcps.close()
input('press any key to quit...')
exit()
#buiding and sending the DHCPDiscover packet
discoverPacket = DHCPDiscover()
dhcps.sendto(discoverPacket.buildPacket(), ('<broadcast>', 67))
print('DHCP Discover sent waiting for reply...\n')
#receiving DHCPOffer packet
dhcps.settimeout(3)
try:
while True:
data = dhcps.recv(1024)
offer = DHCPOffer(data, discoverPacket.transactionID)
if offer.offerIP:
offer.printOffer()
break
except socket.timeout as e:
print(e)
dhcps.close() #we close the socket
input('press any key to quit...')
exit()
|
Thanks for the code !! with Python 2.6 i had to update the code and things looked great. However, it seems that if you do not actually own an IP , you cannot send the broadcast message For example: run "ifconfig XXXXX 0.0.0.0" and then execute this script, on my system it didn't work due to a "network is unreachable". Unless i'm missing something here (new Python/kernel?) i guess that the correct implementation should use raw-sockets instead of standard UDP sockets.
Hello, you're welcome! yes you're right, a better implementation would be with raw sockets. on Windows it works most of the time since Windows assigns an automatic private IP address for the machine.