summaryrefslogtreecommitdiff
path: root/sql/sql_connect.cc
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-07-21 16:39:19 +0200
committerSergei Golubchik <sergii@pisem.net>2013-07-21 16:39:19 +0200
commitb7b5f6f1ab49948b0e15b762266d4640b3d6b7fb (patch)
tree7c302c2025184dbd053aa6135f0ff28c8ce6f359 /sql/sql_connect.cc
parent5f6380adde2dac3f32b40339b9b702c0135eb7d6 (diff)
parentc1d6a2d7e194225ccc19a68ea5d0f368632620d0 (diff)
downloadmariadb-git-b7b5f6f1ab49948b0e15b762266d4640b3d6b7fb.tar.gz
10.0-monty merge
includes: * remove some remnants of "Bug#14521864: MYSQL 5.1 TO 5.5 BUGS PARTITIONING" * introduce LOCK_share, now LOCK_ha_data is strictly for engines * rea_create_table() always creates .par file (even in "frm-only" mode) * fix a 5.6 bug, temp file leak on dummy ALTER TABLE
Diffstat (limited to 'sql/sql_connect.cc')
-rw-r--r--sql/sql_connect.cc156
1 files changed, 134 insertions, 22 deletions
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 19e02cc7dae..f14c43d4c54 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -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);
}
@@ -431,7 +442,7 @@ void init_user_stats(USER_STATS *user_stats,
DBUG_ENTER("init_user_stats");
DBUG_PRINT("enter", ("user: %s priv_user: %s", user, priv_user));
- user_length= min(user_length, sizeof(user_stats->user)-1);
+ user_length= MY_MIN(user_length, sizeof(user_stats->user)-1);
memcpy(user_stats->user, user, user_length);
user_stats->user[user_length]= 0;
user_stats->user_name_length= user_length;
@@ -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,48 +913,116 @@ 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/23 is reserved */
+ struct in_addr *ip4= &((struct sockaddr_in *) sa)->sin_addr;
+ /* See RFC 5737, 192.0.2.0/24 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))
{
- if (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;
- }
+ int 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)
{
if (thd->main_security_ctx.host != my_localhost)
- thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
+ thd->main_security_ctx.host[MY_MIN(strlen(thd->main_security_ctx.host),
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 acl_authenticate(thd, connect_errors, 0);
+ return auth_rc;
}
@@ -1118,9 +1227,10 @@ 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->stmt_da->message());
+ sql_print_warning("%s", thd->get_stmt_da()->message());
/*
now let client to send its first command,
@@ -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;
}