From: beware <beware@bircd.org>
Date: Wed, 15 Mar 2023 16:27:46 +0000 (+0000)
Subject: move ipv6 connectivity check from dnscore init to a reusable function in lcorelocalips
X-Git-Url: http://www.lcore.org/git/lcore.git/commitdiff_plain/b60a32da0a15deb572474b1f66a6c63695ed7491?ds=inline

move ipv6 connectivity check from dnscore init to a reusable function in lcorelocalips
---

diff --git a/dnscore.pas b/dnscore.pas
index e38f35f..08f99d1 100644
--- a/dnscore.pas
+++ b/dnscore.pas
@@ -684,31 +684,16 @@ end;
 {$ifdef ipv6}
 
 procedure initpreferredmode;
-var
-  l:tbiniplist;
-  a:integer;
-  ip:tbinip;
-  ipmask_global,ipmask_6to4,ipmask_teredo:tbinip;
-
 begin
   if preferredmodeinited then exit;
   if useaf <> useaf_default then exit;
-  l := getv6localips;
-  if biniplist_getcount(l) = 0 then exit;
-  useaf := useaf_preferv4;
-  ipstrtobin('2000::',ipmask_global);
-  ipstrtobin('2001::',ipmask_teredo);
-  ipstrtobin('2002::',ipmask_6to4);
-  {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 comparebinipmask(ip,ipmask_global,3) then continue;
-    if comparebinipmask(ip,ipmask_teredo,32) then continue;
-    if comparebinipmask(ip,ipmask_6to4,16) then continue;
-    useaf := useaf_preferv6;
-    preferredmodeinited := true;
-    exit;
-  end;
+
+  if (have_ipv6_connectivity) then
+    useaf := useaf_preferv6
+  else
+    useaf := useaf_preferv4;
+
+  preferredmodeinited := true;
 end;
 
 {$endif}
diff --git a/lcorelocalips.pas b/lcorelocalips.pas
index edd306c..710fbfa 100644
--- a/lcorelocalips.pas
+++ b/lcorelocalips.pas
@@ -53,10 +53,16 @@ function getv6localips:tbiniplist;
 
 function getsystemdnsservers:tbiniplist;
 
+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}
@@ -272,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;
@@ -402,6 +408,54 @@ begin
   {$endif}
 end;
 
+
+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
@@ -419,4 +473,3 @@ end;
 {$endif}
 
 end.
-