1 /* Copyright (c) 2011, 2021, Oracle and/or its affiliates.
2 
3   This program is free software; you can redistribute it and/or modify
4   it under the terms of the GNU General Public License, version 2.0,
5   as published by the Free Software Foundation.
6 
7   This program is also distributed with certain software (including
8   but not limited to OpenSSL) that is licensed under separate terms,
9   as designated in a particular file or component or in included license
10   documentation.  The authors of MySQL hereby grant you an additional
11   permission to link the program and your derivative works with the
12   separately licensed software that they have included with MySQL.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License, version 2.0, for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software Foundation,
21   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22 
23 /**
24   @file storage/perfschema/table_host_cache.cc
25   Table HOST_CACHE (implementation).
26 */
27 
28 #include "my_global.h"
29 #include "my_thread.h"
30 #include "table_host_cache.h"
31 #include "hostname.h"
32 #include "field.h"
33 #include "sql_class.h"
34 
35 THR_LOCK table_host_cache::m_table_lock;
36 
37 static const TABLE_FIELD_TYPE field_types[]=
38 {
39   {
40     { C_STRING_WITH_LEN("IP") },
41     { C_STRING_WITH_LEN("varchar(64)") },
42     { NULL, 0}
43   },
44   {
45     { C_STRING_WITH_LEN("HOST") },
46     { C_STRING_WITH_LEN("varchar(255)") },
47     { NULL, 0}
48   },
49   {
50     { C_STRING_WITH_LEN("HOST_VALIDATED") },
51     { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") },
52     { NULL, 0}
53   },
54   {
55     { C_STRING_WITH_LEN("SUM_CONNECT_ERRORS") },
56     { C_STRING_WITH_LEN("bigint(20)") },
57     { NULL, 0}
58   },
59   {
60     { C_STRING_WITH_LEN("COUNT_HOST_BLOCKED_ERRORS") },
61     { C_STRING_WITH_LEN("bigint(20)") },
62     { NULL, 0}
63   },
64   {
65     { C_STRING_WITH_LEN("COUNT_NAMEINFO_TRANSIENT_ERRORS") },
66     { C_STRING_WITH_LEN("bigint(20)") },
67     { NULL, 0}
68   },
69   {
70     { C_STRING_WITH_LEN("COUNT_NAMEINFO_PERMANENT_ERRORS") },
71     { C_STRING_WITH_LEN("bigint(20)") },
72     { NULL, 0}
73   },
74   {
75     { C_STRING_WITH_LEN("COUNT_FORMAT_ERRORS") },
76     { C_STRING_WITH_LEN("bigint(20)") },
77     { NULL, 0}
78   },
79   {
80     { C_STRING_WITH_LEN("COUNT_ADDRINFO_TRANSIENT_ERRORS") },
81     { C_STRING_WITH_LEN("bigint(20)") },
82     { NULL, 0}
83   },
84   {
85     { C_STRING_WITH_LEN("COUNT_ADDRINFO_PERMANENT_ERRORS") },
86     { C_STRING_WITH_LEN("bigint(20)") },
87     { NULL, 0}
88   },
89   {
90     { C_STRING_WITH_LEN("COUNT_FCRDNS_ERRORS") },
91     { C_STRING_WITH_LEN("bigint(20)") },
92     { NULL, 0}
93   },
94   {
95     { C_STRING_WITH_LEN("COUNT_HOST_ACL_ERRORS") },
96     { C_STRING_WITH_LEN("bigint(20)") },
97     { NULL, 0}
98   },
99   {
100     { C_STRING_WITH_LEN("COUNT_NO_AUTH_PLUGIN_ERRORS") },
101     { C_STRING_WITH_LEN("bigint(20)") },
102     { NULL, 0}
103   },
104   {
105     { C_STRING_WITH_LEN("COUNT_AUTH_PLUGIN_ERRORS") },
106     { C_STRING_WITH_LEN("bigint(20)") },
107     { NULL, 0}
108   },
109   {
110     { C_STRING_WITH_LEN("COUNT_HANDSHAKE_ERRORS") },
111     { C_STRING_WITH_LEN("bigint(20)") },
112     { NULL, 0}
113   },
114   {
115     { C_STRING_WITH_LEN("COUNT_PROXY_USER_ERRORS") },
116     { C_STRING_WITH_LEN("bigint(20)") },
117     { NULL, 0}
118   },
119   {
120     { C_STRING_WITH_LEN("COUNT_PROXY_USER_ACL_ERRORS") },
121     { C_STRING_WITH_LEN("bigint(20)") },
122     { NULL, 0}
123   },
124   {
125     { C_STRING_WITH_LEN("COUNT_AUTHENTICATION_ERRORS") },
126     { C_STRING_WITH_LEN("bigint(20)") },
127     { NULL, 0}
128   },
129   {
130     { C_STRING_WITH_LEN("COUNT_SSL_ERRORS") },
131     { C_STRING_WITH_LEN("bigint(20)") },
132     { NULL, 0}
133   },
134   {
135     { C_STRING_WITH_LEN("COUNT_MAX_USER_CONNECTIONS_ERRORS") },
136     { C_STRING_WITH_LEN("bigint(20)") },
137     { NULL, 0}
138   },
139   {
140     { C_STRING_WITH_LEN("COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS") },
141     { C_STRING_WITH_LEN("bigint(20)") },
142     { NULL, 0}
143   },
144   {
145     { C_STRING_WITH_LEN("COUNT_DEFAULT_DATABASE_ERRORS") },
146     { C_STRING_WITH_LEN("bigint(20)") },
147     { NULL, 0}
148   },
149   {
150     { C_STRING_WITH_LEN("COUNT_INIT_CONNECT_ERRORS") },
151     { C_STRING_WITH_LEN("bigint(20)") },
152     { NULL, 0}
153   },
154   {
155     { C_STRING_WITH_LEN("COUNT_LOCAL_ERRORS") },
156     { C_STRING_WITH_LEN("bigint(20)") },
157     { NULL, 0}
158   },
159   {
160     { C_STRING_WITH_LEN("COUNT_UNKNOWN_ERRORS") },
161     { C_STRING_WITH_LEN("bigint(20)") },
162     { NULL, 0}
163   },
164   {
165     { C_STRING_WITH_LEN("FIRST_SEEN") },
166     { C_STRING_WITH_LEN("timestamp") },
167     { NULL, 0}
168   },
169   {
170     { C_STRING_WITH_LEN("LAST_SEEN") },
171     { C_STRING_WITH_LEN("timestamp") },
172     { NULL, 0}
173   },
174   {
175     { C_STRING_WITH_LEN("FIRST_ERROR_SEEN") },
176     { C_STRING_WITH_LEN("timestamp") },
177     { NULL, 0}
178   },
179   {
180     { C_STRING_WITH_LEN("LAST_ERROR_SEEN") },
181     { C_STRING_WITH_LEN("timestamp") },
182     { NULL, 0}
183   }
184 };
185 
186 TABLE_FIELD_DEF
187 table_host_cache::m_field_def=
188 { 29, field_types };
189 
190 PFS_engine_table_share
191 table_host_cache::m_share=
192 {
193   { C_STRING_WITH_LEN("host_cache") },
194   &pfs_truncatable_acl,
195   table_host_cache::create,
196   NULL, /* write_row */
197   table_host_cache::delete_all_rows,
198   table_host_cache::get_row_count,
199   sizeof(PFS_simple_index), /* ref length */
200   &m_table_lock,
201   &m_field_def,
202   false, /* checked */
203   false  /* perpetual */
204 };
205 
create(void)206 PFS_engine_table* table_host_cache::create(void)
207 {
208   table_host_cache *t= new table_host_cache();
209   if (t != NULL)
210   {
211     THD *thd= current_thd;
212     assert(thd != NULL);
213     t->materialize(thd);
214   }
215   return t;
216 }
217 
218 int
delete_all_rows(void)219 table_host_cache::delete_all_rows(void)
220 {
221   /*
222     TRUNCATE TABLE performance_schema.host_cache
223     is an alternate syntax for
224     FLUSH HOSTS
225   */
226   hostname_cache_refresh();
227   return 0;
228 }
229 
230 ha_rows
get_row_count(void)231 table_host_cache::get_row_count(void)
232 {
233   ha_rows count;
234   hostname_cache_lock();
235   count= hostname_cache_size();
236   hostname_cache_unlock();
237   return count;
238 }
239 
table_host_cache()240 table_host_cache::table_host_cache()
241   : PFS_engine_table(&m_share, &m_pos),
242     m_all_rows(NULL), m_row_count(0),
243     m_row(NULL), m_pos(0), m_next_pos(0)
244 {}
245 
materialize(THD * thd)246 void table_host_cache::materialize(THD *thd)
247 {
248   Host_entry *current;
249   Host_entry *first;
250   uint size;
251   uint index;
252   row_host_cache *rows;
253   row_host_cache *row;
254 
255   assert(m_all_rows == NULL);
256   assert(m_row_count == 0);
257 
258   hostname_cache_lock();
259 
260   size= hostname_cache_size();
261   if (size == 0)
262   {
263     /* Normal case, the cache is empty. */
264     goto end;
265   }
266 
267   rows= (row_host_cache*) thd->alloc(size * sizeof(row_host_cache));
268   if (rows == NULL)
269   {
270     /* Out of memory, this thread will error out. */
271     goto end;
272   }
273 
274   index= 0;
275   row= rows;
276 
277   first= hostname_cache_first();
278   current= first;
279 
280   while ((current != NULL) && (index < size))
281   {
282     make_row(current, row);
283     index++;
284     row++;
285     current= current->next();
286   }
287 
288   m_all_rows= rows;
289   m_row_count= index;
290 
291 end:
292   hostname_cache_unlock();
293 }
294 
make_row(Host_entry * entry,row_host_cache * row)295 void table_host_cache::make_row(Host_entry *entry, row_host_cache *row)
296 {
297   row->m_ip_length= strlen(entry->ip_key);
298   strcpy(row->m_ip, entry->ip_key);
299   row->m_hostname_length= entry->m_hostname_length;
300   if (row->m_hostname_length > 0)
301     strncpy(row->m_hostname, entry->m_hostname, row->m_hostname_length);
302   row->m_host_validated= entry->m_host_validated;
303   row->m_sum_connect_errors= entry->m_errors.m_connect;
304   row->m_count_host_blocked_errors= entry->m_errors.m_host_blocked;
305   row->m_count_nameinfo_transient_errors= entry->m_errors.m_nameinfo_transient;
306   row->m_count_nameinfo_permanent_errors= entry->m_errors.m_nameinfo_permanent;
307   row->m_count_format_errors= entry->m_errors.m_format;
308   row->m_count_addrinfo_transient_errors= entry->m_errors.m_addrinfo_transient;
309   row->m_count_addrinfo_permanent_errors= entry->m_errors.m_addrinfo_permanent;
310   row->m_count_fcrdns_errors= entry->m_errors.m_FCrDNS;
311   row->m_count_host_acl_errors= entry->m_errors.m_host_acl;
312   row->m_count_no_auth_plugin_errors= entry->m_errors.m_no_auth_plugin;
313   row->m_count_auth_plugin_errors= entry->m_errors.m_auth_plugin;
314   row->m_count_handshake_errors= entry->m_errors.m_handshake;
315   row->m_count_proxy_user_errors= entry->m_errors.m_proxy_user;
316   row->m_count_proxy_user_acl_errors= entry->m_errors.m_proxy_user_acl;
317   row->m_count_authentication_errors= entry->m_errors.m_authentication;
318   row->m_count_ssl_errors= entry->m_errors.m_ssl;
319   row->m_count_max_user_connection_errors= entry->m_errors.m_max_user_connection;
320   row->m_count_max_user_connection_per_hour_errors= entry->m_errors.m_max_user_connection_per_hour;
321   row->m_count_default_database_errors= entry->m_errors.m_default_database;
322   row->m_count_init_connect_errors= entry->m_errors.m_init_connect;
323   row->m_count_local_errors= entry->m_errors.m_local;
324 
325   /*
326     Reserved for future use, to help with backward compatibility.
327     When new errors are added in entry->m_errors.m_xxx,
328     report them in this column (GA releases),
329     until the table HOST_CACHE structure can be extended (next development version).
330   */
331   row->m_count_unknown_errors= 0;
332 
333   row->m_first_seen= entry->m_first_seen;
334   row->m_last_seen= entry->m_last_seen;
335   row->m_first_error_seen= entry->m_first_error_seen;
336   row->m_last_error_seen= entry->m_last_error_seen;
337 }
338 
reset_position(void)339 void table_host_cache::reset_position(void)
340 {
341   m_pos.m_index= 0;
342   m_next_pos.m_index= 0;
343 }
344 
rnd_next(void)345 int table_host_cache::rnd_next(void)
346 {
347   int result;
348 
349   m_pos.set_at(&m_next_pos);
350 
351   if (m_pos.m_index < m_row_count)
352   {
353     m_row= &m_all_rows[m_pos.m_index];
354     m_next_pos.set_after(&m_pos);
355     result= 0;
356   }
357   else
358   {
359     m_row= NULL;
360     result= HA_ERR_END_OF_FILE;
361   }
362 
363   return result;
364 }
365 
rnd_pos(const void * pos)366 int table_host_cache::rnd_pos(const void *pos)
367 {
368   set_position(pos);
369   assert(m_pos.m_index < m_row_count);
370   m_row= &m_all_rows[m_pos.m_index];
371   return 0;
372 }
373 
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)374 int table_host_cache::read_row_values(TABLE *table,
375                                       unsigned char *buf,
376                                       Field **fields,
377                                       bool read_all)
378 {
379   Field *f;
380 
381   assert(m_row);
382 
383   /* Set the null bits */
384   assert(table->s->null_bytes == 1);
385   buf[0]= 0;
386 
387   for (; (f= *fields) ; fields++)
388   {
389     if (read_all || bitmap_is_set(table->read_set, f->field_index))
390     {
391       switch(f->field_index)
392       {
393       case 0: /* IP */
394         set_field_varchar_utf8(f, m_row->m_ip, m_row->m_ip_length);
395         break;
396       case 1: /* HOST */
397         if (m_row->m_hostname_length > 0)
398           set_field_varchar_utf8(f, m_row->m_hostname, m_row->m_hostname_length);
399         else
400           f->set_null();
401         break;
402       case 2: /* HOST_VALIDATED */
403         set_field_enum(f, m_row->m_host_validated ? ENUM_YES : ENUM_NO);
404         break;
405       case 3: /* SUM_CONNECT_ERRORS */
406         set_field_ulonglong(f, m_row->m_sum_connect_errors);
407         break;
408       case 4: /* COUNT_HOST_BLOCKED_ERRORS. */
409         set_field_ulonglong(f, m_row->m_count_host_blocked_errors);
410         break;
411       case 5: /* COUNT_NAMEINFO_TRANSIENT_ERRORS */
412         set_field_ulonglong(f, m_row->m_count_nameinfo_transient_errors);
413         break;
414       case 6: /* COUNT_NAMEINFO_PERSISTENT_ERRORS */
415         set_field_ulonglong(f, m_row->m_count_nameinfo_permanent_errors);
416         break;
417       case 7: /* COUNT_FORMAT_ERRORS */
418         set_field_ulonglong(f, m_row->m_count_format_errors);
419         break;
420       case 8: /* COUNT_ADDRINFO_TRANSIENT_ERRORS */
421         set_field_ulonglong(f, m_row->m_count_addrinfo_transient_errors);
422         break;
423       case 9: /* COUNT_ADDRINFO_PERSISTENT_ERRORS */
424         set_field_ulonglong(f, m_row->m_count_addrinfo_permanent_errors);
425         break;
426       case 10: /* COUNT_FCRDNS_ERRORS */
427         set_field_ulonglong(f, m_row->m_count_fcrdns_errors);
428         break;
429       case 11: /* COUNT_HOST_ACL_ERRORS */
430         set_field_ulonglong(f, m_row->m_count_host_acl_errors);
431         break;
432       case 12: /* COUNT_NO_AUTH_PLUGIN_ERRORS */
433         set_field_ulonglong(f, m_row->m_count_no_auth_plugin_errors);
434         break;
435       case 13: /* COUNT_AUTH_PLUGIN_ERRORS */
436         set_field_ulonglong(f, m_row->m_count_auth_plugin_errors);
437         break;
438       case 14: /* COUNT_HANDSHAKE_ERRORS */
439         set_field_ulonglong(f, m_row->m_count_handshake_errors);
440         break;
441       case 15: /* COUNT_PROXY_USER_ERRORS */
442         set_field_ulonglong(f, m_row->m_count_proxy_user_errors);
443         break;
444       case 16: /* COUNT_PROXY_USER_ACL_ERRORS */
445         set_field_ulonglong(f, m_row->m_count_proxy_user_acl_errors);
446         break;
447       case 17: /* COUNT_AUTHENTICATION_ERRORS */
448         set_field_ulonglong(f, m_row->m_count_authentication_errors);
449         break;
450       case 18: /* COUNT_SSL_ERRORS */
451         set_field_ulonglong(f, m_row->m_count_ssl_errors);
452         break;
453       case 19: /* COUNT_MAX_USER_CONNECTION_ERRORS */
454         set_field_ulonglong(f, m_row->m_count_max_user_connection_errors);
455         break;
456       case 20: /* COUNT_MAX_USER_CONNECTION_PER_HOUR_ERRORS */
457         set_field_ulonglong(f, m_row->m_count_max_user_connection_per_hour_errors);
458         break;
459       case 21: /* COUNT_DEFAULT_DATABASE_ERRORS */
460         set_field_ulonglong(f, m_row->m_count_default_database_errors);
461         break;
462       case 22: /* COUNT_INIT_CONNECT_ERRORS */
463         set_field_ulonglong(f, m_row->m_count_init_connect_errors);
464         break;
465       case 23: /* COUNT_LOCAL_ERRORS */
466         set_field_ulonglong(f, m_row->m_count_local_errors);
467         break;
468       case 24: /* COUNT_UNKNOWN_ERRORS */
469         set_field_ulonglong(f, m_row->m_count_unknown_errors);
470         break;
471       case 25: /* FIRST_SEEN */
472         set_field_timestamp(f, m_row->m_first_seen);
473         break;
474       case 26: /* LAST_SEEN */
475         set_field_timestamp(f, m_row->m_last_seen);
476         break;
477       case 27: /* FIRST_ERROR_SEEN */
478         if (m_row->m_first_error_seen != 0)
479           set_field_timestamp(f, m_row->m_first_error_seen);
480         else
481           f->set_null();
482         break;
483       case 28: /* LAST_ERROR_SEEN */
484         if (m_row->m_last_error_seen != 0)
485           set_field_timestamp(f, m_row->m_last_error_seen);
486         else
487           f->set_null();
488         break;
489       default:
490         assert(false);
491       }
492     }
493   }
494 
495   return 0;
496 }
497 
498