大橋のページ

iproute2+tcを使って1台で複数インターネット接続

1 複数のインターネット接続
2 インタフェースとルーティングテーブル
3 ifconfigとrouteコマンド
4 Linuxカーネルのコンパイル 1
5 Linuxカーネルのコンパイル 2
6 iproute2+tcのインストール
7 ipコマンドでインタフェースの登録
8 ipコマンドでルーティング設定
9 namedをインタフェースごとに起動する
10 sendmailをインタフェースごとに起動する

9 namedをインタフェースごとに起動する

複数のnamedを起動するとは

BIND(named)が1つだけならとくに問題はないのですが、筆者の場合、グローバル空間それぞれにnamedがプライマリDNSとして起動していました。それでも通常のやりとりは問題なく行なわれていて、インターネット側からのDNSの問い合わせには正常に答えていました。

しかし、1点だけ問題があって、それはインターネット側にあるセカンダリDNSとのゾーン転送の問題でした。ゾーン転送は、プライマリDNSとセカンダリDNSとの間で、プライマリDNSが持っているゾーン情報をやりとりするものですが、そのやりとりは1回のセッションで行なわれるようなものではないようで(詳細は不明)、結論から言うと、つねに同じルートを経由して行なわれているようです。

つまり、1つのプライマリDNSにとっては正常なルート(かりにルートA)で行なわれていますが、もう1つのプライマリDNSにとっては誤ったルートからセカンダリDNSにゾーン転送を行なっているということになりました。

インターネット-------          -------------インターネット
 セカンダリDNS-1  |          |    セカンダリDNS-2
          |          |
          |          |
         ルータA       ルータB
          |210.160.79.97    |210.163.168.145
          |          |
          ------ゲートウェイ----
        210.160.79.98 | 210.163.168.151
               |
               |
              LAN 192.168.1.0/255.255.255.0

この図でいうと、ゲートウェイ上で動作しているプライマリDNSサーバ(2つのゾーンのプライマリDNS)は、セカンダリDNS-1とセカンダリDNS-2とも、同じルートを経由してゾーン転送を行なおうとするため、片方にとっては正常でも、片方にとっては正常でないルートでやりとりしようとするため、どちらかのセカンダリDNSにとっては、「本来プライマリDNSではないIPアドレスのものからゾーン情報が送られてきた」ことになって、ゾーン転送が行なわれません。

この事態を回避するには、sendmailやApacheなど、ほかのサービスと同様にnamedをインタフェ−スごとに起動する以外ありません。

1台のマシン上で複数のnamedを起動することは、ファイアウォール上で、内部ネットワーク用と外部ネットワーク用で2つのnamedを起動したいときなどに行なわれます。BIND 8.xからは、「allow-query」を使ってゾーンごとに問い合わせに応えるIPアドレスを制限できるため、1つのnamedで内部用ドメインと外部用ドメインを扱うようにし、内部用ドメインを「allow-query」を使って、内部IPアドレスに限定するような方法です。そうすることで、内部ドメインの情報を外部から参照できないようにします。

ただ、この方法では、外部用ドメインと内部用ドメインを別々にしなければなりません(同じゾーンを1つのnamedが扱えない)。そのため、「hyperdyne.local」というようなインターネットのDNS体系とはまったく異なったドメイン名を内部用に割り当てたり、「sub.hyperdyne.co.jp」のように外部ドメインのサブドメインとして内部ドメインを割り当てたりしなければなりません。

内部、外部とも同じドメイン名を使いたい、また、「allow-query」を使った制限でなく、完全に独立したnamedにして、外部から内部ドメイン情報を隔離したいというときには、複数のnamadを起動します。

named.confを編集する

1台のマシン上でnamedを複数起動すると言っても、設定ファイルだけでなく、named本体やユーティリティ、ライブラリの類まで2重化し、完全に独立した空間をそれぞれにもたせる方法もあります。

Dual chrooted BIND/DNS servers
http://spot.etherboy.com/dns/chrootdns.html

しかし、ここではそこまではせず、複数の設定ファイル(named.conf)を用意して、それぞれを指定してnamedを起動するという比較的簡略な方法をとります。

まずnamed.confをcpコマンドなどでコピーして、「named.conf.domain1」と「named.conf.domain2」の2つを作り、さらに内部用に「named.conf.local」を作ります。それぞれのnamed.conf.xxxxxで、まず「listen-on」を使ってインタフェースを指定します。named.conf.domain1では、

