Domanda

Per una comunicazione tra due host, devo inviare l'indirizzo IP del mio host all'altro sito. Il problema è che se richiedo il mio indirizzo IP, è possibile che ottenga il mio indirizzo IP di loopback locale (127.x.x.x), non l'indirizzo IP di rete (ethernet).

Uso il seguente codice:

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

L'unico modo per risolverlo è assicurarsi che il mio nome host in / etc / hosts sia dietro il vero indirizzo di rete, non il loopback locale (predefinito per es. Ubuntu).

C'è un modo per risolverlo senza fare affidamento sul contenuto di / etc / hosts?

Modifica: ho modificato il codice sopra in modo che utilizzi getaddrinfo, ma continuo a recuperare il numero del dispositivo di loopback (127.0,0,1) invece del vero indirizzo 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;

(Ero solito recuperare un elenco di 3 addrinfo con i tre SOCK_STREAM, SOCK_DGRAM e SOCK_RAW, ma il suggerimento lo impedisce)

Quindi la mia domanda è ancora valida ...

È stato utile?

Soluzione

Esiste la funzione POSIX getaddrinfo () che restituisce un elenco di indirizzi collegati per un determinato nome host, quindi è sufficiente passare attraverso tale elenco e trovare un indirizzo non loopback.

Vedi man getaddrinfo .

Altri suggerimenti

Non una risposta, ma un commento pertinente: tieni presente che non appena inizi a inviare informazioni di indirizzamento nel contenuto dei pacchetti, corri il rischio di rendere la tua applicazione incapace di lavorare su NAT: ing router e / o tramite firewall.

Queste tecnologie si basano sulle informazioni nelle intestazioni dei pacchetti IP per tenere traccia del traffico e se le applicazioni scambiano le informazioni di indirizzamento all'interno dei pacchetti, dove rimangono invisibili a questa ispezione, potrebbero rompersi.

Naturalmente, questo potrebbe essere totalmente irrilevante per la tua applicazione, ma ho pensato che valesse la pena sottolineare in questo contesto.

L'indirizzo di origine verrà incluso nel pacchetto inviato ... non è necessario duplicare queste informazioni. Si ottiene accettando la comunicazione dall'host remoto (consultare la guida di beej alla rete, in particolare la parte su accept () )

Mi sono appena imbattuto in una situazione in cui solo / etc / hosts contiene informazioni e quando ho usato getaddrinfo per ottenere l'elenco di indirizzi IP, ogni volta ha restituito 127.0.0.1. A quanto pare, il nome host era alias di localhost ... qualcosa spesso facile da trascurare. Ecco cosa è successo:

Il file / 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

Quindi, ora, quando chiami getaddrinfo con host = " foo " ;, restituisce 127.0.0.1 3 volte. L'errore qui è che foo appare sia sulla riga con "127.0.0.1" e "172.16.1.248". Una volta ho rimosso foo dalla linea con "127.0.0.1" le cose hanno funzionato bene.

Spero che questo aiuti qualcuno.

Guarda questo: Scoprire l'IP pubblico a livello di programmazione

Nota che in alcuni casi un computer può avere più di un indirizzo IP senza loopback, e in quel caso le risposte a quella domanda ti diranno come ottenere quello che è esposto a Internet.

Anche se il computer ha una sola interfaccia di rete fisica (un presupposto che può o non può contenere, anche i netbook hanno due Ethernet e WLAN), le VPN possono aggiungere ancora più indirizzi IP. Ad ogni modo, l'host dall'altra parte dovrebbe essere in grado di determinare l'IP utilizzato dall'host per contattarlo.

Ci sei quasi. Non sono sicuro di come stai ricevendo my_ip da hp .

gethostbyname () restituisce un puntatore a una struttura hostent che ha un campo h_addr_list .

Il campo h_addr_list è un elenco con terminazione null di tutti gli indirizzi IP associati a quell'host.

Penso che stai ricevendo l'indirizzo di loopback perché è la prima voce in h_addr_list .

EDIT: dovrebbe funzionare in questo modo:

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 è ancora lì e lo stesso, cercare tutte le voci di h_addr_list non sarà di aiuto.

Il tuo nuovo codice prevede l'utilizzo di IPv4 (nel campo hint.ai_family) che è un'idea terribile.

A parte questo, sei vicino, dovresti semplicemente scorrere i risultati di getaddrinfo. Il tuo codice ottiene solo il primo indirizzo IP ma c'è un campo aip- > ai_next da seguire ...

struct addrinfo {
       ...
       struct addrinfo *ai_next;       /* next structure in linked list */
};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top