DNS の謎 |
||
SunOS 4.1.4 | YAMAMORI Takenori |
SunOS 4.x で、DNS を直接引くための-誰もやらない-もうひとつの方法。
(LD_PRELOAD を使って libc.so.1.9 を組み換えずに済ます方法)
よく知られている方法として、以下の3種類があります。これをまず説明します。
なお、ypserv が問い合わせを行なう DNS サーバの IP アドレスは /etc/resolv.conf に記述しますが、どうも、ypserv は起動時に一度しか /etc/resolv.conf を参照してくれないようで、途中で DNS サーバの IP アドレスを変更したりする際に不便です。 そこで、ローカルに forwarders への問い合わせ専用のダミーの DNS サーバを立て、その forwarders として本来の DNS サーバの IP アドレスを記述し、/etc/resolv.conf はファイル自体作成しない(/etc/resolv.conf が存在しないと自ホストの DNS サーバに問い合わせるようになる) のがよいと思います。
(SunOS 4.x 用の Netscape は、通常バイナリの netscape の他、netscape_dns というバイナリも同梱されており、これは libresolv.a と static-link したものと思われます)
SunOS 4.1.4 で DNS を引くためのもうひとつの方法を紹介します。
その前に、上記の libc.so.1.9 を組み換える方法についてちょっと考えてみましょう。組み換える必要があるのは、 gethostbyname() などの、libc.so.1.9 全体から見ればごく一部の関数です。なのに、一部の関数のために libc.so.1.9 のバイナリ全体に手を加えなければならないことには違和感を感じます。
さて、SunOS 4.1.4 の ld.so は、マニュアルには明記されていませんが環境変数 LD_PRELOAD を認識しています! (Linux 等では LD_PRELOAD はおなじみかも知れませんが、SunOS 4.1.4 においては LD_LIBRARY_PATH こそよく知られていても、LD_PRELOAD が使えることはほとんど知られていないのではないでしょうか)
LD_PRELOAD が使えるとわかったら話は簡単です!
共有ライブラリとして libresolv.so.1.0 を作成し、DNS
を引かせたいコマンドを実行する際に LD_PRELOAD
を指定すればいいだけです。
ここでは、bind などのソースを使わなくても、SunOS 4.1.4 付属の /usr/lib/libresolv.a を使用しても共有ライブラリが作れることを実証します。
具体的には、次のように実行します。
$ mkdir work; cd work $ ar x /usr/lib/libresolv.a $ rm strcasecmp.o # strcasecmp.o は libc と重複 $ gcc -shared -o libresolv.so.1.0 *.oなんと、これで OK です! これで実際に DNS を引かせるには、例えば、
$ LD_PRELOAD=<絶対PATH>/libresolv.so.1.0 telnetとやれば、この telnet は DNS を引いて動作します。
共有ライブラリ libresolv.so.1.0 の作成時に、通常の静的ライブラリである /usr/lib/libresolv.a をそのまま使いました。 しかし実は、この中に入っている *.o オブジェクトは、-fPIC を付けて作成されているようなのです! したがって、そのまま共有ライブラリ化して何も問題ありません。
ということは、libresolv.a を静的リンクして普通に使う場合は、逆に PIC が付いている分だけ無駄になっていると思われます。
libresolv.a は -fPIC が付いていましたが、たとえ -fPIC が付いていない普通のオブジェクトでも、 強引に共有ライブラリを作ることが出来ます。
そもそも、-fPIC すなわちポジションインディペンデントオプションは、 何のために必要なのでしょうか? それは、共有ライブラリの text ページの書換えを無くすためです。
共有ライブラリとリンクしたバイナリの実行時、ld.so は、共有ライブラリの動的シンボルの解決を行ないます。 この時、共有ライブラリがあらかじめ -fPIC 付きで作成されていれば、text ページ部分の書き換えは無くて済むのです。
SunOS 4.1.4 をはじめ、現在の UNIX の仮想メモリは、 copy-on-write の方法を用いています。つまり、mmap された共有ライブラリの text ページについては、 リロケーション時に書換えが起きればページが単に copy-on-write されるというだけの話です。
つまり、-fPIC を付けずに共有ライブラリを作ると、text ページのコピーが起きてメモリの利用効率が悪くなったりはするものの、 共有ライブラリとしてはちゃんと動作するのです。
試しに、-fPIC が付いていないはずの、通常の静的リンク用ライブラリである libc.a から共有ライブラリを作ってみましたが、ちゃんと動きました。
LD_PRELOAD も、LD_LIBRARY_PATH と同様に、セキュリティー上の理由から set-uid されたコマンドでは無効になります。 このため、set-uid されていない telnet や ftp などでは、LD_PRELOAD 方式が使えますが、ping, rlogin, rsh などでは LD_PRELOAD 方式では DNS は引けません。(ただし、 su すれば LD_PRELOAD が有効になって DNS が引けます)
SunOS/Solaris においては、ネームサービスとしてはあくまでも NIS がメインという考えからか、由来の異なる DNS はずっと異端扱いされてきました。
Solaris 2.x/7/8/9 などの SunOS 5.x系 では、/etc/nsswitch.conf で、NIS, NIS+, DNS, files などの参照順を自由に設定できるようにはなっていますが、 以前は、そのサンプルの設定ファイルとして、NIS, NIS+, files を使うもののみが用意され、DNS 用のサンプルは用意されていないという状況が続いていたこともありました。
Solaris のインストーラにおいても、Solaris 7 08/99 版あたりからは、インストール時のメニューで ネームサービスとして DNS を選択することが出来るようになりましたが、 以前のバージョンのインストーラでは、DNS は選択できませんでした。