原创 水平有限,只为抛砖,有误请指出
这里主要找一下m_connect是什么,以及怎么增加的,因为前文我没有找到,再次用断点的方式
描述一下unauthenticated user
一、m_connect是什么怎么增加的
m_connect实际上就是m_handshake下面是
sql_authentication.cc:
acl_authenticate函数
聚合函数Hostname.cc
sql_authentication.cc:1900
do_auth_once函数调用
下面是错误的宏定义
也就是说每次由于mpvio->write_packet函数问题导致的握手失败都会触发他+1,其实这很可能是网络
问题,关于mpvio->write_packet的返回值感兴趣的可以继续跟中下去
下面是官方关于错误的解释
If the following error occurs, it means that mysqldhas received many connection requests from the given
host that were interrupted in the middle:
Host 'host_name' is blocked because of many connection errors.
Unblock with 'mysqladmin flush-hosts'
The value of the max_connect_errorssystem variable determines how many successive
interrupted connection requests are permitted. (See Section 6.1.4, “Server System Variables”.) After
max_connect_errorsfailed requests without a successful connection, mysqldassumes that something
is wrong (for example, that someone is trying to break in), and blocks the host from further connections
until you issue a FLUSH HOSTSstatement or execute a mysqladmin flush-hostscommand.
By default, mysqldblocks a host after 100 connection errors. You can adjust the value by setting
max_connect_errorsat server startup:
shell> mysqld_safe --max_connect_errors=10000 &
The value can also be set at runtime:
mysql> SET GLOBAL max_connect_errors=10000;
If you get the Host 'host_name' is blockederror message for a given host, you should first verify
that there is nothing wrong with TCP/IP connections from that host. If you are having network problems, it
does you no good to increase the value of the max_connect_errorsvariable.
二、 unauthenticated user为什么和反解析有关
check_connection会调用ip_to_hostname和acl_authenticate进行解析和密码认证过程,但是
ip_to_hostname出现在sql_connect.cc:1166而acl_authenticate出现在sql_connect.cc:1243
可以看到ip_to_hostname确实在acl_authenticate函数前,也就是反解析在密码认证前,也是在MYSQL协议握手成功前。
这也说明什么了为什么解析慢会导致unauthenticated user的用户。
mysql> show processlist;
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined |
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| 5 | unauthenticated user | 192.168.190.60:12770 | NULL | Connect | 35 | login | NULL | 0 | 0 |
| 6 | root | localhost | NULL | Query | 0 | starting | show processlist | 0 | 0 |
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
为了验证我在源码check_connection处增加了等待10秒并且打日志的来验证不然不好观察这个问题,确实如上所诉
mysql> show processlist;
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined |
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| 4 | root | localhost | NULL | Query | 0 | starting | show processlist | 0 | 0 |
| 6 | unauthenticated user | 192.168.190.60:61688 | NULL | Connect | 8 | login | NULL | 0 | 0 |
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
2 rows in set (0.00 sec)
mysql> show processlist;
+----+---------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined |
+----+---------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| 4 | root | localhost | NULL | Query | 0 | starting | show processlist | 0 | 0 |
| 6 | testuuu | 192.168.190.60:61688 | NULL | Connect | 12 | login | NULL | 0 | 0 |
+----+---------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
2 rows in set (0.00 sec)
日志输出:
2017-05-31T22:34:28.605325Z 10 [Note] Before acl_authenticate sleep(10) check unauthenticated user
2017-05-31T22:34:38.606414Z 10 [Note] After acl_authenticate sleep(10) check authenticated user
作者微信:
这里主要找一下m_connect是什么,以及怎么增加的,因为前文我没有找到,再次用断点的方式
描述一下unauthenticated user
一、m_connect是什么怎么增加的
m_connect实际上就是m_handshake下面是
点击(此处)折叠或打开
- Hostname.h
- void sum_connect_errors()
- {
- /* Current (historical) behavior: */
- m_connect= m_handshake;
- }
sql_authentication.cc:
acl_authenticate函数
点击(此处)折叠或打开
- res= do_auth_once(thd, auth_plugin_name, &mpvio);
-
- ...
-
- case CR_AUTH_PLUGIN_ERROR:
- errors.m_auth_plugin= 1;
- break;
- case CR_AUTH_HANDSHAKE:
- errors.m_handshake= 1;//这里m_handshake=1也就是m_connect=1,这里会在后面进行聚合
- break;
- case CR_AUTH_USER_CREDENTIALS:
- errors.m_authentication= 1;
- break;
- case CR_ERROR:
点击(此处)折叠或打开
- void Host_errors::aggregate(const Host_errors *errors)//接受一个Host_errors类型指针,和当前this->* 进行相加
- {
- m_connect+= errors->m_connect; //指针指向的Host_errors Host_errors 和this->m_connect相加 相加后存入 this->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;
sql_authentication.cc:1900
do_auth_once函数调用
点击(此处)折叠或打开
- sql_authentication.cc:2672
- native_password_authenticate函数
- if (mpvio->write_packet(mpvio, (uchar*) mpvio->scramble, SCRAMBLE_LENGTH + 1))
- DBUG_RETURN(CR_AUTH_HANDSHAKE);//这里看到了错误
- ......
- if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
- DBUG_RETURN(CR_AUTH_HANDSHAKE); //这里看到了错误
- DBUG_PRINT("info", ("reply read : pkt_len=%d", pkt_len));
下面是错误的宏定义
点击(此处)折叠或打开
- #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.
-
- The client plugin may set the error code and the error message directly
- in the MYSQL structure and return CR_ERROR. If a CR_xxx specific error
- code was returned, an error message in the MYSQL structure will be
- overwritten. If CR_ERROR is returned without setting the error in MYSQL,
- CR_UNKNOWN_ERROR will be user.
- */
- #define CR_ERROR 0
- /**
- Authentication (client part) was successful. It does not mean that the
- authentication as a whole was successful, usually it only means
- that the client was able to send the user name and the password to the
- server. If CR_OK is returned, the libmysql reads the next packet expecting
- it to be one of OK, ERROR, or CHANGE_PLUGIN packets.
- */
- #define CR_OK -1
- /**
- Authentication was successful.
- It means that the client has done its part successfully and also that
- a plugin has read the last packet (one of OK, ERROR, CHANGE_PLUGIN).
- In this case, libmysql will not read a packet from the server,
- but it will use the data at mysql->net.read_pos.
-
- A plugin may return this value if the number of roundtrips in the
- authentication protocol is not known in advance, and the client plugin
- needs to read one packet more to determine if the authentication is finished
- or not.
- */
- #define CR_OK_HANDSHAKE_COMPLETE -2
也就是说每次由于mpvio->write_packet函数问题导致的握手失败都会触发他+1,其实这很可能是网络
问题,关于mpvio->write_packet的返回值感兴趣的可以继续跟中下去
下面是官方关于错误的解释
If the following error occurs, it means that mysqldhas received many connection requests from the given
host that were interrupted in the middle:
Host 'host_name' is blocked because of many connection errors.
Unblock with 'mysqladmin flush-hosts'
The value of the max_connect_errorssystem variable determines how many successive
interrupted connection requests are permitted. (See Section 6.1.4, “Server System Variables”.) After
max_connect_errorsfailed requests without a successful connection, mysqldassumes that something
is wrong (for example, that someone is trying to break in), and blocks the host from further connections
until you issue a FLUSH HOSTSstatement or execute a mysqladmin flush-hostscommand.
By default, mysqldblocks a host after 100 connection errors. You can adjust the value by setting
max_connect_errorsat server startup:
shell> mysqld_safe --max_connect_errors=10000 &
The value can also be set at runtime:
mysql> SET GLOBAL max_connect_errors=10000;
If you get the Host 'host_name' is blockederror message for a given host, you should first verify
that there is nothing wrong with TCP/IP connections from that host. If you are having network problems, it
does you no good to increase the value of the max_connect_errorsvariable.
二、 unauthenticated user为什么和反解析有关
点击(此处)折叠或打开
- 断点:
- (gdb) info b
- Num Type Disp Enb Address What
- 1 breakpoint keep y 0x0000000000ebd3b3 in main(int, char**) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
- breakpoint already hit 1 time
- 2 breakpoint keep y 0x0000000000ee48ac in do_auth_once(THD*, LEX_CSTRING const&, MPVIO_EXT*)
- at /root/mysql5.7.14/percona-server-5.7.14-7/sql/auth/sql_authentication.cc:1877
- breakpoint already hit 2 times
- 3 breakpoint keep y 0x0000000000f7aeb7 in ip_to_hostname(sockaddr_storage*, char const*, char**, uint*)
- at /root/mysql5.7.14/percona-server-5.7.14-7/sql/hostname.cc:412
- breakpoint already hit 1 time
- 4 breakpoint keep y 0x0000000000ee6f8b in native_password_authenticate(MYSQL_PLUGIN_VIO*, MYSQL_SERVER_AUTH_INFO*)
- at /root/mysql5.7.14/percona-server-5.7.14-7/sql/auth/sql_authentication.cc:2672
- breakpoint already hit 1 time
点击(此处)折叠或打开
- ip_to_hostname栈帧:
- (gdb) bt
- #0 ip_to_hostname (ip_storage=0x7fffe80102e8, ip_string=0x7fffe800d020 "192.168.190.60", hostname=0x7fffec16dc38, connect_errors=0x7fffec16dc5c)
- at /root/mysql5.7.14/percona-server-5.7.14-7/sql/hostname.cc:412
- #1 0x000000000154b73c in check_connection (thd=0x7fffe8007e20, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_connect.cc:1166
- #2 0x000000000154be1c in login_connection (thd=0x7fffe8007e20, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_connect.cc:1292
- #3 0x000000000154c67f in thd_prepare_connection (thd=0x7fffe8007e20, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_connect.cc:1447
- #4 0x00000000016e1d22 in handle_connection (arg=0x3d6d120) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:306
- #5 0x0000000001d72124 in pfs_spawn_thread (arg=0x3f25420) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/perfschema/pfs.cc:2188
- #6 0x0000003ca62079d1 in start_thread () from /lib64/libpthread.so.0
- #7 0x0000003ca5ee8b6d in clone () from /lib64/libc.so.6
点击(此处)折叠或打开
- acl_authenticate栈帧:
- (gdb) bt
- #0 native_password_authenticate (vio=0x7fffec16d140, info=0x7fffec16d158) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/auth/sql_authentication.cc:2672
- #1 0x0000000000ee499f in do_auth_once (thd=0x7fffe8007e20, auth_plugin_name=..., mpvio=0x7fffec16d140)
- at /root/mysql5.7.14/percona-server-5.7.14-7/sql/auth/sql_authentication.cc:1900
- #2 0x0000000000ee54f0 in acl_authenticate (thd=0x7fffe8007e20, command=COM_CONNECT, extra_port_connection=false)
- at /root/mysql5.7.14/percona-server-5.7.14-7/sql/auth/sql_authentication.cc:2170
- #3 0x000000000154bca2 in check_connection (thd=0x7fffe8007e20, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_connect.cc:1243
- #4 0x000000000154be1c in login_connection (thd=0x7fffe8007e20, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_connect.cc:1292
- #5 0x000000000154c67f in thd_prepare_connection (thd=0x7fffe8007e20, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_connect.cc:1447
- #6 0x00000000016e1d22 in handle_connection (arg=0x3d6d120) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:306
- #7 0x0000000001d72124 in pfs_spawn_thread (arg=0x3f25420) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/perfschema/pfs.cc:2188
- #8 0x0000003ca62079d1 in start_thread () from /lib64/libpthread.so.0
- #9 0x0000003ca5ee8b6d in clone () from /lib64/libc.so.6
check_connection会调用ip_to_hostname和acl_authenticate进行解析和密码认证过程,但是
ip_to_hostname出现在sql_connect.cc:1166而acl_authenticate出现在sql_connect.cc:1243
可以看到ip_to_hostname确实在acl_authenticate函数前,也就是反解析在密码认证前,也是在MYSQL协议握手成功前。
这也说明什么了为什么解析慢会导致unauthenticated user的用户。
mysql> show processlist;
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined |
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| 5 | unauthenticated user | 192.168.190.60:12770 | NULL | Connect | 35 | login | NULL | 0 | 0 |
| 6 | root | localhost | NULL | Query | 0 | starting | show processlist | 0 | 0 |
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
为了验证我在源码check_connection处增加了等待10秒并且打日志的来验证不然不好观察这个问题,确实如上所诉
点击(此处)折叠或打开
- sql_print_information("Before acl_authenticate sleep(10) check unauthenticated user");
- sleep(10);
-
- auth_rc= acl_authenticate(thd, COM_CONNECT, extra_port_connection);
-
- sql_print_information("After acl_authenticate sleep(10) check authenticated user");
- sleep(10);
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined |
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| 4 | root | localhost | NULL | Query | 0 | starting | show processlist | 0 | 0 |
| 6 | unauthenticated user | 192.168.190.60:61688 | NULL | Connect | 8 | login | NULL | 0 | 0 |
+----+----------------------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
2 rows in set (0.00 sec)
mysql> show processlist;
+----+---------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined |
+----+---------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
| 4 | root | localhost | NULL | Query | 0 | starting | show processlist | 0 | 0 |
| 6 | testuuu | 192.168.190.60:61688 | NULL | Connect | 12 | login | NULL | 0 | 0 |
+----+---------+----------------------+------+---------+------+----------+------------------+-----------+---------------+
2 rows in set (0.00 sec)
日志输出:
2017-05-31T22:34:28.605325Z 10 [Note] Before acl_authenticate sleep(10) check unauthenticated user
2017-05-31T22:34:38.606414Z 10 [Note] After acl_authenticate sleep(10) check authenticated user
作者微信: