Cで非ループバックネットワークIPアドレスを取得する方法は?
-
05-07-2019 - |
質問
2つのホスト間の通信では、ホストのIPアドレスを他のサイトに送信する必要があります。問題は、IPアドレスを要求すると、ネットワーク(イーサネット)IPアドレスではなく、ローカルループバックIPアドレス(127.x.x.x)が返される可能性があることです。
次のコードを使用します:
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つのSOCK_STREAM、SOCK_DGRAM、およびSOCK_RAWを使用して3つのaddrinfoのリストを取得するために使用していましたが、ヒントはそれを防ぎます)
だから私の質問はまだ残っています...
解決
特定のホスト名のアドレスのリンクリストを返すPOSIX関数 getaddrinfo()
があります。そのため、そのリストを調べて、ループバックされていないアドレスを見つけるだけです。
man getaddrinfo
を参照してください。
他のヒント
答えではなく、関連するコメント:パケットのコンテンツでアドレス指定情報の送信を開始するとすぐに、アプリケーションが NAT:ing ルーターおよび/またはファイアウォール経由。
これらのテクノロジーは、IPパケットヘッダーの情報に依存してトラフィックを追跡します。また、アプリケーションがパケット内のアドレス情報を交換すると、パケットがこの検査から見えなくなり、破損する可能性があります。
もちろん、これはアプリケーションとはまったく無関係かもしれませんが、このコンテキストで指摘する価値があると思いました。
送信元のアドレスは送信されるパケットに含まれます...この情報を複製する必要はありません。これは、リモートホストからの通信を受け入れるときに取得されます(ネットワークのbeejのガイド、特に accept())
/ etc / hostsのみに情報があり、getaddrinfoを使用してIPアドレスリストを取得すると、毎回127.0.0.1が返されるという状況に陥りました。判明したように、ホスト名はローカルホストにエイリアスされていました...見落としがちなものです。起こったことは次のとおりです。
/ 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回返されます。ここでのエラーは、fooが" 127.0.0.1"の行の両方に表示されることです。および「172.16.1.248」。 「127.0.0.1」の行からfooを削除したら、うまくいきました。
これが誰かを助けることを願っています。
これを見てください: プログラムによるパブリックIPの検出
場合によっては、コンピューターに複数の非ループバックIPアドレスを割り当てることができます。その場合、その質問への回答により、インターネットに公開されているIPアドレスを取得する方法がわかります。
コンピューターに物理ネットワークインターフェイスが1つしかない場合(ネットブックにイーサネットとWLANが2つある場合もある)、VPNはさらに多くのIPアドレスを追加できます。とにかく、反対側のホストはあなたのホストがそれに連絡するのに使用したIPを判別できるはずです。
もうすぐです。 hp
から my_ip
を取得する方法がわかりません。
gethostbyname()
は、 h_addr_list
フィールドを持つ hostent
構造体へのポインタを返します。
h_addr_list
フィールドは、そのホストにバインドされているすべてのIPアドレスのヌル終了リストです。
ループバックアドレスは 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
/ etc / hostsがまだ存在し、同じ場合、h_addr_listのすべてのエントリを検索しても解決しません。
新しいコードは、IPv4の使用(hit.ai_familyフィールド内)をハードワイヤードにします。これはひどい考えです。
それとは別に、近いので、getaddrinfoの結果をループするだけです。コードは最初のIPアドレスを取得するだけですが、aip-> ai_nextフィールドが続きます...
struct addrinfo {
...
struct addrinfo *ai_next; /* next structure in linked list */
};