pythonでDHCPサーバ作成 ~③DHCP実装と動作確認~
いよいよDHCPサーバのプロトコル部分の実装を行ってみました。
なお、GUIやUDPソケットの実装内容は以前のDNSサーバと大きく変わりませんので割愛します。(以下参照)
ソースコード
DHCPサーバコードは以下にあります。
以下はプロトコル部分の実装になります。
import dhcp_env
# グローバル変数
s_addr = ""
c_addr = ""
lease_time = ""
subnet_mask = ""
xid = ""
# 初期値設定関数
def init(values):
global s_addr
global c_addr
global lease_time
global subnet_mask
s_addr = values["s_addr"].split(".")
c_addr = values["c_addr"].split(".")
lease_time = int(values["lease_time"])
subnet_mask = values["subnet_mask"].split(".")
def chk_data(data):
global s_addr
global c_addr
chk_cookie = ""
chk_dhcp_msg_type = ""
result = "error"
res = ""
# データ長確認
if dhcp_env.POS_MGIC_COOKIE + 3 < len(data):
# Magic cookie確認
chk_cookie += str(data[dhcp_env.POS_MGIC_COOKIE:dhcp_env.POS_MGIC_COOKIE + dhcp_env.LEN_MGIC_COOKIE].hex())
if dhcp_env.MGIC_COOKIE == chk_cookie:
# メッセージタイプ確認
chk_dhcp_msg_type += str(data[dhcp_env.POS_DHCP_MASAGE_TYPE:dhcp_env.POS_DHCP_MASAGE_TYPE + dhcp_env.LEN_DHCP_MASAGE_TYPE].hex())
if dhcp_env.OP_DHCP_MASAGE_TYPE_DISCOVER == chk_dhcp_msg_type:
print("DHCP DISCOVER受信")
# DHCP OFFER応答
result = "DHCP OFFER"
res = mk_data(data)
elif dhcp_env.OP_DHCP_MASAGE_TYPE_REQUEST == chk_dhcp_msg_type:
print("DHCP REQUEST受信")
# DHCP ACK応答
result = "DHCP ACK"
res = mk_data(data)
return result, res
def mk_data(data):
global s_addr
global c_addr
global lease_time
global subnet_mask
res = dhcp_env.MTYPE_REPLY + dhcp_env.HTYPE_ETHER + dhcp_env.HLEN_MAC + dhcp_env.HOPS
# xid取得、設定
xid = str(data[dhcp_env.POS_XID:dhcp_env.POS_XID + dhcp_env.LEN_XID].hex())
res += xid
# SECS、FLAGS設定
res += dhcp_env.SECS + dhcp_env.FLAGS
# アドレス設定
res += dhcp_env.CIADDR
for i in range(len(c_addr)):
res += format(int(c_addr[i]), '02x')
for i in range(len(s_addr)):
res += format(int(s_addr[i]), '02x')
res += dhcp_env.GIADDR
# chaddr取得、設定
chaddr = str(data[dhcp_env.POS_CHADDR:dhcp_env.POS_CHADDR + dhcp_env.LEN_CHADDR].hex())
res += chaddr
# SAME,FILE設定
res += dhcp_env.SAME
res += dhcp_env.FILE
# Magic Cookie
res += dhcp_env.MGIC_COOKIE
# OP(メッセージタイプ)
recv_type = str(data[dhcp_env.POS_OP_DHCP_MASAGE_TYPE:dhcp_env.POS_OP_DHCP_MASAGE_TYPE + dhcp_env.LEN_OP_DHCP_MASAGE_TYPE].hex())
# 受信メッセージタイプがDICOVER
if dhcp_env.OP_DHCP_MASAGE_TYPE_DISCOVER == recv_type:
res += dhcp_env.OP_DHCP_MASAGE_TYPE_OFFER
# 受信メッセージタイプがREQUEST
elif dhcp_env.OP_DHCP_MASAGE_TYPE_REQUEST == recv_type:
res += dhcp_env.OP_DHCP_MASAGE_TYPE_ACK
# リース時間設定
res += dhcp_env.OP_IP_LEASE_TIME + format(lease_time, '08x')
# サブネットマスク
res += dhcp_env.OP_IP_SUBNET_MASK
for i in range(len(subnet_mask)):
res += format(int(subnet_mask[i]), '02x')
# OP最終位置
res += "FF"
# byte型へ変換
res = bytes.fromhex(res)
return res
MTYPE_REPLY = "02"
HTYPE_ETHER = "01"
HLEN_MAC = "06"
HOPS = "00"
SECS = "0000"
FLAGS = "0000"
CIADDR = "00000000"
# YIADDR
# SIADDR
GIADDR = "00000000"
# CHADDR
SAME = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
FILE = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
MGIC_COOKIE = "63825363"
POS_OP_DHCP_MASAGE_TYPE = 240
LEN_OP_DHCP_MASAGE_TYPE = 3
OP_DHCP_MASAGE_TYPE_DISCOVER = "350101"
OP_DHCP_MASAGE_TYPE_OFFER = "350102"
OP_DHCP_MASAGE_TYPE_REQUEST = "350103"
OP_DHCP_MASAGE_TYPE_ACK = "350105"
OP_IP_LEASE_TIME = "3304"
OP_IP_SUBNET_MASK = "0104"
POS_XID = 4
LEN_XID = 4
POS_MGIC_COOKIE = 236
LEN_MGIC_COOKIE = 4
POS_DHCP_MASAGE_TYPE = 240
LEN_DHCP_MASAGE_TYPE = 3
POS_CHADDR = 28
LEN_CHADDR = 8
起動時のUI
起動時のUI画面は以下の通り。
DHCPサーバのIPアドレス、クライアントへ割り当てるIPアドレス、リース期間、サブネットマスクの4項目をユーザが自由に設定できるようになっています。
なお、今回の簡易DHCPサーバでは上記設定パラメータのみ(必要最低限)のOPしか対応していません。
動作時のコマンドプロンプト
正常に動いていれば以下のように出力されます。
動作確認
実際のIPアドレス開放→再取得による動作が上記になります。
IPアドレスの再取得後、期待するIPアドレスがPCのIPv4アドレスに割り当てられていることが分かります。