kakkotetsu

DHCP Vendor-specific Information Option の Code, Length フィールド長 実装 (Kea, ISC DHCP)

前置き~やること

DHCP には Vendor-specific Information Option というベンダ固有のデータをやり取りするための Option があります。(IPv4 なら Option code 43, IPv6 なら Option code 17)
この中身は基本構造が RFC で定められており、その範囲内で各ベンダが好きに Code と使い道を定義して使うことが出来ます。
利用者は DHCP サーバでベンダが定義した内容を設定して使うことになります。

IPv4 の場合は RFC2132 で外枠と

   Code   Len   Vendor-specific information
   +-----+-----+-----+-----+---
   |  43 |  n  |  i1 |  i2 | ...
   +-----+-----+-----+-----+---

Encapsulated された Vendor-specific information 内の構造が定められています。

    Code   Len   Data item        Code   Len   Data item       Code
   +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
   |  T1 |  n  |  d1 |  d2 | ... |  T2 |  n  |  D1 |  D2 | ... | ... |
   +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

本記事では DHCP Vendor-specific Information Option の Encapsulated vendor-specific options field の Code, Length フィールドの長さに関する Kea と ISC DHCP の実装を調査します。
2021 現在 ISC 的には Kea の開発に注力しており、そちらを使うことを推奨しております。

参考資料

調査のきっかけ

IPv4 の Option 43 で実行スクリプトを取得する際に、ISC DHCP の場合は以下のように定義せよ」というモノがありました。

option space test_opt code width 2 length width 2 hash size 17;
option test_opt.script-url code 36 = text;

subnet 192.0.2.128 netmask 255.255.255.128 {
  option routers 192.0.2.129;
  option subnet-mask 255.255.255.128;
  range dynamic-bootp 192.0.2.220 192.0.2.254;
  vendor-option-space test_opt;
  option test_opt.script-url = "http://192.0.2.130/test_script.py";
}

ここで code width 2 length width 2 と定義しているのが曲者です。
ISC DHCP でそのように設定すると DHCP client から Parameter Request List(Option 53) で Option 43 を求めてきた時に、以下のように Option 43 を返します。

0x00.0x24.0x00.0x21....
  • 0x00.0x24code width 2 の設定通り 2byte 分で Code 36 を示しており
  • 0x00.0x21length width 2 の設定通り 2bytes 分で Length 33 を示しており
  • その後に http://192.0.2.130/test_script.py という 33bits の Data が続く

一方 Kea で以下のように設定すると

"Dhcp4": {
    "option-def": [
        {
            "name": "test_opt_script-url",
            "code": 36,
            "space": "vendor-encapsulated-options-space",
            "type": "string"
        }
    ],

    "subnet4": [

        {
            "subnet": "192.0.2.128/25",
            "pools": [ { "pool": "192.0.2.220 - 192.0.2.254" } ],
            "option-data": [
                {
                    "name": "routers",
                    "data": "192.0.2.129"
                },
                {
                    "name": "test_opt_script-url",
                    "space": "vendor-encapsulated-options-space",
                    "data": "http://192.0.2.130/test_script.py"
                },
                {
                    "name": "vendor-encapsulated-options"
                }
            ]
        }
    ]
}

DHCP client から Parameter Request List(Option 53) で Option 43 を求めてきた時に、以下のように Option 43 を返します

0x24.0x21....
  • 0x24 は 1byte 分で Code 36 を示しており
  • 0x21 は 1byte 分で Length 33 を示しており
  • その後に http://192.0.2.130/test_script.py という 33bits の Data が続く

DHCP client 側は Code と Length を 2bytes ずつで来ることに期待しているようで、解釈してくれず。

調査

RFC

参考資料にあげた RFC に目を通すと

Encapsulated された Vendor-specific information 内の Code, Length は IPv6 の場合には 2bytes ずつ固定、IPv4 の場合には 1byte ずつ固定で良さそうです。

ISC DHCP の実装

前述の「調査のきっかけ」で見たとおり、Encapsulated された Vendor-specific information 内の Codes と Length のフィールド長を設定で変えることが出来ます。
IPv4 であっても 2bytes にしたり。

参考資料にあげたドキュメントにもそう書かれています、option space 設定の文法は IPv4IPv6 も共通なのでそうなるのでしょう。

option space name [ [ code width number ] [ length width number ] [ hash size number ] ] ;

Where the numbers following code width, length width, and hash size respectively identify the number of bytes used to describe option codes, option lengths, and the size in buckets of the hash tables to hold options in this space (most DHCPv4 option spaces use 1 byte codes and lengths, which is the default, whereas most DHCPv6 option spaces use 2 byte codes and lengths).

The code and length widths are used in DHCP protocol - you must configure these numbers to match the applicable option space you are configuring. They each default to 1. Valid values for code widths are 1, 2 or 4. Valid values for length widths are 0, 1 or 2. Most DHCPv4 option spaces use 1 byte codes and lengths, which is the default, whereas most DHCPv6 option spaces use 2 byte codes and lengths. A zero-byte length produces options similar to the DHCPv6 Vendor-specific Information Option - but not their contents!

