現在稼働中のDHCPサーバーは、Ubuntu 18.04で構築したもの。
OS更改が必要な時期なので、DockerでISC DHCP SERVERを構築することにした。
今回、DHCPサーバーがかなりサクサクと動き出して、Alpineってスゴいなーと感じた。
ファイル構成
IPv4とIPv6の両方でDHCPが動作するように構成する。
過去の経験では、IPv4とIPv6は別のプロセスで動かす必要があり、それならAlpineで2つコンテナを動かしてしまえ!と考えた。
リポジトリはこちら。
~/dhpc ├ docker-compose.yml ├ v4 │ ├ Dockerfile │ ├ entrypoint.sh* │ └ dhcpd.conf ├ v6 │ ├ Dockerfile │ ├ entrypoint.sh* │ ├ dhcpd.conf │ └ radvd.conf └ setufw.sh*
*実行権限を付ける
ベースとなるOSはAlpineと考えてパッケージを検索してみたところ、このページが見つかって、パッケージ名が分かった。
Alpine Linux / dhcp-server-vanilla
コンテナ起動後に確認してみたところ、このページで教えてくれているバージョンで間違いなかった(2022/10/10現在)。
# dhcpd --version isc-dhcpd-4.4.3-P1
docker-compse.yml
IPv4とIPv6で少し内容の違うイメージを使って同時に起動させる。
DHCPサーバーが使用するネットワークインターフェースを指定している。
リースファイルを永続化している。
~/dhcp/docker-compose.yml
version: "3.9" services: dhcp4: build: ./v4 image: dhcp4:1.0.0 container_name: dhcp4 restart: "unless-stopped" environment: TZ: Asia/Tokyo DHCPIF: "ens33" hostname: dhcp4 network_mode: "host" volumes: - v4:/var/lib/dhcp dhcp6: build: ./v6 image: dhcp6:1.0.0 container_name: dhcp6 restart: "unless-stopped" environment: TZ: Asia/Tokyo DHCPIF: "ens33" hostname: dhcp6 network_mode: "host" volumes: - v6:/var/lib/dhcp volumes: v4: v6:
IPv4
Dockerfile
AlpineにDHCPサーバーをインストールしている。
~/dhcp/v4/Dockerfile
FROM alpine:latest RUN apk add dhcp-server-vanilla tzdata && \ touch /var/lib/dhcp/dhcpd.leases ADD entrypoint.sh / ADD dhcpd.conf /etc/dhcp/ ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh
DHCPサーバーを起動する。
~/dhcp/v4/entorypoint.sh
#!/bin/ash echo "Start container with parameter : $@" trap sig_term SIGTERM sig_term() { echo "CATCH SIGTERM" pkill -SIGTERM dhcpd wait exit 0 } # Execute paramater. exec "$@" dhcpd -4 -f $DHCPIF & wait exit 1
dhcpd.conf
DHCPサーバーの構成ファイルで、ホームラボのネットワークにあわせた設定にしている。
これを利用するネットワークにあわせて構成しておく。
~/dhcp/v4/dhcpd.conf
#------------------------------- # Global options #------------------------------- authoritative; option domain-name "hogeserver.hogeddns.jp"; option domain-name-servers 192.168.110.10; option routers 192.168.110.10; default-lease-time 86400; # 24 hours. max-lease-time 604800; # 7 days. lease-file-name "/var/lib/dhcp/dhcpd.leases"; #------------------------------- # Subnet #------------------------------- subnet 192.168.110.0 netmask 255.255.255.0 { range 192.168.110.100 192.168.110.199; }
IPv6
Dockerfile
AlpineにDHCPサーバーと、ルーター広告サーバーをインストールしている。
~/dhcp/v6/Dockerfile
FROM alpine:latest RUN apk add dhcp-server-vanilla radvd tzdata && \ touch /var/lib/dhcp/dhcpd.leases && \ mkdir /run/radvd ADD entrypoint.sh / ADD dhcpd.conf /etc/dhcp/ ADD radvd.conf /etc/ ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh
DHCPサーバーを起動する。
~/dhcp/v6/entorypoint.sh
#!/bin/ash echo "Start container with parameter : $@" trap sig_term SIGTERM sig_term() { echo "CATCH SIGTERM" pkill -SIGTERM dhcpd pkill -SIGTERM radvd wait exit 0 } # Execute paramater. exec "$@" dhcpd -6 -f $DHCPIF & radvd -n & wait
dhcpd.conf
DHCPサーバーの構成ファイルで、ホームラボのネットワークにあわせた設定にしている。
これを利用するネットワークにあわせて構成しておく。
~/dhcp/v6/dhcpd.conf
#------------------------------- # Global options #------------------------------- authoritative; option dhcp6.domain-search "hogeserver.hogeddns.jp"; option dhcp6.name-servers fdaa:aaaa:aaaa:aaaa::10; default-lease-time 86400; # 24 hours. max-lease-time 604800; # 7 days. lease-file-name "/var/lib/dhcp/dhcpd.leases"; #------------------------------- # Subnet #------------------------------- subnet6 fdaa:aaaa:aaaa:aaaa::/64 { range6 fdaa:aaaa:aaaa:aaaa::1:0100 fdaa:aaaa:aaaa:aaaa::1:0199; }
radvd.conf
ルーター広告サーバーの構成ファイルで、ホームラボのネットワークにあわせた設定にしている。
クライアントがDHCPサーバーを利用してIPアドレスを構成するように広告している。
AdvCurHopLimitは、DHCPサーバー起動時にHopLimitを設定しようとして、権限が足りずにエラーが発生するために設定したもの。
ホームラボのネットワーク構成は単純なのでこの設定。
~/dhcp/v6/dhcpd.conf
interface ens33 { AdvSendAdvert on; AdvManagedFlag on; AdvOtherConfigFlag on; AdvDefaultPreference low; prefix fdaa:aaaa:aaaa:aaaa::/64 { AdvAutonomous off; }; AdvCurHopLimit 0; };
setufw.sh
ファイアウォールの設定をするスクリプト。
IPv4について、理屈は確認していないが開放しなくても動作しているので、設定していない。
~/dhpc/setufw.sh
#!/bin/bash ufw $1 allow to any port 547 proto udp from any comment "DHCPv6"
実行権限を付けておく。
$ chmod +x ~/dhcp/setufw.sh
起動
ファイアウォールを設定。
$ cd dhcp $ sudo ./setufw
コンテナを起動。
$ sudo docker compose up -d --build
適切な構成(docker-compose.yml, v4/dhcpd.conf, v6/dhcpd.conf)になっていれば、IPアドレスを払い出しはじめる。
固定IPアドレス(IPv4)
MACアドレスが分かれば、固定IPアドレスを払い出すことができる。
Ubuntu
Ubuntuは以下で確認。
$ ip address show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:14:6e:24 brd ff:ff:ff:ff:ff:ff
…
Windows
Windowsは以下で確認。
>ipconfig /all
Windows IP 構成
ホスト名. . . . . . . . . . . . . . .: HogeWin
プライマリ DNS サフィックス . . . . .:
ノード タイプ . . . . . . . . . . . .: ハイブリッド
IP ルーティング有効 . . . . . . . . .: いいえ
WINS プロキシ有効 . . . . . . . . . .: いいえ
DNS サフィックス検索一覧. . . . . . .: hogeserver.hogeddns.jp
イーサネット アダプター イーサネット:
接続固有の DNS サフィックス . . . . .: hogeserver.hogeddns.jp
説明. . . . . . . . . . . . . . . . .: Hoge hoge Controller
物理アドレス. . . . . . . . . . . . .: nn-nn-nn-nn-nn-nn
…
※マスクしている。
DHCPサーバーの設定
MACアドレスに対応するIPアドレスを定義する。
~/dhcp/v4/dhcpd.conf
#------------------------------- # Fixed address #------------------------------- host party { hardware ethernet 00:0C:29:14:6E:24; fixed-address 192.168.110.12; } host party2 { hardware ethernet nn:nn:nn:nn:nn:nn; fixed-address 192.168.110.13; }
※Windows側はマスクしている。
設定を反映。
$ cd ~/dhcp $ sudo docker compose up -d --build
固定IPアドレス(IPv6)
DUID(DHCP Unique Identifier)が分かれば、固定IPアドレスを払い出すことができる。
Ubuntu
自動生成されるDUIDをうまく算出できなかった(後述)。
けれども、固定IPを払い出したいという用途ならば、DUIDにMACアドレスを使用するように設定変更するのが良さそうに見える。
むしろ、そのために機能を作り込んでくれているようだ。
Github / systemd / systemd / systemd-networkd: Automatically generate DUID for DUIDType=link-layer #9805
固定IPアドレスを払い出したいホストで、以下の設定を変更する。
/etc/systemd/networkd.conf
…
[DHCPv6]
#DUIDType=vendor
DUIDType=link-layer
#DUIDRawData=
反映。
$ sudo systemctl restart systemd-networkd
MACアドレスを確認する。
$ ip addr
…
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:14:6e:24 brd ff:ff:ff:ff:ff:ff
…
調べたMACアドレスの先頭に固定値 00:03:00:01 を付与して、この場合だと
00:03:00:01:00:0c:29:14:6e:24
をDUIDとする。
固定値の理屈については後述。
Ubuntu 18.04
Ubuntu 18.04で試したところ、20.04や22.04と同じ結果を得るために、追加で設定が必要。
DUIDTypeにlink-layerを設定しただけだと、DHCPにIPアドレスを聞きに行かない。
/etc/systemd/networkd.conf ※新規作成した
[DHCP] DUIDType=link-layer DUIDRawData=00:01:00:0c:29:82:bc:a8
DUIDRawDataが与えられると先頭に00:03が付与されるので、(00)を補い、イーサネットを意味する1(01)と、MACアドレス(00:0c:29:82:bc:a8)を与えると、Ubuntu 20.04や22.04と同じDUIDが生成された。新しいバージョンではこれを自動生成してくれる、ということのようだ。
Windows
Windowsは以下で確認。
>ipconfig -all
…
イーサネット アダプター イーサネット:
接続固有の DNS サフィックス . . . . .: hogeserver.hogeddns.jp
説明. . . . . . . . . . . . . . . . .: Hoge hoge Controller
…
DHCPv6 クライアント DUID. . . . . . .: nn-nn-nn-nn-nn-nn-nn-nn-nn-nn-nn-nn-nn-nn
…
※マスクしている。
DHCPサーバーの設定
DUIDに対応するIPアドレスを定義する。
~/dhcp/v6/dhcpd.conf
#------------------------------- # Fixed address #------------------------------- host party { host-identifier option dhcp6.client-id 00:03:00:01:00:0c:29:14:6e:24; fixed-address6 fdaa:aaaa:aaaa:aaaa::12; } host party2 { host-identifier option dhcp6.client-id nn-nn-nn-nn-nn-nn-nn-nn-nn-nn-nn-nn-nn-nn; fixed-address6 fdaa:aaaa:aaaa:aaaa::13; }
※Windows側はマスクしている。
設定を反映。
$ cd ~/dhcp $ sudo docker compose up -d --build
やったこと
IPv6のDUIDを調べる
IPv6の固定IPアドレスを払い出したいが、DUIDの調べ方がよく分からず、パケットを見てみることにした。
サーバー側でtsharkをインストールして、パケットキャプチャーしてみる。
$ sudo apt install tshark $ sudo tshark -f "port 547" -V
これで、クライアントとなるホストで
$ sudo netplan apply
等、DHCPサーバーに払い出しの要求を出せば、やりとりが表示される。
…
DHCPv6
Message type: Reply (7)
…
Client Identifier
Option: Client Identifier (1)
Length: 14
DUID: 00020000ab11d7b639e9cb58a506
DUID Type: assigned by vendor based on Enterprise number (2)
Enterprise ID: Tom Gundersen (systemd) (43793)
Identifier: d7b639e9cb58a506
…・
00:02:00:00:ab:11:d7:b6:39:e9:cb:58:a5:06
DUIDType=vendor(デフォルト)の場合、00:02とされていた。
enterprise numberは43793で、00:00:ab:11。
残りは、/etc/machine-idの値から作られるということで、どう作られるのか探してみたけれども見つからなかった。
じゃあ…ということで、色々なアルゴリズムで計算をしてみましたよ。
TechAcademy / PHPでSHA256を使う方法【初心者向け】
<?php $original_string = "<machine-idを入れておく>"; foreach (hash_algos() as $v) { $hased_string = hash($v, $original_string); print_r($hased_string.PHP_EOL); } ?>
実行してみたけれど、どうにも同じ値が出ない。
では…と、ソースを見てみた。
様々な環境に対応するためか、バッファーを特定の値で埋めて、そこにmachine-idを入れて、ハッシュを2回計算して…と単純な計算ではなかった。
以上のことから、DUIDを調べて運用できるのなら、この方法で調べて固定IPアドレスを払い出す。
こんな運用はできそうもない、ということなら、DUIDTypeをlink-layerに設定する、ということにした。
DUIDType=link-layer
DUIDの先頭が何故 00:03:00:01 になるのかがよく分からず確認してみたところ、そもそも要望がそうなっていた。
However dhclient allows this syntax: send dhcp6.client-id = concat(00:03:00, hardware);
後は、hardwareが何に由来するのかを確認すれば良い。
Ubuntu manuals / dhcp-eval
Hardware types include ethernet (1), token-ring (6), and fddi (8).
このことから、00:03:00:01という値は固定値として取り扱って良さそうだと分かった。
さいごに
Alpineってスゴい。とても軽いし、各パッケージも思い通りに動く。
これは人気が出るわけだ。素晴らしい。
こういうのをサクサクと使いこなせるようになっていきたいなぁ。
コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他