+  {$ifdef mswindows}windows,{$endif}\r
+  {$ifdef unix}unix,{$endif}  \r
+  lcorelocalips,\r
+  readtxt2,\r
+  ltimevalstuff,\r
+  sysutils;\r
+\r
+type\r
+  pbiniplist=^tbiniplist;\r
+  thostsfile_entry=record\r
+    l:tbiniplist;\r
+  end;\r
+  phostsfile_entry=^thostsfile_entry;\r
+\r
+  thostsfile_reverseentry=record\r
+    name:ansistring;\r
+  end;\r
+  phostsfile_reverseentry=^thostsfile_reverseentry;\r
+\r
+\r
+function hostsfile_findbyname(const name:ansistring):integer;\r
+begin\r
+  if not hostsfile_entries.Find(name,result) then begin\r
+    if (copy(name,length(name),1) = '.') then begin\r
+      //if the name has a trailing dot, try to find without it\r
+      if not hostsfile_entries.Find(copy(name,1,length(name)-1),result) then result := -1;\r
+    end else begin\r
+      //if the name has no trailing dot, try to find with it\r
+      if not hostsfile_entries.Find(name + '.',result) then result := -1;\r
+    end;\r
+  end;\r
+end;\r
+\r
+\r
+function hostsfile_forwardlookuplist(const name:ansistring):tbiniplist;\r
+var\r
+  index:integer;\r
+  l:tbiniplist;\r
+begin\r
+  hostsfile_init;\r
+  index := hostsfile_findbyname(name);\r
+\r
+  result := biniplist_new;\r
+\r
+  if (index >= 0) then begin\r
+    l := phostsfile_entry(hostsfile_entries.objects[index]).l;\r
+\r
+    {$ifdef ipv6}\r
+    if (useaf <> useaf_v6) and (useaf <> useaf_preferv6) then\r
+    {$endif}\r
+    begin\r
+      addipsoffamily(result,l,af_inet);\r
+    end;\r
+    {$ifdef ipv6}\r
+    if (useaf <> useaf_v4) then begin\r
+      addipsoffamily(result,l,af_inet6);\r
+      if (useaf = useaf_preferv6) then begin\r
+        addipsoffamily(result,l,af_inet);\r
+      end;\r
+    end;\r
+    {$endif}\r
+  end;\r
+end;\r
+\r
+procedure hostsfile_clearreverse;\r
+var\r
+  index:integer;\r
+begin\r
+  for index := hostsfile_reverseentries.count-1 downto 0 do begin\r
+    phostsfile_reverseentry(hostsfile_reverseentries.objects[index]).name := '';\r
+    dispose(phostsfile_reverseentry(hostsfile_reverseentries.objects[index]));\r
+  end;\r
+  hostsfile_reverseentries.clear;\r
+end;\r
+\r
+\r
+procedure hostsfile_initreverse;\r
+var\r
+  index,index2:integer;\r
+  l:tbiniplist;\r
+  a,countbefore:integer;\r
+  ip:tbinip;\r
+  s:ansistring;\r
+  he:phostsfile_reverseentry;\r
+begin\r
+  hostsfile_init;\r
+  if hostsfile_reverseinited then exit;\r
+  hostsfile_reverseinited := true;\r
+\r
+  hostsfile_clearreverse;\r
+\r
+  //build fast search table for reverse lookups\r
+  for index := hostsfile_entries.count-1 downto 0 do begin\r
+    l := phostsfile_entry(hostsfile_entries.objects[index]).l;\r
+    for a := biniplist_getcount(l)-1 downto 0 do begin\r
+      ip := biniplist_get(l,a);\r
+      s := ipbintostr(ip);\r
+\r
+      countbefore := hostsfile_reverseentries.count;\r
+      index2 := hostsfile_reverseentries.Add(s);\r
+      if (hostsfile_reverseentries.count > countbefore) then begin\r
+        new(he);\r
+        hostsfile_reverseentries.objects[index2] := tobject(he);\r
+        he.name := hostsfile_entries[index];\r
+      end;\r
+\r
+    end;\r
+  end;\r
+end;\r
+\r
+function hostsfile_reverselookup(ip:tbinip):ansistring;\r
+var\r
+  index:integer;\r
+  s:ansistring;\r
+begin\r
+  hostsfile_initreverse;\r
+  result := '';\r
+  s := ipbintostr(ip);\r
+\r
+  if hostsfile_reverseentries.find(s,index) then begin\r
+    result := phostsfile_reverseentry(hostsfile_reverseentries.objects[index]).name;\r
+  end;\r
+end;\r
+\r
+procedure hostsfile_clear;\r
+var\r
+  index:integer;\r
+begin\r
+  for index := hostsfile_entries.count-1 downto 0 do begin\r
+    biniplist_free(phostsfile_entry(hostsfile_entries.objects[index]).l);\r
+    dispose(phostsfile_entry(hostsfile_entries.objects[index]));\r
+  end;\r
+  hostsfile_entries.clear;\r
+\r
+  hostsfile_clearreverse;\r
+\r
+  hostsfile_lastfileage := 0;\r
+  hostsfile_lastcheckts := 0;\r
+end;\r
+\r
+procedure hostsfile_add(const name:ansistring;const ip:tbinip);\r
+var\r
+\r
+  a,index,countbefore:integer;\r
+\r
+  ip2:tbinip;\r
+  he:phostsfile_entry;\r
+  l:tbiniplist;\r
+begin\r
+\r
+  countbefore := hostsfile_entries.count;\r
+  //add, with dupignore, will add it if it's not in the list. if it is in the list, it returns the index\r
+  //to know if it was added, see if the count went up. this saves on duplicate searches in the list, for speed\r
+  index := hostsfile_entries.add(name);\r
+\r
+  if (hostsfile_entries.count > countbefore) then begin\r
+   // writeln('name newly added ',name,' ',ipbintostr(ip),' ',index);\r
+\r
+    new(he);\r
+    hostsfile_entries.objects[index] := tobject(he);\r
+    he.l := biniplist_new;\r
+    //he.name := name;\r
+  end else begin\r
+   // writeln('name found ',name,' ',ipbintostr(ip),' ',index);\r
+    //search for IP match\r
+\r
+    he := phostsfile_entry(hostsfile_entries.objects[index]);\r
+    l := he.l;\r
+    for a := biniplist_getcount(l)-1 downto 0 do begin\r
+      ip2 := biniplist_get(l,a);\r
+      if comparebinip(ip,ip2) then begin\r
+      //  writeln('duplicate ip ',name,' ',ipbintostr(ip));\r
+        exit; //duplicate\r
+      end;\r
+    end;\r
+  end;\r
+  //add it\r
+  biniplist_add(he.l,ip);\r
+end;\r
+\r
+\r
+function getts:integer;\r
+{$ifdef mswindows}\r
+begin\r
+  result := GetTickCount;\r
+{$else}\r
+var\r
+  temp:ttimeval;\r
+begin\r
+  gettimemonotonic(temp);\r
+  result := ((temp.tv_usec div 1000) + (temp.tv_sec * 1000));\r
+{$endif}\r
+end;\r
+\r
+\r
+function gethostsfilename:ansistring;\r
+var\r
+{$ifdef mswindows}\r
+  windir:array [0..255] of ansichar;\r
+\r
+  GetSystemWindowsDirectoryA:function(buffer:pansichar;size:integer):integer; stdcall;\r
+  dllhandle:thandle;\r
+  OsVersion                  : TOSVersionInfo;\r
+{$endif}\r
+  filenamesuffix:ansistring;\r
+begin\r
+    {$ifdef mswindows}\r
+\r
+    ZeroMemory(@OsVersion, SizeOf(OsVersion));\r
+    OsVersion.dwOSVersionInfoSize := SizeOf(TOSVERSIONINFO);\r
+\r
+    if ((GetVersionEx(OsVersion)) and (OsVersion.dwPlatformId = VER_PLATFORM_WIN32_NT)) then begin\r
+      filenamesuffix := '\system32\drivers\etc\hosts';\r
+    end else begin\r
+      filenamesuffix := '\hosts';\r
+    end;\r
+\r
+    //first try "user" windows directory. on a multiuser this may not be c:\windows\r
+    GetWindowsDirectoryA(windir,255);\r
+    result := windir;\r
+    if (copy(result,length(result),1) = '\') then result := copy(result,1,length(result)-1);\r
+    result := result + filenamesuffix;\r
+\r
+    if not fileexists(result) then begin\r
+      //then try "system" windows directory which is typically c:\windows on a multiuser system\r
+      dllhandle := loadlibrary('kernel32.dll');\r
+      if (dllhandle <> 0) then begin\r
+        GetSystemWindowsDirectoryA := getprocaddress(dllhandle,'GetSystemWindowsDirectoryA');\r
+        if assigned(GetSystemWindowsDirectoryA) then begin\r
+          GetSystemWindowsDirectoryA(windir,255);\r
+          freelibrary(dllhandle);\r
+          result := windir;\r
+          if (copy(result,length(result),1) = '\') then result := copy(result,1,length(result)-1);\r
+          result := result + filenamesuffix;\r
+        end;\r
+      end;\r
+    end;\r
+\r
+    {$else}\r
+    result := '/etc/hosts';\r
+    {$endif}\r
+end;\r
+\r
+procedure hostsfile_reload;\r
+label lineend;\r
+var\r
+  t:treadtxt;\r
+\r
+  validchar:array[0..255] of boolean;\r
+  ipv4char:array[0..255] of boolean;\r
+  s:ansistring;\r
+  ch:ansichar;\r
+  a,len,field,startindex,labellen:integer;\r
+  lastwasspace,onlyipv4chars:boolean;\r
+  ipstring,hostname:ansistring;\r
+  biniptemp:tbinip;\r
+begin\r
+  hostsfile_clear;\r
+\r
+  if hostsfile_disabled then exit;\r
+  hostsfile_reverseinited := false;\r
+\r
+  //add builtin entries\r
+  hostsfile_add('localhost',ipstrtobinf('127.0.0.1'));\r
+  {$ifdef ipv6}\r
+  hostsfile_add('localhost',ipstrtobinf('::1'));\r