inetdと、tcp wrapperと、iptablesについて

とある某所にて。


tcp wrapper って、tcpの接続の許可/拒否を設定できるんですよね。hosts.allowに書いたのにsshdで接続できないです。
tcp wrapperの設定でポートあけることができるんですよね。
とかいう話を聞かされた。参った。ちょっと調べりゃわかりそうなもんだが、。。
と、思いつつも自分自身への備忘録も兼ねて説明した内容を残す。(間違いがあれば指摘を)


昔々の話。ワークステーションなどという言葉で数百万もするようなunix互換機が売れていた時代。
サーバの性能は今より低かった。たくさんのサーバプロセスをListen状態(というのは、特定のTCPのポートで待ち受け状態にしておくこと)にするには
メモリが足りなかった。仮に、メモリが足りてたとしても、同時にたくさんのポートにお客さん(クライアント)から要求がくると、迅速に対処
できるほど、動作性能は高くなかった。まぁ、そういう時代があったのです。と思って聞いてくださいな。
(当時は少々遅くても我慢できたのかもしれないけれどね)


先人は考えた。個別のプログラムがそれぞれにポートをLISTENするのは大変だ。
監視するポートの数だけプロセスを起動させておくと使わないときはメモリの無駄遣いじゃないか。
ポート番号を監視するだけの専用のプログラムを用意して、特定のポートに要求がきたときだけ、あらかじめ決められたプログラムが起動するようにしよう。
(本当に必要なときだけメモリが確保されるようにしよう)
こうして、inetdができた。「インターネットスーパーサーバ」と今見るとちょっとはずかしいネーミングだが、対外的に公開するポート全てを管理できる、文字通り「スーパー」なサーバデーモンなのだ。
なので、/etc/inetd.confにはポート番号と対応して起動するプログラム(こいつらは標準入力を受け取って標準出力に返すフィルタ)が羅列された。
このころは、百花繚乱の時期で、echoやら、discardやら、fingerやら、rloginやら、、そして、telnetや、ftpも。inetd.confに記載されている。
こういう経緯をもあり、inetd.confに書かれるプログラムはほぼ全て「昔」のプログラムだ。
セキュリティなんて考えが及ばない頃のサービスだと思って間違いない。
(やる気があれば、sshdをinetd経由で動かすこともできたと思うけど、まぁあまりやらないよね。実際お目にかかったことはない)


やがて、時が経ち、ネットワークの向こう側から悪さをする可能性が出てきた。
telnetftpは通信を見るとそのままパスワードが書いてあるし、そもそも、見ず知らずの相手にfingerで自分のことを教える必要もない、という考え方に変わった。
セキュリティの芽生え期だ。
その頃の前提は、ネットワークに公開するプログラムは全てinetd経由での起動だったので(apacheですら昔はそういう設定ができた、今もできるのかな?)
inetdが処理するプログラムに渡す前に、相手を見て許可/拒否ができる仕組みが必要だ。
なので、許可するホスト(IPアドレス)と拒否するホストを記述するファイルが必要だ。というわけで、以下のファイルが作られた
/etc/hosts.allow, /etc/hosts.deny
この二つを見てアクセス制御を行うプログラムを、tcp wrapperという。
ただ、今となって振り返ってみるとデフォルトはヌルくて、禁止にも許可にも書いていないものは「よくわかんないからとりあえず許可しよう」となっているし、
inetd経由のプログラムしか対象じゃないのだから、結局はあまりセキュリティ対策としては機能しない。
でもまぁ、当時は必須だと言われてたんだよ。今でも、telnetftpは普通はinetd経由で動かすのが普通だから、これらを使いたい場合はtcp wrapperの設定が必須だ。


やがて、メモリが増えたり、処理性能があがったり、ワークステーションという言葉が死語になったり、いろいろあったんだけど
クライアントの要求がきてから「必要なプロセスを起動する」方法では、レスポンスを返すのが遅い、と考えるようになった。
昔と比べてハードウェアの性能があがっているのだから、プロセスを常時起動させて、自前でTCPのポートを監視させておいてもさほど問題にはならないだろう。inetdは遅い。
と、考えられるようになった。
だから、最近使われる、sshdや、apacheや、その他多くの「サーバプログラム」は、inetdを経由しないものがほとんどだ。
従って、こいつらにはtcp wrapperの効力は及ばない。/etc/hosts.allowでsshdの接続許可を制御は無理だ。(sshdをinetd経由で起動してればできるのは前述の通り)
だから、個別の設定ファイルにそれぞれの方式で接続許可/拒否を設定できるようになっている。
(httpd.confだったり、sshd.confだったり、、いつの間にやらsshd_configだったり)
これでは、新しいプログラムが出るたびに、新しい設定ファイルと接続許可/拒否の書き方を覚える必要がある。
きめ細かい設定ができるかもしれないけれど、間違いなくめんどくさい。(けど、ある方面の人にとっては必須の素養)


inetdの呪縛を逃れるのが流行とはいえ、起動するサービスごとに、別々の設定ファイルのそれぞれ独自の書式を覚えるのは大変だ。
方式が別々であろうとも、結局やることはTCPへの接続の許可/拒否の判別だ。たかが、ポートがちがう程度の理由で覚えることを増やすなよ。
と、誰かが言ったかどうかはわからないけれど、Linuxの2.4ぐらいが出るまでは、こういう独自方式のTCPのプログラムの制御のために、
ipnatctlというプログラム(他にもあったかもしれない)を駆使してなんとか網の目に掛けようとしていた(時代があった)
やがて、linuxの世界では2.4と共に真打ちがやってきた。iptablesとnetfilterだ。
(他のUnixの世界では、ipfwだったり、pfとか言うのもあったと思うけれど、ここでLinuxに特化するのは単に今日Linuxを触って思ったから)
OS側で接続許可/拒否の設定が済ませられるので、個々のプログラムを意識しなくても済むようになった。
ただ、個々のプログラムは「基本的にLinuxカーネル事情に併せて開発している訳ではない」から、接続許可/拒否が、
OS側の判定(iptables)を通過後に、プログラム側の設定(sshd_config, httpd.conf)を通過するようになった。
これが、現状だ。
一カ所でまとめて設定できるものもあれば、個別で設定できるものもある。それらは同居している。
だから、ネットワーク越しにうまく繋がらないぞーという場合はこういう順序でのトラブルシューティングになる。

繋がらないプロトコルは何か?
ping(icmp)の場合は、iptablesの設定を見直すか、ネットワーク管理者に聞くか、LANケーブルが刺さってるか、いろいろ調べる。
telnet, ftpなどのinetd経由のプログラムは iptables -> /etc/hosts.deny, /etc/hosts.allow
sshdの場合は、iptables -> sshd_config
httpdの場合は、iptables -> httpd.conf
パケットフィルタリングや、ファイヤーウォールや、アクセス制御がごっちゃになっているけれど、リアルワールドで繋がらない場合は
こういう感じで切り分けが進むことになると思う。
現在ではinetd は、tcp wrapper無しではちょっと使えない、という考え方がさらに進んだxinetdという
「新しいインターネットスーパーサーバ」(RedHat系で採用されている)をお目にする機会も増えてきた。
こっちはもう少し賢くて、xinetd = inetd + tcp wrapper というような感じで設定ができる。
ポート番号ごとに許可IPを変えたりもできるから、inetd + tcp wrapperよりも賢いかもしれない。