ネットワークインタフェース

inetd(1M) デーモン

システムに装備されているデーモンの 1 つが inetd(1M) です。システムの起動時に呼び出され、 /etc/inet/inetd.conf ファイルを読み、その内容に従いサービスを取得します。デーモンは /etc/inet/inetd.conf ファイルに記述されている各サービスごとに 1 つのソケットを作成し、各ソケットに適切なポート番号の割り当てを行います。inetd(1M) に関するより詳しい情報は、マニュアルページを参照してください。

inetd(1M) は各ソケットのポーリングを行い、そのソケットに対するサービスの接続要求待ちを行います。SOCK_STREAM タイプのソケットの場合、inetd(1M) は待機ソケットに対し accept(3SOCKET) を実行、新しいファイル記述子 0 および 1 (stdin および stdout) において、新しいソケットに対して fork(2)dup(2) を実行し、その他の開かれているファイル記述子を終了させ適切なサーバーに対し exec(2) を実行します。

inetd(1M) の主な利点は、使用されていないサービスがシステム資源を使用しない点にあります。また、接続の確立に関する処理の大部分を inetd(1M) が請け負う点も大きな利点の 1 つです。inetd(1M) によって開始されたサーバーのソケットは、ファイル記述子 0 および 1 においてクライアントに接続され、ただちに read(2)write(2)send(3SOCKET)、または recv(3SOCKET) の実行が可能です。サーバーは stdio の取り決めに従い、必要な場合に fflush(3C) を利用する限りバッファー入出力の使用が可能です。

getpeername(3SOCKET) はソケットに接続されたピア (処理) のアドレスを戻り値として返します。これは inetd(1M) で開始されたサーバーにおいて、有効な手段です。たとえば、インターネットアドレス (たとえば、クライアントの IPv6 アドレスとしては定型的なアドレス fec0::56:a00:20ff:fe7d:3dd2 など) のログを記録する場合、inetd(1M) を使用しているサーバーならば以下が使用可能です。

    struct sockaddr_storage name;
    int namelen = sizeof (name);
    char abuf[INET6_ADDRSTRLEN];
    struct in6_addr addr6;
    struct in_addr addr;

    if (getpeername(fd, (struct sockaddr *)&name, &namelen) == -1) {
        perror("getpeername");
        exit(1);
    } else {
        addr = ((struct sockaddr_in *)&name)->sin_addr;
        addr6 = ((struct sockaddr_in6 *)&name)->sin6_addr;
        if (name.ss_family == AF_INET) {
                (void) inet_ntop(AF_INET, &addr, abuf, sizeof (abuf));
        } else if (name.ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&addr6)) {
                /* これは IPv4 によりマップされた IPv6 アドレスです。*/
                IN6_MAPPED_TO_IN(&addr6, &addr);
                (void) inet_ntop(AF_INET, &addr, abuf, sizeof (abuf));
        } else if (name.ss_family == AF_INET6) {
                (void) inet_ntop(AF_INET6, &addr6, abuf, sizeof (abuf));

        }
        syslog("Connection from %s¥n", abuf);
    }