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  }