web-dev-qa-db-ja.com

関数gethostbynameをコード化する静的バイナリをコンパイルします

コードに関数gethostbynameが含まれている静的バイナリをコンパイルする方法、および次のような警告なしでコンパイルした場合の解決方法:

警告:静的にリンクされたアプリケーションで 'gethostbyname'を使用するには、実行時にリンクに使用されるglibcバージョンの共有ライブラリが必要です

私はコマンドでubuntu 12.04でコンパイルします:

$ gcc -static lookup.c -o lookup

これはlookup.cのコードです。

  /* lookup.c */

  #include <stdio.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <string.h>
  #include <errno.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <netdb.h>

  extern int h_errno;

  int main(int argc,char **argv) {
     int x, x2;
     struct hostent *hp;

     for ( x=1; x<argc; ++x ) {
        hp = gethostbyname(argv[x]);
        if ( !hp ) {
           fprintf(stderr,
                   "%s: Host '%s'\n",
                   hstrerror(h_errno),
                   argv[x]);
           continue;
        }

        printf("Host %s : \n" ,argv[x]);
        printf(" Officially:\t%s\n", hp->h_name);
        fputs(" Aliases:\t",stdout);
        for ( x2=0; hp->h_aliases[x2]; ++x2 ) {
           if ( x2 ) {
              fputs(", ",stdout);
             }
        fputs(hp->h_aliases[x2],stdout);
        }     
        fputc('\n',stdout);
        printf(" Type:\t\t%s\n",
               hp->h_addrtype == AF_INET
               ? "AF_INET" : "AF_INET6");
        if ( hp->h_addrtype == AF_INET ) {
           for ( x2=0; hp->h_addr_list[x2]; ++x2 ) {
              printf(" Address:\t%s\n",
                     inet_ntoa( *(struct in_addr *)
                      hp->h_addr_list[x2]));
           }
        }
     putchar('\n');
     }
     return 0;
  }

$ file lookupで確認すると、次のような出力が得られます。

ルックアップ:ELF 32ビットLSB実行可能ファイル、Intel 80386、バージョン1(GNU/Linux)、静的にリンク、GNU/Linux 2.6.24用、BuildID [sha1] = 0x6fcb2684ad8e5e842036936abb50911cdde47c73、ストリップされない

このようではありません:

ルックアップ:ELF 32ビットLSB実行可能ファイル、Intel 80386、バージョン1(SYSV)、動的にリンク(共有ライブラリを使用)、GNU/Linux 2.6.24、BuildID [sha1] = 0xf9f18671751927bea80de676d207664abfdcf5dc、ストリップされない

私が知っているLinuxごとにlibcが異なるため、スタティックなしで使用することをお勧めします。コメントする必要がないことを望みます。なぜ静的に固執するのですか?静的に強制的に使用する必要があるため、バイナリファイルは動的でなく静的でなければなりません。

私はこれを2週間以上探していますが、これまでのところ成功していません。

私の重い問題を解決するのを助けてくれてありがとう。

20
Loren Ramly

あなたが求めていることは非常に困難になるでしょう。

getaddrinfoに関するこのStackOverflowの質問 を参照してください。基本的に、getaddrinfo/gethostbynameの下にはglibcのNSSレイヤーがあります。これにより、システム管理者は「ホスト名をIPアドレスに解決するためにDNSを使用する」、「LDAPを使用する」、または「/etc/hosts以外は使用しない」と言うことができます。このコントロールは実行時です。 sysadminは、ホスト名をIPに解決する方法をいつでも変更できます。

この柔軟性のため、glibcのすべての名前解決呼び出しは、ヘルパーライブラリ(基本的にはプラグイン)を使用して、解決の大まかな作業を行います。 LDAPアドレス指定用、ファイル用、DNS用、YP用などの1つの共有ライブラリがあります。

プログラムを100%静的にリンクする場合は、ホスト名をIPアドレスに変換するために(gethostbynameではなく)別の場所に移動する必要があります。 DNS のようなリゾルバーライブラリを使用してこれを行うことができます(これとまったく同じではありません-同様のツールが利用可能です)。ただし、バイナリはDNSを使用しないように設定されているシステムで正しいことをします!

代わりに、プログラムを(技術的に)動的にリンクしたままにすることをお勧めします。どのプラットフォームでも確実に実行できるようにしたい場合は、glibcをバイナリに同梱することもできますが、これにはLGPLへの準拠が必要です。この1つのダイナミックリンクをそのままにしておくと、glibcのバージョンが正しくないシステムで作業できなくなるだけで、大きな互換性の問題は発生しません。

ライセンスコンプライアンスと言えば、glibcを静的にリンクする場合、glibcのLGPLライセンスに準拠するには、アプリケーション全体のソースコードを出荷する必要がある可能性が高いことに注意してください。私は弁護士ではありません。これは適法な法的助言ではありませんが、LGPLを読むと、glibcを静的にリンクするアプリケーションがオープンソースである必要があることが明確になります。 トピックに関するこのStackOverflowの質問 を参照してください。

26
Borealid

同じ警告が表示され、修正するためにglibcを再コンパイルしました。スイッチをオン--enable-static-nss機能させるために設定するとき。

9
kimi shi

私は2つの答えがあります-

  1. プログラムの主要部分を静的にリンクしたままにし、単一の関数プログラムを分離してgethostbyname()を呼び出すだけにします。後者を動的にリンクできるようにします。 forkを使用してexecでこの別のプログラムを実行し、ドメイン名のアドレスを取得します。 fork then execの代わりにsystem()を使用することもできますが、インターネット上でネームサーバーを検索するのに時間がかかるので、心配する必要はありません(ミリ秒単位)。

  2. 私が行ったように、DNSを実行するためのソースコードを記述します。アーカイブ(.a)にコンパイルし、静的リンクで検索します。

0
Clive