Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
ecbf36a9
Commit
ecbf36a9
authored
Jun 27, 2013
by
unknown
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-4058
MySQL 5.6.10 performance schema: merge of host_cache table
parent
68262ba6
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1062 additions
and
237 deletions
+1062
-237
include/mysql/plugin_auth_common.h
include/mysql/plugin_auth_common.h
+21
-0
scripts/mysql_performance_tables.sql
scripts/mysql_performance_tables.sql
+3
-4
sql/hash_filo.h
sql/hash_filo.h
+76
-17
sql/hostname.cc
sql/hostname.cc
+554
-159
sql/hostname.h
sql/hostname.h
+160
-6
sql/mysqld.cc
sql/mysqld.cc
+46
-0
sql/mysqld.h
sql/mysqld.h
+6
-0
sql/sql_acl.cc
sql/sql_acl.cc
+43
-18
sql/sql_connect.cc
sql/sql_connect.cc
+131
-19
sql/sql_parse.cc
sql/sql_parse.cc
+4
-4
sql/sys_vars.cc
sql/sys_vars.cc
+17
-0
storage/perfschema/pfs_engine_table.cc
storage/perfschema/pfs_engine_table.cc
+1
-7
storage/perfschema/table_host_cache.cc
storage/perfschema/table_host_cache.cc
+0
-3
No files found.
include/mysql/plugin_auth_common.h
View file @
ecbf36a9
...
...
@@ -34,6 +34,27 @@
return values of the plugin authenticate_user() method.
*/
/**
Authentication failed, plugin internal error.
An error occurred in the authentication plugin itself.
These errors are reported in table performance_schema.host_cache,
column COUNT_AUTH_PLUGIN_ERRORS.
*/
#define CR_AUTH_PLUGIN_ERROR 3
/**
Authentication failed, client server handshake.
An error occurred during the client server handshake.
These errors are reported in table performance_schema.host_cache,
column COUNT_HANDSHAKE_ERRORS.
*/
#define CR_AUTH_HANDSHAKE 2
/**
Authentication failed, user credentials.
For example, wrong passwords.
These errors are reported in table performance_schema.host_cache,
column COUNT_AUTHENTICATION_ERRORS.
*/
#define CR_AUTH_USER_CREDENTIALS 1
/**
Authentication failed. Additionally, all other CR_xxx values
(libmysql error code) can be used too.
...
...
scripts/mysql_performance_tables.sql
View file @
ecbf36a9
...
...
@@ -497,10 +497,9 @@ SET @cmd="CREATE TABLE performance_schema.host_cache("
")ENGINE=PERFORMANCE_SCHEMA;"
;
SET
@
str
=
IF
(
@
have_pfs
=
1
,
@
cmd
,
'SET @dummy = 0'
);
#
Host
cache
is
disable
until
host
cache
code
is
merged
from
5
.
6
#
PREPARE
stmt
FROM
@
str
;
#
EXECUTE
stmt
;
#
DROP
PREPARE
stmt
;
PREPARE
stmt
FROM
@
str
;
EXECUTE
stmt
;
DROP
PREPARE
stmt
;
--
-- TABLE MUTEX_INSTANCES
...
...
sql/hash_filo.h
View file @
ecbf36a9
/* Copyright (c) 2000, 201
0
, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 201
1
, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
...
...
@@ -47,8 +47,11 @@ private:
class
hash_filo
{
const
uint
size
,
key_offset
,
key_length
;
private:
const
uint
key_offset
,
key_length
;
const
my_hash_get_key
get_key
;
/** Size of this hash table. */
uint
m_size
;
my_hash_free_key
free_element
;
bool
init
;
CHARSET_INFO
*
hash_charset
;
...
...
@@ -61,9 +64,12 @@ public:
hash_filo
(
uint
size_arg
,
uint
key_offset_arg
,
uint
key_length_arg
,
my_hash_get_key
get_key_arg
,
my_hash_free_key
free_element_arg
,
CHARSET_INFO
*
hash_charset_arg
)
:
size
(
size_arg
),
key_offset
(
key_offset_arg
),
key_length
(
key_length_arg
),
get_key
(
get_key_arg
),
free_element
(
free_element_arg
),
init
(
0
),
hash_charset
(
hash_charset_arg
)
:
key_offset
(
key_offset_arg
),
key_length
(
key_length_arg
),
get_key
(
get_key_arg
),
m_size
(
size_arg
),
free_element
(
free_element_arg
),
init
(
0
),
hash_charset
(
hash_charset_arg
),
first_link
(
NULL
),
last_link
(
NULL
)
{
bzero
((
char
*
)
&
cache
,
sizeof
(
cache
));
}
...
...
@@ -86,32 +92,61 @@ public:
}
if
(
!
locked
)
mysql_mutex_lock
(
&
lock
);
first_link
=
NULL
;
last_link
=
NULL
;
(
void
)
my_hash_free
(
&
cache
);
(
void
)
my_hash_init
(
&
cache
,
hash_charset
,
size
,
key_offset
,
(
void
)
my_hash_init
(
&
cache
,
hash_charset
,
m_
size
,
key_offset
,
key_length
,
get_key
,
free_element
,
0
);
if
(
!
locked
)
mysql_mutex_unlock
(
&
lock
);
first_link
=
last_link
=
0
;
}
hash_filo_element
*
first
()
{
mysql_mutex_assert_owner
(
&
lock
);
return
first_link
;
}
hash_filo_element
*
last
()
{
mysql_mutex_assert_owner
(
&
lock
);
return
last_link
;
}
hash_filo_element
*
search
(
uchar
*
key
,
size_t
length
)
{
mysql_mutex_assert_owner
(
&
lock
);
hash_filo_element
*
entry
=
(
hash_filo_element
*
)
my_hash_search
(
&
cache
,(
uchar
*
)
key
,
length
);
if
(
entry
)
{
// Found; link it first
DBUG_ASSERT
(
first_link
!=
NULL
);
DBUG_ASSERT
(
last_link
!=
NULL
);
if
(
entry
!=
first_link
)
{
// Relink used-chain
if
(
entry
==
last_link
)
last_link
=
entry
->
prev_used
;
{
last_link
=
last_link
->
prev_used
;
/*
The list must have at least 2 elements,
otherwise entry would be equal to first_link.
*/
DBUG_ASSERT
(
last_link
!=
NULL
);
last_link
->
next_used
=
NULL
;
}
else
{
DBUG_ASSERT
(
entry
->
next_used
!=
NULL
);
DBUG_ASSERT
(
entry
->
prev_used
!=
NULL
);
entry
->
next_used
->
prev_used
=
entry
->
prev_used
;
entry
->
prev_used
->
next_used
=
entry
->
next_used
;
}
if
((
entry
->
next_used
=
first_link
))
first_link
->
prev_used
=
entry
;
first_link
=
entry
;
entry
->
prev_used
=
NULL
;
entry
->
next_used
=
first_link
;
first_link
->
prev_used
=
entry
;
first_link
=
entry
;
}
}
return
entry
;
...
...
@@ -119,10 +154,20 @@ public:
bool
add
(
hash_filo_element
*
entry
)
{
if
(
cache
.
records
==
size
)
if
(
!
m_size
)
return
1
;
if
(
cache
.
records
==
m_size
)
{
hash_filo_element
*
tmp
=
last_link
;
last_link
=
last_link
->
prev_used
;
last_link
=
last_link
->
prev_used
;
if
(
last_link
!=
NULL
)
{
last_link
->
next_used
=
NULL
;
}
else
{
/* Pathological case, m_size == 1 */
first_link
=
NULL
;
}
my_hash_delete
(
&
cache
,(
uchar
*
)
tmp
);
}
if
(
my_hash_insert
(
&
cache
,(
uchar
*
)
entry
))
...
...
@@ -131,13 +176,27 @@ public:
(
*
free_element
)(
entry
);
// This should never happen
return
1
;
}
if
((
entry
->
next_used
=
first_link
))
first_link
->
prev_used
=
entry
;
entry
->
prev_used
=
NULL
;
entry
->
next_used
=
first_link
;
if
(
first_link
!=
NULL
)
first_link
->
prev_used
=
entry
;
else
last_link
=
entry
;
first_link
=
entry
;
last_link
=
entry
;
first_link
=
entry
;
return
0
;
}
uint
size
()
{
return
m_size
;
}
void
resize
(
uint
new_size
)
{
mysql_mutex_lock
(
&
lock
);
m_size
=
new_size
;
clear
(
true
);
mysql_mutex_unlock
(
&
lock
);
}
};
#endif
sql/hostname.cc
View file @
ecbf36a9
...
...
@@ -24,7 +24,6 @@
Hostnames are checked with reverse name lookup and checked that they
doesn't resemble an IP address.
*/
#include "sql_priv.h"
#include "hostname.h"
#include "my_global.h"
...
...
@@ -50,54 +49,101 @@ extern "C" { // Because of SCO 3.2V4.2
}
#endif
/*
HOST_ENTRY_KEY_SIZE -- size of IP address string in the hash cache.
*/
#define HOST_ENTRY_KEY_SIZE INET6_ADDRSTRLEN
/**
An entry in the hostname hash table cache.
Host name cache does two things:
- caches host names to save DNS look ups;
- counts connect errors from IP.
Host name can be NULL (that means DNS look up failed), but connect errors
still are counted.
*/
class
Host_entry
:
public
hash_filo_element
Host_errors
::
Host_errors
()
:
m_connect
(
0
),
m_host_blocked
(
0
),
m_nameinfo_transient
(
0
),
m_nameinfo_permanent
(
0
),
m_format
(
0
),
m_addrinfo_transient
(
0
),
m_addrinfo_permanent
(
0
),
m_FCrDNS
(
0
),
m_host_acl
(
0
),
m_no_auth_plugin
(
0
),
m_auth_plugin
(
0
),
m_handshake
(
0
),
m_proxy_user
(
0
),
m_proxy_user_acl
(
0
),
m_authentication
(
0
),
m_ssl
(
0
),
m_max_user_connection
(
0
),
m_max_user_connection_per_hour
(
0
),
m_default_database
(
0
),
m_init_connect
(
0
),
m_local
(
0
)
{}
Host_errors
::~
Host_errors
()
{}
void
Host_errors
::
reset
()
{
public:
/**
Client IP address. This is the key used with the hash table.
The client IP address is always expressed in IPv6, even when the
network IPv6 stack is not present.
This IP address is never used to connect to a socket.
*/
char
ip_key
[
HOST_ENTRY_KEY_SIZE
];
/**
Number of errors during handshake phase from the IP address.
*/
uint
connect_errors
;
m_connect
=
0
;
m_host_blocked
=
0
;
m_nameinfo_transient
=
0
;
m_nameinfo_permanent
=
0
;
m_format
=
0
;
m_addrinfo_transient
=
0
;
m_addrinfo_permanent
=
0
;
m_FCrDNS
=
0
;
m_host_acl
=
0
;
m_no_auth_plugin
=
0
;
m_auth_plugin
=
0
;
m_handshake
=
0
;
m_proxy_user
=
0
;
m_proxy_user_acl
=
0
;
m_authentication
=
0
;
m_ssl
=
0
;
m_max_user_connection
=
0
;
m_max_user_connection_per_hour
=
0
;
m_default_database
=
0
;
m_init_connect
=
0
;
m_local
=
0
;
}
/**
One of the host names for the IP address. May be NULL.
*/
const
char
*
hostname
;
};
void
Host_errors
::
aggregate
(
const
Host_errors
*
errors
)
{
m_connect
+=
errors
->
m_connect
;
m_host_blocked
+=
errors
->
m_host_blocked
;
m_nameinfo_transient
+=
errors
->
m_nameinfo_transient
;
m_nameinfo_permanent
+=
errors
->
m_nameinfo_permanent
;
m_format
+=
errors
->
m_format
;
m_addrinfo_transient
+=
errors
->
m_addrinfo_transient
;
m_addrinfo_permanent
+=
errors
->
m_addrinfo_permanent
;
m_FCrDNS
+=
errors
->
m_FCrDNS
;
m_host_acl
+=
errors
->
m_host_acl
;
m_no_auth_plugin
+=
errors
->
m_no_auth_plugin
;
m_auth_plugin
+=
errors
->
m_auth_plugin
;
m_handshake
+=
errors
->
m_handshake
;
m_proxy_user
+=
errors
->
m_proxy_user
;
m_proxy_user_acl
+=
errors
->
m_proxy_user_acl
;
m_authentication
+=
errors
->
m_authentication
;
m_ssl
+=
errors
->
m_ssl
;
m_max_user_connection
+=
errors
->
m_max_user_connection
;
m_max_user_connection_per_hour
+=
errors
->
m_max_user_connection_per_hour
;
m_default_database
+=
errors
->
m_default_database
;
m_init_connect
+=
errors
->
m_init_connect
;
m_local
+=
errors
->
m_local
;
}
static
hash_filo
*
hostname_cache
;
ulong
host_cache_size
;
void
hostname_cache_refresh
()
{
hostname_cache
->
clear
();
}
uint
hostname_cache_size
()
{
return
hostname_cache
->
size
();
}
void
hostname_cache_resize
(
uint
size
)
{
hostname_cache
->
resize
(
size
);
}
bool
hostname_cache_init
()
{
Host_entry
tmp
;
...
...
@@ -120,6 +166,16 @@ void hostname_cache_free()
hostname_cache
=
NULL
;
}
void
hostname_cache_lock
()
{
mysql_mutex_lock
(
&
hostname_cache
->
lock
);
}
void
hostname_cache_unlock
()
{
mysql_mutex_unlock
(
&
hostname_cache
->
lock
);
}
static
void
prepare_hostname_cache_key
(
const
char
*
ip_string
,
char
*
ip_key
)
{
...
...
@@ -130,69 +186,119 @@ static void prepare_hostname_cache_key(const char *ip_string,
memcpy
(
ip_key
,
ip_string
,
ip_string_length
);
}
Host_entry
*
hostname_cache_first
()
{
return
(
Host_entry
*
)
hostname_cache
->
first
();
}
static
inline
Host_entry
*
hostname_cache_search
(
const
char
*
ip_key
)
{
return
(
Host_entry
*
)
hostname_cache
->
search
((
uchar
*
)
ip_key
,
0
);
}
static
bool
add_hostname_impl
(
const
char
*
ip_key
,
const
char
*
hostname
)
static
void
add_hostname_impl
(
const
char
*
ip_key
,
const
char
*
hostname
,
bool
validated
,
Host_errors
*
errors
,
ulonglong
now
)
{
if
(
hostname_cache_search
(
ip_key
))
return
FALSE
;
size_t
hostname_size
=
hostname
?
strlen
(
hostname
)
+
1
:
0
;
Host_entry
*
entry
=
(
Host_entry
*
)
malloc
(
sizeof
(
Host_entry
)
+
hostname_size
);
if
(
!
entry
)
return
TRUE
;
char
*
hostname_copy
;
Host_entry
*
entry
;
bool
need_add
=
false
;
memcpy
(
&
entry
->
ip_key
,
ip_key
,
HOST_ENTRY_KEY_SIZE
);
entry
=
hostname_cache_search
(
ip_key
);
if
(
hostname_size
)
if
(
likely
(
entry
==
NULL
)
)
{
hostname_copy
=
(
char
*
)
(
entry
+
1
);
memcpy
(
hostname_copy
,
hostname
,
hostname_size
);
DBUG_PRINT
(
"info"
,
(
"Adding '%s' -> '%s' to the hostname cache...'"
,
(
const
char
*
)
ip_key
,
(
const
char
*
)
hostname_copy
));
entry
=
(
Host_entry
*
)
malloc
(
sizeof
(
Host_entry
));
if
(
entry
==
NULL
)
return
;
need_add
=
true
;
memcpy
(
&
entry
->
ip_key
,
ip_key
,
HOST_ENTRY_KEY_SIZE
);
entry
->
m_errors
.
reset
();
entry
->
m_hostname_length
=
0
;
entry
->
m_host_validated
=
false
;
entry
->
m_first_seen
=
now
;
entry
->
m_last_seen
=
now
;
entry
->
m_first_error_seen
=
0
;
entry
->
m_last_error_seen
=
0
;
}
else
{
hostname_copy
=
NULL
;
entry
->
m_last_seen
=
now
;
}
DBUG_PRINT
(
"info"
,
(
"Adding '%s' -> NULL to the hostname cache...'"
,
(
const
char
*
)
ip_key
));
if
(
validated
)
{
if
(
hostname
!=
NULL
)
{
uint
len
=
strlen
(
hostname
);
if
(
len
>
sizeof
(
entry
->
m_hostname
)
-
1
)
len
=
sizeof
(
entry
->
m_hostname
)
-
1
;
memcpy
(
entry
->
m_hostname
,
hostname
,
len
);
entry
->
m_hostname
[
len
]
=
'\0'
;
entry
->
m_hostname_length
=
len
;
DBUG_PRINT
(
"info"
,
(
"Adding/Updating '%s' -> '%s' (validated) to the hostname cache...'"
,
(
const
char
*
)
ip_key
,
(
const
char
*
)
entry
->
m_hostname
));
}
else
{
entry
->
m_hostname_length
=
0
;
DBUG_PRINT
(
"info"
,
(
"Adding/Updating '%s' -> NULL (validated) to the hostname cache...'"
,
(
const
char
*
)
ip_key
));
}
entry
->
m_host_validated
=
true
;
/*
New errors that are considered 'blocking',
that will eventually cause the IP to be black listed and blocked.
*/
errors
->
sum_connect_errors
();
}
else
{
entry
->
m_hostname_length
=
0
;
entry
->
m_host_validated
=
false
;
/* Do not count new blocking errors during DNS failures. */
errors
->
clear_connect_errors
();
DBUG_PRINT
(
"info"
,
(
"Adding/Updating '%s' -> NULL (not validated) to the hostname cache...'"
,
(
const
char
*
)
ip_key
));
}
entry
->
hostname
=
hostname_copy
;
entry
->
connect_errors
=
0
;
if
(
errors
->
has_error
())
entry
->
set_error_timestamps
(
now
);
entry
->
m_errors
.
aggregate
(
errors
);
return
hostname_cache
->
add
(
entry
);
if
(
need_add
)
hostname_cache
->
add
(
entry
);
return
;
}
static
bool
add_hostname
(
const
char
*
ip_key
,
const
char
*
hostname
)
static
void
add_hostname
(
const
char
*
ip_key
,
const
char
*
hostname
,
bool
validated
,
Host_errors
*
errors
)
{
if
(
specialflag
&
SPECIAL_NO_HOST_CACHE
)
return
FALSE
;
return
;
ulonglong
now
=
my_time
();
mysql_mutex_lock
(
&
hostname_cache
->
lock
);
bool
err_status
=
add_hostname_impl
(
ip_key
,
hostname
);
add_hostname_impl
(
ip_key
,
hostname
,
validated
,
errors
,
now
);
mysql_mutex_unlock
(
&
hostname_cache
->
lock
);
return
err_status
;
return
;
}
void
inc_host_errors
(
const
char
*
ip_string
)
void
inc_host_errors
(
const
char
*
ip_string
,
Host_errors
*
errors
)
{
if
(
!
ip_string
)
return
;
ulonglong
now
=
my_time
();
char
ip_key
[
HOST_ENTRY_KEY_SIZE
];
prepare_hostname_cache_key
(
ip_string
,
ip_key
);
...
...
@@ -201,13 +307,20 @@ void inc_host_errors(const char *ip_string)
Host_entry
*
entry
=
hostname_cache_search
(
ip_key
);
if
(
entry
)
entry
->
connect_errors
++
;
{
if
(
entry
->
m_host_validated
)
errors
->
sum_connect_errors
();
else
errors
->
clear_connect_errors
();
entry
->
m_errors
.
aggregate
(
errors
);
entry
->
set_error_timestamps
(
now
);
}
mysql_mutex_unlock
(
&
hostname_cache
->
lock
);
}
void
reset_host_errors
(
const
char
*
ip_string
)
void
reset_host_connect_errors
(
const
char
*
ip_string
)
{
if
(
!
ip_string
)
return
;
...
...
@@ -220,12 +333,11 @@ void reset_host_errors(const char *ip_string)
Host_entry
*
entry
=
hostname_cache_search
(
ip_key
);
if
(
entry
)
entry
->
connect_errors
=
0
;
entry
->
m_errors
.
clear_connect_errors
()
;
mysql_mutex_unlock
(
&
hostname_cache
->
lock
);
}
static
inline
bool
is_ip_loopback
(
const
struct
sockaddr
*
ip
)
{
switch
(
ip
->
sa_family
)
{
...
...
@@ -277,6 +389,7 @@ static inline bool is_hostname_valid(const char *hostname)
- returns host name if IP-address is validated;
- set value to out-variable connect_errors -- this variable represents the
number of connection errors from the specified IP-address.
- update the host_cache statistics
NOTE: connect_errors are counted (are supported) only for the clients
where IP-address can be resolved and FCrDNS check is passed.
...
...
@@ -287,37 +400,43 @@ static inline bool is_hostname_valid(const char *hostname)
@param [out] connect_errors
@return Error status
@retval
FALSE
Success
@retval
TRUE Error
@retval
0
Success
@retval
RC_BLOCKED_HOST The host is blocked.
The function does not set/report MySQL server error in case of failure.
It's caller's responsibility to handle failures of this function
properly.
*/
bool
ip_to_hostname
(
struct
sockaddr_storage
*
ip_storage
,
const
char
*
ip_string
,
char
**
hostname
,
uint
*
connect_errors
)
int
ip_to_hostname
(
struct
sockaddr_storage
*
ip_storage
,
const
char
*
ip_string
,
char
**
hostname
,
uint
*
connect_errors
)
{
const
struct
sockaddr
*
ip
=
(
const
sockaddr
*
)
ip_storage
;
int
err_code
;
bool
err_status
;
Host_errors
errors
;
DBUG_ENTER
(
"ip_to_hostname"
);
DBUG_PRINT
(
"info"
,
(
"IP address: '%s'; family: %d."
,
(
const
char
*
)
ip_string
,
(
int
)
ip
->
sa_family
));
/* Default output values, for most cases. */
*
hostname
=
NULL
;
*
connect_errors
=
0
;
/* Check if we have loopback address (127.0.0.1 or ::1). */
if
(
is_ip_loopback
(
ip
))
{
DBUG_PRINT
(
"info"
,
(
"Loopback address detected."
));
*
connect_errors
=
0
;
/* Do not count connect errors from localhost. */
/* Do not count connect errors from localhost. */
*
hostname
=
(
char
*
)
my_localhost
;
DBUG_RETURN
(
FALSE
);
DBUG_RETURN
(
0
);
}
/* Prepare host name cache key. */
...
...
@@ -329,27 +448,45 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
if
(
!
(
specialflag
&
SPECIAL_NO_HOST_CACHE
))
{
ulonglong
now
=
my_time
();
mysql_mutex_lock
(
&
hostname_cache
->
lock
);
Host_entry
*
entry
=
hostname_cache_search
(
ip_key
);
if
(
entry
)
{
*
connect_errors
=
entry
->
connect_errors
;
*
hostname
=
NULL
;
entry
->
m_last_seen
=
now
;
if
(
entry
->
m_errors
.
m_connect
>
max_connect_errors
)
{
entry
->
m_errors
.
m_host_blocked
++
;
entry
->
set_error_timestamps
(
now
);
*
connect_errors
=
entry
->
m_errors
.
m_connect
;
mysql_mutex_unlock
(
&
hostname_cache
->
lock
);
DBUG_RETURN
(
RC_BLOCKED_HOST
);
}
if
(
entry
->
hostname
)
*
hostname
=
my_strdup
(
entry
->
hostname
,
MYF
(
0
));
/*
If there is an IP -> HOSTNAME association in the cache,
but for a hostname that was not validated,
do not return that hostname: perform the network validation again.
*/
if
(
entry
->
m_host_validated
)
{
if
(
entry
->
m_hostname_length
)
*
hostname
=
my_strdup
(
entry
->
m_hostname
,
MYF
(
0
));
DBUG_PRINT
(
"info"
,(
"IP (%s) has been found in the cache. "
"Hostname: '%s'; connect_errors: %d
"
,
(
const
char
*
)
ip_key
,
(
const
char
*
)
(
*
hostname
?
*
hostname
:
"null"
),
(
int
)
*
connect_errors
));
DBUG_PRINT
(
"info"
,(
"IP (%s) has been found in the cache. "
"Hostname: '%s'
"
,
(
const
char
*
)
ip_key
,
(
const
char
*
)
(
*
hostname
?
*
hostname
:
"null"
)
));
mysql_mutex_unlock
(
&
hostname_cache
->
lock
);
mysql_mutex_unlock
(
&
hostname_cache
->
lock
);
DBUG_RETURN
(
FALSE
);
DBUG_RETURN
(
0
);
}
}
mysql_mutex_unlock
(
&
hostname_cache
->
lock
);
...
...
@@ -367,13 +504,60 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
err_code
=
vio_getnameinfo
(
ip
,
hostname_buffer
,
NI_MAXHOST
,
NULL
,
0
,
NI_NAMEREQD
);
/* BEGIN : DEBUG */
DBUG_EXECUTE_IF
(
"addr_fake_ipv4"
,
/*
===========================================================================
DEBUG code only (begin)
Simulate various output from vio_getnameinfo().
===========================================================================
*/
DBUG_EXECUTE_IF
(
"getnameinfo_error_noname"
,
{
strcpy
(
hostname_buffer
,
"<garbage>"
);
err_code
=
EAI_NONAME
;
}
);
DBUG_EXECUTE_IF
(
"getnameinfo_error_again"
,
{
strcpy
(
hostname_buffer
,
"<garbage>"
);
err_code
=
EAI_AGAIN
;
}
);
DBUG_EXECUTE_IF
(
"getnameinfo_fake_ipv4"
,
{
strcpy
(
hostname_buffer
,
"santa.claus.ipv4.example.com"
);
err_code
=
0
;
};);
/* END : DEBUG */
}
);
DBUG_EXECUTE_IF
(
"getnameinfo_fake_ipv6"
,
{
strcpy
(
hostname_buffer
,
"santa.claus.ipv6.example.com"
);
err_code
=
0
;
}
);
DBUG_EXECUTE_IF
(
"getnameinfo_format_ipv4"
,
{
strcpy
(
hostname_buffer
,
"12.12.12.12"
);
err_code
=
0
;
}
);
DBUG_EXECUTE_IF
(
"getnameinfo_format_ipv6"
,
{
strcpy
(
hostname_buffer
,
"12:DEAD:BEEF:0"
);
err_code
=
0
;
}
);
/*
===========================================================================
DEBUG code only (end)
===========================================================================
*/
if
(
err_code
)
{
...
...
@@ -387,23 +571,29 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
(
const
char
*
)
ip_key
,
(
const
char
*
)
gai_strerror
(
err_code
));
bool
validated
;
if
(
vio_is_no_name_error
(
err_code
))
{
/*
The no-name error means that there is no reverse address mapping
for the IP address. A host name can not be resolved.
*/
errors
.
m_nameinfo_permanent
=
1
;
validated
=
true
;
}
else
{
/*
If it is not the no-name error, we should not cache the hostname
(or rather its absence), because the failure might be transient.
Only the ip error statistics are cached.
*/
add_hostname
(
ip_key
,
NULL
);
*
hostname
=
NULL
;
*
connect_errors
=
0
;
/* New IP added to the cache. */
errors
.
m_nameinfo_transient
=
1
;
validated
=
false
;
}
add_hostname
(
ip_key
,
NULL
,
validated
,
&
errors
);
DBUG_RETURN
(
FALSE
);
DBUG_RETURN
(
0
);
}
DBUG_PRINT
(
"info"
,
(
"IP '%s' resolved to '%s'."
,
...
...
@@ -439,24 +629,21 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
(
const
char
*
)
ip_key
,
(
const
char
*
)
hostname_buffer
);
err_status
=
add_hostname
(
ip_key
,
NULL
);
*
hostname
=
NULL
;
*
connect_errors
=
0
;
/* New IP added to the cache. */
errors
.
m_format
=
1
;
add_hostname
(
ip_key
,
hostname_buffer
,
false
,
&
errors
);
DBUG_RETURN
(
err_status
);
DBUG_RETURN
(
false
);
}
/*
To avoid crashing the server in DBUG_EXECUTE_IF,
Define a variable which depicts state of addr_info_list.
*/
bool
free_addr_info_list
=
false
;
/* Get IP-addresses for the resolved host name (FCrDNS technique). */
struct
addrinfo
hints
;
struct
addrinfo
*
addr_info_list
;
/*
Makes fault injection with DBUG_EXECUTE_IF easier.
Invoking free_addr_info(NULL) crashes on some platforms.
*/
bool
free_addr_info_list
=
false
;
memset
(
&
hints
,
0
,
sizeof
(
struct
addrinfo
));
hints
.
ai_flags
=
AI_PASSIVE
;
...
...
@@ -470,8 +657,72 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
if
(
err_code
==
0
)
free_addr_info_list
=
true
;
/* BEGIN : DEBUG */
DBUG_EXECUTE_IF
(
"addr_fake_ipv4"
,
/*
===========================================================================
DEBUG code only (begin)
Simulate various output from getaddrinfo().
===========================================================================
*/
DBUG_EXECUTE_IF
(
"getaddrinfo_error_noname"
,
{
if
(
free_addr_info_list
)
freeaddrinfo
(
addr_info_list
);
addr_info_list
=
NULL
;
err_code
=
EAI_NONAME
;
free_addr_info_list
=
false
;
}
);
DBUG_EXECUTE_IF
(
"getaddrinfo_error_again"
,
{
if
(
free_addr_info_list
)
freeaddrinfo
(
addr_info_list
);
addr_info_list
=
NULL
;
err_code
=
EAI_AGAIN
;
free_addr_info_list
=
false
;
}
);
DBUG_EXECUTE_IF
(
"getaddrinfo_fake_bad_ipv4"
,
{
if
(
free_addr_info_list
)
freeaddrinfo
(
addr_info_list
);
struct
sockaddr_in
*
debug_addr
;
/*
Not thread safe, which is ok.
Only one connection at a time is tested with
fault injection.
*/
static
struct
sockaddr_in
debug_sock_addr
[
2
];
static
struct
addrinfo
debug_addr_info
[
2
];
/* Simulating ipv4 192.0.2.126 */
debug_addr
=
&
debug_sock_addr
[
0
];
debug_addr
->
sin_family
=
AF_INET
;
debug_addr
->
sin_addr
.
s_addr
=
inet_addr
(
"192.0.2.126"
);
/* Simulating ipv4 192.0.2.127 */
debug_addr
=
&
debug_sock_addr
[
1
];
debug_addr
->
sin_family
=
AF_INET
;
debug_addr
->
sin_addr
.
s_addr
=
inet_addr
(
"192.0.2.127"
);
debug_addr_info
[
0
].
ai_addr
=
(
struct
sockaddr
*
)
&
debug_sock_addr
[
0
];
debug_addr_info
[
0
].
ai_addrlen
=
sizeof
(
struct
sockaddr_in
);
debug_addr_info
[
0
].
ai_next
=
&
debug_addr_info
[
1
];
debug_addr_info
[
1
].
ai_addr
=
(
struct
sockaddr
*
)
&
debug_sock_addr
[
1
];
debug_addr_info
[
1
].
ai_addrlen
=
sizeof
(
struct
sockaddr_in
);
debug_addr_info
[
1
].
ai_next
=
NULL
;
addr_info_list
=
&
debug_addr_info
[
0
];
err_code
=
0
;
free_addr_info_list
=
false
;
}
);
DBUG_EXECUTE_IF
(
"getaddrinfo_fake_good_ipv4"
,
{
if
(
free_addr_info_list
)
freeaddrinfo
(
addr_info_list
);
...
...
@@ -500,30 +751,186 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
addr_info_list
=
&
debug_addr_info
[
0
];
err_code
=
0
;
free_addr_info_list
=
false
;
};);
}
);
/* END : DEBUG */
#ifdef HAVE_IPV6
DBUG_EXECUTE_IF
(
"getaddrinfo_fake_bad_ipv6"
,
{
if
(
free_addr_info_list
)
freeaddrinfo
(
addr_info_list
);
if
(
err_code
==
EAI_NONAME
)
{
/*
Don't cache responses when the DNS server is down, as otherwise
transient DNS failure may leave any number of clients (those
that attempted to connect during the outage) unable to connect
indefinitely.
*/
struct
sockaddr_in6
*
debug_addr
;
struct
in6_addr
*
ip6
;
/*
Not thread safe, which is ok.
Only one connection at a time is tested with
fault injection.
*/
static
struct
sockaddr_in6
debug_sock_addr
[
2
];
static
struct
addrinfo
debug_addr_info
[
2
];
/* Simulating ipv6 2001:DB8::6:7E */
debug_addr
=
&
debug_sock_addr
[
0
];
debug_addr
->
sin6_family
=
AF_INET6
;
ip6
=
&
debug_addr
->
sin6_addr
;
/* inet_pton not available on Windows XP. */
ip6
->
s6_addr
[
0
]
=
0x20
;
ip6
->
s6_addr
[
1
]
=
0x01
;
ip6
->
s6_addr
[
2
]
=
0x0d
;
ip6
->
s6_addr
[
3
]
=
0xb8
;
ip6
->
s6_addr
[
4
]
=
0x00
;
ip6
->
s6_addr
[
5
]
=
0x00
;
ip6
->
s6_addr
[
6
]
=
0x00
;
ip6
->
s6_addr
[
7
]
=
0x00
;
ip6
->
s6_addr
[
8
]
=
0x00
;
ip6
->
s6_addr
[
9
]
=
0x00
;
ip6
->
s6_addr
[
10
]
=
0x00
;
ip6
->
s6_addr
[
11
]
=
0x00
;
ip6
->
s6_addr
[
12
]
=
0x00
;
ip6
->
s6_addr
[
13
]
=
0x06
;
ip6
->
s6_addr
[
14
]
=
0x00
;
ip6
->
s6_addr
[
15
]
=
0x7e
;
/* Simulating ipv6 2001:DB8::6:7F */
debug_addr
=
&
debug_sock_addr
[
1
];
debug_addr
->
sin6_family
=
AF_INET6
;
ip6
=
&
debug_addr
->
sin6_addr
;
ip6
->
s6_addr
[
0
]
=
0x20
;
ip6
->
s6_addr
[
1
]
=
0x01
;
ip6
->
s6_addr
[
2
]
=
0x0d
;
ip6
->
s6_addr
[
3
]
=
0xb8
;
ip6
->
s6_addr
[
4
]
=
0x00
;
ip6
->
s6_addr
[
5
]
=
0x00
;
ip6
->
s6_addr
[
6
]
=
0x00
;
ip6
->
s6_addr
[
7
]
=
0x00
;
ip6
->
s6_addr
[
8
]
=
0x00
;
ip6
->
s6_addr
[
9
]
=
0x00
;
ip6
->
s6_addr
[
10
]
=
0x00
;
ip6
->
s6_addr
[
11
]
=
0x00
;
ip6
->
s6_addr
[
12
]
=
0x00
;
ip6
->
s6_addr
[
13
]
=
0x06
;
ip6
->
s6_addr
[
14
]
=
0x00
;
ip6
->
s6_addr
[
15
]
=
0x7f
;
debug_addr_info
[
0
].
ai_addr
=
(
struct
sockaddr
*
)
&
debug_sock_addr
[
0
];
debug_addr_info
[
0
].
ai_addrlen
=
sizeof
(
struct
sockaddr_in6
);
debug_addr_info
[
0
].
ai_next
=
&
debug_addr_info
[
1
];
err_status
=
add_hostname
(
ip_key
,
NULL
);
debug_addr_info
[
1
].
ai_addr
=
(
struct
sockaddr
*
)
&
debug_sock_addr
[
1
];
debug_addr_info
[
1
].
ai_addrlen
=
sizeof
(
struct
sockaddr_in6
);
debug_addr_info
[
1
].
ai_next
=
NULL
;
*
hostname
=
NULL
;
*
connect_errors
=
0
;
/* New IP added to the cache. */
addr_info_list
=
&
debug_addr_info
[
0
];
err_code
=
0
;
free_addr_info_list
=
false
;
}
);
DBUG_RETURN
(
err_status
);
}
else
if
(
err_code
)
DBUG_EXECUTE_IF
(
"getaddrinfo_fake_good_ipv6"
,
{
if
(
free_addr_info_list
)
freeaddrinfo
(
addr_info_list
);
struct
sockaddr_in6
*
debug_addr
;
struct
in6_addr
*
ip6
;
/*
Not thread safe, which is ok.
Only one connection at a time is tested with
fault injection.
*/
static
struct
sockaddr_in6
debug_sock_addr
[
2
];
static
struct
addrinfo
debug_addr_info
[
2
];
/* Simulating ipv6 2001:DB8::6:7 */
debug_addr
=
&
debug_sock_addr
[
0
];
debug_addr
->
sin6_family
=
AF_INET6
;
ip6
=
&
debug_addr
->
sin6_addr
;
ip6
->
s6_addr
[
0
]
=
0x20
;
ip6
->
s6_addr
[
1
]
=
0x01
;
ip6
->
s6_addr
[
2
]
=
0x0d
;
ip6
->
s6_addr
[
3
]
=
0xb8
;
ip6
->
s6_addr
[
4
]
=
0x00
;
ip6
->
s6_addr
[
5
]
=
0x00
;
ip6
->
s6_addr
[
6
]
=
0x00
;
ip6
->
s6_addr
[
7
]
=
0x00
;
ip6
->
s6_addr
[
8
]
=
0x00
;
ip6
->
s6_addr
[
9
]
=
0x00
;
ip6
->
s6_addr
[
10
]
=
0x00
;
ip6
->
s6_addr
[
11
]
=
0x00
;
ip6
->
s6_addr
[
12
]
=
0x00
;
ip6
->
s6_addr
[
13
]
=
0x06
;
ip6
->
s6_addr
[
14
]
=
0x00
;
ip6
->
s6_addr
[
15
]
=
0x07
;
/* Simulating ipv6 2001:DB8::6:6 */
debug_addr
=
&
debug_sock_addr
[
1
];
debug_addr
->
sin6_family
=
AF_INET6
;
ip6
=
&
debug_addr
->
sin6_addr
;
ip6
->
s6_addr
[
0
]
=
0x20
;
ip6
->
s6_addr
[
1
]
=
0x01
;
ip6
->
s6_addr
[
2
]
=
0x0d
;
ip6
->
s6_addr
[
3
]
=
0xb8
;
ip6
->
s6_addr
[
4
]
=
0x00
;
ip6
->
s6_addr
[
5
]
=
0x00
;
ip6
->
s6_addr
[
6
]
=
0x00
;
ip6
->
s6_addr
[
7
]
=
0x00
;
ip6
->
s6_addr
[
8
]
=
0x00
;
ip6
->
s6_addr
[
9
]
=
0x00
;
ip6
->
s6_addr
[
10
]
=
0x00
;
ip6
->
s6_addr
[
11
]
=
0x00
;
ip6
->
s6_addr
[
12
]
=
0x00
;
ip6
->
s6_addr
[
13
]
=
0x06
;
ip6
->
s6_addr
[
14
]
=
0x00
;
ip6
->
s6_addr
[
15
]
=
0x06
;
debug_addr_info
[
0
].
ai_addr
=
(
struct
sockaddr
*
)
&
debug_sock_addr
[
0
];
debug_addr_info
[
0
].
ai_addrlen
=
sizeof
(
struct
sockaddr_in6
);
debug_addr_info
[
0
].
ai_next
=
&
debug_addr_info
[
1
];
debug_addr_info
[
1
].
ai_addr
=
(
struct
sockaddr
*
)
&
debug_sock_addr
[
1
];
debug_addr_info
[
1
].
ai_addrlen
=
sizeof
(
struct
sockaddr_in6
);
debug_addr_info
[
1
].
ai_next
=
NULL
;
addr_info_list
=
&
debug_addr_info
[
0
];
err_code
=
0
;
free_addr_info_list
=
false
;
}
);
#endif
/* HAVE_IPV6 */
/*
===========================================================================
DEBUG code only (end)
===========================================================================
*/
if
(
err_code
!=
0
)
{
DBUG_PRINT
(
"error"
,
(
"getaddrinfo() failed with error code %d."
,
err_code
));
DBUG_RETURN
(
TRUE
);
sql_print_warning
(
"Host name '%s' could not be resolved: %s"
,
(
const
char
*
)
hostname_buffer
,
(
const
char
*
)
gai_strerror
(
err_code
));
bool
validated
;
if
(
err_code
==
EAI_NONAME
)
{
errors
.
m_addrinfo_permanent
=
1
;
validated
=
true
;
}
else
{
/*
Don't cache responses when the DNS server is down, as otherwise
transient DNS failure may leave any number of clients (those
that attempted to connect during the outage) unable to connect
indefinitely.
Only cache error statistics.
*/
errors
.
m_addrinfo_transient
=
1
;
validated
=
false
;
}
add_hostname
(
ip_key
,
NULL
,
validated
,
&
errors
);
DBUG_RETURN
(
false
);
}
/* Check that getaddrinfo() returned the used IP (FCrDNS technique). */
...
...
@@ -545,7 +952,7 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
DBUG_PRINT
(
"info"
,
(
" - '%s'"
,
(
const
char
*
)
ip_buffer
));
if
(
strcmp
(
ip_key
,
ip_buffer
)
==
0
)
if
(
strc
asec
mp
(
ip_key
,
ip_buffer
)
==
0
)
{
/* Copy host name string to be stored in the cache. */
...
...
@@ -557,7 +964,7 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
if
(
free_addr_info_list
)
freeaddrinfo
(
addr_info_list
);
DBUG_RETURN
(
TRUE
);
DBUG_RETURN
(
true
);
}
break
;
...
...
@@ -568,9 +975,11 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
if
(
!*
hostname
)
{
sql_print_information
(
"Hostname '%s' does not resolve to '%s'."
,
(
const
char
*
)
hostname_buffer
,
(
const
char
*
)
ip_key
);
errors
.
m_FCrDNS
=
1
;
sql_print_warning
(
"Hostname '%s' does not resolve to '%s'."
,
(
const
char
*
)
hostname_buffer
,
(
const
char
*
)
ip_key
);
sql_print_information
(
"Hostname '%s' has the following IP addresses:"
,
(
const
char
*
)
hostname_buffer
);
...
...
@@ -584,30 +993,16 @@ bool ip_to_hostname(struct sockaddr_storage *ip_storage,
ip_buffer
,
sizeof
(
ip_buffer
));
DBUG_ASSERT
(
!
err_status
);
sql_print_information
(
" - %s
\n
"
,
(
const
char
*
)
ip_buffer
);
sql_print_information
(
" - %s"
,
(
const
char
*
)
ip_buffer
);
}
}
/* Free the result of getaddrinfo(). */
/* Add an entry for the IP to the cache. */
add_hostname
(
ip_key
,
*
hostname
,
true
,
&
errors
);
/* Free the result of getaddrinfo(). */
if
(
free_addr_info_list
)
freeaddrinfo
(
addr_info_list
);
/* Add an entry for the IP to the cache. */
if
(
*
hostname
)
{
err_status
=
add_hostname
(
ip_key
,
*
hostname
);
*
connect_errors
=
0
;
}
else
{
DBUG_PRINT
(
"error"
,(
"Couldn't verify hostname with getaddrinfo()."
));
err_status
=
add_hostname
(
ip_key
,
NULL
);
*
hostname
=
NULL
;
*
connect_errors
=
0
;
}
DBUG_RETURN
(
err_status
);
DBUG_RETURN
(
false
);
}
sql/hostname.h
View file @
ecbf36a9
/* Copyright (c) 2006, 201
0
, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2006, 201
1
, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
...
...
@@ -17,14 +17,168 @@
#define HOSTNAME_INCLUDED
#include "my_global.h"
/* uint */
#include "my_net.h"
#include "hash_filo.h"
bool
ip_to_hostname
(
struct
sockaddr_storage
*
ip_storage
,
const
char
*
ip_string
,
char
**
hostname
,
uint
*
connect_errors
);
void
inc_host_errors
(
const
char
*
ip_string
);
void
reset_host_errors
(
const
char
*
ip_string
);
struct
Host_errors
{
public:
Host_errors
();
~
Host_errors
();
void
reset
();
void
aggregate
(
const
Host_errors
*
errors
);
/** Number of connect errors. */
ulong
m_connect
;
/** Number of host blocked errors. */
ulong
m_host_blocked
;
/** Number of transient errors from getnameinfo(). */
ulong
m_nameinfo_transient
;
/** Number of permanent errors from getnameinfo(). */
ulong
m_nameinfo_permanent
;
/** Number of errors from is_hostname_valid(). */
ulong
m_format
;
/** Number of transient errors from getaddrinfo(). */
ulong
m_addrinfo_transient
;
/** Number of permanent errors from getaddrinfo(). */
ulong
m_addrinfo_permanent
;
/** Number of errors from Forward-Confirmed reverse DNS checks. */
ulong
m_FCrDNS
;
/** Number of errors from host grants. */
ulong
m_host_acl
;
/** Number of errors from missing auth plugin. */
ulong
m_no_auth_plugin
;
/** Number of errors from auth plugin. */
ulong
m_auth_plugin
;
/** Number of errors from authentication plugins. */
ulong
m_handshake
;
/** Number of errors from proxy user. */
ulong
m_proxy_user
;
/** Number of errors from proxy user acl. */
ulong
m_proxy_user_acl
;
/** Number of errors from authentication. */
ulong
m_authentication
;
/** Number of errors from ssl. */
ulong
m_ssl
;
/** Number of errors from max user connection. */
ulong
m_max_user_connection
;
/** Number of errors from max user connection per hour. */
ulong
m_max_user_connection_per_hour
;
/** Number of errors from the default database. */
ulong
m_default_database
;
/** Number of errors from init_connect. */
ulong
m_init_connect
;
/** Number of errors from the server itself. */
ulong
m_local
;
bool
has_error
()
const
{
return
((
m_host_blocked
!=
0
)
||
(
m_nameinfo_transient
!=
0
)
||
(
m_nameinfo_permanent
!=
0
)
||
(
m_format
!=
0
)
||
(
m_addrinfo_transient
!=
0
)
||
(
m_addrinfo_permanent
!=
0
)
||
(
m_FCrDNS
!=
0
)
||
(
m_host_acl
!=
0
)
||
(
m_no_auth_plugin
!=
0
)
||
(
m_auth_plugin
!=
0
)
||
(
m_handshake
!=
0
)
||
(
m_proxy_user
!=
0
)
||
(
m_proxy_user_acl
!=
0
)
||
(
m_authentication
!=
0
)
||
(
m_ssl
!=
0
)
||
(
m_max_user_connection
!=
0
)
||
(
m_max_user_connection_per_hour
!=
0
)
||
(
m_default_database
!=
0
)
||
(
m_init_connect
!=
0
)
||
(
m_local
!=
0
));
}
void
sum_connect_errors
()
{
/* Current (historical) behavior: */
m_connect
=
m_handshake
;
}
void
clear_connect_errors
()
{
m_connect
=
0
;
}
};
/** Size of IP address string in the hash cache. */
#define HOST_ENTRY_KEY_SIZE INET6_ADDRSTRLEN
/**
An entry in the hostname hash table cache.
Host name cache does two things:
- caches host names to save DNS look ups;
- counts errors from IP.
Host name can be empty (that means DNS look up failed),
but errors still are counted.
*/
class
Host_entry
:
public
hash_filo_element
{
public:
Host_entry
*
next
()
{
return
(
Host_entry
*
)
hash_filo_element
::
next
();
}
/**
Client IP address. This is the key used with the hash table.
The client IP address is always expressed in IPv6, even when the
network IPv6 stack is not present.
This IP address is never used to connect to a socket.
*/
char
ip_key
[
HOST_ENTRY_KEY_SIZE
];
/**
One of the host names for the IP address. May be a zero length string.
*/
char
m_hostname
[
HOSTNAME_LENGTH
+
1
];
/** Length in bytes of @c m_hostname. */
uint
m_hostname_length
;
/** The hostname is validated and used for authorization. */
bool
m_host_validated
;
ulonglong
m_first_seen
;
ulonglong
m_last_seen
;
ulonglong
m_first_error_seen
;
ulonglong
m_last_error_seen
;
/** Error statistics. */
Host_errors
m_errors
;
void
set_error_timestamps
(
ulonglong
now
)
{
if
(
m_first_error_seen
==
0
)
m_first_error_seen
=
now
;
m_last_error_seen
=
now
;
}
};
/** The size of the host_cache. */
extern
ulong
host_cache_size
;
#define RC_OK 0
#define RC_BLOCKED_HOST 1
int
ip_to_hostname
(
struct
sockaddr_storage
*
ip_storage
,
const
char
*
ip_string
,
char
**
hostname
,
uint
*
connect_errors
);
void
inc_host_errors
(
const
char
*
ip_string
,
Host_errors
*
errors
);
void
reset_host_connect_errors
(
const
char
*
ip_string
);
bool
hostname_cache_init
();
void
hostname_cache_free
();
void
hostname_cache_refresh
(
void
);
uint
hostname_cache_size
();
void
hostname_cache_resize
(
uint
size
);
void
hostname_cache_lock
();
void
hostname_cache_unlock
();
Host_entry
*
hostname_cache_first
();
#endif
/* HOSTNAME_INCLUDED */
sql/mysqld.cc
View file @
ecbf36a9
...
...
@@ -612,6 +612,19 @@ const char *in_left_expr_name= "<left expr>";
const
char
*
in_additional_cond
=
"<IN COND>"
;
const
char
*
in_having_cond
=
"<IN HAVING>"
;
/** Number of connection errors when selecting on the listening port */
ulong
connection_errors_select
=
0
;
/** Number of connection errors when accepting sockets in the listening port. */
ulong
connection_errors_accept
=
0
;
/** Number of connection errors from TCP wrappers. */
ulong
connection_errors_tcpwrap
=
0
;
/** Number of connection errors from internal server errors. */
ulong
connection_errors_internal
=
0
;
/** Number of connection errors from the server max_connection limit. */
ulong
connection_errors_max_connection
=
0
;
/** Number of errors when reading the peer address. */
ulong
connection_errors_peer_addr
=
0
;
/* classes for comparation parsing/processing */
Eq_creator
eq_creator
;
Ne_creator
ne_creator
;
...
...
@@ -3648,6 +3661,12 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific)
static
int
init_common_variables
()
{
umask
(((
~
my_umask
)
&
0666
));
connection_errors_select
=
0
;
connection_errors_accept
=
0
;
connection_errors_tcpwrap
=
0
;
connection_errors_internal
=
0
;
connection_errors_max_connection
=
0
;
connection_errors_peer_addr
=
0
;
my_decimal_set_zero
(
&
decimal_zero
);
// set decimal_zero constant;
if
(
pthread_key_create
(
&
THR_THD
,
NULL
)
||
...
...
@@ -5655,6 +5674,7 @@ void create_thread_to_handle_connection(THD *thd)
mysql_mutex_unlock
(
&
LOCK_connection_count
);
statistic_increment
(
aborted_connects
,
&
LOCK_status
);
statistic_increment
(
connection_errors_internal
,
&
LOCK_status
);
/* Can't use my_error() since store_globals has not been called. */
my_snprintf
(
error_message_buff
,
sizeof
(
error_message_buff
),
ER_THD
(
thd
,
ER_CANT_CREATE_THREAD
),
error
);
...
...
@@ -5705,6 +5725,7 @@ static void create_new_thread(THD *thd)
close_connection
(
thd
,
ER_CON_COUNT_ERROR
);
statistic_increment
(
denied_connections
,
&
LOCK_status
);
delete
thd
;
statistic_increment
(
connection_errors_max_connection
,
&
LOCK_status
);
DBUG_VOID_RETURN
;
}
...
...
@@ -5819,6 +5840,12 @@ void handle_connections_sockets()
{
if
(
socket_errno
!=
SOCKET_EINTR
)
{
/*
select(2)/poll(2) failed on the listening port.
There is not much details to report about the client,
increment the server global status variable.
*/
statistic_increment
(
connection_errors_accept
,
&
LOCK_status
);
if
(
!
select_errors
++
&&
!
abort_loop
)
/* purecov: inspected */
sql_print_error
(
"mysqld: Got error %d from select"
,
socket_errno
);
/* purecov: inspected */
}
...
...
@@ -5899,6 +5926,12 @@ void handle_connections_sockets()
#endif
if
(
mysql_socket_getfd
(
new_sock
)
==
INVALID_SOCKET
)
{
/*
accept(2) failed on the listening port, after many retries.
There is not much details to report about the client,
increment the server global status variable.
*/
statistic_increment
(
connection_errors_accept
,
&
LOCK_status
);
if
((
error_count
++
&
255
)
==
0
)
// This can happen often
sql_perror
(
"Error in accept"
);
MAYBE_BROKEN_SYSCALL
;
...
...
@@ -5938,6 +5971,11 @@ void handle_connections_sockets()
(
void
)
mysql_socket_shutdown
(
new_sock
,
SHUT_RDWR
);
(
void
)
mysql_socket_close
(
new_sock
);
/*
The connection was refused by TCP wrappers.
There are no details (by client IP) available to update the host_cache.
*/
statistic_increment
(
connection_tcpwrap_errors
,
&
LOCK_status
);
continue
;
}
}
...
...
@@ -5968,6 +6006,7 @@ void handle_connections_sockets()
{
(
void
)
mysql_socket_shutdown
(
new_sock
,
SHUT_RDWR
);
(
void
)
mysql_socket_close
(
new_sock
);
statistic_increment
(
connection_errors_internal
,
&
LOCK_status
);
continue
;
}
/* Set to get io buffers to be part of THD */
...
...
@@ -5996,6 +6035,7 @@ void handle_connections_sockets()
}
delete
thd
;
set_current_thd
(
0
);
statistic_increment
(
connection_errors_internal
,
&
LOCK_status
);
continue
;
}
...
...
@@ -7363,6 +7403,12 @@ SHOW_VAR status_vars[]= {
{
"Com"
,
(
char
*
)
com_status_vars
,
SHOW_ARRAY
},
{
"Compression"
,
(
char
*
)
&
show_net_compression
,
SHOW_SIMPLE_FUNC
},
{
"Connections"
,
(
char
*
)
&
thread_id
,
SHOW_LONG_NOFLUSH
},
{
"Connection_errors_accept"
,
(
char
*
)
&
connection_errors_accept
,
SHOW_LONG
},
{
"Connection_errors_internal"
,
(
char
*
)
&
connection_errors_internal
,
SHOW_LONG
},
{
"Connection_errors_max_connections"
,
(
char
*
)
&
connection_errors_max_connection
,
SHOW_LONG
},
{
"Connection_errors_peer_address"
,
(
char
*
)
&
connection_errors_peer_addr
,
SHOW_LONG
},
{
"Connection_errors_select"
,
(
char
*
)
&
connection_errors_select
,
SHOW_LONG
},
{
"Connection_errors_tcpwrap"
,
(
char
*
)
&
connection_errors_tcpwrap
,
SHOW_LONG
},
{
"Cpu_time"
,
(
char
*
)
offsetof
(
STATUS_VAR
,
cpu_time
),
SHOW_DOUBLE_STATUS
},
{
"Created_tmp_disk_tables"
,
(
char
*
)
offsetof
(
STATUS_VAR
,
created_tmp_disk_tables_
),
SHOW_LONG_STATUS
},
{
"Created_tmp_files"
,
(
char
*
)
&
my_tmp_file_created
,
SHOW_LONG
},
...
...
sql/mysqld.h
View file @
ecbf36a9
...
...
@@ -213,6 +213,12 @@ extern int bootstrap_error;
extern
I_List
<
THD
>
threads
;
extern
char
err_shared_dir
[];
extern
TYPELIB
thread_handling_typelib
;
extern
ulong
connection_errors_select
;
extern
ulong
connection_errors_accept
;
extern
ulong
connection_errors_tcpwrap
;
extern
ulong
connection_errors_internal
;
extern
ulong
connection_errors_max_connection
;
extern
ulong
connection_errors_peer_addr
;
extern
ulong
log_warnings
;
/*
...
...
sql/sql_acl.cc
View file @
ecbf36a9
...
...
@@ -1829,6 +1829,13 @@ bool acl_check_host(const char *host, const char *ip)
}
}
mysql_mutex_unlock
(
&
acl_cache
->
lock
);
if
(
ip
!=
NULL
)
{
/* Increment HOST_CACHE.COUNT_HOST_ACL_ERRORS. */
Host_errors
errors
;
errors
.
m_host_acl
=
1
;
inc_host_errors
(
ip
,
&
errors
);
}
return
1
;
// Host is not allowed
}
...
...
@@ -8354,7 +8361,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
DBUG_ASSERT
(
net
->
read_pos
[
pkt_len
]
==
0
);
if
(
mpvio
->
connect_errors
)
reset_host_errors
(
thd
->
main_security_ctx
.
ip
);
reset_host_
connect_
errors
(
thd
->
main_security_ctx
.
ip
);
ulong
client_capabilities
=
uint2korr
(
net
->
read_pos
);
if
(
client_capabilities
&
CLIENT_PROTOCOL_41
)
...
...
@@ -8731,7 +8738,6 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
err:
if
(
mpvio
->
status
==
MPVIO_EXT
::
FAILURE
)
{
inc_host_errors
(
mpvio
->
thd
->
security_ctx
->
ip
);
if
(
!
mpvio
->
thd
->
is_error
())
{
if
(
mpvio
->
make_it_fail
)
...
...
@@ -8891,6 +8897,9 @@ static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name,
else
{
/* Server cannot load the required plugin. */
Host_errors
errors
;
errors
.
m_no_auth_plugin
=
1
;
inc_host_errors
(
mpvio
->
thd
->
security_ctx
->
ip
,
&
errors
);
my_error
(
ER_PLUGIN_IS_NOT_LOADED
,
MYF
(
0
),
auth_plugin_name
->
str
);
res
=
CR_ERROR
;
}
...
...
@@ -9018,8 +9027,26 @@ bool acl_authenticate(THD *thd, uint connect_errors,
if
(
res
>
CR_OK
&&
mpvio
.
status
!=
MPVIO_EXT
::
SUCCESS
)
{
Host_errors
errors
;
DBUG_ASSERT
(
mpvio
.
status
==
MPVIO_EXT
::
FAILURE
);
switch
(
res
)
{
case
CR_AUTH_PLUGIN_ERROR
:
errors
.
m_auth_plugin
=
1
;
break
;
case
CR_AUTH_HANDSHAKE
:
errors
.
m_handshake
=
1
;
break
;
case
CR_AUTH_USER_CREDENTIALS
:
errors
.
m_authentication
=
1
;
break
;
case
CR_ERROR
:
default:
/* Unknown of unspecified auth plugin error. */
errors
.
m_auth_plugin
=
1
;
break
;
}
inc_host_errors
(
mpvio
.
thd
->
security_ctx
->
ip
,
&
errors
);
if
(
!
thd
->
is_error
())
login_failed_error
(
thd
);
DBUG_RETURN
(
1
);
...
...
@@ -9207,7 +9234,7 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
create_random_string
(
thd
->
scramble
,
SCRAMBLE_LENGTH
,
&
thd
->
rand
);
/* and send it to the client */
if
(
mpvio
->
write_packet
(
mpvio
,
(
uchar
*
)
thd
->
scramble
,
SCRAMBLE_LENGTH
+
1
))
DBUG_RETURN
(
CR_
ERROR
);
DBUG_RETURN
(
CR_
AUTH_HANDSHAKE
);
}
/* reply and authenticate */
...
...
@@ -9249,7 +9276,7 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
/* read the reply with the encrypted password */
if
((
pkt_len
=
mpvio
->
read_packet
(
mpvio
,
&
pkt
))
<
0
)
DBUG_RETURN
(
CR_
ERROR
);
DBUG_RETURN
(
CR_
AUTH_HANDSHAKE
);
DBUG_PRINT
(
"info"
,
(
"reply read : pkt_len=%d"
,
pkt_len
));
#ifdef NO_EMBEDDED_ACCESS_CHECKS
...
...
@@ -9257,23 +9284,22 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
#endif
if
(
pkt_len
==
0
)
/* no password */
DBUG_RETURN
(
info
->
auth_string
[
0
]
?
CR_ERROR
:
CR_OK
);
DBUG_RETURN
(
mpvio
->
acl_user
->
salt_len
!=
0
?
CR_AUTH_USER_CREDENTIALS
:
CR_OK
);
info
->
password_used
=
PASSWORD_USED_YES
;
if
(
pkt_len
==
SCRAMBLE_LENGTH
)
{
if
(
!
mpvio
->
acl_user
->
salt_len
)
DBUG_RETURN
(
CR_
ERROR
);
DBUG_RETURN
(
CR_
AUTH_USER_CREDENTIALS
);
if
(
check_scramble
(
pkt
,
thd
->
scramble
,
mpvio
->
acl_user
->
salt
))
DBUG_RETURN
(
CR_
ERROR
);
DBUG_RETURN
(
CR_
AUTH_USER_CREDENTIALS
);
else
DBUG_RETURN
(
CR_OK
);
}
inc_host_errors
(
mpvio
->
thd
->
security_ctx
->
ip
);
my_error
(
ER_HANDSHAKE_ERROR
,
MYF
(
0
));
DBUG_RETURN
(
CR_
ERROR
);
DBUG_RETURN
(
CR_
AUTH_HANDSHAKE
);
}
static
int
old_password_authenticate
(
MYSQL_PLUGIN_VIO
*
vio
,
...
...
@@ -9290,12 +9316,12 @@ static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
create_random_string
(
thd
->
scramble
,
SCRAMBLE_LENGTH
,
&
thd
->
rand
);
/* and send it to the client */
if
(
mpvio
->
write_packet
(
mpvio
,
(
uchar
*
)
thd
->
scramble
,
SCRAMBLE_LENGTH
+
1
))
return
CR_
ERROR
;
return
CR_
AUTH_HANDSHAKE
;
}
/* read the reply and authenticate */
if
((
pkt_len
=
mpvio
->
read_packet
(
mpvio
,
&
pkt
))
<
0
)
return
CR_
ERROR
;
return
CR_
AUTH_HANDSHAKE
;
#ifdef NO_EMBEDDED_ACCESS_CHECKS
return
CR_OK
;
...
...
@@ -9310,26 +9336,25 @@ static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
pkt_len
=
strnlen
((
char
*
)
pkt
,
pkt_len
);
if
(
pkt_len
==
0
)
/* no password */
return
info
->
auth_string
[
0
]
?
CR_
ERROR
:
CR_OK
;
return
info
->
auth_string
[
0
]
?
CR_
AUTH_USER_CREDENTIALS
:
CR_OK
;
if
(
secure_auth
(
thd
))
return
CR_
ERROR
;
return
CR_
AUTH_HANDSHAKE
;
info
->
password_used
=
PASSWORD_USED_YES
;
if
(
pkt_len
==
SCRAMBLE_LENGTH_323
)
{
if
(
!
mpvio
->
acl_user
->
salt_len
)
return
CR_
ERROR
;
return
CR_
AUTH_USER_CREDENTIALS
;
return
check_scramble_323
(
pkt
,
thd
->
scramble
,
(
ulong
*
)
mpvio
->
acl_user
->
salt
)
?
CR_
ERROR
:
CR_OK
;
CR_
AUTH_USER_CREDENTIALS
:
CR_OK
;
}
inc_host_errors
(
mpvio
->
thd
->
security_ctx
->
ip
);
my_error
(
ER_HANDSHAKE_ERROR
,
MYF
(
0
));
return
CR_
ERROR
;
return
CR_
AUTH_HANDSHAKE
;
}
static
struct
st_mysql_auth
native_password_handler
=
...
...
sql/sql_connect.cc
View file @
ecbf36a9
...
...
@@ -124,6 +124,7 @@ end:
int
check_for_max_user_connections
(
THD
*
thd
,
USER_CONN
*
uc
)
{
int
error
=
1
;
Host_errors
errors
;
DBUG_ENTER
(
"check_for_max_user_connections"
);
mysql_mutex_lock
(
&
LOCK_user_conn
);
...
...
@@ -135,6 +136,8 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
!
(
thd
->
security_ctx
->
master_access
&
SUPER_ACL
))
{
my_error
(
ER_TOO_MANY_USER_CONNECTIONS
,
MYF
(
0
),
uc
->
user
);
error
=
1
;
errors
.
m_max_user_connection
=
1
;
goto
end
;
}
time_out_user_resource_limits
(
thd
,
uc
);
...
...
@@ -144,6 +147,8 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
my_error
(
ER_USER_LIMIT_REACHED
,
MYF
(
0
),
uc
->
user
,
"max_user_connections"
,
(
long
)
uc
->
user_resources
.
user_conn
);
error
=
1
;
errors
.
m_max_user_connection
=
1
;
goto
end
;
}
if
(
uc
->
user_resources
.
conn_per_hour
&&
...
...
@@ -152,6 +157,8 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
my_error
(
ER_USER_LIMIT_REACHED
,
MYF
(
0
),
uc
->
user
,
"max_connections_per_hour"
,
(
long
)
uc
->
user_resources
.
conn_per_hour
);
error
=
1
;
errors
.
m_max_user_connection_per_hour
=
1
;
goto
end
;
}
uc
->
conn_per_hour
++
;
...
...
@@ -169,6 +176,10 @@ end:
thd
->
user_connect
=
NULL
;
}
mysql_mutex_unlock
(
&
LOCK_user_conn
);
if
(
error
)
{
inc_host_errors
(
thd
->
main_security_ctx
.
ip
,
&
errors
);
}
DBUG_RETURN
(
error
);
}
...
...
@@ -867,7 +878,10 @@ bool init_new_connection_handler_thread()
{
pthread_detach_this_thread
();
if
(
my_thread_init
())
{
statistic_increment
(
connection_errors_internal
,
&
LOCK_status
);
return
1
;
}
return
0
;
}
...
...
@@ -887,6 +901,7 @@ bool init_new_connection_handler_thread()
static
int
check_connection
(
THD
*
thd
)
{
uint
connect_errors
=
0
;
int
auth_rc
;
NET
*
net
=
&
thd
->
net
;
DBUG_PRINT
(
"info"
,
...
...
@@ -898,37 +913,103 @@ static int check_connection(THD *thd)
if
(
!
thd
->
main_security_ctx
.
host
)
// If TCP/IP connection
{
my_bool
peer_rc
;
char
ip
[
NI_MAXHOST
];
if
(
vio_peer_addr
(
net
->
vio
,
ip
,
&
thd
->
peer_port
,
NI_MAXHOST
))
{
my_error
(
ER_BAD_HOST_ERROR
,
MYF
(
0
));
return
1
;
}
/* BEGIN : DEBUG */
DBUG_EXECUTE_IF
(
"addr_fake_ipv4"
,
peer_rc
=
vio_peer_addr
(
net
->
vio
,
ip
,
&
thd
->
peer_port
,
NI_MAXHOST
);
/*
===========================================================================
DEBUG code only (begin)
Simulate various output from vio_peer_addr().
===========================================================================
*/
DBUG_EXECUTE_IF
(
"vio_peer_addr_error"
,
{
peer_rc
=
1
;
}
);
DBUG_EXECUTE_IF
(
"vio_peer_addr_fake_ipv4"
,
{
struct
sockaddr
*
sa
=
(
sockaddr
*
)
&
net
->
vio
->
remote
;
sa
->
sa_family
=
AF_INET
;
struct
in_addr
*
ip4
=
&
((
struct
sockaddr_in
*
)
sa
)
->
sin_addr
;
/* See RFC 5737, 192.0.2.0/2
3 is reserved
*/
struct
in_addr
*
ip4
=
&
((
struct
sockaddr_in
*
)
sa
)
->
sin_addr
;
/* See RFC 5737, 192.0.2.0/2
4 is reserved.
*/
const
char
*
fake
=
"192.0.2.4"
;
ip4
->
s_addr
=
inet_addr
(
fake
);
strcpy
(
ip
,
fake
);
};);
/* END : DEBUG */
peer_rc
=
0
;
}
);
#ifdef HAVE_IPV6
DBUG_EXECUTE_IF
(
"vio_peer_addr_fake_ipv6"
,
{
struct
sockaddr_in6
*
sa
=
(
sockaddr_in6
*
)
&
net
->
vio
->
remote
;
sa
->
sin6_family
=
AF_INET6
;
struct
in6_addr
*
ip6
=
&
sa
->
sin6_addr
;
/* See RFC 3849, ipv6 2001:DB8::/32 is reserved. */
const
char
*
fake
=
"2001:db8::6:6"
;
/* inet_pton(AF_INET6, fake, ip6); not available on Windows XP. */
ip6
->
s6_addr
[
0
]
=
0x20
;
ip6
->
s6_addr
[
1
]
=
0x01
;
ip6
->
s6_addr
[
2
]
=
0x0d
;
ip6
->
s6_addr
[
3
]
=
0xb8
;
ip6
->
s6_addr
[
4
]
=
0x00
;
ip6
->
s6_addr
[
5
]
=
0x00
;
ip6
->
s6_addr
[
6
]
=
0x00
;
ip6
->
s6_addr
[
7
]
=
0x00
;
ip6
->
s6_addr
[
8
]
=
0x00
;
ip6
->
s6_addr
[
9
]
=
0x00
;
ip6
->
s6_addr
[
10
]
=
0x00
;
ip6
->
s6_addr
[
11
]
=
0x00
;
ip6
->
s6_addr
[
12
]
=
0x00
;
ip6
->
s6_addr
[
13
]
=
0x06
;
ip6
->
s6_addr
[
14
]
=
0x00
;
ip6
->
s6_addr
[
15
]
=
0x06
;
strcpy
(
ip
,
fake
);
peer_rc
=
0
;
}
);
#endif
/* HAVE_IPV6 */
/*
===========================================================================
DEBUG code only (end)
===========================================================================
*/
if
(
peer_rc
)
{
/*
Since we can not even get the peer IP address,
there is nothing to show in the host_cache,
so increment the global status variable for peer address errors.
*/
statistic_increment
(
connection_errors_peer_addr
,
&
LOCK_status
);
my_error
(
ER_BAD_HOST_ERROR
,
MYF
(
0
));
return
1
;
}
if
(
!
(
thd
->
main_security_ctx
.
ip
=
my_strdup
(
ip
,
MYF
(
MY_WME
))))
{
/*
No error accounting per IP in host_cache,
this is treated as a global server OOM error.
TODO: remove the need for my_strdup.
*/
statistic_increment
(
connection_errors_internal
,
&
LOCK_status
);
return
1
;
/* The error is set by my_strdup(). */
}
thd
->
main_security_ctx
.
host_or_ip
=
thd
->
main_security_ctx
.
ip
;
if
(
!
(
specialflag
&
SPECIAL_NO_RESOLVE
))
{
i
f
(
ip_to_hostname
(
&
net
->
vio
->
remote
,
thd
->
main_security_ctx
.
ip
,
&
thd
->
main_security_ctx
.
host
,
&
connect_errors
))
{
my_error
(
ER_BAD_HOST_ERROR
,
MYF
(
0
));
return
1
;
}
i
nt
rc
;
rc
=
ip_to_hostname
(
&
net
->
vio
->
remote
,
thd
->
main_security_ctx
.
ip
,
&
thd
->
main_security_ctx
.
host
,
&
connect_errors
);
/* Cut very long hostnames to avoid possible overflows */
if
(
thd
->
main_security_ctx
.
host
)
...
...
@@ -938,8 +1019,10 @@ static int check_connection(THD *thd)
HOSTNAME_LENGTH
)]
=
0
;
thd
->
main_security_ctx
.
host_or_ip
=
thd
->
main_security_ctx
.
host
;
}
if
(
connect_errors
>
max_connect_errors
)
if
(
rc
==
RC_BLOCKED_HOST
)
{
/* HOST_CACHE stats updated by ip_to_hostname(). */
my_error
(
ER_HOST_IS_BLOCKED
,
MYF
(
0
),
thd
->
main_security_ctx
.
host_or_ip
);
return
1
;
}
...
...
@@ -951,6 +1034,7 @@ static int check_connection(THD *thd)
thd
->
main_security_ctx
.
ip
:
"unknown ip"
)));
if
(
acl_check_host
(
thd
->
main_security_ctx
.
host
,
thd
->
main_security_ctx
.
ip
))
{
/* HOST_CACHE stats updated by acl_check_host(). */
my_error
(
ER_HOST_NOT_PRIVILEGED
,
MYF
(
0
),
thd
->
main_security_ctx
.
host_or_ip
);
return
1
;
...
...
@@ -967,9 +1051,34 @@ static int check_connection(THD *thd)
vio_keepalive
(
net
->
vio
,
TRUE
);
if
(
thd
->
packet
.
alloc
(
thd
->
variables
.
net_buffer_length
))
{
/*
Important note:
net_buffer_length is a SESSION variable,
so it may be tempting to account OOM conditions per IP in the HOST_CACHE,
in case some clients are more demanding than others ...
However, this session variable is *not* initialized with a per client
value during the initial connection, it is initialized from the
GLOBAL net_buffer_length variable from the server.
Hence, there is no reason to account on OOM conditions per client IP,
we count failures in the global server status instead.
*/
statistic_increment
(
connection_errors_internal
,
&
LOCK_status
);
return
1
;
/* The error is set by alloc(). */
}
auth_rc
=
acl_authenticate
(
thd
,
connect_errors
,
0
);
if
(
auth_rc
==
0
&&
connect_errors
!=
0
)
{
/*
A client connection from this IP was successful,
after some previous failures.
Reset the connection error counter.
*/
reset_host_connect_errors
(
thd
->
main_security_ctx
.
ip
);
}
return
a
cl_authenticate
(
thd
,
connect_errors
,
0
)
;
return
a
uth_rc
;
}
...
...
@@ -1118,6 +1227,7 @@ void prepare_new_connection_state(THD* thd)
execute_init_command
(
thd
,
&
opt_init_connect
,
&
LOCK_sys_init_connect
);
if
(
thd
->
is_error
())
{
Host_errors
errors
;
thd
->
killed
=
KILL_CONNECTION
;
thd
->
print_aborted_warning
(
0
,
"init_connect command failed"
);
sql_print_warning
(
"%s"
,
thd
->
get_stmt_da
()
->
message
());
...
...
@@ -1145,6 +1255,8 @@ void prepare_new_connection_state(THD* thd)
thd
->
server_status
&=
~
SERVER_STATUS_CLEAR_SET
;
thd
->
protocol
->
end_statement
();
thd
->
killed
=
KILL_CONNECTION
;
errors
.
m_init_connect
=
1
;
inc_host_errors
(
thd
->
main_security_ctx
.
ip
,
&
errors
);
return
;
}
...
...
sql/sql_parse.cc
View file @
ecbf36a9
...
...
@@ -1148,7 +1148,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
case
COM_CHANGE_USER
:
{
bool
rc
;
int
auth_
rc
;
status_var_increment
(
thd
->
status_var
.
com_other
);
thd
->
change_user
();
...
...
@@ -1179,13 +1179,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if
(
thd
->
failed_com_change_user
>=
3
)
{
my_message
(
ER_UNKNOWN_COM_ERROR
,
ER
(
ER_UNKNOWN_COM_ERROR
),
MYF
(
0
));
rc
=
1
;
auth_
rc
=
1
;
}
else
rc
=
acl_authenticate
(
thd
,
0
,
packet_length
);
auth_
rc
=
acl_authenticate
(
thd
,
0
,
packet_length
);
MYSQL_AUDIT_NOTIFY_CONNECTION_CHANGE_USER
(
thd
);
if
(
rc
)
if
(
auth_
rc
)
{
/* Free user if allocated by acl_authenticate */
my_free
(
thd
->
security_ctx
->
user
);
...
...
sql/sys_vars.cc
View file @
ecbf36a9
...
...
@@ -48,6 +48,7 @@
// mysql_user_table_is_in_short_password_format
#include "derror.h" // read_texts
#include "sql_base.h" // close_cached_tables
#include "hostname.h" // host_cache_size
#include <myisam.h>
#include "log_slow.h"
#include "debug_sync.h" // DEBUG_SYNC
...
...
@@ -3773,6 +3774,22 @@ static Sys_var_tz Sys_time_zone(
SESSION_VAR
(
time_zone
),
NO_CMD_LINE
,
DEFAULT
(
&
default_tz
),
NO_MUTEX_GUARD
,
IN_BINLOG
);
static
bool
fix_host_cache_size
(
sys_var
*
,
THD
*
,
enum_var_type
)
{
hostname_cache_resize
((
uint
)
host_cache_size
);
return
false
;
}
static
Sys_var_ulong
Sys_host_cache_size
(
"host_cache_size"
,
"How many host names should be cached to avoid resolving."
,
GLOBAL_VAR
(
host_cache_size
),
CMD_LINE
(
REQUIRED_ARG
),
VALID_RANGE
(
0
,
65536
),
DEFAULT
(
HOST_CACHE_SIZE
),
BLOCK_SIZE
(
1
),
NO_MUTEX_GUARD
,
NOT_IN_BINLOG
,
ON_CHECK
(
NULL
),
ON_UPDATE
(
fix_host_cache_size
));
static
Sys_var_charptr
Sys_ignore_db_dirs
(
"ignore_db_dirs"
,
"Specifies a directory to add to the ignore list when collecting "
...
...
storage/perfschema/pfs_engine_table.cc
View file @
ecbf36a9
...
...
@@ -105,9 +105,7 @@ static PFS_engine_table_share *all_shares[]=
&
table_file_instances
::
m_share
,
&
table_file_summary_by_event_name
::
m_share
,
&
table_file_summary_by_instance
::
m_share
,
#ifdef QQ_NOT_YET
&
table_host_cache
::
m_share
,
#endif
&
table_mutex_instances
::
m_share
,
&
table_os_global_by_type
::
m_share
,
&
table_performance_timers
::
m_share
,
...
...
@@ -164,7 +162,7 @@ void PFS_engine_table_share::check_all_tables(THD *thd)
DBUG_EXECUTE_IF
(
"tampered_perfschema_table1"
,
{
/* Hack SETUP_INSTRUMENT, incompatible change. */
all_shares
[
19
]
->
m_field_def
->
count
++
;
all_shares
[
20
]
->
m_field_def
->
count
++
;
});
for
(
current
=
&
all_shares
[
0
];
(
*
current
)
!=
NULL
;
current
++
)
...
...
@@ -1412,11 +1410,7 @@ bool pfs_show_status(handlerton *hton, THD *thd,
- no host_cache.memory
*/
name
=
"host_cache.size"
;
#ifdef NOT_YET_IMPLEMENTED
size
=
sizeof
(
Host_entry
);
#else
size
=
0
;
#endif
break
;
/*
...
...
storage/perfschema/table_host_cache.cc
View file @
ecbf36a9
...
...
@@ -23,8 +23,6 @@
#include "table_host_cache.h"
#include "hostname.h"
#ifdef NOT_YET_PORTED
THR_LOCK
table_host_cache
::
m_table_lock
;
static
const
TABLE_FIELD_TYPE
field_types
[]
=
...
...
@@ -478,4 +476,3 @@ int table_host_cache::read_row_values(TABLE *table,
return
0
;
}
#endif
/* NOT_YET_PORTED */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment