hostname.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #include <util/memory/tempbuf.h>
  2. #include <util/generic/singleton.h>
  3. #include <util/generic/yexception.h>
  4. #include <util/network/ip.h>
  5. #if defined(_unix_)
  6. #include <unistd.h>
  7. #include <ifaddrs.h>
  8. #include <netdb.h>
  9. #endif
  10. #if defined(_win_)
  11. #include <WinSock2.h>
  12. #endif
  13. #include "defaults.h"
  14. #include "yassert.h"
  15. #include "hostname.h"
  16. namespace {
  17. struct THostNameHolder {
  18. inline THostNameHolder() {
  19. TTempBuf hostNameBuf;
  20. if (gethostname(hostNameBuf.Data(), hostNameBuf.Size() - 1)) {
  21. ythrow TSystemError() << "can not get host name";
  22. }
  23. HostName = hostNameBuf.Data();
  24. }
  25. TString HostName;
  26. };
  27. struct TFQDNHostNameHolder {
  28. inline TFQDNHostNameHolder() {
  29. char buf[1024];
  30. memset(buf, 0, sizeof(buf));
  31. int res = gethostname(buf, sizeof(buf) - 1);
  32. if (res) {
  33. ythrow TSystemError() << "can not get hostname";
  34. }
  35. #ifdef _darwin_
  36. // On Darwin gethostname returns fqdn, see hostname.c in shell_cmds:
  37. // https://github.com/apple-oss-distributions/shell_cmds/blob/main/hostname/hostname.c
  38. // There are macs in the wild that don't have fqdn hostnames, but
  39. // which have search domains in their resolv.conf, so any attempt to
  40. // resolve AI_CANONNAME for the short hostname will result in the
  41. // EAI_NONAME error.
  42. // It seems using gethostname is enough to emulate the result of
  43. // `hostname -f`, which still works on those macs.
  44. FQDNHostName = buf;
  45. #else
  46. // On Linux `hostname -f` calls getaddrinfo with AI_CANONNAME flag
  47. // to find the fqdn and will fail on any error.
  48. // Hosts often have a short hostname and fqdn is resolved over dns.
  49. // It is also very common to have a short hostname alias in
  50. // /etc/hosts, which works as a fallback (e.g. no fqdn in search
  51. // domains, otherwise `hostname -f` fails with an error and it is
  52. // obvious the host is not configured correctly).
  53. // Note that getaddrinfo may sometimes return EAI_NONAME even when
  54. // host actually has fqdn, but dns is temporary unavailable, so we
  55. // cannot ignore any errors on Linux.
  56. struct addrinfo hints;
  57. struct addrinfo* ais{nullptr};
  58. memset(&hints, 0, sizeof(hints));
  59. hints.ai_family = AF_UNSPEC;
  60. hints.ai_flags = AI_CANONNAME;
  61. res = getaddrinfo(buf, nullptr, &hints, &ais);
  62. if (res) {
  63. ythrow TSystemError() << "can not get FQDN (return code is " << res << ", hostname is \"" << buf << "\")";
  64. }
  65. FQDNHostName = ais->ai_canonname;
  66. FQDNHostName.to_lower();
  67. freeaddrinfo(ais);
  68. #endif
  69. }
  70. TString FQDNHostName;
  71. };
  72. } // namespace
  73. const TString& HostName() {
  74. return (Singleton<THostNameHolder>())->HostName;
  75. }
  76. const char* GetHostName() {
  77. return HostName().data();
  78. }
  79. const TString& FQDNHostName() {
  80. return (Singleton<TFQDNHostNameHolder>())->FQDNHostName;
  81. }
  82. const char* GetFQDNHostName() {
  83. return FQDNHostName().data();
  84. }
  85. bool IsFQDN(const TString& name) {
  86. TString absName = name;
  87. if (!absName.EndsWith('.')) {
  88. absName.append(".");
  89. }
  90. try {
  91. // ResolveHost() can't be used since it is ipv4-only, port is not important
  92. TNetworkAddress addr(absName, 0);
  93. } catch (const TNetworkResolutionError&) {
  94. return false;
  95. }
  96. return true;
  97. }