2016-02-03

ActiveDirectory DDNS + dhclient

開発者にとって Linux 仮想マシンは無くてはならないものだが、IP アドレスをどうするかは常に悩ましい問題。例えば次のような環境は多いはず。

  • 社内は ActiveDirectory DNS/DHCP 環境。
  • 勝手に固定 IP アドレスを使えない。
  • 仮想マシンを社内ネットワークに繋ぐ必要がある、またはその方が便利。

このような場合 DHCP を使うことになるが、暫く起動しないと IP アドレスが変わって接続する際に一手間かかって面倒くさい。個人的にはこういう場合 Samba (の nmbd)を使っている。サービスを起動しておくだけで Windows PC からホスト名(NetBIOS 名)でアクセスできるので、何かと便利。

しかし最近、ActiveDirectory のドメインに入らなくても、DHCP から DNS レコードを登録できることを知った。少なくとも ActiveDirectory の DNS/DHCP にはそういう機能があり、そして私の社内ではそれが有効になっている。

そうすると後は DHCP クライアント側の話。RHEL では、次の設定でそれができる。(詳細は man dhclient.conf)

RHEL6: /etc/dhcp/dhclient.conf:

send fqdn.fqdn "myhost.example.local.";
send fqdn.server-update off;

RHEL5 ではファイルの場所が /etc/dhclient.conf となる。RHEL4 以前は知らない。

ネット上には、同じく dhclient.conf の host-name や ifcfg-* の DHCP_HOSTNAME でできるよ、みたいな情報も見つかる。しかし BIND はそれで動くのかも知れないが、私が試した限り、社内の ActiveDirectory では動かなかった。

また、dhclient.conf はデバイス毎に設定が可能で、その場合はグローバルな dhclient.conf は無視されるので注意。この辺はソースを読んだ方が理解が早い。

RHEL5.11: /etc/sysconfig/network-scripts/ifup-eth:

    # allow users to use generic '/etc/dhclient.conf' (as documented in manpage!)
    # if per-device file doesn't exist or is empty
    if [ -s /etc/dhclient-${DEVICE}.conf ]; then
       DHCLIENTCONF="-cf /etc/dhclient-${DEVICE}.conf";
    else
       DHCLIENTCONF='';
    fi;

RHEL6.7: /etc/sysconfig/network-scripts/network-functions:

generate_config_file_name () {
        local ver=$1
        if [ -s /etc/dhcp/dhclient$ver-${DEVICE}.conf ]; then
                DHCLIENTCONF="-cf /etc/dhcp/dhclient$ver-${DEVICE}.conf";
        elif [ -s /etc/dhclient$ver-${DEVICE}.conf ]; then
                DHCLIENTCONF="-cf /etc/dhclient$ver-${DEVICE}.conf";
        else
                DHCLIENTCONF='';
        fi
}

例えば私の環境では、RHEL5.11 のインストール直後に /etc/dhclient-eth0.conf が存在したので、この場合 /etc/dhclient.conf で設定しても動かない。

で、話を戻して、結局のところ nmbd とどちらが好ましいかということだが、個人的には Windows PC からアクセスするだけなら nmbd の方を勧めたい。わざわざ DNS レコードをゴニョゴニョせずに済むなら、それに越したことはない。

