table_host_cache.cc 15 KB
Newer Older
Sergei Golubchik's avatar
Sergei Golubchik committed
1
/* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
2 3

  This program is free software; you can redistribute it and/or modify
Oleksandr Byelkin's avatar
Oleksandr Byelkin committed
4 5 6 7 8 9 10 11 12
  it under the terms of the GNU General Public License, version 2.0,
  as published by the Free Software Foundation.

  This program is also distributed with certain software (including
  but not limited to OpenSSL) that is licensed under separate terms,
  as designated in a particular file or component or in included license
  documentation.  The authors of MySQL hereby grant you an additional
  permission to link the program and your derivative works with the
  separately licensed software that they have included with MySQL.
13 14 15 16

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Oleksandr Byelkin's avatar
Oleksandr Byelkin committed
17
  GNU General Public License, version 2.0, for more details.
18 19 20

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
Vicențiu Ciorbaru's avatar
Vicențiu Ciorbaru committed
21
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

/**
  @file storage/perfschema/table_host_cache.cc
  Table HOST_CACHE (implementation).
*/

#include "my_global.h"
#include "my_pthread.h"
#include "table_host_cache.h"
#include "hostname.h"

THR_LOCK table_host_cache::m_table_lock;

PFS_engine_table_share
table_host_cache::m_share=
{
  { C_STRING_WITH_LEN("host_cache") },
  &pfs_truncatable_acl,
  &table_host_cache::create,
  NULL, /* write_row */
  table_host_cache::delete_all_rows,
  NULL, /* get_row_count */
  1000, /* records */
  sizeof(PFS_simple_index), /* ref length */
  &m_table_lock,
Sergey Vojtovich's avatar
Sergey Vojtovich committed
47
  { C_STRING_WITH_LEN("CREATE TABLE host_cache("
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
                      "IP VARCHAR(64) not null comment 'Client IP address.',"
                      "HOST VARCHAR(255) collate utf8_bin comment 'IP''s resolved DNS host name, or NULL if unknown.',"
                      "HOST_VALIDATED ENUM ('YES', 'NO') not null comment 'YES if the IP-to-host DNS lookup was successful, and the HOST column can be used to avoid DNS calls, or NO if unsuccessful, in which case DNS lookup is performed for each connect until either successful or a permanent error.',"
                      "SUM_CONNECT_ERRORS BIGINT not null comment 'Number of connection errors. Counts only protocol handshake errors for hosts that passed validation. These errors count towards max_connect_errors.',"
                      "COUNT_HOST_BLOCKED_ERRORS BIGINT not null comment 'Number of blocked connections because SUM_CONNECT_ERRORS exceeded the max_connect_errors system variable.',"
                      "COUNT_NAMEINFO_TRANSIENT_ERRORS BIGINT not null comment 'Number of transient errors during IP-to-host DNS lookups.',"
                      "COUNT_NAMEINFO_PERMANENT_ERRORS BIGINT not null comment 'Number of permanent errors during IP-to-host DNS lookups.',"
                      "COUNT_FORMAT_ERRORS BIGINT not null comment 'Number of host name format errors, for example a numeric host column.',"
                      "COUNT_ADDRINFO_TRANSIENT_ERRORS BIGINT not null comment 'Number of transient errors during host-to-IP reverse DNS lookups.',"
                      "COUNT_ADDRINFO_PERMANENT_ERRORS BIGINT not null comment 'Number of permanent errors during host-to-IP reverse DNS lookups.',"
                      "COUNT_FCRDNS_ERRORS BIGINT not null comment 'Number of forward-confirmed reverse DNS errors, which occur when IP-to-host DNS lookup does not match the originating IP address.',"
                      "COUNT_HOST_ACL_ERRORS BIGINT not null comment 'Number of errors occurring because no user from the host is permitted to log in. These attempts return error code 1130 ER_HOST_NOT_PRIVILEGED and do not proceed to username and password authentication.',"
                      "COUNT_NO_AUTH_PLUGIN_ERRORS BIGINT not null comment 'Number of errors due to requesting an authentication plugin that was not available. This can be due to the plugin never having been loaded, or the load attempt failing.',"
                      "COUNT_AUTH_PLUGIN_ERRORS BIGINT not null comment 'Number of errors reported by an authentication plugin. Plugins can increment COUNT_AUTHENTICATION_ERRORS or COUNT_HANDSHAKE_ERRORS instead, but, if specified or the error is unknown, this column is incremented.',"
                      "COUNT_HANDSHAKE_ERRORS BIGINT not null comment 'Number of errors detected at the wire protocol level.',"
                      "COUNT_PROXY_USER_ERRORS BIGINT not null comment 'Number of errors detected when a proxy user is proxied to a user that does not exist.',"
                      "COUNT_PROXY_USER_ACL_ERRORS BIGINT not null comment 'Number of errors detected when a proxy user is proxied to a user that exists, but the proxy user doesn''t have the PROXY privilege.',"
                      "COUNT_AUTHENTICATION_ERRORS BIGINT not null comment 'Number of errors where authentication failed.',"
                      "COUNT_SSL_ERRORS BIGINT not null comment 'Number of errors due to TLS problems.',"
                      "COUNT_MAX_USER_CONNECTIONS_ERRORS BIGINT not null comment 'Number of errors due to the per-user quota being exceeded.',"
                      "COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS BIGINT not null comment 'Number of errors due to the per-hour quota being exceeded.',"
                      "COUNT_DEFAULT_DATABASE_ERRORS BIGINT not null comment 'Number of errors due to the user not having permission to access the specified default database, or it not existing.',"
                      "COUNT_INIT_CONNECT_ERRORS BIGINT not null comment 'Number of errors due to statements in the init_connect system variable.',"
                      "COUNT_LOCAL_ERRORS BIGINT not null comment 'Number of local server errors, such as out-of-memory errors, unrelated to network, authentication, or authorization.',"
                      "COUNT_UNKNOWN_ERRORS BIGINT not null comment 'Number of unknown errors that cannot be allocated to another column.',"
                      "FIRST_SEEN TIMESTAMP(0) NOT NULL default 0 comment 'Timestamp of the first connection attempt by the IP.',"
                      "LAST_SEEN TIMESTAMP(0) NOT NULL default 0 comment 'Timestamp of the most recent connection attempt by the IP.',"
                      "FIRST_ERROR_SEEN TIMESTAMP(0) null default 0 comment 'Timestamp of the first error seen from the IP.',"
                      "LAST_ERROR_SEEN TIMESTAMP(0) null default 0 comment 'Timestamp of the most recent error seen from the IP.')") }
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
};

