Pergunta

Para uma comunicação entre dois hosts, eu preciso enviar o endereço IP do meu anfitrião para o outro site. O problema é que se eu pedir meu endereço IP, pode ser que eu voltar meus locais addres IP de auto-retorno (127.x.x.x), e não a rede (ethernet) endereço IP.

Eu uso o seguinte 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;
}

A única maneira de resolver isso é para ter certeza que meu nome de host em / etc / hosts está por trás do endereço de rede real, não o loopback local (o padrão para, por exemplo, Ubuntu).

Existe uma maneira de resolver isso sem contar com o conteúdo de / etc / hosts?

Editar: eu mudei o código acima assim que faz uso de getaddrinfo, mas eu ainda voltar o número do dispositivo de auto-retorno (127.0,0,1) em vez do endereço 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;

(Eu costumava receber de volta uma lista de 3 addrinfo Com os três SOCK_STREAM, SOCK_DGRAM e SOCK_RAW, mas os impede dica de que)

Então, minha pergunta continua de pé ...

Foi útil?

Solução

Há POSIX função getaddrinfo() que retorna lista de endereços para determinado hostname ligada, assim você só precisa passar por essa lista e encontrar o endereço não-auto-retorno.

Veja man getaddrinfo.

Outras dicas

Não é uma resposta, mas um comentário relevante: estar ciente de que, logo que você começar a enviar informações de endereçamento no conteúdo dos pacotes, você corre o risco de tornar a sua aplicação incapaz de trabalho em todo NAT: ing. routers e / ou através de firewalls

Estas tecnologias confiar na informação nos cabeçalhos dos pacotes IP para controlar o tráfego, e se aplicações de intercâmbio de informações de endereçamento dentro de pacotes, onde permanecem invisíveis para esta inspeção, eles podem quebrar.

Claro, isso pode ser totalmente irrelevante para a sua aplicação, mas eu pensei que salientar neste contexto.

O endereço de origem serão incluídos no pacote enviado ... não há necessidade de duplicar esta informação. É obtido ao aceitar a comunicação do host remoto (consulte o guia do beej a rede, especificamente a parte em aceitar () )

Eu corri em uma situação onde, quando apenas / etc / hosts tem informações nele e quando eu usei getaddrinfo para obter a lista de endereços IP, ele retornou 127.0.0.1 cada vez. Como se viu, o nome do host foi alias para localhost ... algo muitas vezes fácil de ignorar. Eis o que aconteceu:

O arquivo / etc / anfitriões:
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

Então, agora, quando você chamar getaddrinfo com host = "foo", ele retorna 127.0.0.1 3 vezes. O erro aqui, é que foo aparece tanto na linha com "127.0.0.1" e "172.16.1.248". Uma vez que eu removido foo da linha com "127.0.0.1" coisas funcionou bem.

Espero que isso ajude alguém.

Olhe para isto: Discovering IP pública programaticamente

Note que, em alguns casos, um computador pode ter mais do que um não loopback-IP endereço, e nesse caso as respostas a essa pergunta dizer-lhe como obter o que é exposto à internet.

Mesmo se o computador tem apenas um físico interface de rede (uma suposição que podem ou não podem realizar, mesmo netbooks têm dois - Ethernet e WLAN), VPNs pode adicionar ainda mais IP endereços. De qualquer forma, o anfitrião do outro lado deve ser capaz de determinar o IP do seu host usado para o contato-lo.

Você está quase lá. Eu não sei como você está recebendo my_ip de hp.

gethostbyname() retorna um ponteiro para uma estrutura hostent que tem um campo h_addr_list.

O campo h_addr_list é uma lista terminada em null de todos os endereços IP vinculados a esse host.

Eu acho que você está recebendo o endereço de auto-retorno, porque é a primeira entrada na h_addr_list.

EDIT: Ele deve funcionar algo parecido com isto:

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

Se / etc / hosts ainda está lá e ainda o mesmo, olhando para todas as entradas de h_addr_list não vai ajudar.

Seu novo código faz uma ligação do uso de IPv4 (no campo hint.ai_family), que é uma péssima idéia.

Além disso, você está perto, você apenas deve percorrer os resultados de getaddrinfo. Seu código só fica o primeiro endereço IP, mas há uma aip-> ai_next campo a seguir ...

struct addrinfo {
       ...
       struct addrinfo *ai_next;       /* next structure in linked list */
};
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top