inetdデーモンは、長い間使われてきました。その機能を受け継ぐプログラムにはいくつかありますが、最も柔軟で簡単なものはxinetdでしょう。xinetdは、inetdを凌ぐ機能を備えており、TCPラッピング、モジュール構成、接続要求リダイレクション、着信接続要求に対する負荷制限などの機能だけを見ても、xinetdがシステム管理者にとって申し分のない選択肢であることがわかります。
この記事は、初級から中級のシステム管理者を対象にしており、ここで示す説明と例は、inetdにそれほど詳しくないユーザーでも理解できるものです。この記事では、インストールからセキュリティー・ポリシーの実施まで、xinetdの簡単な使い方について考察します。
この記事の目的上、システムは最新(2000年以降)のメインストリームUNIX(Linux、Solaris、BSD)であることが望まれます。しかし、他のオペレーティング・システムでも同様に動作するはずです。古いバージョンのPerlおよびUNIXその他のオペレーティング・システムでも動作する可能性はありますが、動作しない場合は、皆さん自身の課題として取り組んでみてください。ここで示される例は、Red Hat Linux環境のものですが、他のシステムでも動作する(ただしchkconfig以外)はずです。
UNIXシステム管理者にとって、inetdは、cp/rm/mvコマンドと同じくらい基本的なものであり、着信要求の処理に欠かせないものです。しかし、実際にはどのようなものであり、何を行うものなのでしょうか。
その答えとしてまず挙げられるのはTCP/IPです(UDPも含まれますが、ここでは取り上げないことにしましょう)。ホストとの接続を確立する際、実際にはTCP/IP接続(通常はソケット)が生成されます。これは、ホストとの間の電話通話接続のようなものです。TCP/IP接続は、発信側ホストと受信側ホストによって一意に定義されますが、識別子はその他にもあります。私たちがサーバーに接続する際、サーバーはどのような方法でwebserver、telnet、SSH、FTPなどの接続を識別するのでしょうか。ソケットは、接続に使用されるポートによって定義されます。たとえば、ポート21は着信FTP、ポート22はSSH、ポート23はTELNETというように決まっています(その他のポートについては、UNIXシステムの/etc/servicesを参照してください)。
接続が確立されたということは、相手側が受話器をとったということと同じです。そしてこれには、「オペレーターを通した通話」と「直接通話」があります。「直接通話」は「サーバーへの直接接続」に相当し、また「オペレーターを通した通話」は「inetdを使用する方法」に相当します。オペレーターは一連の着信回線(ホスト上のポート)の処理を行い、それをプログラム(サーバー)に渡します。
UDPの接続方法は他のものとは異なります。TCPなども基本的には相手側との通信ですが、信頼性は保証されません。先ほどと同様に電話にたとえると、UDPは、メッセージをコンベヤー・ベルトに載せて受信者に送るようなものです。このコンベヤー・ベルトを使うことによって、より多くのメッセージの処理が可能となりますが、メッセージがあまりに多い(ネットワーク・トラフィックが多い)場合、あるいは、メッセージを読むのに時間がかかりすぎる(サーバーのビジー状態)場合には、受信者が送られたメッセージの一部を失う可能性があります。
Inetdを使用すると、いくつかのチェックの後に特定のサーバーに対して接続がリダイレクトされます。そして、すべての着信接続要求の管理は、inetd.confという1つのファイルによって行われます。これにより、システムにおけるサービスの追加/削除/変更/検討がより簡単に行えるようになります。たとえば、TCPラッパーを持つSolarisシステムでは、ftpは次のように定義されています。
リスト1. inetd.confにおけるFTPサービスの定義
ftp stream tcp nowait root /usr/sbin/tcpd in.ftpd
|
これらはすべて、FTP接続に必要なパラメーターです。これはすなわち、TCP/IP(tcp)をストリーム指向(stream)モードで使用し、同時(nowait)に複数のFTP接続を許可し、rootとして実行し、FTPを起動(TCPラッパーを起動し、それによってFTPデーモンを起動)しているということです。
構文解析が難しいと言われれば確かにそうですが、複雑でなければならないということは決してありません。xinetdは、inetdの設計を継承しつつ、それをモジュール化しています。つまり、サービスごとに独自の構成ファイルを持たせることができます。また、xinetdには、TCPラッパーなど、簡単な構成を可能とする機能も追加されています。
xinetdは、一元構成(オペレーター)のアプローチを維持しており、すべての構成ファイルを1カ所(通常は/etc/xinetd.confと/etc/xinetd.d/*)に格納することができ、容易なシステム管理が可能です。また、モジュール構成であるため、xinetd.dディレクトリーへのコピー/削除によってサービスを複数のマシンに分散させることができます。また、その他のインクルード・ディレクトリーの指定も可能です。
なお、xinetd FAQ(この記事末尾の参考文献を参照)によると、RPCプログラムとxinetdの相性はよくないようです。しかし、RPCにinetdを使用し、その他のプログラムにxinetdを使用するようにすれば問題はありません。これは、大勢の外国人の中に1人だけ別の国の言葉を話す人がいた場合、どうしても2人の通訳が必要になってしまうのと同じことです。
では、xinetdとはどのようなものなのでしょうか。まあ、はっきり言うと単なるプログラムにすぎません。着信ネットワーク接続要求の処理に関しては特筆すべき点はなく、PerlやPython、Javaでも同じことが可能です。xinetdはCで書かれており、速度に関しては、少なくとも従来のinetdに劣るということはありません(たとえば、TCPラッパーは、着信接続要求ごとに実行する必要はなく、メモリーに対して起動時にロードされます)。
xinetdは開発途上のプログラムである(皆さんがお持ちのバージョンは古いバージョンかもしれません。ホーム・ページ(参考文献を参照)で最新版をチェックしてみてください)ため、パッチのリリースに時間がかかるinetdとは違い、xinetdのセキュリティー・ホールに対するパッチは速やかにリリースされます。もちろん、xinetdにはソース・コードが付属しているため、ソース・コードをレビューすれば脆弱性に関するチェックを自分で行うこともできます。
xinetdに対してサービスを定義するには、/etc/xinetd.confに指定された汎用パラメーターとは別に、特定の構成を指定するサービス・ファイルを作成します。したがって、/etc/xinetd.confが次のようなものである場合には、
リスト2. xinetd.confの例(標準のRed Hat 7.1)
defaults
{
instances = 60
log_type = SYSLOG authpriv
log_on_success = HOST PID
log_on_failure = HOST
cps = 25 30
}
service telnet
{
flags = REUSE
socket_type = stream wait = no
user = root
server = /usr/sbin/in.telnetd
log_on_failure += USERID
disable = yes
}
includedir /etc/xinetd.d
|
/etc/xinetd.dに置かれたすべてのサービス・ファイルはこれらのデフォルトを継承し、それぞれのパラメーターを指定します。そして、telnetサービスは、サブディレクトリーではなくトップレベルで定義されています。これはきわめて優れた点であり、また、このモジュール構成によって、複雑な構成も可能となります。
xinetdによって構成ファイルを再度読み込む場合は、USR2信号を送るだけでよく、再起動の必要はありません。
これらのパラメーターにどのような意味があるのか、リスト全体をザッと見てみましょう。manページが正しくインストールされていれば、コマンド・ラインでman xinetd.confを実行してリストを見ることもできますが、ここでは、ソケットやサービスについて完全に把握していない方でも理解できるように、各パラメーターについてわかりやすく説明します。ただし、いくつかのパラメーター(rpc_version、rpc_number)は省略しました。
- id
- 当該のサービスを表す一意の名前。サービス名は、中括弧の前ですでに指定されていますが、IDによって論理的に同一のサービスに対して複数のプロトコルを指定することができるようになります。ただし、これは一時的ユーザーに限られます。たとえば、NFSサービスは、UDPまたはTCP伝送プロトコルを介して実行することができます。xinetd内部のtimeサービスは、Red Hat Linux 7.1用のTCPバージョンとUDPバージョンがそれぞれ/etc/xinetd.d/timeと/etc/xinetd.d/time-udpにあります。
- type
- これは、専用のサービスのみに適用されることから、実際には「specialtype」と呼ぶべきものです。RPCサービスを表す「RPC」(Sunの「リモート・プロシージャー呼び出し」は、セキュリティー上のさまざまな問題の原因となるため、避けた方がよいでしょう)、timeサービスなど、xinetdに組み込まれたサービスを表す「INTERNAL」、システムのリスト(/etc/services、またはRPCサービスの場合は/etc/rpc)に含まれていない標準外サービスを表す「UNLISTED」を組み合わせて指定することができます。
- flags
- 追加フラグはすべてここで指定します。このリストは、非常に膨大かつ詳細です。興味深いフラグとしては、REUSE(telnetなどのソケット再使用)、NAMEINARGS/NOLIBWRAP(TCPラッパーを手動で呼び出す場合、またはラッパー全体を回避する場合)、NODELAY/KEEPALIVE(TCPソケットの調整)、DISABLE(トップレベルの「disable」パラメーターのオーバーライド)、SENSOR(ある種のサービス拒否(DoS)ネットワーク攻撃の検知/阻止)などがあります。
- disable
- サービスを無効にする場合以外は常に「no」に設定します。Red Hat Linuxのchkconfigプログラムは、「disable」パラメーターの切り替えが可能です。Red Hatで特定のサービスを有効化/無効化する場合は、おそらく、chkconfigを使う方が手動よりも簡単です。ただし、chkconfigを使用する場合、サービス・ファイルが/etc/xinetd.d/SERVICEに格納されている必要があります。先ほどのリスト2の例に関する限り、chkconfigは、要求されてもtelnetのオン/オフを行いません。見方によって、これはバグとも仕様とも考えることができます。
- socket_type
- 通常は「stream」に設定します。ただし、UDPサービスを使用している場合は「dgram」に設定します。その他にも「raw」と「seqpacket」がありますが、これらを使用する状況はかなりまれです。
- protocol
- これは、接続に使用されるプロトコルです。通常は"tcp"または"udp"ですが、理論上は/etc/protocolsにあるものなら何でも使用することができます。
- wait
- 「no」に設定した場合、xinetdは、当該のサービスに対して接続ごとに新しいハンドラーを起動します。「yes」に設定した場合は、ハンドラーが停止するまで、1つのハンドラーによって後続の接続要求がすべて処理されます。ほとんどの場合、「no」に設定します。
- server、server_args
- ハンドラーのプログラム名、およびハンドラーが取得するパラメーター。inetdの場合と同様、引数にはハンドラー名を入れません。
- port
- 当該サービスのポート。ポートは/etc/servicesファイルによってサービスにマップされるため、通常は不要です。
- redirect
- xinetdによって、サービスに対するすべてのトラフィックを別のホストに送信することが可能となります。これにより、ファイアウォールを持つホストは、xinetdの集中転送機能を介して、外部ネットワークに接続する必要なく、セキュリティーが確保されたトラフィックを受け入れることができます。この機能を利用すれば、わずかな労力で、2つのホスト間におけるサービスのフェイルオーバーも行えるようになります。
- banner、banner_success、banner_fail
- 接続の成功時/失敗時にファイルから印刷するカスタム・テキスト・ブロック。
- enabled
- 「disabled」パラメーターおよびDISABLEフラグをグローバル・レベルで補います。
- include、includedir
- ファイル/ディレクトリーをインクルードするようxinetdに指示します。
- user、group、umask、groups
- サービス・ハンドラーの起動の際にxinetdが扮するUNIX属性。これは主に、セキュアではないサービスのために使われます。
- nice
- 当該サービスのシステムに対する重要度を決定するUNIX優先レベル。システムに合わせた調整が可能です。詳しくは、「nice」のmanページをご覧ください。
- env
- サービス・ハンドラー用の環境変数。
- passenv
- xinetdからサービス・ハンドラーに渡す環境変数。
- instances
- 同時に起動できるハンドラーの数。これを調整することによって、サービス拒否攻撃を防止することができます。デフォルト(無制限)の設定は「UNLIMITED」です。
- max_load
- システムが過負荷の場合に、接続要求の受信を停止します。負荷の数はシステムによって異なるため、正確に分かる場合以外は、調整は避けましょう。
- rlimit_as、rlmist_cpu、rlimit_data、rlimit_rss、rlimit_stack
- rlimitパラメーターは、サービス・ハンドラーのリソース限界(メモリー、CPU、特定のメモリー域)を指定します。
- only_from、no_access
- これは、TCPラッパーを補うものであり、接続要求を行うホストをブロックする手段となります。TCPラッパー(ルールは通常、/etc/hosts.allowにあります)によって特に指定されていない限り、デフォルトではすべてのアクセスを許可します。
- access_times
- 1日のうちのサービス利用可能時間。たとえば、「6:00-23:00」と指定した場合、午前6時から午後11時1分までサービスを利用できることになります。
- log_type、log_on_success、log_on_failure
- 各種ロギング・オプション。特にUSERIDフラグには問題があります。接続中のマシンに対して、接続しているユーザーに関する問い合わせを行うため、パフォーマンスの低下につながります。できればUSERIDの使用は避けた方がよいでしょう。
- bind
- 通常はセキュリティー上の理由により、サービスを特定のインターフェースに限定します。たとえば、内部ネットワーク上でのFTPサービスは単にFTPとして扱い、外部からのFTP接続に対して侵入者警報を生成することができます。これには「id」パラメーターが有用です。
- per_source
- 1つのソースIPからの最大サービス・インスタンス数を指定します。単一ソースからのサービス拒否攻撃や過度の接続要求を行う異常なプログラムへの対処に役立ちます。
- cps
- 1秒当たりの最大許容接続要求数、およびサービスを再び有効化するまでの秒数。「30 45」は、「1秒当たりの着信接続要求数を30に制限し、その制限を超えた場合は45秒間待機する」という意味です。主にサービス拒否攻撃の防止に役立ちます。
- deny_time
- SENSORフラグが設定された人からのサービスを拒否する期間。
TCPラッパー・パッケージは、非常に役に立つツールです。一元化されたファイル(通常は/etc/hosts.allowと/etc/hosts.deny)によって、必要に応じて任意のホストからのアクセスをサービスごとに許可/拒否することができます。しかし、残念なことに、TCPラッパー・ライブラリーは、システム負荷、リソース限定、攻撃などがあまり考慮されていません。xinetdにはTCPラッパー機能が組み込まれているため(libwrapライブラリーを介して)、従来と同じ構成ファイルを使用しながら、スムーズにxinetdに移行することができます。
移行は、きわめて簡単に行うことができます。従来のhosts.denyおよびhosts.allowファイルはそのままxinetdに使うことができます。また、xinetdにはTCPラッパーの機能を向上させるさまざまな接続制御オプションがあります。たとえば、1秒当たりの接続要求数の制限や負荷が高すぎる場合の接続要求数の制限などは、サーバー管理上のきわめて有用な機能です。
まず、xinetdをコンパイルする際は、必ずlibwrapオプションを指定してください。このオプションを指定しないと、TCPラッパーが認識されません。Red Hat LinuxでRPMからxinetdを呼び出す場合は、マシンを公開する前に必ずTCPラッパー・ファイルが正常に動作することを確認してください。
xinetdにはさまざまな使い方がありますが、特にredirectパラメーターはきわめて興味深い使い方ができます。ご存じのとおり、フェイルオーバーはかなり難しい作業であり、ハードウェアによるフェイルオーバーはコストがかかります。これから説明する方法は、シンプルなソフトウェアによるもので、低コストで効果を得ることができます。ただし、リダイレクト・ステーションがシングル・ポイント障害(SPOF)となるため、その点を許容できるかどうか検討が必要です。許容できない場合には、(高コストな)ハードウェアによるフェイルオーバーを採用できるかどうか考えてみてください。
まず、複数のマシンの中から「アクティブ」マシンを選ぶ方法を決めます。では、スクリプト「set_active.pl」を使って行ってみましょう(ここではtelnetサービスを対象としていますが、代替サーバーへの切り替えが問題なくできるものであれば、他のサービスでも可能です)。このスクリプトは、新規フェイルオーバーの設定に使用するマシン名と、編集するべき適切な/etc/xinetd.d/SERVICEファイルを示すサービス名を取得します。スクリプトを自由にカスタマイズして別のファイルを編集したり、別のパラメーターを設定したりしてみてください。この作業は、「perl -p -i -e」の1行スクリプトでもできますが、このようなやり方の方が可能性がより拡がり、パラメーターのエラーのチェックも可能となります。
これは非常に簡単で、後は手動、クローン・ジョブ、別のプログラムによる起動など、このスクリプトを呼び出すプロシージャーを決めるだけです。こうなると後はアーキテクチャーの問題です。この時点で、忘れずにUSR2信号をxinetdに送るか、または必要に応じて再起動してください。Red Hat Linuxでは、「pkill -USR2 xinetd」によって信号の自動化が可能です。また、Linuxや他のほとんどのUNIXシステムでは、「/etc/rc.d/init.d/xinetd restart」のみでxinetdの再起動ができます。
この種のフェイルオーバーは、データベース接続ではデータベース側にかなりの工夫を加えないと動作しません。rsync、ssh、ftp、telnetなど、フェイルオーバー・マシン間に依存関係がないプロトコルに対して使用をお勧めします。
xinetdが提供する多くの機能を見ると、xinetdは明らかに使用する価値のあるものです。また、「バグは報告に応じてきわめて迅速に修正される」「ソース・コードを自由に入手できる」「既存のinetd構成から容易に移行できる(xinetdに付属するitoxヘルパー・プログラムを使用すれば)」といった、xinetdの他の利点も忘れてはなりません。
xinetdをぜひ使ってみてはどうでしょうか。もし使用できないとすれば、その第一の理由は下位互換性の問題、続いて特定のプラットフォームとの互換性の問題が挙げられるでしょう。xinetdソフトウェアは、SolarisサーバーやLinuxサーバーではきわめて一般的なものですが、その他のプラットフォームにおいては未解決の問題もあるかもしれません。
- この記事で使用した、複数のマシンの中から「アクティブ」マシンを選ぶPerlスクリプトset_active.plです。
- Frederic Raynal氏のxinetdに関する記事をご覧ください。
- MacSecurity.orgのxinetd tutorialをご覧ください。
- developerWorksの「洗練されたPerl」シリーズで、Teodor Zlatanov氏の他のPerl関連記事もご覧ください。
- あるプログラマーのLinux指向セットアップ
- Perlでのアプリケーション構成
- PerlによるUNIXのシステム管理の自動化
- 楽々Perlデバッグ
- JAPHのすばらしさ
- Perlでの遺伝的アルゴリズムの使用
- ワンライナー101
- Perlモジュールによる構文解析
- CおよびJavaプログラマーのためのPerl 5.6
- PerlによるExcelファイルの読み取り/書き込み
- 「Programming Perl, Third Edition」のレビュー
- Perlでデータ保管
- 全体的な眺望に関する小さな考察
- 平易な英語によるPerlプログラムの作成
- developerWorksに掲載されているその他のLinux参考文献もご覧ください。
- developerWorksに掲載されているその他のOpen source参考文献もご覧ください。