2009-03-09 11 views
3

Für eine Kommunikation zwischen zwei Hosts, muss ich die IP-Adresse meines Hosts an die andere Seite senden. Das Problem ist, dass, wenn ich meine IP-Adresse anfrage, es sein kann, dass ich meine lokalen Loopback-IP-Adressen (127.x.x.x), nicht die Netzwerk (Ethernet) IP-Adresse zurückbekomme.Wie bekomme ich meine nicht-Loopback-Netzwerk-IP-Adresse in C?

Ich verwende den folgenden Code ein:

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; 
} 

Der einzige Weg, um es zu lösen ist mein Hostname in/etc/hosts, um sicherzustellen, hinter der realen Netzwerk-Adresse, nicht der lokale Loopback (der Standard für zB Ubuntu).

Gibt es eine Möglichkeit, dies zu lösen, ohne sich auf den Inhalt von/etc/hosts zu verlassen?

Edit: änderte ich den obigen Code, so dass es die Verwendung von getaddrinfo macht, aber ich habe immer noch die Loopback-Device Nummer (127.0,0,1) anstelle der realen IP-Adresse zurück:

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; 

(ich habe mit den drei SOCK_STREAM, SOCK_DGRAM und SOCK_RAW eine Liste von 3 addrinfo die zurück zu bekommen, aber der Hinweis, dass verhindert)

Also meine Frage steht immer noch ...

+2

gethostbyname ist seit vielen Jahren veraltet (einer der Gründe dafür, dass es nur mit einer Adressfamilie funktioniert). Wie von qrdl erwähnt, sollten Sie getaddrinfo verwenden – bortzmeyer

+0

Ok, danke für die Info. Dieser Originalcode ist 12+ Jahre alt. – Roalt

Antwort

9

Es ist POSIX-Funktion getaddrinfo(), die zurückgibt verknüpfte Liste von Adressen für bestimmte Hostnamen (beej Leitfaden für die Vernetzung, insbesondere der Teil auf accept() sehen), so dass Sie nur durch das muss gehen Liste und finde die Nicht-Loopback-Adresse.

Siehe man getaddrinfo.

1

Blick auf diese: Discovering public IP programmatically

Beachten Sie, dass ein Computer in einigen Fällen mehr als eine nicht-Loopback IP-Adresse haben kann, und in diesem Fall die Antworten auf diese Frage Ihnen sagen, wie Sie die mit dem Internet ausgesetzt werden.

+0

Ich brauche es von C, nicht von einem Shell-Skript oder Java – Roalt

+0

Die akzeptierte Antwort, zumindest, ist immer noch relevant - Sie können diese Website von C. –

4

Keine Antwort, aber ein relevanter Kommentar: Seien Sie sich bewusst, dass Sie, sobald Sie Adressinformationen im Inhalt von Paketen senden, das Risiko eingehen, dass Ihre Anwendung nicht über NAT:ing Router und/oder Firewalls funktioniert.

Diese Technologien basieren auf den Informationen in IP-Paketheadern, um den Verkehr zu verfolgen. Wenn Anwendungen Adressinformationen innerhalb von Paketen austauschen, wo sie für diese Inspektion unsichtbar bleiben, können sie brechen.

Natürlich könnte dies für Ihre Anwendung völlig irrelevant sein, aber ich denke, es lohnt sich, in diesem Zusammenhang darauf hinzuweisen.

+0

zugreifen Ja, es ist irrelevant, da es immer in einem lokalen LAN läuft , aber Ihr Punkt ist in der Tat für größere Anwendungen relevant. – Roalt

+0

Seien Sie vorsichtig: Code hat einen Weg, der über Ihre ursprüngliche Absicht hinausreicht. Seien Sie sich nur darüber im Klaren, dass jemand es irgendwann über das lokale LAN hinaus führen möchte. (Dies mag keinen Sinn ergeben, aber sie werden es tun wollen). –

0

Auch wenn der Computer nur über eine physikalische Netzwerkschnittstelle verfügt (eine Annahme, die auch nicht reicht, sogar Netbooks haben zwei - Ethernet und WLAN), können VPNs noch mehr IP-Adressen hinzufügen. Wie dem auch sei, der Host auf der anderen Seite sollte in der Lage sein, die IP zu ermitteln, mit der Ihr Host ihn kontaktiert hat.

4

