package  net 
 
import  ( 
	"errors"  
	"internal/bytealg"  
	"io/fs"  
	"net/netip"  
	"sync"  
	"time"  
) 
 
const  cacheMaxAge = 5  * time .Second  
 
func  parseLiteralIP(addr  string ) string  { 
	ip , err  := netip .ParseAddr (addr ) 
	if  err  != nil  { 
		return  ""  
	} 
	return  ip .String () 
} 
 
type  byName struct  { 
	addrs         []string  
	canonicalName string  
} 
 
 
var  hosts struct  { 
	sync .Mutex  
 
	 
 
 
 
	byName map [string ]byName  
 
	 
 
 
	byAddr map [string ][]string  
 
	expire time .Time  
	path   string  
	mtime  time .Time  
	size   int64  
} 
 
func  readHosts() { 
	now  := time .Now () 
	hp  := testHookHostsPath  
 
	if  now .Before (hosts .expire ) && hosts .path  == hp  && len (hosts .byName ) > 0  { 
		return  
	} 
	mtime , size , err  := stat (hp ) 
	if  err  == nil  && hosts .path  == hp  && hosts .mtime .Equal (mtime ) && hosts .size  == size  { 
		hosts .expire  = now .Add (cacheMaxAge ) 
		return  
	} 
 
	hs  := make (map [string ]byName ) 
	is  := make (map [string ][]string ) 
 
	file , err  := open (hp ) 
	if  err  != nil  { 
		if  !errors .Is (err , fs .ErrNotExist ) && !errors .Is (err , fs .ErrPermission ) { 
			return  
		} 
	} 
 
	if  file  != nil  { 
		defer  file .close () 
		for  line , ok  := file .readLine (); ok ; line , ok  = file .readLine () { 
			if  i  := bytealg .IndexByteString (line , '#' ); i  >= 0  { 
				 
				line  = line [0 :i ] 
			} 
			f  := getFields (line ) 
			if  len (f ) < 2  { 
				continue  
			} 
			addr  := parseLiteralIP (f [0 ]) 
			if  addr  == ""  { 
				continue  
			} 
 
			var  canonical  string  
			for  i  := 1 ; i  < len (f ); i ++ { 
				name  := absDomainName (f [i ]) 
				h  := []byte (f [i ]) 
				lowerASCIIBytes (h ) 
				key  := absDomainName (string (h )) 
 
				if  i  == 1  { 
					canonical  = key  
				} 
 
				is [addr ] = append (is [addr ], name ) 
 
				if  v , ok  := hs [key ]; ok  { 
					hs [key ] = byName { 
						addrs :         append (v .addrs , addr ), 
						canonicalName : v .canonicalName , 
					} 
					continue  
				} 
 
				hs [key ] = byName { 
					addrs :         []string {addr }, 
					canonicalName : canonical , 
				} 
			} 
		} 
	} 
	 
	hosts .expire  = now .Add (cacheMaxAge ) 
	hosts .path  = hp  
	hosts .byName  = hs  
	hosts .byAddr  = is  
	hosts .mtime  = mtime  
	hosts .size  = size  
} 
 
 
func  lookupStaticHost(host  string ) ([]string , string ) { 
	hosts .Lock () 
	defer  hosts .Unlock () 
	readHosts () 
	if  len (hosts .byName ) != 0  { 
		if  hasUpperCase (host ) { 
			lowerHost  := []byte (host ) 
			lowerASCIIBytes (lowerHost ) 
			host  = string (lowerHost ) 
		} 
		if  byName , ok  := hosts .byName [absDomainName (host )]; ok  { 
			ipsCp  := make ([]string , len (byName .addrs )) 
			copy (ipsCp , byName .addrs ) 
			return  ipsCp , byName .canonicalName  
		} 
	} 
	return  nil , ""  
} 
 
 
func  lookupStaticAddr(addr  string ) []string  { 
	hosts .Lock () 
	defer  hosts .Unlock () 
	readHosts () 
	addr  = parseLiteralIP (addr ) 
	if  addr  == ""  { 
		return  nil  
	} 
	if  len (hosts .byAddr ) != 0  { 
		if  hosts , ok  := hosts .byAddr [addr ]; ok  { 
			hostsCp  := make ([]string , len (hosts )) 
			copy (hostsCp , hosts ) 
			return  hostsCp  
		} 
	} 
	return  nil  
} 
  
The pages are generated with Golds   v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds  is a Go 101  project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1  (reachable from the left QR code) to get the latest news of Golds .