+\r
+\r
+{$ifdef ipv6}\r
+\r
+{$ifdef linux}\r
+function getv6localips:tbiniplist;\r
+var\r
+ t:textfile;\r
+ s,s2:ansistring;\r
+ ip:tbinip;\r
+ a:integer;\r
+begin\r
+ result := biniplist_new;\r
+\r
+ assignfile(t,'/proc/net/if_inet6');\r
+ {$i-}reset(t);{$i+}\r
+ if ioresult <> 0 then exit; {none found, return empty list}\r
+\r
+ while not eof(t) do begin\r
+ readln(t,s);\r
+ s2 := '';\r
+ for a := 0 to 7 do begin\r
+ if (s2 <> '') then s2 := s2 + ':';\r
+ s2 := s2 + copy(s,(a shl 2)+1,4);\r
+ end;\r
+ ipstrtobin(s2,ip);\r
+ if ip.family <> 0 then biniplist_add(result,ip);\r
+ end;\r
+ closefile(t);\r
+end;\r
+\r
+{$else}\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, getaddrinfo seems unreliable (not working on XP atleast)\r
+}\r
+const\r
+ SIO_ROUTING_INTERFACE_QUERY = $c8000014;\r
+ function WSAIoctl(s: TSocket; code:integer; const Buf; len: Integer; var output; outlen:integer; var outreturned: Integer; overlapped:pointer; completion: pointer): Integer; stdcall; external 'ws2_32.dll' name 'WSAIoctl';\r
+\r
+function getlocalipforip(const ip:tbinip):tbinip;\r
+var\r
+ handle:integer;\r
+ a,b:integer;\r
+ inaddrv,inaddrv2:tinetsockaddrv;\r
+ srcx:winsock.tsockaddr absolute inaddrv2;\r
+begin\r
+ makeinaddrv(ip,'0',inaddrv);\r
+ handle := Socket(inaddrv.inaddr.family,SOCK_DGRAM,IPPROTO_UDP);\r
+ if WSAIoctl(handle, SIO_ROUTING_INTERFACE_QUERY, inaddrv, sizeof(inaddrv), inaddrv2, sizeof(inaddrv2), a, nil, nil) <> 0\r
+ then raise exception.create('getlocalipforip failed with error: '+inttostr(wsagetlasterror));\r
+ result := inaddrvtobinip(inaddrv2);\r
+ closesocket(handle);\r
+end;\r
+\r
+function getv6localips:tbiniplist;\r
+begin\r
+ result := biniplist_new;\r
+ {this IP is chosen because it's the first normal global v6 IP that has no special purpose}\r
+ biniplist_add(result,getlocalipforip(ipstrtobinf('2001:200::')));\r
+end;\r
+{$endif}\r
+\r
+procedure initpreferredmode;\r
+var\r
+ l:tbiniplist;\r
+ a:integer;\r
+ ip:tbinip;\r
+ ipmask_global,ipmask_6to4,ipmask_teredo:tbinip;\r
+\r
+begin\r
+ if preferredmodeinited then exit;\r
+ if useaf <> useaf_default then exit;\r
+ l := getv6localips;\r
+ if biniplist_getcount(l) = 0 then exit;\r
+ useaf := useaf_preferv4;\r
+ ipstrtobin('2000::',ipmask_global);\r
+ ipstrtobin('2001::',ipmask_teredo);\r
+ ipstrtobin('2002::',ipmask_6to4);\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 comparebinipmask(ip,ipmask_global,3) then continue;\r
+ if comparebinipmask(ip,ipmask_teredo,32) then continue;\r
+ if comparebinipmask(ip,ipmask_6to4,16) then continue;\r
+ useaf := useaf_preferv6;\r
+ preferredmodeinited := true;\r
+ exit;\r
+ end;\r
+end;\r
+\r
+{$endif}\r
+\r
+\r