hostname.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:7k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /*
  14.   Get hostname for an IP.  Hostnames are checked with reverse name lookup and
  15.   checked that they doesn't resemble an ip.
  16. */
  17. #include "mysql_priv.h"
  18. #include "hash_filo.h"
  19. #include <m_ctype.h>
  20. #ifdef __cplusplus
  21. extern "C" { // Because of SCO 3.2V4.2
  22. #endif
  23. #if !defined( __WIN__) && !defined(OS2)
  24. #ifdef HAVE_SYS_UN_H
  25. #include <sys/un.h>
  26. #endif
  27. #include <netdb.h>
  28. #include <sys/utsname.h>
  29. #endif // __WIN__
  30. #ifdef __cplusplus
  31. }
  32. #endif
  33. class host_entry :public hash_filo_element
  34. {
  35. public:
  36.   char  ip[sizeof(((struct in_addr *) 0)->s_addr)];
  37.   uint  errors;
  38.   char  *hostname;
  39. };
  40. static hash_filo *hostname_cache;
  41. static pthread_mutex_t LOCK_hostname;
  42. void hostname_cache_refresh()
  43. {
  44.   hostname_cache->clear();
  45. }
  46. bool hostname_cache_init()
  47. {
  48.   host_entry tmp;
  49.   uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp);
  50.   if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset,
  51.      sizeof(struct in_addr),NULL,
  52.      (hash_free_key) free,
  53.      &my_charset_latin1)))
  54.     return 1;
  55.   hostname_cache->clear();
  56.   (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
  57.   return 0;
  58. }
  59. void hostname_cache_free()
  60. {
  61.   if (hostname_cache)
  62.   {
  63.     (void) pthread_mutex_destroy(&LOCK_hostname);
  64.     delete hostname_cache;
  65.     hostname_cache= 0;
  66.   }
  67. }
  68. static void add_hostname(struct in_addr *in,const char *name)
  69. {
  70.   if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  71.   {
  72.     VOID(pthread_mutex_lock(&hostname_cache->lock));
  73.     host_entry *entry;
  74.     if (!(entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
  75.     {
  76.       uint length=name ? (uint) strlen(name) : 0;
  77.       if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1)))
  78.       {
  79. char *new_name;
  80. memcpy_fixed(&entry->ip, &in->s_addr, sizeof(in->s_addr));
  81. if (length)
  82.   memcpy(new_name= (char *) (entry+1), name, length+1);
  83. else
  84.   new_name=0;
  85. entry->hostname=new_name;
  86. entry->errors=0;
  87. (void) hostname_cache->add(entry);
  88.       }
  89.     }
  90.     VOID(pthread_mutex_unlock(&hostname_cache->lock));
  91.   }
  92. }
  93. inline void add_wrong_ip(struct in_addr *in)
  94. {
  95.   add_hostname(in,NullS);
  96. }
  97. void inc_host_errors(struct in_addr *in)
  98. {
  99.   VOID(pthread_mutex_lock(&hostname_cache->lock));
  100.   host_entry *entry;
  101.   if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
  102.     entry->errors++;
  103.   VOID(pthread_mutex_unlock(&hostname_cache->lock));
  104. }
  105. void reset_host_errors(struct in_addr *in)
  106. {
  107.   VOID(pthread_mutex_lock(&hostname_cache->lock));
  108.   host_entry *entry;
  109.   if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
  110.     entry->errors=0;
  111.   VOID(pthread_mutex_unlock(&hostname_cache->lock));
  112. }
  113. /* Deal with systems that don't defined INADDR_LOOPBACK */
  114. #ifndef INADDR_LOOPBACK
  115. #define INADDR_LOOPBACK 0x7f000001UL
  116. #endif
  117. my_string ip_to_hostname(struct in_addr *in, uint *errors)
  118. {
  119.   uint i;
  120.   host_entry *entry;
  121.   DBUG_ENTER("ip_to_hostname");
  122.   *errors= 0;
  123.   /* We always treat the loopback address as "localhost". */
  124.   if (in->s_addr == htonl(INADDR_LOOPBACK))
  125.     DBUG_RETURN((char *)my_localhost);
  126.   /* Check first if we have name in cache */
  127.   if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  128.   {
  129.     VOID(pthread_mutex_lock(&hostname_cache->lock));
  130.     if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
  131.     {
  132.       char *name;
  133.       if (!entry->hostname)
  134. name=0; // Don't allow connection
  135.       else
  136. name=my_strdup(entry->hostname,MYF(0));
  137.       *errors= entry->errors;
  138.       VOID(pthread_mutex_unlock(&hostname_cache->lock));
  139.       DBUG_RETURN(name);
  140.     }
  141.     VOID(pthread_mutex_unlock(&hostname_cache->lock));
  142.   }
  143.   struct hostent *hp, *check;
  144.   char *name;
  145.   LINT_INIT(check);
  146. #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  147.   char buff[GETHOSTBYADDR_BUFF_SIZE],buff2[GETHOSTBYNAME_BUFF_SIZE];
  148.   int tmp_errno;
  149.   struct hostent tmp_hostent, tmp_hostent2;
  150. #ifdef HAVE_purify
  151.   bzero(buff,sizeof(buff)); // Bug in purify
  152. #endif
  153.   if (!(hp=gethostbyaddr_r((char*) in,sizeof(*in),
  154.    AF_INET,
  155.    &tmp_hostent,buff,sizeof(buff),&tmp_errno)))
  156.   {
  157.     DBUG_PRINT("error",("gethostbyaddr_r returned %d",tmp_errno));
  158.     return 0;
  159.   }
  160.   if (!(check=my_gethostbyname_r(hp->h_name,&tmp_hostent2,buff2,sizeof(buff2),
  161.  &tmp_errno)))
  162.   {
  163.     DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno));
  164.     /*
  165.       Don't cache responses when the DSN server is down, as otherwise
  166.       transient DNS failure may leave any number of clients (those
  167.       that attempted to connect during the outage) unable to connect
  168.       indefinitely.
  169.     */
  170.     if (tmp_errno == HOST_NOT_FOUND || tmp_errno == NO_DATA)
  171.       add_wrong_ip(in);
  172.     my_gethostbyname_r_free();
  173.     DBUG_RETURN(0);
  174.   }
  175.   if (!hp->h_name[0])
  176.   {
  177.     DBUG_PRINT("error",("Got an empty hostname"));
  178.     add_wrong_ip(in);
  179.     my_gethostbyname_r_free();
  180.     DBUG_RETURN(0); // Don't allow empty hostnames
  181.   }
  182.   if (!(name=my_strdup(hp->h_name,MYF(0))))
  183.   {
  184.     my_gethostbyname_r_free();
  185.     DBUG_RETURN(0); // out of memory
  186.   }
  187.   my_gethostbyname_r_free();
  188. #else
  189.   VOID(pthread_mutex_lock(&LOCK_hostname));
  190.   if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET)))
  191.   {
  192.     VOID(pthread_mutex_unlock(&LOCK_hostname));
  193.     DBUG_PRINT("error",("gethostbyaddr returned %d",errno));
  194.     if (errno == HOST_NOT_FOUND || errno == NO_DATA)
  195.       goto add_wrong_ip_and_return;
  196.     /* Failure, don't cache responce */
  197.     DBUG_RETURN(0);
  198.   }
  199.   if (!hp->h_name[0]) // Don't allow empty hostnames
  200.   {
  201.     VOID(pthread_mutex_unlock(&LOCK_hostname));
  202.     DBUG_PRINT("error",("Got an empty hostname"));
  203.     goto add_wrong_ip_and_return;
  204.   }
  205.   if (!(name=my_strdup(hp->h_name,MYF(0))))
  206.   {
  207.     VOID(pthread_mutex_unlock(&LOCK_hostname));
  208.     DBUG_RETURN(0); // out of memory
  209.   }
  210.   check=gethostbyname(name);
  211.   VOID(pthread_mutex_unlock(&LOCK_hostname));
  212.   if (!check)
  213.   {
  214.     DBUG_PRINT("error",("gethostbyname returned %d",errno));
  215.     my_free(name,MYF(0));
  216.     DBUG_RETURN(0);
  217.   }
  218. #endif
  219.   /* Don't accept hostnames that starts with digits because they may be
  220.      false ip:s */
  221.   if (my_isdigit(&my_charset_latin1,name[0]))
  222.   {
  223.     char *pos;
  224.     for (pos= name+1 ; my_isdigit(&my_charset_latin1,*pos); pos++) ;
  225.     if (*pos == '.')
  226.     {
  227.       DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
  228.       my_free(name,MYF(0));
  229.       goto add_wrong_ip_and_return;
  230.     }
  231.   }
  232.   /* Check that 'gethostbyname' returned the used ip */
  233.   for (i=0; check->h_addr_list[i]; i++)
  234.   {
  235.     if (*(uint32*)(check->h_addr_list)[i] == in->s_addr)
  236.     {
  237.       add_hostname(in,name);
  238.       DBUG_RETURN(name);
  239.     }
  240.   }
  241.   DBUG_PRINT("error",("Couldn't verify hostname with gethostbyname"));
  242.   my_free(name,MYF(0));
  243. add_wrong_ip_and_return:
  244.   add_wrong_ip(in);
  245.   DBUG_RETURN(0);
  246. }