I need to get the IP6-Address that has PrefixOrigin = IpPrefixOriginDhcp.
https://learn.microsoft.com/en-us/windows-hardware/drivers/network/nl-prefix-origin
AFAIK there's no way to achieve that with GStack.GetLocalAddressList, as it does not return the prefixes.
As a workaround I modified GetLocalAddressesByAdaptersAddresses in IdStackWindows.pas ( XXXX marked)
by using the global variable gIndyIP6FilterPrefixOrigin
But it would be wiser to pass that as an additional GetLocalAddressList-parameter.
Could this be implemented?
In the meantime is there a way to add that filter without modifying the original Indy source?
I tried a class helper but that does not give access to the local variables (in the 'implement' section)
.
IdStackWindows.pas modifications: ( XXXX marked)
global variable defined in IdStackWindows.pas: (and set by my application)
gIndyIP6FilterPrefixOrigin: integer = -1; // -1 : no filter XXXX
function GetLocalAddressesByAdaptersAddresses: Boolean;
var
Ret: DWORD;
BufLen: ULONG;
Adapter, Adapters: PIP_ADAPTER_ADDRESSES;
UnicastAddr: PIP_ADAPTER_UNICAST_ADDRESS;
IPAddr: string;
SubNetStr: String;
SubNetMasks: TStringList;
begin
// assume True unless ERROR_NOT_SUPPORTED is reported...
Result := True;
// MSDN says:
// The recommended method of calling the GetAdaptersAddresses function is
// to pre-allocate a 15KB working buffer pointed to by the AdapterAddresses
// parameter. On typical computers, this dramatically reduces the chances
// that the GetAdaptersAddresses function returns ERROR_BUFFER_OVERFLOW,
// which would require calling GetAdaptersAddresses function multiple times.
BufLen := 1024*15;
GetMem(Adapters, BufLen);
try
repeat
// TODO: include GAA_FLAG_INCLUDE_PREFIX on XPSP1+?
// TODO: include GAA_FLAG_INCLUDE_ALL_INTERFACES on Vista+?
Ret := GetAdaptersAddresses(PF_UNSPEC, GAA_FLAG_SKIP_ANYCAST or GAA_FLAG_SKIP_MULTICAST or GAA_FLAG_SKIP_DNS_SERVER or GAA_FLAG_SKIP_FRIENDLY_NAME, nil, Adapters, BufLen);
case Ret of
ERROR_SUCCESS:
begin
// Windows CE versions earlier than 4.1 may return ERROR_SUCCESS and
// BufLen=0 if no adapter info is available, instead of returning
// ERROR_NO_DATA as documented...
if BufLen = 0 then begin
Exit;
end;
Break;
end;
ERROR_NOT_SUPPORTED:
begin
Result := False;
Exit;
end;
ERROR_NO_DATA,
ERROR_ADDRESS_NOT_ASSOCIATED:
Exit;
ERROR_BUFFER_OVERFLOW:
ReallocMem(Adapters, BufLen);
else
SetLastError(Ret);
IndyRaiseLastError;
end;
until False;
if Ret = ERROR_SUCCESS then
begin
SubNetMasks := nil;
try
AAddresses.BeginUpdate;
try
Adapter := Adapters;
repeat
if (Adapter.IfType <> IF_TYPE_SOFTWARE_LOOPBACK) and
((Adapter.Flags and IP_ADAPTER_RECEIVE_ONLY) = 0) then
begin
UnicastAddr := Adapter^.FirstUnicastAddress;
while UnicastAddr <> nil do
begin
if UnicastAddr^.DadState = IpDadStatePreferred then
begin
case UnicastAddr^.Address.lpSockaddr.sin_family of
AF_INET:
if (gIndyIP6FilterPrefixOrigin < 0) then // XXXX ignore IP4 entries when IP6-filter is actice
begin
IPAddr := TranslateTInAddrToString(PSockAddrIn(UnicastAddr^.Address.lpSockaddr)^.sin_addr, Id_IPv4);
// The OnLinkPrefixLength member is only available on Windows Vista and later
if IndyCheckWindowsVersion(6) then begin
SubNetStr := IPv4MaskLengthToString(UnicastAddr^.OnLinkPrefixLength);
end else
begin
// TODO: on XP SP1+, can the subnet mask be determined
// by analyzing the Adapter's Prefix list without resorting
// to reading the Registry?
if SubNetMasks = nil then
begin
SubNetMasks := TStringList.Create;
GetIPv4SubNetMasks(SubNetMasks);
end;
SubNetStr := SubNetMasks.Values[IPAddr];
end;
TIdStackLocalAddressIPv4.Create(AAddresses, IPAddr, SubNetStr);
end;
AF_INET6: begin
if (gIndyIP6FilterPrefixOrigin < 0) or (gIndyIP6FilterPrefixOrigin= ord(UnicastAddr^.PrefixOrigin) ) then // XXXX
TIdStackLocalAddressIPv6.Create(AAddresses, TranslateTInAddrToString(PSockAddrIn6(UnicastAddr^.Address.lpSockaddr)^.sin6_addr, Id_IPv6));
end;
end;
end;
UnicastAddr := UnicastAddr^.Next;
end;
end;
Adapter := Adapter^.Next;
until Adapter = nil;
finally
AAddresses.EndUpdate;
end;
finally
SubNetMasks.Free;
end;
end;
finally
FreeMem(Adapters);
end;
end;
.
using that in my application:
function GetAllAdaptors(onlyIP6dhpc: boolean=false) : string;
const
// IdStackWindows IP6 IpPrefixOrigin
IP6_FLT_NoFilter = -1;
IP6_FLT_IpPrefixOriginOther = 0;
IP6_FLT_IpPrefixOriginManual = 1;
IP6_FLT_IpPrefixOriginWellKnown= 2;
IP6_FLT_IpPrefixOriginDhcp = 3;
IP6_FLT_IpPrefixOriginRouterAdvertisement= 4;
var
i: integer;
LList: TIdStackLocalAddressList;
PcAdapters: TStringlist;
begin
result:= '';
if onlyIP6dhpc then
IdStackWindows.gIndyIP6FilterPrefixOrigin:= IP6_FLT_IpPrefixOriginDhcp;
PcAdapters:= TStringlist.Create;
LList:= TIdStackLocalAddressList.Create;
try
TIdStack.IncUsage;
try
GStack.GetLocalAddressList(LList);
finally
TIdStack.DecUsage;
end;
IdStackWindows.gIndyIP6FilterPrefixOrigin:= IP6_FLT_NoFilter;
if LList.Count > 0 then
begin
// use reported IP(s) as needed...
for i:= 0 to LList.Count-1 do
if LList.addresses[i].IPVersion = Id_IPv4 then
PcAdapters.Add(LList.addresses[i].IPAddress);
for i:= 0 to LList.Count-1 do
if LList.addresses[i].IPVersion = Id_IPv6 then
PcAdapters.Add(LList.addresses[i].IPAddress);
end
else
begin
// use 127.0.0.1/::1 as needed...
end;
finally
LList.Free;
end;
result:= PcAdapters.text;
PcAdapters.Free;
end;
I need to get the IP6-Address that has PrefixOrigin = IpPrefixOriginDhcp.
https://learn.microsoft.com/en-us/windows-hardware/drivers/network/nl-prefix-origin
AFAIK there's no way to achieve that with GStack.GetLocalAddressList, as it does not return the prefixes.
As a workaround I modified GetLocalAddressesByAdaptersAddresses in IdStackWindows.pas ( XXXX marked)
by using the global variable
gIndyIP6FilterPrefixOriginBut it would be wiser to pass that as an additional GetLocalAddressList-parameter.
Could this be implemented?
In the meantime is there a way to add that filter without modifying the original Indy source?
I tried a class helper but that does not give access to the local variables (in the 'implement' section)
.
IdStackWindows.pas modifications: ( XXXX marked)
.
using that in my application: