从 GetAdaptersAddresses() 获取 IP_ADDRESS_STRING?

发布于 2024-09-28 15:21:18 字数 1649 浏览 2 评论 0原文

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< /a>

如果您还没有像我一样感到头晕,并遵循了这个迷宫般的定义,您可能会注意到检索 IP 地址的老式点分字符串样式是一场噩梦,因为它过去使用起来要容易得多GetAdaptersInfo()

我的问题是:是否有一个真正的 IP Helper 函数可以将 IP_ADAPTER_UNICAST_ADDRESS 转换为 IPv4 点字符串(或 IPv6 字符串)?

GetAdaptersAddresses() will get you addresses in IP_ADAPTER_UNICAST_ADDRESS format, which is defined as:

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;

The only field that seems to suggest the human-readable IP address string is Address, which is a SOCKET_ADDRESS structure defined as:

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

Which, in turn, uses another structure, SOCKADDR, defined as:

Sorry, it's way to complex to post here, as it varies depending on IPv4 vs. IPv6 and the Windows edition... so here is a link to the definition:

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

If you haven't gotten dizzy yet like I did and followed through this maze of definitions, you probably noticed that it's a nightmare to retrieve the good old dotted string style of an IP address, as it used to be much easier using GetAdaptersInfo().

My question is: Is there a truly IP Helper function that can convert IP_ADAPTER_UNICAST_ADDRESS to an IPv4 dotted string (or an IPv6 string)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

方圜几里 2024-10-05 15:21:19

您只需将 _SOCKET_ADDRESS.lpSockaddr_SOCKET_ADDRESS.iSockaddrLength 作为 lpsaAddressdwAddressLength 参数传递给 WSAddressToString 函数。 WSAddressToString 将为您进行必要的转换,无需深入挖掘。

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;

You can simply pass _SOCKET_ADDRESS.lpSockaddr and _SOCKET_ADDRESS.iSockaddrLength as lpsaAddress and dwAddressLength arguments to WSAAddressToString function. WSAAddressToString will do necessary conversion for you, no need to dig deeper.

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;
愛放△進行李 2024-10-05 15:21:18

您可以使用 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_ADDRESSAddress 中包含一个 SOCKET_ADDRESS,而后者又包含一个 LPSOCKADDR > 在 lpSockAddr 中 - 您可以使用 WSAddressToString

You can use GetIpAddrTable - the returned data structure contains a DWORD dwAddr that is the IPv4 address. The sample code on that first link should show you what you want. Brief excerpt to show you what I mean:

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

The IP_ADAPTER_UNICAST_ADDRESS contains a SOCKET_ADDRESS in Address, which in turn contains a LPSOCKADDR in lpSockAddr - you can convert this to the ipv4 string form using WSAAddressToString.

年华零落成诗 2024-10-05 15:21:18

查看 的文档SOCKADDR。这引导我们查看 的文档SOCKADDR_STORAGE,它是 IPv4 和 IPv6 的辅助结构。

引用 sockaddr 文档:

使用 sockaddr 的 Winsock 函数没有严格解释
指向 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;
};

Take a look at the documentation for SOCKADDR. That leads us to the documentation for SOCKADDR_STORAGE, which is a helper struct for both IPv4 and IPv6.

Quote from the sockaddr documentation:

Winsock functions using sockaddr are not strictly interpreted to be
pointers to a sockaddr structure. The structure is interpreted
differently in the context of different address families.

For ipv4, you can cast a sockaddr pointer to a sockaddr_in pointer and then access the IPv4 address information from there. Then you can use your favorite string builder to produce a dotted-quad formatted string.

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

I would imagine that you can also cast the address for ipv6 in a similar way given the struct definitions (copied below).

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;
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文