# coding=utf-8
# Сервер DHCP на Python 3.5 с коннектором к БД MySQL
# Данный код создан и распространяется по лицензии GPL v3
# Изначальный автор данного кода - Грибов Павел
# http://грибовы.рф
import socket
from struct import *
from pprint import pprint
# парсим входящий пакет
def parsepacketIn(data):
try:
print("Len data:",len(data))
op="unknown"
if data[0]==1: op="DHCPDISCOVER/DHCPREQUEST";
if data[0]==2: op="DHCPOFFER/DHCPACK";
if data[1]==1: htype="MAC"
else : htype="unknown"
hlen=data[2]
hops=data[3]
xidhex=hex(data[4])[2:]+hex(data[5])[2:]+hex(data[6])[2:]+hex(data[7])[2:]
xidbyte=data[4:8]
secs=data[8]*256+data[9];
flags=pack('BB',data[10],data[11])
ciaddr=socket.inet_ntoa(pack('BBBB',data[12],data[13],data[14],data[15]));
siaddr=socket.inet_ntoa(pack('BBBB',data[16],data[17],data[18],data[19]));
giaddr=socket.inet_ntoa(pack('BBBB',data[20],data[21],data[22],data[23]));
chaddr=data[28:34].hex()
magic_cookie=data[236:240]
print("Magic:",magic_cookie[0],magic_cookie[1],magic_cookie[2],magic_cookie[3])
res={"op":op,"htype":htype,"hlen":hlen,"hops":hops,"xidbyte":xidbyte,"xidhex":xidhex,"secs":secs,"flags":flags,"ciaddr":ciaddr,"siaddr":siaddr,"giaddr":giaddr,"chaddr":chaddr,"magic_cookie":magic_cookie}
if magic_cookie==b'c\x82Sc':
# парсим опции
print("--парсим опции");
options=data[240:len(data)]
print("Options:",options);
res["gpoz"]=240;
while res["gpoz"]<len(data):
print("Option:",data[res["gpoz"]]," hex",hex(data[res["gpoz"]])[2:])
res=FindOptions(data,res)
res["gpoz"]=res["gpoz"]+1
res["result"]=True
else:
res["result"]=False
except IndexError:
res["result"]=False
return res
# находим опции в пакете
def FindOptions(data,res):
#Тип запроса
if data[res["gpoz"]]==53:
res["option53"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
if data[res["gpoz"]+2]==1: res["op"]="DHCPDISCOVER"
if data[res["gpoz"]+2]==3: res["op"]="DHCPREQUEST"
if data[res["gpoz"]+2]==2: res["op"]="DHCPOFFER"
if data[res["gpoz"]+2]==4: res["op"]="DHCPOFFER"
if data[res["gpoz"]+2]==5: res["op"]="DHCPACK"
res["gpoz"]=res["gpoz"]+ln+1;
return res
#MAC address клиента
if data[res["gpoz"]]==61:
res["option61"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
htype=data[res["gpoz"]+2]
res["HType"]="unknown";
if htype==1:res["HType"]="Ethernet";
res["ClientMacAddress"]=data[res["gpoz"]+3:res["gpoz"]+2+ln].hex()
res["ClientMacAddressByte"]=data[res["gpoz"]+3:res["gpoz"]+2+ln]
res["gpoz"]=res["gpoz"]+ln+1;
return res
#DHCP Auto
if data[res["gpoz"]]==116:
res["option116"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["DHCPAUTO"]=True;
res["gpoz"]=res["gpoz"]+ln+1;
return res
#HostName - имя железки
if data[res["gpoz"]]==12:
res["option12"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["HostName"]=data[res["gpoz"]+2:res["gpoz"]+ln+2]
res["gpoz"]=res["gpoz"]+ln+1;
return res
#Vendor - производитель
if data[res["gpoz"]]==60:
res["option60"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["Vendor"]=data[res["gpoz"]+2:res["gpoz"]+ln+2]
res["gpoz"]=res["gpoz"]+ln+1;
return res
#Request List - список чего запрашивает железка
if data[res["gpoz"]]==55:
res["option55"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
preq=0;
while preq<ln:
if data[res["gpoz"]+2+preq]==1:res["ReqListSubnetMask"]=True;
if data[res["gpoz"]+2+preq]==15:res["ReqListDomainName"]=True;
if data[res["gpoz"]+2+preq]==3:res["ReqListRouter"]=True;
if data[res["gpoz"]+2+preq]==6:res["ReqListDNS"]=True;
if data[res["gpoz"]+2+preq]==31:res["ReqListPerfowmRouterDiscover"]=True;
if data[res["gpoz"]+2+preq]==33:res["ReqListStaticRoute"]=True;
if data[res["gpoz"]+2+preq]==43:res["ReqListVendorSpecInfo"]=43;
preq=preq+1
res["gpoz"]=res["gpoz"]+ln+1;
return res
# Запрошенный IP адрес
if data[res["gpoz"]]==50:
res["option50"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["RequestedIpAddress"]=socket.inet_ntoa(pack('BBBB',data[res["gpoz"]+2],data[res["gpoz"]+3],data[res["gpoz"]+4],data[res["gpoz"]+5]));
res["gpoz"]=res["gpoz"]+ln+1;
return res
# IP DHCP сервера
if data[res["gpoz"]]==54:
res["option54"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["DHCPServerIP"]=socket.inet_ntoa(pack('BBBB',data[res["gpoz"]+2],data[res["gpoz"]+3],data[res["gpoz"]+4],data[res["gpoz"]+5]));
res["gpoz"]=res["gpoz"]+ln+1;
return res
# IP Lease Time
if data[res["gpoz"]]==51:
res["option51"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["DHCPLeaseTime"]=data[res["gpoz"]+2]*256*256*256*256+data[res["gpoz"]+3]*256*256+data[res["gpoz"]+4]*256+data[res["gpoz"]+5];
res["gpoz"]=res["gpoz"]+ln+1;
return res
# Subnet Mask
if data[res["gpoz"]]==1:
res["option1"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["SubnetMask"]=socket.inet_ntoa(pack('BBBB',data[res["gpoz"]+2],data[res["gpoz"]+3],data[res["gpoz"]+4],data[res["gpoz"]+5]));
res["gpoz"]=res["gpoz"]+ln+1;
return res
# Router
if data[res["gpoz"]]==3:
res["option3"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["Router"]=socket.inet_ntoa(pack('BBBB',data[res["gpoz"]+2],data[res["gpoz"]+3],data[res["gpoz"]+4],data[res["gpoz"]+5]));
res["gpoz"]=res["gpoz"]+ln+1;
return res
# DNS
if data[res["gpoz"]]==6:
res["option6"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["DNS"]=socket.inet_ntoa(pack('BBBB',data[res["gpoz"]+2],data[res["gpoz"]+3],data[res["gpoz"]+4],data[res["gpoz"]+5]));
res["gpoz"]=res["gpoz"]+ln+1;
return res
# NTPS сервер времени
if data[res["gpoz"]]==42:
res["option42"]=data[res["gpoz"]];
ln=data[res["gpoz"]+1]
res["NTPS"]=socket.inet_ntoa(pack('BBBB',data[res["gpoz"]+2],data[res["gpoz"]+3],data[res["gpoz"]+4],data[res["gpoz"]+5]));
res["gpoz"]=res["gpoz"]+ln+1;
return res
return res
def padding0(cnt):
res=b''
pz=0
while pz<cnt:
res=res+pack("B",0)
pz=pz+1
return res
# Собираем предложение DHCPOFFER
def CreateDHCPOFFER(packet):
print("---собираемся отвечать..")
res=pack("B",2) # тип ответа
res=res+pack("B",1) # тип железа Ethernet
res=res+pack("B",6) # длина мас адреса
res=res+pack("B",0) # количество шагов
res=res+pack("BBBB",packet["xidbyte"][0],packet["xidbyte"][1],packet["xidbyte"][2],packet["xidbyte"][3]) # идентификатор посылки
res=res+pack("BB",0,0) # сколько времени прошло?
res=res+pack("BB",0,0) # флаги
res=res+pack("BBBB",0,0,0,0) # кому отсылаем (всем)
res=res+socket.inet_pton(socket.AF_INET, "192.168.0.19") # какой IP предлагает
res=res+socket.inet_pton(socket.AF_INET, "192.168.0.71") # какой IP у DHCP сервера
res=res+socket.inet_pton(socket.AF_INET, "0.0.0.0") # какой Relay
res=res+pack("BBBBBB",packet["ClientMacAddressByte"][0],packet["ClientMacAddressByte"][1],packet["ClientMacAddressByte"][2],packet["ClientMacAddressByte"][3],packet["ClientMacAddressByte"][4],packet["ClientMacAddressByte"][5]) # MAC получателя
res=res+padding0(202);
res=res+packet["magic_cookie"]; # магическое число
res=res+pack("BBB",53,1,2) # 53 опция, обозначем, что это пакет OFFER (предложение)
res=res+pack("BB",54,4) # 54 опция, кто дает адрес?
res=res+socket.inet_pton(socket.AF_INET, "192.168.0.71")
res=res+pack("BBBBBB",51,4,0,0,1,255) # 51 опция, время жизни адреса
res=res+pack("BB",1,4) # 1 опция Mask
res=res+socket.inet_pton(socket.AF_INET, "255.255.255.0")
res=res+pack("BB",3,4) # 1 опция Router
res=res+socket.inet_pton(socket.AF_INET, "192.168.0.1")
res=res+pack("BB",6,4) # 6 опция DNS
res=res+socket.inet_pton(socket.AF_INET, "8.8.8.8")
res=res+pack("B",255) # END
res=res+padding0(28);
#print ("LEN:",len(res));
return res
def CreateDHCPACK(packet):
print("---собираемся отвечать..")
res=pack("B",2) # тип ответа
res=res+pack("B",1) # тип железа Ethernet
res=res+pack("B",6) # длина мас адреса
res=res+pack("B",0) # количество шагов
res=res+pack("BBBB",packet["xidbyte"][0],packet["xidbyte"][1],packet["xidbyte"][2],packet["xidbyte"][3]) # идентификатор посылки
res=res+pack("BB",0,0) # сколько времени прошло?
res=res+pack("BB",0,0) # флаги
res=res+pack("BBBB",0,0,0,0) # кому отсылаем (всем)
res=res+socket.inet_pton(socket.AF_INET, "192.168.0.19") # какой IP предлагает
res=res+socket.inet_pton(socket.AF_INET, "192.168.0.71") # какой IP у DHCP сервера
res=res+socket.inet_pton(socket.AF_INET, "0.0.0.0") # какой Relay
res=res+pack("BBBBBB",packet["ClientMacAddressByte"][0],packet["ClientMacAddressByte"][1],packet["ClientMacAddressByte"][2],packet["ClientMacAddressByte"][3],packet["ClientMacAddressByte"][4],packet["ClientMacAddressByte"][5]) # MAC получателя
res=res+padding0(202);
res=res+packet["magic_cookie"]; # магическое число
res=res+pack("BBB",53,1,5) # 53 опция, обозначем, что это пакет ACK (подтверждение)
res=res+pack("BB",54,4) # 54 опция, кто дает адрес?
res=res+socket.inet_pton(socket.AF_INET, "192.168.0.71")
res=res+pack("BBBBBB",51,4,0,0,1,255) # 51 опция, время жизни адреса
res=res+pack("BB",1,4) # 1 опция Mask
res=res+socket.inet_pton(socket.AF_INET, "255.255.255.0")
res=res+pack("BB",3,4) # 1 опция Router
res=res+socket.inet_pton(socket.AF_INET, "192.168.0.1")
res=res+pack("BB",6,4) # 6 опция DNS
res=res+socket.inet_pton(socket.AF_INET, "8.8.8.8")
res=res+pack("B",255) # END
res=res+padding0(28);
#print ("LEN:",len(res));
return res