PFS_engine_table* table_host_cache::create(void)
{
  table_host_cache *t= new table_host_cache();
  if (t != NULL)
  {
    THD *thd= current_thd;
    DBUG_ASSERT(thd != NULL);
    t->materialize(thd);
  }
  return t;
}

int
table_host_cache::delete_all_rows(void)
{
  /*
    TRUNCATE TABLE performance_schema.host_cache
    is an alternate syntax for
    FLUSH HOSTS
  */
  hostname_cache_refresh();
  return 0;
}

table_host_cache::table_host_cache()
  : PFS_engine_table(&m_share, &m_pos),
    m_all_rows(NULL), m_row_count(0),
    m_row(NULL), m_pos(0), m_next_pos(0)
{}

void table_host_cache::materialize(THD *thd)
{
  Host_entry *current;
  Host_entry *first;
  uint size;
  uint index;
  row_host_cache *rows;
  row_host_cache *row;

  DBUG_ASSERT(m_all_rows == NULL);
  DBUG_ASSERT(m_row_count == 0);

  hostname_cache_lock();

  size= hostname_cache_size();
  if (size == 0)
  {
    /* Normal case, the cache is empty. */
    goto end;
  }

  rows= (row_host_cache*) thd->alloc(size * sizeof(row_host_cache));
  if (rows == NULL)
  {
    /* Out of memory, this thread will error out. */
    goto end;
  }

  index= 0;
  row= rows;

  first= hostname_cache_first();
  current= first;

  while ((current != NULL) && (index < size))
  {
    make_row(current, row);
    index++;
    row++;
    current= current->next();
  }

  m_all_rows= rows;
  m_row_count= index;

end:
  hostname_cache_unlock();
}

void table_host_cache::make_row(Host_entry *entry, row_host_cache *row)
{
160
  row->m_ip_length= (int)strlen(entry->ip_key);
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
  strcpy(row->m_ip, entry->ip_key);
  row->m_hostname_length= entry->m_hostname_length;
  if (row->m_hostname_length > 0)
    strncpy(row->m_hostname, entry->m_hostname, row->m_hostname_length);
  row->m_host_validated= entry->m_host_validated;
  row->m_sum_connect_errors= entry->m_errors.m_connect;
  row->m_count_host_blocked_errors= entry->m_errors.m_host_blocked;
  row->m_count_nameinfo_transient_errors= entry->m_errors.m_nameinfo_transient;
  row->m_count_nameinfo_permanent_errors= entry->m_errors.m_nameinfo_permanent;
  row->m_count_format_errors= entry->m_errors.m_format;
  row->m_count_addrinfo_transient_errors= entry->m_errors.m_addrinfo_transient;
  row->m_count_addrinfo_permanent_errors= entry->m_errors.m_addrinfo_permanent;
  row->m_count_fcrdns_errors= entry->m_errors.m_FCrDNS;
  row->m_count_host_acl_errors= entry->m_errors.m_host_acl;
  row->m_count_no_auth_plugin_errors= entry->m_errors.m_no_auth_plugin;
  row->m_count_auth_plugin_errors= entry->m_errors.m_auth_plugin;
  row->m_count_handshake_errors= entry->m_errors.m_handshake;
  row->m_count_proxy_user_errors= entry->m_errors.m_proxy_user;
  row->m_count_proxy_user_acl_errors= entry->m_errors.m_proxy_user_acl;
  row->m_count_authentication_errors= entry->m_errors.m_authentication;
  row->m_count_ssl_errors= entry->m_errors.m_ssl;
  row->m_count_max_user_connection_errors= entry->m_errors.m_max_user_connection;
  row->m_count_max_user_connection_per_hour_errors= entry->m_errors.m_max_user_connection_per_hour;
  row->m_count_default_database_errors= entry->m_errors.m_default_database;
  row->m_count_init_connect_errors= entry->m_errors.m_init_connect;
  row->m_count_local_errors= entry->m_errors.m_local;

  /*
    Reserved for future use, to help with backward compatibility.
    When new errors are added in entry->m_errors.m_xxx,
    report them in this column (GA releases),
    until the table HOST_CACHE structure can be extended (next development version).
  */
  row->m_count_unknown_errors= 0;

  row->m_first_seen= entry->m_first_seen;
  row->m_last_seen= entry->m_last_seen;
  row->m_first_error_seen= entry->m_first_error_seen;
  row->m_last_error_seen= entry->m_last_error_seen;
}

void table_host_cache::reset_position(void)
{
  m_pos.m_index= 0;
  m_next_pos.m_index= 0;
}

int table_host_cache::rnd_next(void)
{
  int result;

  m_pos.set_at(&m_next_pos);

  if (m_pos.m_index < m_row_count)
  {
    m_row= &m_all_rows[m_pos.m_index];
    m_next_pos.set_after(&m_pos);
    result= 0;
  }
  else
  {
    m_row= NULL;
    result= HA_ERR_END_OF_FILE;
  }

  return result;
}

int table_host_cache::rnd_pos(const void *pos)
{
  set_position(pos);
  DBUG_ASSERT(m_pos.m_index < m_row_count);
  m_row= &m_all_rows[m_pos.m_index];
  return 0;
}