options {
        directory "/var/named";
        pid-file "/var/run/named.domain1.pid";
        allow-transfer{
                210.xxx.xxx.xxx/32;
        };
        listen-on {
                210.160.79.98;
        };
};
controls {
        unix "/var/run/ndc.domain1"
        perm 0600
        owner 0
        group 0;
};
zone "." {
        type hint;
        file "named.ca";
};
zone "domain1.co.jp"{
        type master;
        file "domain1.zone";
};
zone "96.79.160.210.in-addr.arpa"{
        type master;
        file "96.79.160.210.in-addr.arpa";
};

とします。インタフェースは「210.160.79.98」、正引き空間として「domain1.co.jp」を、逆引き空間として「210.160.79.96/28」を管理しています。「210.xxx.xxx.xxx/32」はセカンダリDNSサーバのIPアドレスです。

同様にnamed.conf.domain2を次のようにします。インタフェースは「210.163.168.151」、正引き空間として「domain2.co.jp」を、逆引き空間として「210.163.168.144/28」を管理しています。「210.xxx.xxx.xxx/32」はセカンダリDNSサーバのIPアドレスです。

options {
        directory "/var/named";
        pid-file "/var/run/named.domain2.pid";
        allow-transfer{
                210.xxx.xxx.xxx/32;
        };
        listen-on {
                210.163.168.151;
        };
};
controls {
        unix "/var/run/ndc.domain2"
        perm 0600
        owner 0
        group 0;
};
zone "." {
        type hint;
        file "named.ca";
};
zone "domain2.co.jp"{
        type master;
        file "domain2.zone";
};
zone "144.168.163.210.in-addr.arpa"{
        type master;
        file "144.168.163.210.in-addr.arpa";
};

最後にnamed.conf.localを次のようにします。インタフェースは「192.168.1.1」、正引き空間として「domain1.co.jp」「domain2.co.jp」(どちらも内部LAN用)を、逆引き空間として「192.168.1.0/24」を管理しています。また、ループバックインタフェース「127.0.0.1」もこれで管理します。

options {
        directory "/var/named";
        pid-file "/var/run/named.local.pid";
        forwarders { 210.163.168.151; };
        allow-transfer{
                192.168.1.0/24;
                127.0.0.1/32;
        };
        listen-on {
                192.168.1.1;
                127.0.0.1;
        };
};
controls {
        unix "/var/run/ndc.local"
        perm 0600
        owner 0
        group 0;
};
zone "." {
        type hint;
        file "named.ca";
};
zone "0.0.127.in-addr.arpa" {
        type master;
        file "hyperdyne.loop";
};
zone "1.168.192.in-addr.arpa" {
        type master;
        file "1.168.192.in-addr.arpa";
};
zone "domain1.co.jp" {
        type master;
        file "domain1.local";
};
zone "domain2.co.jp" {
        type master;
        file "domain2.local";
};

内部LAN用namedでは、「forwarders { 210.163.168.151; };」として、別のnamedにフォワードしてしまいます。

設定のポイントとしては、

  • PIDファイルをそれぞれ指定する 「pid-file "/var/run/named.domain2.pid";」
  • インタフェースをそれぞれ指定する 「listen-on」行
  • listen-on行では、ループバックインタフェース「127.0.0.1」はいずれか1つのインタフェースで指定する(重複するとnamedの起動に2分くらいかかる)
  • controls行でndc(named daemon controller)ユーティリティに関する設定をする

の4つがあります。

「pid-file」は、それぞれのnamadごとのPIDファイルを設定することでバッティングしないようにします。「listen-on」では「listen-on port xxx」とポート番号を指定することもできます。

とくにndcに関しては、注意が必要で、ここでの設定を省略すると

Mar 14 12:46:21 xxxx named[973]: ctl_server: bind: Address already in use

というエラーメッセージが出ます。これは、namedがバッティングしているのではなく、ndcがバッティングしているためのもの(と思われます)で、それを回避するために「unix "/var/run/ndc.domain1"」として、それぞれのPIDファイルを指定します。「perm 0600」ではそのファイルのパーミッションを、「owner 0」と「group 0」でそのファイルのオーナーとグループを「0」(root)であると指定します。

/etc/rc.d/init.d/namedを編集する

RedHatでは、各サービスの起動・再起動・終了などをコントロ−ルするためのスクリプト(シェルスクリプト)が、「/etc/rc.d/init.d」ディレクトリにあります。namedの場合、「named」です。RedHat6.2Jでは標準で次のようになっています。

#!/bin/sh
#
# named           This shell script takes care of starting and stopping
#                 named (BIND DNS server).
#
# chkconfig: - 55 45
# description: named (BIND) is a Domain Name Server (DNS) \
# that is used to resolve host names to IP addresses.
# probe: true

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

[ -f /usr/sbin/named ] || exit 0

[ -f /etc/named.conf ] || exit 0


RETVAL=0

# See how we were called.
case "$1" in
  start)
        # Start daemons.
        echo -n "Starting named: "
        daemon named -u named
        RETVAL=$?
        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/named
        echo
        ;;
  stop)
        # Stop daemons.
        echo -n "Shutting down named: "
        killproc named
        RETVAL=$?
        [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/named
        echo
        ;;
  status)
        /usr/sbin/ndc status
        exit $?
        ;;
  restart)
        $0 stop
        $0 start
        ;;
  reload)
        /usr/sbin/ndc reload
        exit $?
        ;;
  probe)
        # named knows how to reload intelligently; we don't want linuxconf
        # to offer to restart every time
        /usr/sbin/ndc reload >/dev/null 2>&1 || echo start
        exit 0
        ;;

  *)
        echo "Usage: named {start|stop|status|restart}"
        exit 1
esac

exit $RETVAL

これを改造して、3つのnamedが起動し、終了し、再起動し、またリロード(設定ファイルの再読み込み)したり、ステータスを表示したりできるようにします。ただ、筆者はシェルスクリプトなどにそれほど詳しくありません。とりあえず動くようにしたものです。セキュリティ上問題があるかもしれません。もっとスマートな書き方があるかもしれません。

#!/bin/sh
#
# named           This shell script takes care of starting and stopping
#                 named (BIND DNS server).
#
# chkconfig: - 55 45
# description: named (BIND) is a Domain Name Server (DNS) \
# that is used to resolve host names to IP addresses.
# probe: true

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

[ -f /usr/sbin/named ] || exit 0

[ -f /etc/named.conf.domain1 ] || exit 0

[ -f /etc/named.conf.domain2 ] || exit 0

[ -f /etc/named.conf.local ] || exit 0

RETVAL=0

# See how we were called.
case "$1" in
  start)
        # Start daemons.
        echo -n "Starting Domain1 named: "
        daemon /usr/sbin/named -b /etc/named.conf.domain1 -u named
        RETVAL=$?
        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/named.domain1
        echo
        echo -n "Starting Domain2 named: "
        /usr/sbin/named -b /etc/named.conf.domain2 -u named
        RETVAL=$?
        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/named.domain2
        echo -n "Starting Local named: "
        /usr/sbin/named -b /etc/named.conf.local -u named
        RETVAL=$?
        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/named.local
        echo
        ;;
  stop)
        # Stop daemons.
        echo -n "Shutting down Domain1 named: "
        killproc named.domain1
        RETVAL=$?
        [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/named.domain1
        echo
        echo -n "Shutting down Domain2 named: "
        killproc named.domain2
        RETVAL=$?
        [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/named.domain2
        echo -n "Shutting down Local named: "
        killproc named.local
        RETVAL=$?
        [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/named.local
        echo
        ;;
  status)
        echo "Domain1 named status: "
        /usr/sbin/ndc -c /var/run/ndc.domain1 status
        echo
        echo "Domain2 named status: "
        /usr/sbin/ndc -c /var/run/ndc.domain2 status
        echo
        echo "Local named status: "
        /usr/sbin/ndc -c /var/run/ndc.local status
        echo
        exit $?
        ;;
  restart)
        $0 stop
        $0 start
        ;;
  reload)
        su -l named -c '/usr/sbin/ndc -c /var/run/ndc.domain1 reload'
        su -l named -c '/usr/sbin/ndc -c /var/run/ndc.domain2 reload'
        su -l named -c '/usr/sbin/ndc -c /var/run/ndc.local reload'
        exit $?
        ;;
  probe)
        # named knows how to reload intelligently; we don't want linuxconf
        # to offer to restart every time
        su -l named -c '/usr/sbin/ndc -c /var/run/ndc.domain1 reload'>/dev/null 
2>&1 || echo start
        su -l named -c '/usr/sbin/ndc -c /var/run/ndc.hyperdyne reload' >/dev/nu
ll 2>&1 || echo start
        su -l named -c '/usr/sbin/ndc -c /var/run/ndc.local reload' >/dev/null 2
>&1 || echo start
exit 0
        ;;

  *)
        echo "Usage: named {start|stop|status|restart}"
        exit 1
esac

exit $RETVAL

startオプションで「/usr/sbin/named -b /etc/named.conf.domain2 -u named」となっていて、「daemon」がないのは、なぜか「daemon」を付けると正常に起動しなかったためです。おわかりになるかたがいらっしゃったら、お教えください。

reloadやprobeオプションで「su -l named -c '/usr/sbin/ndc -c /var/run/ndc.domain1 reload'」となっているのは、namedユーザとして実行しないと、

Mar 18 12:23:09 xxxx named[604]: couldn't create pid file '/var/run/named.domain
1.pid'

というエラーが出てうまく動作しなかったためです。このあたりも正しい対処法がおわかりになる方がいらっしゃったらお教えいただきたいものです。

動作を確認し、稼動状況を監視する

設定が終わったら、必要なゾーンファイルを「/var/named」に配置して、起動、終了など各オプションを付けて、「/etc/rc.d/init.d/named」スクリプトを実行してみます。実行結果を「/var/log/messages」を見て確認します。正常に読み込まれたり、終了したりしているようであれば、起動し、nslookupコマンドで各インタフェースごとにゾーン情報に関して確認します。

# nslookup
> www.hyperdyne.co.jp
Server:  [192.168.1.1]
Address:  192.168.1.1

Name:    www.hyperdyne.co.jp
Address:  192.168.1.1

>

原因は不明ですが、Serverが[と]で囲われて表示されます。

namedはきわめて重要なサービスですから、設定が終了しても、少なくても1週間くらい、場合によっては1ヶ月間くらいはログを見て動作を確認しましょう。

そのほか

RedHatでは、各ログの切り替えが自動的に行なわれていて、「/etc/logrotate.d」ディレクトリに「named」という設定ファイルがあります。

/var/log/named.log {
    missingok
    postrotate
        /usr/bin/killall -HUP named
    endscript
}

ここでは、named.logの切り替えが設定されていますが、namedのログは「/var/log/messages」に記録されるため、実際には不要なものです。「#」で無効にしてしまうか、ファイルそのものを削除してしまいます。そのままにしておくと、ログ切り替え時にnamedが再起動され、標準の設定ファイル「/etc/named.conf」を読み込んで、namedが1つ再起動してしまいます。

また、セカンダリDNS(スレーブ)として、インターネット側にあるプライマリDNSのゾーン転送を受け入れるためには、「/var/named」ディレクトリのアクセス権を変更する必要があります。標準では、オーナー「root」、グループ「root」として、「755」が設定され、各ゾーンファイルもオーナー「root」、グループ「root」で「644」になっています。しかし、namedはユーザ「named」として動作しているため、

Mar 19 19:12:14 xxxxx named-xfer[10919]: can't make tmpfile (xxxxxx.zone.Ffpjx
h): Permission denied

とテンポラリファイルを作ることができず、またファイルそのものも書き込めません。そのため、ユーザnamedが「/var/named」に書き込むことができるようアクセス権を設定します。いろいろな対応法が考えられますが、筆者の場合、「/var/named」ディレクトリを「root.named」で「775」、各ゾーンファイルを「root.named」で「664」としました。

# chown root.named /var/named
# chmod 775 /var/named
# chown root.named /var/named/*
# chmod 664 /var/named/*

セカンダリDNSとのゾーン転送

以上の設定で、インターネット側にあるセカンダリDNSとの間のゾーン転送は行なえているようですが、インターネット側にプライマリDNSがあって、こちら側がセカンダリDNSの場合には、named-xferコマンドが実行されたとき、デフォルトルートを使って行なわれるため、相手の側で「allow-transfer」などの設定で許可してもらわないと正常に転送が行なわれませんでした。named-xferでは、インタフェースを指定したり、自分自身のIPアドレスを指定したりなどができないため、解決できていません。

大変参考になった資料

Dual chrooted BIND/DNS servers
「ほとんどそのまんまやんけ」という意見もある^^;
http://spot.etherboy.com/dns/chrootdns.html

Chroot-BIND-HOWTO
http://www.ibiblio.org/pub/linux/docs/HOWTO/Chroot-BIND-HOWTO

堀田倫英さんのHPの中にある「bind-8で、外向けと内向けのDNSを1台で運用する」
ただし、Slackwareではndcはスクリプトのようだが、RedHatではバイナリのプログラムのため、そのままではうまくゆかない
http://www.net-newbie.com/dns/dns-integration.html

namedのman(日本語)
http://www.linux.or.jp/JM/html/bind/man8/named.8.html

ndcのman(日本語)
http://www.linux.or.jp/JM/html/bind/man8/ndc.8.html

named-xferのman(日本語)
http://www.linux.or.jp/JM/html/bind/man8/named-xfer.8.html

著作権、商標等について (C) 2001 HyperDyne Inc.