Получить IP_ADDRESS_STRING от GetAdaptersAddresses ()? - PullRequest
7 голосов
/ 21 октября 2010

GetAdaptersAddresses () получит ваши адреса в формате IP_ADAPTER_UNICAST_ADDRESS, который определен как:

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;

Единственное поле, которое, по-видимому, предлагает читабельную человеком строку IP-адреса, - это Address, который представляет собой структуру SOCKET_ADDRESS, определенную как:

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

Который, в свою очередь, использует другую структуру, SOCKADDR, определенную как:

Извините, здесь сложно размещать сообщения, поскольку они различаются в зависимости от IPv4 по сравнению с IPv6 и редакцией Windows ... поэтому здесь есть ссылка на определение:

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

Если вы еще не почувствовали головокружение, как я, и прошли через этот лабиринт определений, вы, вероятно, заметили, что это кошмар, чтобы извлечь старый добрый стиль пунктирной строки IP-адреса, так как раньше было гораздо проще использовать GetAdaptersInfo () .

У меня такой вопрос: существует ли действительно функция IP Helper, которая может конвертировать IP_ADAPTER_UNICAST_ADDRESS в строку с точками IPv4 (или строку IPv6)?

Ответы [ 3 ]

6 голосов
/ 21 октября 2010

Вы можете использовать GetIpAddrTable - возвращаемая структура данных содержит DWORD dwAddr, который является IPv4-адресом.Пример кода на этой первой ссылке должен показать вам, что вы хотите.Краткая выдержка, чтобы показать вам, что я имею в виду:

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

IP_ADAPTER_UNICAST_ADDRESS содержит SOCKET_ADDRESS в Address, который, в свою очередь, содержит LPSOCKADDR в lpSockAddr - вы можете преобразовать это в ipv4строковая форма с использованием WSAAddressToString .

4 голосов
/ 27 ноября 2012

Ознакомьтесь с документацией для SOCKADDR .Это приводит нас к документации для SOCKADDR_STORAGE , которая является вспомогательной структурой для IPv4 и IPv6.

Цитата из документации sockaddr:

Функции Winsock с использованиемsockaddr не строго интерпретируется как указатель на структуру sockaddr.Структура интерпретируется по-разному в контексте разных семейств адресов.

Для ipv4 вы можете привести указатель sockaddr к указателю sockaddr_in, а затем получить доступ к информации об адресе IPv4 оттуда.Затем вы можете использовать ваш любимый построитель строк для создания строки в формате точечных квадратов.

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

Я мог бы представить, что вы также можете привести адрес для ipv6 аналогичным образом, учитывая определения структуры (скопировано ниже).

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;
};
0 голосов
/ 20 марта 2018

Вы можете просто передать _SOCKET_ADDRESS.lpSockaddr и _SOCKET_ADDRESS.iSockaddrLength как lpsaAddress и dwAddressLength аргументы функции WSAAddressToString. WSAAddressToString сделает необходимое преобразование для вас, не нужно копать глубже.

function SOCKET_ADDRESS_ToString(const Addr: SOCKET_ADDRESS): String;
var
  Len: DWORD;
begin
  if (Addr.lpSockaddr = nil) or (Addr.iSockaddrLength <= 0) then
  begin
    Result := '';
    Exit;
  end;
  Len := 0;
  WSAAddressToString(Addr.lpSockaddr, Addr.iSockaddrLength, nil, nil, Len);
  SetLength(Result, Len);
  if WSAAddressToString(Addr.lpSockaddr, Addr.iSockaddrLength, nil, PChar(Result), Len) = 0 then
    SetLength(Result, Len - 1)
  else
    Result := '';
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...