int table_host_cache::read_row_values(TABLE *table,
                                      unsigned char *buf,
                                      Field **fields,
                                      bool read_all)
{
  Field *f;

  DBUG_ASSERT(m_row);

  /* Set the null bits */
  DBUG_ASSERT(table->s->null_bytes == 1);
  buf[0]= 0;

  for (; (f= *fields) ; fields++)
  {
    if (read_all || bitmap_is_set(table->read_set, f->field_index))
    {
      switch(f->field_index)
      {
      case 0: /* IP */
        set_field_varchar_utf8(f, m_row->m_ip, m_row->m_ip_length);
        break;
      case 1: /* HOST */
        if (m_row->m_hostname_length > 0)
          set_field_varchar_utf8(f, m_row->m_hostname, m_row->m_hostname_length);
        else
          f->set_null();
        break;
      case 2: /* HOST_VALIDATED */
        set_field_enum(f, m_row->m_host_validated ? ENUM_YES : ENUM_NO);
        break;
      case 3: /* SUM_CONNECT_ERRORS */
        set_field_ulonglong(f, m_row->m_sum_connect_errors);
        break;
      case 4: /* COUNT_HOST_BLOCKED_ERRORS. */
        set_field_ulonglong(f, m_row->m_count_host_blocked_errors);
        break;
      case 5: /* COUNT_NAMEINFO_TRANSIENT_ERRORS */
        set_field_ulonglong(f, m_row->m_count_nameinfo_transient_errors);
        break;
      case 6: /* COUNT_NAMEINFO_PERSISTENT_ERRORS */
        set_field_ulonglong(f, m_row->m_count_nameinfo_permanent_errors);
        break;
      case 7: /* COUNT_FORMAT_ERRORS */
        set_field_ulonglong(f, m_row->m_count_format_errors);
        break;
      case 8: /* COUNT_ADDRINFO_TRANSIENT_ERRORS */
        set_field_ulonglong(f, m_row->m_count_addrinfo_transient_errors);
        break;
      case 9: /* COUNT_ADDRINFO_PERSISTENT_ERRORS */
        set_field_ulonglong(f, m_row->m_count_addrinfo_permanent_errors);
        break;
      case 10: /* COUNT_FCRDNS_ERRORS */
        set_field_ulonglong(f, m_row->m_count_fcrdns_errors);
        break;
      case 11: /* COUNT_HOST_ACL_ERRORS */
        set_field_ulonglong(f, m_row->m_count_host_acl_errors);
        break;
      case 12: /* COUNT_NO_AUTH_PLUGIN_ERRORS */
        set_field_ulonglong(f, m_row->m_count_no_auth_plugin_errors);
        break;
      case 13: /* COUNT_AUTH_PLUGIN_ERRORS */
        set_field_ulonglong(f, m_row->m_count_auth_plugin_errors);
        break;
      case 14: /* COUNT_HANDSHAKE_ERRORS */
        set_field_ulonglong(f, m_row->m_count_handshake_errors);
        break;
      case 15: /* COUNT_PROXY_USER_ERRORS */
        set_field_ulonglong(f, m_row->m_count_proxy_user_errors);
        break;
      case 16: /* COUNT_PROXY_USER_ACL_ERRORS */
        set_field_ulonglong(f, m_row->m_count_proxy_user_acl_errors);
        break;
      case 17: /* COUNT_AUTHENTICATION_ERRORS */
        set_field_ulonglong(f, m_row->m_count_authentication_errors);
        break;
      case 18: /* COUNT_SSL_ERRORS */
        set_field_ulonglong(f, m_row->m_count_ssl_errors);
        break;
      case 19: /* COUNT_MAX_USER_CONNECTION_ERRORS */
        set_field_ulonglong(f, m_row->m_count_max_user_connection_errors);
        break;
      case 20: /* COUNT_MAX_USER_CONNECTION_PER_HOUR_ERRORS */
        set_field_ulonglong(f, m_row->m_count_max_user_connection_per_hour_errors);
        break;
      case 21: /* COUNT_DEFAULT_DATABASE_ERRORS */
        set_field_ulonglong(f, m_row->m_count_default_database_errors);
        break;
      case 22: /* COUNT_INIT_CONNECT_ERRORS */
        set_field_ulonglong(f, m_row->m_count_init_connect_errors);
        break;
      case 23: /* COUNT_LOCAL_ERRORS */
        set_field_ulonglong(f, m_row->m_count_local_errors);
        break;
      case 24: /* COUNT_UNKNOWN_ERRORS */
        set_field_ulonglong(f, m_row->m_count_unknown_errors);
        break;
      case 25: /* FIRST_SEEN */
        set_field_timestamp(f, m_row->m_first_seen);
        break;
      case 26: /* LAST_SEEN */
        set_field_timestamp(f, m_row->m_last_seen);
        break;
      case 27: /* FIRST_ERROR_SEEN */
        if (m_row->m_first_error_seen != 0)
          set_field_timestamp(f, m_row->m_first_error_seen);
        else
          f->set_null();
        break;
      case 28: /* LAST_ERROR_SEEN */
        if (m_row->m_last_error_seen != 0)
          set_field_timestamp(f, m_row->m_last_error_seen);
        else
          f->set_null();
        break;
      default:
        DBUG_ASSERT(false);
      }
    }
  }

  return 0;
}