inetd
inetd(アイネットディー)は、多くのUNIXシステムで採用されたインターネットサービスを管理するスーパーサーバ型デーモンである。InternetDaemonの略。4.3BSDで初めて採用され[1]、通常/usr/sbin/inetd
にある。
後継のスーパーサーバ型デーモンとしては、xinetdがある。
経緯
[編集]inetd登場以前は、1台のサーバで複数のサービス(FTPサーバ、TELNETサーバ等)を稼働させておくには、それぞれのサービスのデーモン(ftpd、tftpd等)を起動しておき、それぞれのデーモンが、それぞれの待ち受けポートを監視する - というスタイルだった。しかし、この方法では、監視するポートの数だけデーモンが起動していることとなるため、実際にそのサービスが利用されていない時には、実質、メモリの無駄遣いということとなる。そこで、待ち受けポートを監視する専用の中継デーモンを用意し、待ち受けポートに要求がきた時には、あらかじめ決められたデーモン(ftpd、tftpd等)を起動させるという動作が用意されるようになった。
- メリット
- メモリの浪費解消
- デメリット
- inetdが中継動作することとなるので、動作レスポンスが遅れる。
- そのため、httpd等はinetdを経由させず、常時起動させておくことが多い。
機能
[編集]inetdは、FTP、POP3、telnet といったインターネットサービスが使うポート番号を(指定されて)監視する。監視対象のポートにTCPパケットあるいはUDPパケットが届くと、inetdは対応するサーバプログラムを起動し、コネクションを制御させる。この方式では、必要にならない限りサービスが起動されないため、メモリ利用効率がよい。さらに、個々のサーバデーモンはソケットが標準入出力および標準エラー出力にフックされた状態で起動されるため、ネットワークに関するコードを必要としない。トラフィックの多いHTTPやPOP3などのプロトコルでは、直接トラフィックを受け付ける専用サーバの方が望ましい(頻繁にサーバプロセスを起動する無駄を避けるため)。
設定
[編集]ポート番号とサービス名の対応付けは/etc/services
というファイルで行われ、サービス名とサーバ名の対応付けは/etc/inetd.conf
というファイルで行われる。例えば、23番のポートにTCP要求が来る場合、/etc/services
には次のように記述される。
telnet 23/tcp
/etc/inetd.conf
には、これに対応して次の行が記述される(以下の内容はAIX 5.1の動作するマシンから取得)。
telnet stream tcp6 nowait root /usr/sbin/telnetd telnetd -a
これによると、inetdは/usr/sbin/telnetd
というプログラムをtelnetd -a
という引数付きで起動する。inetdは標準入出力および標準エラー出力をソケットにフックした状態でサーバプログラムを起動する。
一般にTCPソケットは個別のサーバをコネクション毎に並行して起動することで制御される。UDPソケットは一般に単一のサーバインスタンスがそのポート番号の全パケットを扱う。
echoなどの単純なサービスはinetd自身が扱い、別にサーバを起動することはない。
inetd サービスの生成
[編集]以下のコードはC言語で書かれた単純なinetdサービスの一例である。オプションでファイル名を引数として受け取り、それをログファイル名とし、そのソケット経由で送られてきた文字列を全てそのログファイルに記録する。これは例えば、異なるマシン上の複数のプロセスからメッセージを受け付けて、分散コンピューティングにおけるロギングサービスを実現するものである。inetd
サービスをロギングメッセージ受信に使うことで、全てのマシンがメッセージを1つのマシンに送り、単一のログファイルにそれらを格納できる。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv)
{
/* メッセージのログ用バッファ */
char str[4096];
/* ログファイルへのポインタ */
FILE *fp = NULL;
/* inetdが引数を渡してきた場合は、それをファイル名として使用 */
if(argc == 2)
fp = fopen(argv[1], "at");
else
/* さもなくば、/tmpディレクトリでファイルをオープン */
fp = fopen("/tmp/errorLog.txt", "at");
/* ログファイルをオープンできない場合は異常終了 */
if(fp == NULL)
return -1;
while(!feof(stdin))
{
/* 改行まで読み込む。最大4095文字。
fgetsは文字列をNULLでターミネートする。 */
fgets(str, 4096, stdin);
/* ログファイルに文字列を書き込み、フラッシュする。 */
fprintf(fp, "%s", str);
fflush(fp);
}
/* ログファイルをクローズし、終了する。 */
fclose(fp);
return 0;
}
この場合、全メッセージを単一のファイルに記録したいので、サービスは1つのインスタンスのみで全要求に応えるようにしたい。従って、使うプロトコルとしてはUDPが適切である。まず、使っていないポート番号を選択する。ここでは9999が使われていなかったものとし、それを使うことにする。/etc/services
には次のような一行が書かれる。
errorLogger 9999/udp
そして/etc/inetd.conf
には次のように書かれる。
errorLogger dgram udp wait root /usr/local/bin/errlogd errlogd /tmp/logfile.txt
これによりinetdは /usr/local/bin/errlogd
というプログラムをerrlogd /tmp/logfile.txt
という引数で起動する(inetd.confの他のフィールドの意味については、inetd.confのmanページを参照されたい)。第1引数は常に実行ファイル名であり、第2引数はログファイルのファイル名/tmp/logfile.txt
である。inetdは必要に応じてサービスを起動し、入出力ストリームをポート番号9999にアタッチし、そのポートに送られた全文字列がログファイルに記録される。waitと指定することで、全要求を単一のサーバインスタンスで扱うことを inetdに知らせる。上で示したtelnetの場合とは異なる(telnetは要求が来るたびに新たなサーバが起動される)。
なお、この例で示したような機能は通常syslogを使って実装される。そのサーバであるsyslogdはinetdサービスではなく、inetdとは独立に起動される。
代替実装
[編集]inetdはセキュリティへの配慮が乏しいため、最近では代替実装としてxinetd、rlinetd、ucspi-tcp、systemd などがよく使われている。Linuxの対応はディストリビューションによって様々である。macOSは(Mac OS X v10.2 以降)xinetdを使っていた。Mac OS X v10.4では、inetdの機能はlaunchdに統合されている。
inetdが提供するサービスは完全に切捨て可能である。これは、マシンを単機能サーバとする場合によく使われるようになりつつある。例えば、HTTPサーバは、httpdだけを起動するよう設定し、他のポートを全くオープンしないようにできる。ファイアウォール専用マシンは全くサービスを起動しないようにできる。
セキュリティ問題
[編集]サービスディスパッチャとしてのinetdはセキュアでないというわけではないが、inetdが提供するサービスの長いリストはセキュリティ専門家でも正しく保つのが難しい。サービスに潜在的なセキュリティ問題がある可能性などを考慮する必要がある。このため不要なサービスをデフォルトではOFFにしておくのが一般化している。/etc/inetd.confのほぼ全てのサービスがコメントアウトされたディストリビューションも珍しくない。