3

2 つのホスト間の通信のために、ホストの IP アドレスを他のサイトに送信する必要があります。問題は、IP アドレスを要求すると、ネットワーク (イーサネット) IP アドレスではなく、ローカル ループバック IP アドレス (127.xxx) が返される可能性があることです。

次のコードを使用します。

char myhostname[32];


gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

if( (my_ip % 256) == 127) {
  /* Wrong IP adress as it's 127.x.x.x */
  printf("Error, local IP address!");
  return;
}

これを解決する唯一の方法は、/etc/hosts のホスト名がローカル ループバック (Ubuntu などのデフォルト) ではなく、実際のネットワーク アドレスの背後にあることを確認することです。

/etc/hosts の内容に頼らずにこれを解決する方法はありますか?

編集: getaddrinfo を使用するように上記のコードを変更しましたが、実際の IP アドレスの代わりにループバック デバイスの番号 (127.0,0,1) が返されます。

struct addrinfo hint = {0};
struct addrinfo *aip = NULL;
unsigned ip = 0;
struct sockaddr_in *sinp = NULL;

hint.ai_family = AF_INET; /* IPv4 */
hint.ai_socktype = SOCK_STREAM;

if(getaddrinfo(hostname, NULL, &hint, &aip) != 0) {
    return 0;
}
sinp = (struct sockaddr_in *) aip->ai_addr;
ip   = *(unsigned *) &sinp->sin_addr;

(以前は 3 つの addrinfo のリストを 3 つの SOCK_STREAM、SOCK_DGRAM、SOCK_RAW で取得していましたが、ヒントによってそれが妨げられています)

だから私の質問はまだ残っています...

4

10 に答える 10

9

指定されたホスト名のアドレスのリンクリストを返すPOSIX関数getaddrinfo()があるため、そのリストを調べて非ループバックアドレスを見つける必要があります。

を参照してくださいman getaddrinfo

于 2009-03-09T10:36:30.837 に答える
4

送信元のアドレスは送信されるパケットに含まれます...この情報を複製する必要はありません。これは、リモートホストからの通信を受け入れるときに取得されます(ネットワークに関するbeejのガイド、特にaccept()の部分を参照してください) 。

于 2009-03-09T10:27:02.730 に答える
4

答えではありませんが、関連するコメントです。パケットの内容でアドレス情報を送信し始めるとすぐに、アプリケーションがNAT 経由で機能しなくなるリスクがあることに注意してください:ルーターやファイアウォールを通過します。

これらのテクノロジーは、IP パケット ヘッダーの情報に依存してトラフィックを追跡します。アプリケーションがパケット内でアドレッシング情報を交換すると、この検査では見えないままになるため、アプリケーションが壊れる可能性があります。

もちろん、これはアプリケーションとはまったく無関係かもしれませんが、この文脈で指摘する価値があると思いました.

于 2009-03-09T10:22:25.003 に答える
3

/etc/hosts だけに情報があり、getaddrinfo を使用して IP アドレス リストを取得すると、毎回 127.0.0.1 が返されるという状況に遭遇しました。結局のところ、ホスト名は localhost にエイリアス化されていました...これは見過ごされがちです。何が起こったかは次のとおりです。

/etc/hosts ファイル:
127.0.0.1 localhost.localdomain localhost foo
::1 localhost6.localdomain6 localhost6
172.16.1.248 foo
172.16.1.249 bie
172.16.1.250 bletch

これで、host="foo" を指定して getaddrinfo を呼び出すと、127.0.0.1 が 3 回返されます。ここでのエラーは、「127.0.0.1」と「172.16.1.248」の両方の行に foo が表示されることです。「127.0.0.1」の行から foo を削除すると、問題なく動作しました。

これが誰かに役立つことを願っています。

于 2010-01-08T22:08:08.217 に答える
1

これを見てください: プログラムによるパブリック IP の検出

場合によっては、コンピューターが複数の非ループバック IP アドレスを持つ可能性があることに注意してください。その場合、その質問への回答は、インターネットに公開されているものを取得する方法を示しています。

于 2009-03-09T10:19:04.577 に答える
0

使用するgetaddrinfo()

于 2009-03-09T10:27:01.750 に答える
0

新しいコードは、ひどい考えであるIPv4(hint.ai_familyフィールド内)の使用をハードワイヤードします。

それとは別に、あなたは近くにいます、あなたはただgetaddrinfoの結果をループするべきです。コードは最初のIPアドレスを取得するだけですが、続くaip->ai_nextフィールドがあります...

struct addrinfo {
       ...
       struct addrinfo *ai_next;       /* next structure in linked list */
};
于 2009-03-31T21:37:33.717 に答える
0

あなたはほとんどそこにいます。my_ipからどのように取得しているかわかりませんhp

gethostbyname()hostentフィールドを持つ構造体へのポインタを返しますh_addr_list

このh_addr_listフィールドは、そのホストにバインドされたすべての IP アドレスの null で終わるリストです。

の最初のエントリなので、ループバック アドレスを取得していると思いますh_addr_list

編集:次のように動作するはずです:

gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

for (int i = 0; hp->h_addr_list[i] != 0; ++i) {
  if (hp->h_addr_list[i] != INADDR_LOOPBACK) {
    // hp->addr_list[i] is a non-loopback address
  }
}
// no address found
于 2009-03-09T14:04:56.030 に答える