Получение неправильных IP-адресов

Я пытаюсь автоматически обнаружить и сообщить о доступности IPv6 для программирования сокетов Delphi.

Для "localhost" следующий код возвращает "1700::" для IPv6 и "2.0.0.0" для IPv4. Этот адрес предназначен для простого тестирования и должен возвращать::1 или 127.0.0.1 для моей машины. Я не получаю никаких ошибок API сокетов в вызывающем коде, поэтому я пытаюсь выяснить, что я делаю неправильно, пытаясь преобразовать localhost в различные IP-адреса. Я использую заголовки Indy.

Объявления типа:

TLSocketAddress = record
  case Integer of
    AF_INET:
      (IPv4: TSockAddrIn);
    AF_INET6:
      (IPv6: TSockAddrIn6);
end;

TLIpInfo = record
private
  function GetFamily: TProtocolFamily;
public
  Address : TLSocketAddress;
  HostName: string;
  Machine: string;
  IP6 : string;
  IP4 : string;
  Port : integer;
  Error : integer;
  property Family : TProtocolFamily read GetFamily;
end;

и процедура поиска:

function GetIpInfo(
  const AHostName : string;
  const APort     : integer
  ): TLIpInfo;
var
  nameRet   : PAnsiChar;
  ptr       : Pointer;
  Hints     : TAddrInfoW;
  AddrInfo  : PAddrInfoW;
  NextInfo  : PAddrInfoW;
  RetVal    : Integer;
  ip,
  machine   : string;
  namelen   : integer;
begin
  ZeroMemory(@Result, SizeOf(Result));
  FillChar(Hints, SizeOf(Hints), 0);
  Hints.ai_family := AF_UNSPEC;

  AddrInfo := nil;
  RetVal := GetAddrInfo(PWideChar(AHostName), nil, @Hints, @AddrInfo);
  if RetVal = 0 then
  try
    Result.HostName := AHostName;
    Result.Port := APort;
    NextInfo := AddrInfo;
    while NextInfo <> nil do
    begin
      if (NextInfo.ai_family = AF_INET) or (NextInfo.ai_family = AF_INET6) then
      begin
        if (Result.Machine = '') then
        begin
          SetLength(machine, NI_MAXHOST);
          RetVal := GetNameInfo(NextInfo.ai_addr, NextInfo.ai_addrlen,
            PChar(machine), NI_MAXHOST, nil, 0, 0);
          if (RetVal <> 0) then
          begin
            NextInfo := NextInfo.ai_next;
            continue;
          end;
          Result.Machine := PChar(machine);
        end;

        if NextInfo.ai_family = AF_INET then
        begin
          ptr := PSockAddrIn(NextInfo.ai_addr);
          namelen := INET_ADDRSTRLEN;
          SetLength(ip, namelen);
        end
        else
        begin
          ptr := PSockAddrIn6(NextInfo.ai_addr);
          namelen := INET6_ADDRSTRLEN;
          SetLength(ip, namelen);
        end;

        nameRet := inet_ntop(NextInfo.ai_family, ptr, PChar(ip), namelen);
        if (nameRet = nil) then
        begin
          NextInfo := NextInfo.ai_next;
          continue;
        end;

        if (NextInfo.ai_family = AF_INET6) then
          Result.IP6 := PChar(ip)
        else
          Result.IP4 := PChar(ip);
      end;
      NextInfo := NextInfo.ai_next;
    end;
  finally
    FreeAddrInfo(AddrInfo);
  end;
end;

1 ответ

Я знаю, что это может быть слишком поздно для автора, но я боролся сегодня с той же проблемой и заметил, что вы передаете указатель на всю структуру ADDRINFO в inet_ntop, однако вы должны только передавать указатель на двоичный адрес.
Так что вызов intet_ntop для адресов IPv4 должен быть:

inet_ntop(NextInfo.ai_family, @PSockAddrIn(NextInfo.ai_addr).sin_addr, PChar(ip), namelen)

а для IPv6 должно быть:

inet_ntop(NextInfo.ai_family, @PSockAddrIn6(NextInfo.ai_addr).sin6_addr, PChar(ip), namelen)
Другие вопросы по тегам