Delphi 中的 TCP netstat ipv4/ipv6

TCP netstat ipv4/ipv6 in Delphi

我正在尝试 "reproduce" Delphi 的 netstat 并遇到了一些问题:

到目前为止,这是我的代码:

program NetstatExample;

{$APPTYPE CONSOLE}

uses
  Windows,
  Winsock2;

const
  TCP_TABLE_OWNER_PID_ALL = 5;
  ANY_SIZE                = 1;

type
  TCP_TABLE_CLASS = Integer;

  in6_addr = record
    case Integer of
      0: (Byte: array [0..15] of u_char);
      1: (Word: array[0..7] of u_short);
      2: (s6_bytes: array [0..15] of u_char);
      3: (s6_addr: array [0..15] of u_char);
      4: (s6_words: array[0..7] of u_short);
  end;
  TIn6Addr = in6_addr;
  PIn6Addr = ^in6_addr;

  PTMib_TCP6Row = ^TMib_TCP6Row;
  TMib_TCP6Row = packed record
    LocalAddr       : IN6_ADDR    ;
    dwLocalScopeId  : DWORD       ;
    dwLocalPort     : DWORD       ;
    RemoteAddr      : IN6_ADDR    ;
    dwRemoteScopeId : DWORD       ;
    dwRemotePort    : DWORD       ;
    dwState         : DWORD       ;
    dwProcessId     : DWORD       ;
  end;

  PTMIB_TCP6TABLE = ^TMIB_TCP6TABLE;
  TMIB_TCP6TABLE = record
    dwNumEntries : DWORD;
    Table: array[0..ANY_SIZE - 1] of TMib_TCP6Row;
  end;

var
  GetExtendedTcpTable   : function (pTcpTable: Pointer; dwSize: PDWORD; bOrder: BOOL; lAf: ULONG; TableClass: TCP_TABLE_CLASS; Reserved: ULONG): DWord; stdcall;

  iphHandle             : HMODULE;
  TableSize             : DWORD;
  TCPTable              : PTMIB_TCP6TABLE;
  I                     : Integer;

begin
  try
    iphHandle := LoadLibrary('iphlpapi.dll');
    if iphHandle = 0 then Exit;
    GetExtendedTcpTable := GetProcAddress(iphHandle, 'GetExtendedTcpTable');
    if @GetExtendedTcpTable = NIL then Exit;
    if GetExtendedTcpTable(nil, @TableSize, False, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0) <> ERROR_INSUFFICIENT_BUFFER then Exit;
    GetMem(TCPTable, TableSize);
    try
      if GetExtendedTcpTable(TCPTable, @TableSize, False, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0) <> NO_ERROR then Exit;
      for I := 0 to TCPTable^.dwNumEntries - 1 do
      begin
        // Detect AF_INET6 and/or AF_INET4 family
        // Display Remote Address in proper format for each family - XP compatible?!
      end;
    finally
      FreeMem(TCPTable, TableSize);
    end;

  finally
    readln;
  end;
end.

在这里,我使用 AF_INET6 所以我也可以获得 ipv6 连接。

问题是:

  1. 如何安全地区分 ipv4 和 ipv6?
  2. 我怎样才能以正确的格式为两个系列显示远程地址,并且仍然使其与 XP 兼容? (InetNtop 在 Windows XP 中尚不存在)

Q1:您的GetExtendedTcpTable调用了指定地址族中的returns地址,即。如果你传递它 AF_INET6 它只有 returns IPv6 地址,如果你传递它 AF_INET 它只有 returns IPv4 地址。所以没有必要区分,你只是将返回的 table 转换为正确的 table 类型,如文档的备注部分所述(上面链接)。

Q2:这是我的实现(我希望它是正确的):

function AddrStr(Addr: Cardinal): string;
var
  P: PAnsiChar;
begin
  P := inet_ntoa(PInAddr(@Addr)^);
  SetString(Result, P, StrLen(P));
end;

function Addr6Str(const Addr: IN6_ADDR): string;
var
  I: Integer;
begin
  Result := '';

  for I := 0 to 7 do
  begin
    if Result <> '' then
      Result := Result + ':';
    Result := Result + LowerCase(IntToHex(ntohs(Addr.Word[I]), 1));
  end;
  Result := '[' + Result + ']';
end;

...或查看 Free Pascal 的套接字单元,NetAddrToStr and NetAddrToStr6