00001 /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 00018 /* 00019 Get hostname for an IP. Hostnames are checked with reverse name lookup and 00020 checked that they doesn't resemble an ip. 00021 */ 00022 00023 #include "mysql_priv.h" 00024 #include "hash_filo.h" 00025 #include <m_ctype.h> 00026 #ifdef __cplusplus 00027 extern "C" { // Because of SCO 3.2V4.2 00028 #endif 00029 #if !defined( __WIN__) 00030 #ifdef HAVE_SYS_UN_H 00031 #include <sys/un.h> 00032 #endif 00033 #include <netdb.h> 00034 #include <sys/utsname.h> 00035 #endif // __WIN__ 00036 #ifdef __cplusplus 00037 } 00038 #endif 00039 00040 00041 class host_entry :public hash_filo_element 00042 { 00043 public: 00044 char ip[sizeof(((struct in_addr *) 0)->s_addr)]; 00045 uint errors; 00046 char *hostname; 00047 }; 00048 00049 static hash_filo *hostname_cache; 00050 static pthread_mutex_t LOCK_hostname; 00051 00052 void hostname_cache_refresh() 00053 { 00054 hostname_cache->clear(); 00055 } 00056 00057 bool hostname_cache_init() 00058 { 00059 host_entry tmp; 00060 uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp); 00061 if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset, 00062 sizeof(struct in_addr),NULL, 00063 (hash_free_key) free, 00064 &my_charset_bin))) 00065 return 1; 00066 hostname_cache->clear(); 00067 (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW); 00068 return 0; 00069 } 00070 00071 void hostname_cache_free() 00072 { 00073 if (hostname_cache) 00074 { 00075 (void) pthread_mutex_destroy(&LOCK_hostname); 00076 delete hostname_cache; 00077 hostname_cache= 0; 00078 } 00079 } 00080 00081 00082 static void add_hostname(struct in_addr *in,const char *name) 00083 { 00084 if (!(specialflag & SPECIAL_NO_HOST_CACHE)) 00085 { 00086 VOID(pthread_mutex_lock(&hostname_cache->lock)); 00087 host_entry *entry; 00088 if (!(entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0))) 00089 { 00090 uint length=name ? (uint) strlen(name) : 0; 00091 00092 if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1))) 00093 { 00094 char *new_name; 00095 memcpy_fixed(&entry->ip, &in->s_addr, sizeof(in->s_addr)); 00096 if (length) 00097 memcpy(new_name= (char *) (entry+1), name, length+1); 00098 else 00099 new_name=0; 00100 entry->hostname=new_name; 00101 entry->errors=0; 00102 (void) hostname_cache->add(entry); 00103 } 00104 } 00105 VOID(pthread_mutex_unlock(&hostname_cache->lock)); 00106 } 00107 } 00108 00109 00110 inline void add_wrong_ip(struct in_addr *in) 00111 { 00112 add_hostname(in,NullS); 00113 } 00114 00115 void inc_host_errors(struct in_addr *in) 00116 { 00117 VOID(pthread_mutex_lock(&hostname_cache->lock)); 00118 host_entry *entry; 00119 if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0))) 00120 entry->errors++; 00121 VOID(pthread_mutex_unlock(&hostname_cache->lock)); 00122 } 00123 00124 void reset_host_errors(struct in_addr *in) 00125 { 00126 VOID(pthread_mutex_lock(&hostname_cache->lock)); 00127 host_entry *entry; 00128 if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0))) 00129 entry->errors=0; 00130 VOID(pthread_mutex_unlock(&hostname_cache->lock)); 00131 } 00132 00133 /* Deal with systems that don't defined INADDR_LOOPBACK */ 00134 #ifndef INADDR_LOOPBACK 00135 #define INADDR_LOOPBACK 0x7f000001UL 00136 #endif 00137 00138 my_string ip_to_hostname(struct in_addr *in, uint *errors) 00139 { 00140 uint i; 00141 host_entry *entry; 00142 DBUG_ENTER("ip_to_hostname"); 00143 *errors=0; 00144 00145 /* We always treat the loopback address as "localhost". */ 00146 if (in->s_addr == htonl(INADDR_LOOPBACK)) // is expanded inline by gcc 00147 DBUG_RETURN((char *)my_localhost); 00148 00149 /* Check first if we have name in cache */ 00150 if (!(specialflag & SPECIAL_NO_HOST_CACHE)) 00151 { 00152 VOID(pthread_mutex_lock(&hostname_cache->lock)); 00153 if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0))) 00154 { 00155 char *name; 00156 if (!entry->hostname) 00157 name=0; // Don't allow connection 00158 else 00159 name=my_strdup(entry->hostname,MYF(0)); 00160 *errors= entry->errors; 00161 VOID(pthread_mutex_unlock(&hostname_cache->lock)); 00162 DBUG_RETURN(name); 00163 } 00164 VOID(pthread_mutex_unlock(&hostname_cache->lock)); 00165 } 00166 00167 struct hostent *hp, *check; 00168 char *name; 00169 LINT_INIT(check); 00170 #if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST) 00171 char buff[GETHOSTBYADDR_BUFF_SIZE],buff2[GETHOSTBYNAME_BUFF_SIZE]; 00172 int tmp_errno; 00173 struct hostent tmp_hostent, tmp_hostent2; 00174 #ifdef HAVE_purify 00175 bzero(buff,sizeof(buff)); // Bug in purify 00176 #endif 00177 if (!(hp=gethostbyaddr_r((char*) in,sizeof(*in), 00178 AF_INET, 00179 &tmp_hostent,buff,sizeof(buff),&tmp_errno))) 00180 { 00181 DBUG_PRINT("error",("gethostbyaddr_r returned %d",tmp_errno)); 00182 return 0; 00183 } 00184 if (!(check=my_gethostbyname_r(hp->h_name,&tmp_hostent2,buff2,sizeof(buff2), 00185 &tmp_errno))) 00186 { 00187 DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno)); 00188 /* 00189 Don't cache responses when the DSN server is down, as otherwise 00190 transient DNS failure may leave any number of clients (those 00191 that attempted to connect during the outage) unable to connect 00192 indefinitely. 00193 */ 00194 if (tmp_errno == HOST_NOT_FOUND || tmp_errno == NO_DATA) 00195 add_wrong_ip(in); 00196 my_gethostbyname_r_free(); 00197 DBUG_RETURN(0); 00198 } 00199 if (!hp->h_name[0]) 00200 { 00201 DBUG_PRINT("error",("Got an empty hostname")); 00202 add_wrong_ip(in); 00203 my_gethostbyname_r_free(); 00204 DBUG_RETURN(0); // Don't allow empty hostnames 00205 } 00206 if (!(name=my_strdup(hp->h_name,MYF(0)))) 00207 { 00208 my_gethostbyname_r_free(); 00209 DBUG_RETURN(0); // out of memory 00210 } 00211 my_gethostbyname_r_free(); 00212 #else 00213 VOID(pthread_mutex_lock(&LOCK_hostname)); 00214 if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET))) 00215 { 00216 VOID(pthread_mutex_unlock(&LOCK_hostname)); 00217 DBUG_PRINT("error",("gethostbyaddr returned %d",errno)); 00218 00219 if (errno == HOST_NOT_FOUND || errno == NO_DATA) 00220 goto add_wrong_ip_and_return; 00221 /* Failure, don't cache responce */ 00222 DBUG_RETURN(0); 00223 } 00224 if (!hp->h_name[0]) // Don't allow empty hostnames 00225 { 00226 VOID(pthread_mutex_unlock(&LOCK_hostname)); 00227 DBUG_PRINT("error",("Got an empty hostname")); 00228 goto add_wrong_ip_and_return; 00229 } 00230 if (!(name=my_strdup(hp->h_name,MYF(0)))) 00231 { 00232 VOID(pthread_mutex_unlock(&LOCK_hostname)); 00233 DBUG_RETURN(0); // out of memory 00234 } 00235 check=gethostbyname(name); 00236 VOID(pthread_mutex_unlock(&LOCK_hostname)); 00237 if (!check) 00238 { 00239 DBUG_PRINT("error",("gethostbyname returned %d",errno)); 00240 my_free(name,MYF(0)); 00241 DBUG_RETURN(0); 00242 } 00243 #endif 00244 00245 /* Don't accept hostnames that starts with digits because they may be 00246 false ip:s */ 00247 if (my_isdigit(&my_charset_latin1,name[0])) 00248 { 00249 char *pos; 00250 for (pos= name+1 ; my_isdigit(&my_charset_latin1,*pos); pos++) ; 00251 if (*pos == '.') 00252 { 00253 DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'")); 00254 my_free(name,MYF(0)); 00255 goto add_wrong_ip_and_return; 00256 } 00257 } 00258 00259 /* Check that 'gethostbyname' returned the used ip */ 00260 for (i=0; check->h_addr_list[i]; i++) 00261 { 00262 if (*(uint32*)(check->h_addr_list)[i] == in->s_addr) 00263 { 00264 add_hostname(in,name); 00265 DBUG_RETURN(name); 00266 } 00267 } 00268 DBUG_PRINT("error",("Couldn't verify hostname with gethostbyname")); 00269 my_free(name,MYF(0)); 00270 00271 add_wrong_ip_and_return: 00272 add_wrong_ip(in); 00273 DBUG_RETURN(0); 00274 }
1.4.7

