github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/utils/fqdn/fqdn.go (about) 1 package fqdn 2 3 import ( 4 "net" 5 "os" 6 "strings" 7 "sync" 8 ) 9 10 // defining os and net package functions in their own variables 11 // so that we can mock them for unit tests 12 var ( 13 osHostname = os.Hostname 14 netLookupIP = net.LookupIP 15 netLookupAddr = net.LookupAddr 16 ) 17 18 const unknownHostname = "unknown" 19 20 // InitializeAlternativeHostname can be used to set an alternative hostname that is being used by `FindFQDN`. 21 // The enforcer can use this during startup to provide an alternative value. 22 func InitializeAlternativeHostname(hostname string) { 23 if hostname != "" { 24 alternativeHostnameOnce.Do(func() { 25 alternativeHostnameLock.Lock() 26 27 alternativeHostname = hostname 28 29 alternativeHostnameLock.Unlock() 30 }) 31 } 32 } 33 34 func getAlternativeHostname() string { 35 alternativeHostnameLock.RLock() 36 defer alternativeHostnameLock.RUnlock() 37 return alternativeHostname 38 } 39 40 var ( 41 alternativeHostnameOnce = &sync.Once{} 42 alternativeHostnameLock sync.RWMutex 43 alternativeHostname string 44 ) 45 46 // Find returns fqdn. It uses the following algorithm: 47 // First of all, it will return the globally set alternative hostname if it has been initialized with previously with `IntializeAlternativeHostname` 48 // If this is not set, it will try to determine the hostname, resolve the hostname to an IP, 49 // and based on the hostname it will perform a reverse DNS lookup for the IP. 50 // The first entry of the reverse DNS lookup will be returned. 51 // If there are any errors during this process, this function will return "unknown". 52 // It will never return an empty string. 53 func Find() string { 54 // return with the global alternative hostname if this is what we really want to do 55 alternativeHostname := getAlternativeHostname() 56 if alternativeHostname != "" { 57 return alternativeHostname 58 } 59 60 // for some cloud providers (like AWS at some point) we prefer different FQDNs 61 // return with th 62 63 hostnameRaw, err := osHostname() 64 if err != nil { 65 return unknownHostname 66 } 67 68 // net.LookupIP will actually error if hostname is empty 69 // so if there is no hostname set in the kernel, also return unknown 70 // as in all other error cases we want to return a valid string 71 // make sure that it is set to either os.Hostname or "unknown", but is never empty 72 hostname := hostnameRaw 73 if hostnameRaw == "" { 74 hostname = unknownHostname 75 } 76 77 addrs, err := netLookupIP(hostnameRaw) 78 if err != nil { 79 return hostname 80 } 81 82 for _, addr := range addrs { 83 if ipv4 := addr.To4(); ipv4 != nil { 84 ip, err := ipv4.MarshalText() 85 if err != nil { 86 // impossible case and only possible if there is a bug in golang: 87 // this will only error if this is not a valid IP address 88 // To4() already proves that 89 continue 90 } 91 hosts, err := netLookupAddr(string(ip)) 92 if err != nil || len(hosts) == 0 { 93 continue 94 } 95 fqdn := hosts[0] 96 ret := strings.TrimSuffix(fqdn, ".") // return fqdn without trailing dot 97 if ret != "" { 98 return ret 99 } 100 } 101 if ipv6 := addr.To16(); ipv6 != nil { 102 ip, err := ipv6.MarshalText() 103 if err != nil { 104 // impossible case and only possible if there is a bug in golang: 105 // this will only error if this is not a valid IP address 106 // To16() already proves that 107 continue 108 } 109 hosts, err := netLookupAddr(string(ip)) 110 if err != nil || len(hosts) == 0 { 111 continue 112 } 113 fqdn := hosts[0] 114 ret := strings.TrimSuffix(fqdn, ".") // return fqdn without trailing dot 115 if ret != "" { 116 return ret 117 } 118 } 119 } 120 121 // fall back to os.Hostname or unknown if none of that worked 122 return hostname 123 }