X-Git-Url: http://www.lcore.org/git/lcore.git/blobdiff_plain/3ac664ec654230b9ad26ab12242c1db6f636a26f..HEAD:/lcorelocalips.pas?ds=inline

diff --git a/lcorelocalips.pas b/lcorelocalips.pas
index ae2a00b..710fbfa 100644
--- a/lcorelocalips.pas
+++ b/lcorelocalips.pas
@@ -36,7 +36,9 @@ notes:
 }
 
 unit lcorelocalips;
-
+{$ifdef fpc}
+  {$mode delphi}
+{$endif}
 interface
 
 uses binipstuff,pgtypes;
@@ -51,10 +53,16 @@ function getv6localips:tbiniplist;
 
 function getsystemdnsservers:tbiniplist;
 
-{$ifdef win32}
+function have_ipv6_connectivity:boolean;
+
+{$ifdef mswindows}
 function gethostname:ansistring;
+function getlocalipforip(const ip:tbinip):tbinip;
 {$endif}
 
+const
+  v6_check_ip='2001:200::';  //a globally routeable v6 IP that is used in "get local IP for IP" etc, it should never actually be communicated with.
+
 implementation
 
 {$ifdef unix}
@@ -188,7 +196,7 @@ end;
 {$else}
 
 uses
-  sysutils,windows,winsock,dnssync;
+  sysutils,windows,winsock,dnswin;
 
 {the following code's purpose is to determine what IP windows would come from, to reach an IP
 it can be abused to find if there's any global v6 IPs on a local interface}
@@ -255,8 +263,10 @@ function getlocalips:tbiniplist;
 var
   a:integer;
   ip:tbinip;
+  usewindnstemp:boolean;
+  error:integer;
 begin
-  result := forwardlookuplist('',0);
+  result := winforwardlookuplist('',0,error);
 
   {$ifdef ipv6}
 
@@ -268,7 +278,7 @@ begin
   end;
 
   try
-    ip := getlocalipforip(ipstrtobinf('2001:200::'));
+    ip := getlocalipforip(ipstrtobinf(v6_check_ip));
     if (ip.family = AF_INET6) then biniplist_add(result,ip);
   except
   end;
@@ -282,7 +292,7 @@ end;
 
 
 
-{$ifdef win32}
+{$ifdef mswindows}
   const
     MAX_HOSTNAME_LEN = 132;
     MAX_DOMAIN_NAME_LEN = 132;
@@ -348,7 +358,7 @@ end;
 
 function getsystemdnsservers:tbiniplist;
 var
-  {$ifdef win32}
+  {$ifdef mswindows}
     fixed_info : pfixed_info;
     currentdnsserver : pip_addr_string;
   {$else}
@@ -362,7 +372,7 @@ begin
 
   result := biniplist_new;
 
-  {$ifdef win32}
+  {$ifdef mswindows}
     fixed_info := callgetnetworkparams;
     if fixed_info = nil then exit;
 
@@ -398,7 +408,55 @@ begin
   {$endif}
 end;
 
-{$ifdef win32}
+
+function have_ipv6_connectivity:boolean;
+var
+  l:tbiniplist;
+  a:integer;
+  ip:tbinip;
+  ipmask_global,ipmask_6to4,ipmask_teredo:tbinip;
+
+function ip_is_suitable_v6:boolean;
+begin
+  result := false;
+  if (ip.family <> AF_INET6) then exit;
+  if not comparebinipmask(ip,ipmask_global,3) then exit;
+  if comparebinipmask(ip,ipmask_teredo,32) then exit;
+  if comparebinipmask(ip,ipmask_6to4,16) then exit;
+  result := true;
+end;
+
+begin
+  result := false;
+
+  ipstrtobin('2000::',ipmask_global);
+  ipstrtobin('2001::',ipmask_teredo);
+  ipstrtobin('2002::',ipmask_6to4);
+
+  {$ifdef mswindows}
+  //better way on windows to check for ipv6 that works (returns no ipv6) if a v6 IP is assigned, but there is no connectivity
+  try
+    ip := getlocalipforip(ipstrtobinf(v6_check_ip));
+    if ip_is_suitable_v6 then result := true;
+  except
+  end;
+  {$else} {unix}
+
+  l := getv6localips;
+  if biniplist_getcount(l) = 0 then exit;
+
+  {if there is any v6 IP which is globally routable and not 6to4 and not teredo, prefer v6}
+  for a := biniplist_getcount(l)-1 downto 0 do begin
+    ip := biniplist_get(l,a);
+    if not ip_is_suitable_v6 then continue;
+    result := true;
+    exit;
+  end;
+  {$endif}
+end;
+
+
+{$ifdef mswindows}
 function gethostname:ansistring;
 var
     fixed_info : pfixed_info;