Comment obtenir mon adresse IP réseau sans bouclage en C?

Pour une communication entre deux hôtes, je dois envoyer l’adresse IP de mon hôte à l’autre site. Le problème est que si je demande mon adresse IP, il se peut que je récupère mon adresse IP de bouclage local (127.xxx), pas l’adresse IP du réseau (Ethernet).

J’utilise le code suivant:

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.xxx */ printf("Error, local IP address!"); return; } 

La seule façon de le résoudre est de s’assurer que mon nom d’hôte dans / etc / hosts se trouve derrière la véritable adresse réseau, pas le bouclage local (valeur par défaut pour Ubuntu, par exemple).

Existe-t-il un moyen de résoudre ce problème sans s’appuyer sur le contenu de / etc / hosts?

Edit: j’ai changé le code ci-dessus pour qu’il utilise getaddrinfo, mais je récupère toujours le numéro du périphérique de bouclage (127.0,0,1) au lieu de la véritable adresse IP:

 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; 

(J’avais l’habitude de récupérer une liste de 3 addrinfo avec les trois SOCK_STREAM, SOCK_DGRAM et SOCK_RAW, mais l’indice l’empêche)

Donc ma question est toujours valable …

Il existe une fonction POSIX getaddrinfo() qui renvoie une liste d’adresses liée pour un nom d’hôte donné. Vous devez donc simplement parcourir cette liste et rechercher une adresse qui ne fait pas l’object d’un bouclage.

Voir l’ man getaddrinfo .

Ce n’est pas une réponse, mais un commentaire pertinent: sachez que dès que vous commencez à envoyer des informations d’adressage dans le contenu des paquets, vous courez le risque de rendre votre application incapable de fonctionner avec les routeurs NAT et / ou avec les pare-feu.

Ces technologies reposent sur les informations contenues dans les en-têtes de paquets IP pour garder une trace du trafic. Si les applications échangent des informations d’adressage à l’intérieur de paquets, là où ils restnt invisibles pour cette inspection, ils risquent de se rompre.

Bien sûr, cela pourrait être totalement hors de propos pour votre candidature, mais j’ai pensé que cela valait la peine d’être souligné dans ce contexte.

L’adresse d’origine sera incluse dans le paquet envoyé … il n’est pas nécessaire de dupliquer cette information. Il est obtenu lors de l’acceptation de la communication de l’hôte distant (voir le guide de mise en réseau de beej, en particulier la partie sur accept () ).

Je viens de rencontrer une situation où, lorsque seul / etc / hosts contient des informations et lorsque j’ai utilisé getaddrinfo pour obtenir la liste d’adresses IP, 127.0.0.1 était renvoyé à chaque fois. Il s’est avéré que le nom d’hôte était associé à localhost … ce qui est souvent facile à négliger. Voici ce qui s’est passé:

Le fichier / 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

Donc, maintenant, lorsque vous appelez getaddrinfo avec host = “foo”, il renvoie 127.0.0.1 3 fois. L’erreur ici est que foo apparaît à la fois sur la ligne “127.0.0.1” et “172.16.1.248”. Une fois que j’ai supprimé foo de la ligne avec “127.0.0.1”, tout a bien fonctionné.

J’espère que ça aide quelqu’un.

Regardez ceci: Découverte d’IP publique par programmation

Notez que dans certains cas, un ordinateur peut avoir plusieurs adresses IP autres que le bouclage. Dans ce cas, les réponses à cette question vous expliquent comment obtenir l’adresse exposée à Internet.

Même si l’ordinateur ne possède qu’une seule interface réseau physique (hypothèse qui peut être ou ne pas être vérifiée, même les netbooks en ont deux: Ethernet et WLAN), les VPN peuvent append encore plus d’adresses IP. Quoi qu’il en soit, l’hôte de l’autre côté devrait pouvoir déterminer l’adresse IP utilisée par votre hôte pour le contacter.

Utilisez getaddrinfo()

Tu y es presque. Je ne sais pas comment vous obtenez my_ip de hp .

gethostbyname() renvoie un pointeur sur une structure hostent ayant un champ h_addr_list .

Le champ h_addr_list est une liste de toutes les adresses IP liées à cet hôte, terminée par un h_addr_list .

Je pense que vous obtenez l’adresse de bouclage parce que c’est la première entrée de h_addr_list .

EDIT: Cela devrait fonctionner quelque chose comme ça:

 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 

Si / etc / hosts existe toujours et rest identique, la recherche de toutes les entrées de h_addr_list ne vous aidera pas.

Votre nouveau code enregistre l’utilisation d’IPv4 (dans le champ indice.ai_family), ce qui est une idée terrible.

En dehors de cela, vous êtes proches, vous devez simplement parcourir les résultats de getaddrinfo. Votre code obtient juste la première adresse IP mais il y a un champ aip-> ai_next à suivre …

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