Die Ursprungsadresse wird in das Paket aufgenommen werden gesendet ... gibt es keine Notwendigkeit, diese Informationen zu duplizieren. Es wird erhalten, wenn die Kommunikation von dem entfernten Host zu akzeptieren

0

Sie sind fast da.Ich bin mir nicht sicher, wie Sie my_ip von hp bekommen.

gethostbyname() gibt einen Zeiger auf eine hostent Struktur zurück, die ein Feld h_addr_list enthält. Das Feld h_addr_list ist eine nullterminierte Liste aller IP-Adressen, die an diesen Host gebunden sind.

Ich denke, Sie erhalten die Loopback-Adresse, weil es der erste Eintrag in h_addr_list ist.

EDIT: Es sollte wie folgt funktionieren:

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 
+0

gethostbyname ist seit April 1997 veraltet ... (Veröffentlichung von RFC 2133) – bortzmeyer

+0

Ich habe die Zeile, die das my_ip von HP jetzt zu der ursprünglichen Frage hat, hinzugefügt. – Roalt

0

Wenn/etc/hosts ist immer noch da und immer noch die gleichen, für alle Einträge von h_addr_list sucht, wird nicht helfen.

+0

Was meinst du, sollte oder sollte nicht in/etc/hosts platziert werden? Das Problem ist, dass auf unserem normalen System (RHEL) der Hostname nicht hinter dem Eintrag 127.0.0.1 steht (sondern die echte eth0-Adresse), aber auf Systemen wie Ubuntu wird der Hostname nach dem Eintrag 127.0.0.1 gesetzt. – Roalt

+0

Versuchen Sie, die Datei/etc/hosts loszuwerden (im Zweifelsfall umzubenennen), dann erhalten Sie die eth0 IP direkt, wenn das für Sie akzeptabel ist.Wahrscheinlich die schlechtere Wahl, aber wenn Sie nur eine Maschine haben, um ... –

0

Ihr neuer Code verdrahtet die Verwendung von IPv4 (im Feld tipp.ai_family), was eine schreckliche Idee ist.

Abgesehen davon, Sie sind in der Nähe, sollten Sie nur die Ergebnisse von getaddrinfo durchlaufen. Ihr Code wird nur die erste IP-Adresse, aber es ist ein aip-> ai_next Feld zu folgen ...

struct addrinfo { 
     ... 
     struct addrinfo *ai_next;  /* next structure in linked list */ 
}; 
+0

Stellen Sie einen Haltepunkt nach der getaddrinfo Struktur und durchsuchen durch die ai_next nicht alle die IP-Adresse, ich bekomme nur entweder die lokale Adresse oder die reale Ethernet-Adresse, abhängig davon, wo der Hostname in/etc/hosts steht. – Roalt

+0

Wie ich in einem Kommentar zu der Frage gesagt habe, ist der * Algorithmus * sowieso fehlerhaft. Meine Antwort war nur zu erklären, wie man den fehlerhaften Algorithmus implementiert :-) – bortzmeyer

3

ich gerade in einer Situation, wo lief, wenn nur/etc/hosts Informationen in ihm hat, und wenn ich verwendet getaddrinfo, um die IP-Adressliste zu erhalten, gab es jedesmal 127.0.0.1 zurück. Wie sich herausstellte, war der Hostname Alias ​​für localhost ... etwas, das oft leicht zu übersehen war. Hier ist, was passiert ist:

Die Datei/etc/hosts-Datei:
127.0.0.1 localhost localhost.localdomain foo
:: 1 localhost6.localdomain6 localhost6
172.16.1.248 foo
172.16.1.249 bie
172.16. 1.250 bletch

So, jetzt, wenn Sie getaddrinfo mit Host = "foo" aufrufen, gibt es dreimal 127.0.0.1 zurück. Der Fehler hier ist, dass foo sowohl in der Zeile mit "127.0.0.1" als auch "172.16.1.248" erscheint. Sobald ich foo von der Leitung mit "127.0.0.1" entfernte, funktionierten die Dinge gut.

Ich hoffe, das hilft jemandem.

+0

Ja, das könnte sehr wohl das Problem gewesen sein, das habe ich auch selbst herausgefunden. Ihr System sollte sicherstellen, dass Ihr Hostname auf die richtige IP-Adresse eingestellt ist. Es kann also ohne eine Ethernet-Verbindung in Ordnung sein, aber sobald eine zusätzliche Verbindung hinzugefügt wurde, sollte die/etc/hosts vom System geändert werden. – Roalt