ここまで延々とネットワークプログラムやデーモンの作り方を 説明してきましたが、実はもっと簡単にデーモンを作る方法があります。 ただし、この方法を使うためには あなたが スーパーユーザーつまり root である必要があります。
デーモンプログラムのデーモンたる部分、つまり socket, bind, listen, accept, fork, close それに signal,wait などの 部分は、どのような仕事をするデーモンも皆同じ作りになります。 なので、誰かがその部分を簡単なパッケージにしていてくれても よさそうなものです。それを提供してくれるのが internet super deamon 略称 inetd と呼ばれるデーモンです。
Inetdは普通、マシンが起動するときに root権限で動き出すデーモンです。 そして外からアクセスがあるたびに適切なプログラムを起動して 各種サービスを外に提供します。デーモンプログラムの部分はすべて このinetdがまかない、データの送受信の所だけを別なプログラムで 行うわけです。Inetdの動作を決定する設定ファイルは /etc/inetd.conf, /etc/services, /etc/hosts.allow の3つのファイルです。
設定ファイル /etc/inetd.conf を見て下さい。抜粋したものを以下に載せます。
有名な対外サービスの名前とそれを行うプログラム名が列挙されています。# /etc/inetd.conf ftp stream tcp nowait root /usr/libexec/ftpd ftpd -l telnet stream tcp nowait root /usr/libexec/telnetd telnetd tcpmux stream tcp nowait root internal finger stream tcp nowait/3/10 nobody /usr/libexec/fingerd fingerd -s
設定ファイル /etc/services を見て下さい。抜粋したものを以下に載せます。
有名な対外サービスの名前とポート番号が列挙されています。 サーバー側とクライアント側の両方がこのファイルを持っていないとなりません。# /etc/services tcpmux 1/tcp #TCP Port Service Multiplexer ftp 21/tcp #File Transfer [Control] ssh 22/tcp #Secure Shell Login telnet 23/tcp smtp 25/tcp mail #Simple Mail Transfer finger 79/tcp http 80/tcp www www-http #World Wide Web HTTP
設定ファイル /etc/hosts.allow を見て下さい。抜粋したものを以下に載せます。
有名なサービスに対して、クライアントのホストごとに アクセスを許可するか拒絶するかが指定されています。 例えば finger の項目では localhost からのアクセスは許可(allow)され、 .evil.craker.example.comのドメインからのアクセスは拒否(deny)され、 その他該当しない所からのアクセスはすべて許可されます。# /etc/hosts.allow sshd : .evil.cracker.example.com : deny sshd : ALL : allow sendmail : localhost : allow sendmail : .nice.guy.example.com : allow sendmail : .evil.cracker.example.com : deny sendmail : ALL : allow finger : localhost : allow finger : .nice.guy.example.com : allow finger : .evil.cracker.example.com : deny finger : ALL : allow ALL : ALL : deny
クライアントが telnet somehost finger とすると telnetコマンドはクライアントのマシンにある /etc/services から finger の項目を探し、見つけた 79番 ポートで、相手のマシンに接続しようとします。
サーバーの inetd は 79番ポートの接続要求を知ると、 /etc/inetd.conf と /etc/service のデータを照合して、これが finger のサービスへの接続要求であると判断します。
次に inetd は /etc/hosts.allow のデータを思い出して、 finger のサービスがこのクライアントに許可できることを確認します。
そして /etc/inetd.conf に書かれた finger の設定に従って /usr/libexec/fingerd を オプション -s 付きで実行します。 その際、クライアントに継っているネットワークソケットを fingerdの標準入出力に繋げてくれます。なので fingerd プログラムは 標準入出力を読み書きするだけでクライアントと通信できるのです。 このfingerdのプログラムは実際に接続されているときだけ 実行されるので、各プログラムがデーモンになって accept の所で 寝ているよりもメモリ資源の節約になるのです。
Inetdに自分独自のプログラムをサービスとして加えるには TCPMUXと呼ばれる inetd 自身が提供する特殊なサービスを利用します。 まず、サービスを提供するプログラムを以下のように作ります。 名前は hello.cc とでもしておきましょうか。
これをコンパイルして /usr/local/libexec/hello にでも置いておきましょう。 置き場所や名前はなんでも構いません。// program hello.cc #include int main( void ) { char msg[64]; printf("Your name, sir/madam: " ); fflush( stdout ); fgets( msg, sizeof(msg), stdin ); printf("Hello, %s.", msg ); fflush( stdout ); return 0; }
次に /etc/inetd.conf を編集して以下の2行を追加します。
helloの行にある nobody はこのプログラムを nobody 権限で実行することを意味します。tcpmux stream tcp nowait root internal tcpmux/hello stream tcp nowait nobody /usr/local/libexec/hello hello
そして /etc/hosts.allow の冒頭に以下の1行を追加します。
こうして、現在走っている inetd デーモンに HUP シグナルを浴びせて inetd を再起動させます。オプション -wW を付けておくのが良いでしょう。hello : ALL : allow
telnetで繋げて見ましょう。繋げるサービス名は tcpmux です。
と、ここで黙ってしまいますが、ここで hello リターンと打ち込んで下さい。 すると hello のプログラムが動き出します。[local] /home/naoki>telnet somehost tcpmux Trying 123.45.67.8... Connected to somehost.somewhere.com Escape character is '^]'.
hello Your name, sir/madam: Naoki Hello, Naoki. Connection closed by foreign host. [local] /home/naoki>
一旦 inetd の設定がうまくいけば、プログラムの変更はいつでもできますし、 その変更が直ちにサービスに反映されます。 これほど簡単にネットワークサービスのプログラムを自分で作ることができて、 なおかつアクセス制限もしてくれるので、これではもう自分でネットワーク プログラムを組む必要も無いかというと、やはりプログラマは 自分でプログラムしたがるのでしょう。Inetdに管理させるサービスには 利用頻度の高いサービスは向いていません。例えば sendmail や httpd は inetdではなく独立(standalone)にデーモンとして動かすべきなのです。
getpeername関数をデスクリプタ 0 または 1 に対して 実行するとクライアントのアドレスを入手できます。
sockaddr_in c_addr; socklen_t len = sizeof(c_addr); getpeername( 0, (sockaddr*)&c_addr, &len ); printf("Client IP %s, PORT %u\n", inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port) );