と、これで話が終われば幸せだった・・・。残念ながら、以上は RHEL6 までの話。RHEL7 では話が変わる。:-(

周知の通り、RHEL7 では NetworkManager が幅を利かせていて、NetworkManager は前述のスクリプトを使わずに自力で処理を行う。(但しスクリプト自体は存在していて、NetworkManager が無効のときに使われると思われる)

まず dhclient.conf 未設定の状態で、どうなるのか確認してみる。

[rhel7]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.2 (Maipo)

[rhel7]# rpm -q NetworkManager
NetworkManager-1.0.6-27.el7.x86_64

[rhel7]# cat /etc/dhcp/dhclient.conf
cat: /etc/dhcp/dhclient.conf: No such file or directory

このときデバイスの dhclient 設定は、デバイス起動時に下記の場所に作成される。

[rhel7]# cat /var/lib/NetworkManager/dhclient-enp0s17.conf
# NetworkManager で作成されています

send host-name "rhel7"; # added by NetworkManager

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
option ms-classless-static-routes code 249 = array of unsigned integer 8;
option wpad code 252 = string;

also request rfc3442-classless-static-routes;
also request ms-classless-static-routes;
also request static-routes;
also request wpad;
also request ntp-servers;

dhclient.conf を作ってデバイスを再起動すると、上記が更新される。しかし・・・、

[rhel7]# cat /etc/dhcp/dhclient.conf
send fqdn.fqdn "rhel7.example.local.";
send fqdn.server-update off;

[rhel7]# systemctl restart network

[rhel7]# cat /var/lib/NetworkManager/dhclient-enp0s17.conf
# NetworkManager で作成されています
# /etc/dhcp/dhclient.conf からマージされています

send fqdn.server-update off;
send host-name "rhel7"; # added by NetworkManager

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
option ms-classless-static-routes code 249 = array of unsigned integer 8;
option wpad code 252 = string;

also request rfc3442-classless-static-routes;
also request ms-classless-static-routes;
also request static-routes;
also request wpad;
also request ntp-servers;

fqdn.fqdn がマージされていない!

ソースコードを確認してみる。

#define HOSTNAME4_TAG    "send host-name"
#define HOSTNAME4_FORMAT HOSTNAME4_TAG " \"%s\"; # added by NetworkManager"

#define FQDN_TAG    "send fqdn.fqdn"
#define FQDN_FORMAT FQDN_TAG " \"%s\"; # added by NetworkManager"

/* ...snip... */

char *
nm_dhcp_dhclient_create_config (const char *interface,
                                gboolean is_ip6,
                                GBytes *client_id,
                                const char *anycast_addr,
                                const char *hostname,
                                const char *orig_path,
                                const char *orig_contents,
                                GBytes **out_new_client_id)
{
	/* ...snip... */

			/* Override config file hostname and use one from the connection */
			if (hostname) {
				if (strncmp (p, HOSTNAME4_TAG, strlen (HOSTNAME4_TAG)) == 0)
					continue;
				if (strncmp (p, FQDN_TAG, strlen (FQDN_TAG)) == 0)
					continue;
			}

fqdn.fqdn をスキップしている。かといって fqdn.fqdn が完全に抹殺される訳でもなく、

static void
add_hostname4 (GString *str, const char *format, const char *hostname)
{
	char *plain_hostname, *dot;

	if (hostname) {
		plain_hostname = g_strdup (hostname);
		dot = strchr (plain_hostname, '.');
		/* get rid of the domain */
		if (dot)
			*dot = '\0';

		g_string_append_printf (str, format, plain_hostname);
		g_free (plain_hostname);
	}
}

/* ...snip... */

static void
add_hostname6 (GString *str, const char *hostname)
{
	/* dhclient only supports the fqdn.fqdn for DHCPv6 and requires a fully-
	 * qualified name for this option, so we must require one here too.
	 */
	if (hostname && strchr (hostname, '.')) {
		g_string_append_printf (str, FQDN_FORMAT "\n", hostname);
		g_string_append (str,
		                 "send fqdn.encoded on;\n"
		                 "send fqdn.server-update on;\n");
		g_string_append_c (str, '\n');
	}
}

何故か IPv6 では fqdn.fqdn を設定している。IPv6 の動作は未確認だが、このコードだと IPv4 で fqdn.fqdn を送る術がないように見える。

もう NetworkManager ってほんと ks だわ、と思っていたら、

どうやら NetworkManager の設定項目に ipv4.dhcp-fqdn が増える模様。果たしてこれは RHEL7.3 に入ってくれるのだろうか。

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。