Получение неправильных 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)