Kea の実装

ドキュメント

これを見ても Encapsulated された Vendor-specific information 内の Codes と Length のフィールド長については明記されていないようです。

ISC DHCP の設定を Kea に convert (KEA Migration Assistant (aka keama))

KEA Migration Assistant (aka keama) という ISC DHCP の設定ファイルを Kea の設定ファイルに convert するツールが ISC 公式であります。

試しにこれを使って option space test_opt code width 2 length width 2 hash size 17; 設定を含む ISC DHCP 設定ファイルを convert してみます。

$ curl -1sLf \
>   'https://dl.cloudsmith.io/public/isc/keama/setup.deb.sh' \
>   | sudo -E bash

$ apt search isc-dhcp-keama
Sorting... Done
Full Text Search... Done
isc-dhcp-keama/focal 4.4.2 amd64
  ISC DHCP Kea Migration Assistant

$ sudo apt install -y isc-dhcp-keama

$ keama -h
Unknown command: -h
Usage: keama [-4|-6] [-D] [-N] [-r {perform|fatal|pass}\n [-l hook-library-path] [-i input-file] [-o output-file]


$ keama -4 -i /etc/dhcp/dhcpd.conf -o /tmp/keama_output

生成されたファイルを見ると

$ more /tmp/keama_output
{
  # dhcpd.conf
  #
  # Sample configuration file for ISC dhcpd
  #
  # Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as
  # configuration file instead of this file.
  #
  # option definitions common to all supported networks...
  /// This configuration declares some subnets but has no interfaces-config
  /// Reference Kea #245
  "Dhcp4": {
//  "option-space": {
//    "name": "test_opt",
//    /// Only code width 1 is supported
//    "code-width": 2,
//    /// Only length width 1 is supported
//    "length-width": 2
//  },
    "option-def": [
      {
        "space": "test_opt",
        "name": "script-url",
        "code": 36,
        "type": "string"
      }
    ],
    "subnet4": [
      {
        "id": 2,
        "subnet": "192.0.2.128/25",
        "option-data": [
          {
            "space": "dhcp4",
            "name": "routers",
            "code": 3,
            "data": "192.0.2.129"
          },
          {
            "space": "dhcp4",
            "name": "subnet-mask",
            "code": 1,
            "data": "255.255.255.128"
          },
          {
            "name": "vendor-encapsulated-options",
            "code": 43
          },
          {
            "space": "test_opt",
            "name": "script-url",
            "code": 36,
            "csv-format": false,
//          "original-data": "http://192.0.2.130/test_script.py",
            "data": "687474703a2f2f3139322e302e322e3133302f746573745f7363726970742e7079"
          }
        ],
        "pools": [
          {
            "pool": "192.0.2.220 - 192.0.2.254"
          }
        ],
        "option-def": [
          {
            "name": "vendor-encapsulated-options",
            "code": 43,
            "type": "empty",
            "encapsulate": "test_opt"
          }
        ]
      }
    ]
  }
}

思いっきり Only code width 1 is supported と書かれています

 //  "option-space": {
 //    "name": "test_opt",
 //    /// Only code width 1 is supported
 //    "code-width": 2,
 //    /// Only length width 1 is supported
 //    "length-width": 2
 //  },

Kea メーリングリストより

Kea のメーリングリストで 2021/04/23 に ISC 開発者の方からの以下メールがありました。

[Kea-users] How to define "code width" / "length width" on Vendor-Specific Information option (code 43)

You can't: Kea wires these widths to the DHCP version (one octet for v4 and two for v6). You have to use the binary format or to write a hook converting the option content.

BTW if the RFC 2132 loosely specifies the option 43 there is a SHOULD about the suboption format which clearly does not allow 2x2 widths. Now I saw enough options 43 with not compliant contents I am not surprised...

Regards

Encapsulated された Vendor-specific information 内の Codes と Length のフィールド長は IPv4 なら 1byte 固定で IPv6 なら 2bytes 固定 (hook を書いて無理矢理どうにかしない限り)、という実装のようです。

おしまい

DHCP の Vendor-specific Information Option を用いる場合、ベンダは通常「Encapsulated された Vendor-specific information 内の Codes と Length のフィールド長は、IPv4 ならば 1byte を使い IPv6 なら 2bytes を使う」ことを示してそう実装するのが良いでしょう。
というか普通はそうなっていると思います。今回私が出会った実装がイマイチだったので突っ込んでおきましょう...。

それにしても ISC が Kea を推奨して何年か経ちますが、世間の設定例ではまだまだ ISC DHCP の例示が多いですね。Kea での例示に変わっていくと良いのですが。
まあ 2021 年に DHCP サーバを自前で立てて運用している層がどれだけいるんだって話もありますが...。