2010-10-21 12 views
5

GetAdaptersAddresses() ti porterà gli indirizzi in formato IP_ADAPTER_UNICAST_ADDRESS, che è definito come:Ottieni un IP_ADDRESS_STRING da GetAdaptersAddresses()?

typedef struct _IP_ADAPTER_UNICAST_ADDRESS { 
    union { 
    struct { 
     ULONG Length; 
     DWORD Flags; 
    } ; 
    } ; 
    struct _IP_ADAPTER_UNICAST_ADDRESS *Next; 
    SOCKET_ADDRESS      Address; 
    IP_PREFIX_ORIGIN     PrefixOrigin; 
    IP_SUFFIX_ORIGIN     SuffixOrigin; 
    IP_DAD_STATE      DadState; 
    ULONG        ValidLifetime; 
    ULONG        PreferredLifetime; 
    ULONG        LeaseLifetime; 
    UINT8        OnLinkPrefixLength; 
} IP_ADAPTER_UNICAST_ADDRESS, *PIP_ADAPTER_UNICAST_ADDRESS; 

L'unico campo che sembra suggerire la stringa indirizzo IP leggibile è l'indirizzo, che è una struttura SOCKET_ADDRESS definita come:

typedef struct _SOCKET_ADDRESS { 
    LPSOCKADDR lpSockaddr; 
    INT  iSockaddrLength; 
} SOCKET_ADDRESS, *PSOCKET_ADDRESS; 

quale, a sua volta, utilizza un'altra struttura, SOCKADDR, definita come:

Purtroppo, è troppo complessi da pubblicare qui, in quanto varia a seconda IPv4 vs IPv6 e W indows edizione ... ecco un link per la definizione:

http://msdn.microsoft.com/en-us/library/ms740496%28v=VS.85%29.aspx

Se non hai ancora avuto le vertigini come ho fatto io e seguito attraverso questo labirinto di definizioni, probabilmente notato che si tratta di un incubo per recupera il buon vecchio stile di stringa punteggiata di un indirizzo IP, in quanto era molto più semplice usando .

La mia domanda è: C'è una vera funzione IP Helper che può convertire IP_ADAPTER_UNICAST_ADDRESS a un IPv4 punteggiata stringa (o una stringa IPv6)?

risposta

6

È possibile utilizzare GetIpAddrTable - il returned data structure contiene un DWORD dwAddr ovvero l'indirizzo IPv4. Il codice di esempio sul primo collegamento dovrebbe mostrarti ciò che desideri. Breve estratto per mostrare cosa intendo:

if ((dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)) != NO_ERROR) { 
    printf("GetIpAddrTable failed with error %d\n", dwRetVal); 
    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),  // Default language 
         (LPTSTR) & lpMsgBuf, 0, NULL)) { 
     printf("\tError: %s", lpMsgBuf); 
     LocalFree(lpMsgBuf); 
    } 
    exit(1); 
} 

printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); 
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { 
    printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); 
    IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; 
    printf("\tIP Address[%d]:  \t%s\n", i, inet_ntoa(IPAddr)); 

Il IP_ADAPTER_UNICAST_ADDRESS contiene un SOCKET_ADDRESS in Address, che a sua volta contiene un LPSOCKADDR in lpSockAddr - è possibile convertire questo per la forma di stringa ipv4 utilizzando WSAAddressToString.

+0

@Steve, grazie, ma questo non è proprio quello che stavo cercando. GetAdaptersAddresses() fornisce molte più informazioni, sia per IPv4 che per IPv6, e mi piacerebbe attenervisi seguendo le raccomandazioni di Microsoft.Tutto quello che mi manca è una funzione di convenienza "traduttore" che prenderebbe IP_ADAPTER_UNICAST_ADDRESS come parametro e produrrà una stringa. Invece di reinventare la ruota e scriverla da sola, forse sai di una funzione così esistente? Nell'API stesso o altrove, forse qualche esempio? –

+2

@Android Eve - vedi edit, puoi usare 'WSAAddressToString' per questo. –

+0

Ancora una volta, si dimostra una conoscenza impressionante dello spazio IP Helper di PSDK. Grazie alla tua risposta, sono stato in grado di individuare alcune funzioni più correlate, in particolare RtlIpv4AddressToString() e RtlIpv6AddressToString() che, sfortunatamente, esistono nel WDK, non nel PSDK. Segnerò brevemente la tua risposta come accettata. A meno che una nuova risposta suggerisca una funzione che fa lo stesso per * entrambi * IPv6 e IPv4. –

3

Dai un'occhiata alla documentazione di SOCKADDR. Questo ci porta alla documentazione di SOCKADDR_STORAGE, che è una struttura di supporto per IPv4 e IPv6.

Citazione dalla documentazione sockaddr:

funzioni Winsock utilizzando sockaddr non sono strettamente interpretato essere puntatori a una struttura sockaddr. La struttura è interpretata in modo diverso da nel contesto di diverse famiglie di indirizzi.

Per ipv4, è possibile eseguire il cast di un puntatore sockaddr su un puntatore sockaddr_in e quindi accedere alle informazioni sull'indirizzo IPv4 da lì. Quindi è possibile utilizzare il generatore di stringhe preferito per produrre una stringa formattata a quattro punti.

sockaddr_in* address = (sockaddr_in*) temp->Address.lpSockaddr; 
uint32_t ipv4 = address->sin_addr.S_un.S_addr; 
// First octet: address->sin_addr.S_un.S_un_b.s_b1 
// Second octet: address->sin_addr.S_un.S_un_b.s_b2 
// Third octet: address->sin_addr.S_un.S_un_b.s_b3 
// Fourth octet: address->sin_addr.S_un.S_un_b.s_b4 

mi immagino che si può anche lanciare l'indirizzo per IPv6 in modo simile date le definizioni struct (copiate sotto).

struct sockaddr { 
     ushort sa_family; 
     char sa_data[14]; 
}; 

struct sockaddr_in { 
     short sin_family; 
     u_short sin_port; 
     struct in_addr sin_addr; 
     char sin_zero[8]; 
}; 

struct sockaddr_in6 { 
     short sin6_family; 
     u_short sin6_port; 
     u_long sin6_flowinfo; 
     struct in6_addr sin6_addr; 
     u_long sin6_scope_id; 
};