Pregunta

Para una comunicación entre dos hosts, necesito enviar la dirección IP de mi host al otro sitio. El problema es que si solicito mi dirección IP, es posible que recupere mi dirección IP de bucle de retorno local (127.x.x.x), no la dirección IP de la red (Ethernet).

Uso el siguiente código:

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

La única forma de resolverlo es asegurarse de que mi nombre de host en / etc / hosts esté detrás de la dirección de red real, no del bucle de retorno local (el valor predeterminado para, por ejemplo, Ubuntu).

¿Hay alguna forma de resolver esto sin confiar en el contenido de / etc / hosts?

Editar: cambié el código anterior para que use getaddrinfo, pero todavía recupero el número del dispositivo de bucle de retorno (127.0,0,1) en lugar de la dirección IP real:

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;

(solía recuperar una lista de 3 addrinfo con los tres SOCK_STREAM, SOCK_DGRAM y SOCK_RAW, pero la sugerencia lo impide)

Así que mi pregunta sigue en pie ...

¿Fue útil?

Solución

Existe la función getaddrinfo () de POSIX que devuelve la lista enlazada de direcciones para un nombre de host dado, por lo que solo debes revisar esa lista y encontrar una dirección sin bucle.

Consulte man getaddrinfo .

Otros consejos

No es una respuesta, sino un comentario relevante: tenga en cuenta que en cuanto comienza a enviar información de direccionamiento en el contenido de los paquetes, corre el riesgo de que su aplicación no pueda funcionar en NAT: ing routers y / o a través de firewalls.

Estas tecnologías se basan en la información de los encabezados de paquetes IP para realizar un seguimiento del tráfico, y si las aplicaciones intercambian información de direccionamiento dentro de paquetes, donde permanecen invisibles para esta inspección, podrían interrumpirse.

Por supuesto, esto puede ser totalmente irrelevante para su aplicación, pero creo que vale la pena señalarlo en este contexto.

La dirección de origen se incluirá en el paquete enviado ... no es necesario duplicar esta información. Se obtiene al aceptar la comunicación desde el host remoto (consulte la guía de beej para redes, específicamente la parte en accept () )

Me acabo de encontrar con una situación en la que cuando solo / etc / hosts tiene información y cuando usé getaddrinfo para obtener la lista de direcciones IP, devolví 127.0.0.1 cada vez. Al final resultó que, el nombre de host fue asignado a localhost ... algo que a menudo es fácil de pasar por alto. Esto es lo que pasó:

El archivo / 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

Entonces, ahora, cuando llamas a getaddrinfo con host = " foo " ;, devuelve 127.0.0.1 3 veces. El error aquí es que foo aparece en la línea con " 127.0.0.1 " y " 172.16.1.248 " ;. Una vez que eliminé foo de la línea con " 127.0.0.1 " las cosas funcionaron bien.

Espero que esto ayude a alguien.

Mira esto: Descubriendo la IP pública programáticamente

Tenga en cuenta que en algunos casos, una computadora puede tener más de una dirección IP sin loopback, y en ese caso las respuestas a esa pregunta le indican cómo obtener la que está expuesta a Internet.

Incluso si la computadora solo tiene una interfaz de red física (una suposición que puede o no ser válida, incluso las netbooks tienen dos redes Ethernet y WLAN), las VPN pueden agregar aún más direcciones IP. De todos modos, el host del otro lado debe poder determinar la IP que usó su host para contactarlo.

Ya casi estás allí. No estoy seguro de cómo obtienes my_ip de hp .

gethostbyname () devuelve un puntero a una estructura hostent que tiene un campo h_addr_list .

El campo h_addr_list es una lista terminada en cero de todas las direcciones IP vinculadas a ese host.

Creo que obtienes la dirección de loopback porque es la primera entrada en h_addr_list .

EDITAR: Debería funcionar algo como esto:

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 sigue allí y sigue igual, buscar todas las entradas de h_addr_list no ayudará.

Su nuevo código cablea el uso de IPv4 (en el campo hint.ai_family), lo cual es una idea terrible.

Aparte de eso, estás cerca, solo debes recorrer los resultados de getaddrinfo. Su código solo obtiene la primera dirección IP, pero hay un campo aip- > ai_next a seguir ...

struct addrinfo {
       ...
       struct addrinfo *ai_next;       /* next structure in linked list */
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top