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