pythonでDHCPサーバ作成 ~③DHCP実装と動作確認~

DHCPサーバ作成,python

いよいよ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アドレスに割り当てられていることが分かります。

関連記事