mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
Backport of WL#798 (MySQL IPv6 support) from 6.0.
The following 6.0 revisions were analyzed: - sp1r-brian@zim.(none)-20071228102738-21894 - sp1r-brian@zim.(none)-20071228121841-56447 - sp1r-brian@zim.(none)-20071228205403-56423 - sp1r-brian@zim.(none)-20071228221139-55341 - sp1r-brian@zim.(none)-20071228233443-55352 - sp1r-brian@zim.(none)-20071229094527-61763 - sp1r-brian@zim.(none)-20071230203739-61746 - sp1r-brian@zim.(none)-20080102213805-61741 - sp1r-brian@zim.(none)-20080103201041-61746 - sp1r-brian@zim.(none)-20080104234927-59875 - sp1r-brian@zim.(none)-20080105005827-59874 - sp1r-brian@zim.(none)-20080105012020-59865 - sp1r-brian@zim.(none)-20080106003858-59857 - sp1r-brian@zim.(none)-20080123195552-31680 - sp1r-brian@zim.(none)-20080124201848-29999 - sp1r-brian@zim.(none)-20080129075144-36991 - sp1r-cbell/Chuck@mysql_cab_desk.-20080215041806-21954 - sp1r-vvaintroub@wva.-20080212124547-06272 - sp1r-dfischer/mysqldev@mysql.com/production.mysql.com-20071223184258-15140 - sp1r-brian@zim.(none)-20080206122216-35774 - sp1r-baker@bk-internal.mysql.com-20080209005622-35947 - sp1r-baker@bk-internal.mysql.com-20080224215608-24613 - sp1r-baker@bk-internal.mysql.com-20080307170710-63543 - sp1r-baker@bk-internal.mysql.com-20080312233205-13069 - sp1r-Reggie@core.-20080402175211-28643 - kpettersson@mysql.com-20080901101150-4ne74r8v0492vv42 - alik@sun.com-20090805173811-9fzt0ymcp9tsvn7k - alik@sun.com-20090805173937-fcv1fdveodq5x9gb - alik@sun.com-20090805175009-g1od16i3t1xkw2qr - kostja@sun.com-20090805200643-j9i4fy7ii8ijho5c - alik@sun.com-20090807195303-j4fb5m4l1dgdahwo - alik@sun.com-20090808114848-3rkzr9kifrijzaqy - alik@sun.com-20090810041739-ugmx34h34uid8mox - alik@sun.com-20090810105306-rf43rfyzzblsy5e7 - alik@sun.com-20090810123113-ccdjwai68b5woqdm - alik@sun.com-20090811080423-gb7pibec1znaydzy - alik@sun.com-20090811082130-5uckar1vx3kdsw7g - alik@sun.com-20090812202051-uqkfwwxxcjvo5ean The following bugfixes are also backported within this patch: - Bug#34292: netdb.h missing in hostname.cc - Bug#39153: Failing to lookup a host name can lead to crash in current IPv6 implementation - Bug#38247: Server does not resolve connecting ip's - Bug#43006: main.skip_name_resolve fails on Windows in PB2 - Bug#45606: ACL requires IPv4-mapped addresses to be used - Bug#45584: Host name cache does not work as a cache
This commit is contained in:
parent
027a2fff15
commit
7eb84da890
18 changed files with 1059 additions and 402 deletions
|
@ -39,6 +39,9 @@ ADD_DEFINITIONS(-DDEFAULT_CHARSET_HOME="c:/Program Files/MySQL/MySQL Server ${MY
|
|||
ADD_DEFINITIONS(-DPACKAGE=mysql)
|
||||
ADD_DEFINITIONS(-DSHAREDIR="share")
|
||||
|
||||
# Enable IPv6 handling code
|
||||
ADD_DEFINITIONS(-DHAVE_IPV6)
|
||||
|
||||
# Set debug options
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DFORCE_INIT_OF_VARS")
|
||||
|
||||
|
|
42
configure.in
42
configure.in
|
@ -863,6 +863,42 @@ AC_CHECK_DECLS(MHA_MAPSIZE_VA,
|
|||
|
||||
fi
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check for IPv6 support
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_CHECK_HEADERS(netinet/in6.h)
|
||||
|
||||
AC_CHECK_TYPES([struct sockaddr_in6, struct in6_addr],
|
||||
[have_in6_types=yes],
|
||||
[have_in6_types=no],
|
||||
[[
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN6_H
|
||||
#include <netinet/in6.h>
|
||||
#endif
|
||||
]])
|
||||
|
||||
AC_MSG_CHECKING([for IPv6 support])
|
||||
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AS_HELP_STRING([--disable-ipv6], [Disable support for IPv6 networking]),
|
||||
[disable_ipv6=yes], [disable_ipv6=no])
|
||||
|
||||
if test x"$disable_ipv6" = xyes -o x"$have_in6_types" = xno; then
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
AC_DEFINE([HAVE_IPV6], [1], [Define if IPv6 networking support is present])
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check for TCP wrapper support
|
||||
#--------------------------------------------------------------------
|
||||
|
@ -961,12 +997,6 @@ AC_CHECK_TYPES([int8, uint8, int16, uint16, int32, uint32, int64, uint64,
|
|||
uchar, uint, ulong],[],[], [
|
||||
#include <sys/types.h>
|
||||
])
|
||||
AC_CHECK_TYPES([in_addr_t], [], [], [
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
])
|
||||
AC_CHECK_TYPES([fp_except], [], [], [
|
||||
#include <sys/types.h>
|
||||
#include <ieeefp.h>
|
||||
|
|
|
@ -20,6 +20,13 @@
|
|||
|
||||
#define BIG_TABLES
|
||||
|
||||
/*
|
||||
Minimal version of Windows we should be able to run on.
|
||||
Currently Windows XP.
|
||||
*/
|
||||
#define _WIN32_WINNT 0x0501
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
/* Avoid endless warnings about sprintf() etc. being unsafe. */
|
||||
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||
|
@ -27,6 +34,7 @@
|
|||
|
||||
#include <sys/locking.h>
|
||||
#include <winsock2.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <malloc.h>
|
||||
|
@ -88,6 +96,12 @@
|
|||
|
||||
#define S_IROTH S_IREAD /* for my_lib */
|
||||
|
||||
/* Winsock2 constant (Vista SDK and later)*/
|
||||
#define IPPROTO_IPV6 41
|
||||
#ifndef IPV6_V6ONLY
|
||||
#define IPV6_V6ONLY 27
|
||||
#endif
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#define FILE_BINARY O_BINARY /* my_fopen in binary mode */
|
||||
#define O_TEMPORARY 0
|
||||
|
|
|
@ -43,7 +43,7 @@ C_MODE_START
|
|||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__) && !defined(__NETWARE__)
|
||||
#if !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__NETWARE__)
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
|
@ -73,11 +73,6 @@ C_MODE_START
|
|||
#define in_addr_t uint32
|
||||
#endif
|
||||
|
||||
/* On some operating systems (e.g. Solaris) INADDR_NONE is not defined */
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE -1 /* Error value from inet_addr */
|
||||
#endif
|
||||
|
||||
/* Thread safe or portable version of some functions */
|
||||
|
||||
void my_inet_ntoa(struct in_addr in, char *buf);
|
||||
|
@ -86,9 +81,6 @@ void my_inet_ntoa(struct in_addr in, char *buf);
|
|||
Handling of gethostbyname_r()
|
||||
*/
|
||||
|
||||
#if !defined(HPUX10)
|
||||
struct hostent;
|
||||
#endif /* HPUX */
|
||||
#if !defined(HAVE_GETHOSTBYNAME_R)
|
||||
struct hostent *my_gethostbyname_r(const char *name,
|
||||
struct hostent *result, char *buffer,
|
||||
|
@ -118,11 +110,5 @@ struct hostent *my_gethostbyname_r(const char *name,
|
|||
#define GETHOSTBYNAME_BUFF_SIZE 2048
|
||||
#endif
|
||||
|
||||
/* On SCO you get a link error when refering to h_errno */
|
||||
#ifdef SCO
|
||||
#undef h_errno
|
||||
#define h_errno errno
|
||||
#endif
|
||||
|
||||
C_MODE_END
|
||||
#endif
|
||||
|
|
|
@ -81,13 +81,19 @@ int vio_errno(Vio*vio);
|
|||
/* Get socket number */
|
||||
my_socket vio_fd(Vio*vio);
|
||||
/* Remote peer's address and name in text form */
|
||||
my_bool vio_peer_addr(Vio* vio, char *buf, uint16 *port);
|
||||
/* Remotes in_addr */
|
||||
void vio_in_addr(Vio *vio, struct in_addr *in);
|
||||
my_bool vio_peer_addr(Vio *vio, char *buf, uint16 *port, size_t buflen);
|
||||
my_bool vio_poll_read(Vio *vio, uint timeout);
|
||||
my_bool vio_is_connected(Vio *vio);
|
||||
ssize_t vio_pending(Vio *vio);
|
||||
|
||||
my_bool vio_get_normalized_ip_string(const struct sockaddr *addr, int addr_length,
|
||||
char *ip_string, size_t ip_string_size);
|
||||
|
||||
int vio_getnameinfo(const struct sockaddr *sa,
|
||||
char *hostname, size_t hostname_size,
|
||||
char *port, size_t port_size,
|
||||
int flags);
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#include <openssl/opensslv.h>
|
||||
#if OPENSSL_VERSION_NUMBER < 0x0090700f
|
||||
|
@ -154,8 +160,7 @@ void vio_end(void);
|
|||
#define vio_should_retry(vio) (vio)->should_retry(vio)
|
||||
#define vio_was_interrupted(vio) (vio)->was_interrupted(vio)
|
||||
#define vio_close(vio) ((vio)->vioclose)(vio)
|
||||
#define vio_peer_addr(vio, buf, prt) (vio)->peer_addr(vio, buf, prt)
|
||||
#define vio_in_addr(vio, in) (vio)->in_addr(vio, in)
|
||||
#define vio_peer_addr(vio, buf, prt, buflen) (vio)->peer_addr(vio, buf, prt, buflen)
|
||||
#define vio_timeout(vio, which, seconds) (vio)->timeout(vio, which, seconds)
|
||||
#define vio_poll_read(vio, timeout) (vio)->poll_read(vio, timeout)
|
||||
#define vio_is_connected(vio) (vio)->is_connected(vio)
|
||||
|
@ -180,8 +185,9 @@ struct st_vio
|
|||
HANDLE hPipe;
|
||||
my_bool localhost; /* Are we from localhost? */
|
||||
int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */
|
||||
struct sockaddr_in local; /* Local internet address */
|
||||
struct sockaddr_in remote; /* Remote internet address */
|
||||
struct sockaddr_storage local; /* Local internet address */
|
||||
struct sockaddr_storage remote; /* Remote internet address */
|
||||
int addrLen; /* Length of remote address */
|
||||
enum enum_vio_type type; /* Type of connection */
|
||||
char desc[30]; /* String description */
|
||||
char *read_buffer; /* buffer for vio_read_buff */
|
||||
|
@ -197,8 +203,8 @@ struct st_vio
|
|||
my_bool (*is_blocking)(Vio*);
|
||||
int (*viokeepalive)(Vio*, my_bool);
|
||||
int (*fastsend)(Vio*);
|
||||
my_bool (*peer_addr)(Vio*, char *, uint16*);
|
||||
void (*in_addr)(Vio*, struct in_addr*);
|
||||
my_bool (*peer_addr)(Vio*, char *, uint16*, size_t);
|
||||
void (*in_addr)(Vio*, struct sockaddr_storage*);
|
||||
my_bool (*should_retry)(Vio*);
|
||||
my_bool (*was_interrupted)(Vio*);
|
||||
int (*vioclose)(Vio*);
|
||||
|
|
|
@ -15,7 +15,7 @@ DROP USER mysqltest_1@'127.0.0.1/255.255.255.255';
|
|||
# Bug#13407 Remote connecting crashes server
|
||||
# Server crashed when one used USER() function in connection for which
|
||||
# was impossible to obtain peer hostname.
|
||||
connect (con1, 127.0.0.1, root, , test, $MASTER_MYPORT, );
|
||||
connect (con1, localhost, root, , test, $MASTER_MYPORT, );
|
||||
--replace_column 1 #
|
||||
SELECT USER();
|
||||
# We are only interested in the fact that statement below doesn't
|
||||
|
|
|
@ -24,6 +24,7 @@ set @current_hostname= @@hostname;
|
|||
INSERT INTO tmp_user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
|
||||
REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0 FROM dual WHERE LOWER( @current_hostname) != 'localhost';
|
||||
REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
|
||||
REPLACE INTO tmp_user VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
|
||||
INSERT INTO tmp_user (host,user) VALUES ('localhost','');
|
||||
INSERT INTO tmp_user (host,user) SELECT @current_hostname,'' FROM dual WHERE LOWER(@current_hostname ) != 'localhost';
|
||||
INSERT INTO user SELECT * FROM tmp_user WHERE @had_user_table=0;
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
|
||||
#include "mysql.h"
|
||||
|
||||
#ifndef __WIN__
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
/* Remove client convenience wrappers */
|
||||
#undef max_allowed_packet
|
||||
#undef net_buffer_length
|
||||
|
@ -2227,9 +2231,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
{
|
||||
char buff[NAME_LEN+USERNAME_LENGTH+100];
|
||||
char *end,*host_info= NULL;
|
||||
my_socket sock;
|
||||
in_addr_t ip_addr;
|
||||
struct sockaddr_in sock_addr;
|
||||
ulong pkt_length;
|
||||
NET *net= &mysql->net;
|
||||
#ifdef MYSQL_SERVER
|
||||
|
@ -2335,7 +2336,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
else
|
||||
{
|
||||
mysql->options.protocol=MYSQL_PROTOCOL_MEMORY;
|
||||
sock=0;
|
||||
unix_socket = 0;
|
||||
host=mysql->options.shared_memory_base_name;
|
||||
my_snprintf(host_info=buff, sizeof(buff)-1,
|
||||
|
@ -2350,12 +2350,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
(unix_socket || mysql_unix_port) &&
|
||||
(!host || !strcmp(host,LOCAL_HOST)))
|
||||
{
|
||||
host=LOCAL_HOST;
|
||||
if (!unix_socket)
|
||||
unix_socket=mysql_unix_port;
|
||||
host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
|
||||
DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
|
||||
if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
|
||||
DBUG_PRINT("info", ("Using socket"));
|
||||
my_socket sock= socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock == SOCKET_ERROR)
|
||||
{
|
||||
set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR,
|
||||
unknown_sqlstate,
|
||||
|
@ -2363,12 +2360,28 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
socket_errno);
|
||||
goto error;
|
||||
}
|
||||
|
||||
net->vio= vio_new(sock, VIO_TYPE_SOCKET,
|
||||
VIO_LOCALHOST | VIO_BUFFERED_READ);
|
||||
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
|
||||
UNIXaddr.sun_family = AF_UNIX;
|
||||
if (!net->vio)
|
||||
{
|
||||
DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol));
|
||||
set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
|
||||
closesocket(sock);
|
||||
goto error;
|
||||
}
|
||||
|
||||
host= LOCAL_HOST;
|
||||
if (!unix_socket)
|
||||
unix_socket= mysql_unix_port;
|
||||
host_info= (char*) ER(CR_LOCALHOST_CONNECTION);
|
||||
DBUG_PRINT("info", ("Using UNIX sock '%s'", unix_socket));
|
||||
|
||||
bzero((char*) &UNIXaddr, sizeof(UNIXaddr));
|
||||
UNIXaddr.sun_family= AF_UNIX;
|
||||
strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1);
|
||||
if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
|
||||
|
||||
if (my_connect(sock, (struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
|
||||
mysql->options.connect_timeout))
|
||||
{
|
||||
DBUG_PRINT("error",("Got error %d on connect to local server",
|
||||
|
@ -2377,6 +2390,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
unknown_sqlstate,
|
||||
ER(CR_CONNECTION_ERROR),
|
||||
unix_socket, socket_errno);
|
||||
vio_delete(net->vio);
|
||||
net->vio= 0;
|
||||
goto error;
|
||||
}
|
||||
mysql->options.protocol=MYSQL_PROTOCOL_SOCKET;
|
||||
|
@ -2387,7 +2402,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
(host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
|
||||
(! have_tcpip && (unix_socket || !host && is_NT()))))
|
||||
{
|
||||
sock=0;
|
||||
if ((hPipe= create_named_pipe(mysql, mysql->options.connect_timeout,
|
||||
(char**) &host, (char**) &unix_socket)) ==
|
||||
INVALID_HANDLE_VALUE)
|
||||
|
@ -2417,94 +2431,124 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
(!mysql->options.protocol ||
|
||||
mysql->options.protocol == MYSQL_PROTOCOL_TCP))
|
||||
{
|
||||
int status= -1;
|
||||
struct addrinfo *res_lst, hints, *t_res;
|
||||
int gai_errno;
|
||||
char port_buf[NI_MAXSERV];
|
||||
my_socket sock= SOCKET_ERROR;
|
||||
int UNINIT_VAR(saved_error), status= -1;
|
||||
|
||||
unix_socket=0; /* This is not used */
|
||||
|
||||
if (!port)
|
||||
port=mysql_port;
|
||||
port= mysql_port;
|
||||
|
||||
if (!host)
|
||||
host=LOCAL_HOST;
|
||||
my_snprintf(host_info=buff,sizeof(buff)-1,ER(CR_TCP_CONNECTION),host);
|
||||
DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
|
||||
host= LOCAL_HOST;
|
||||
|
||||
my_snprintf(host_info=buff, sizeof(buff)-1, ER(CR_TCP_CONNECTION), host);
|
||||
DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host, port));
|
||||
#ifdef MYSQL_SERVER
|
||||
thr_alarm_init(&alarmed);
|
||||
thr_alarm(&alarmed, mysql->options.connect_timeout, &alarm_buff);
|
||||
#endif
|
||||
/* _WIN64 ; Assume that the (int) range is enough for socket() */
|
||||
sock = (my_socket) socket(AF_INET,SOCK_STREAM,0);
|
||||
|
||||
DBUG_PRINT("info",("IP '%s'", "client"));
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
thr_end_alarm(&alarmed);
|
||||
#endif
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype= SOCK_STREAM;
|
||||
hints.ai_protocol= IPPROTO_TCP;
|
||||
hints.ai_family= AF_UNSPEC;
|
||||
|
||||
DBUG_PRINT("info",("IPV6 getaddrinfo %s", host));
|
||||
my_snprintf(port_buf, NI_MAXSERV, "%d", port);
|
||||
gai_errno= getaddrinfo(host, port_buf, &hints, &res_lst);
|
||||
|
||||
if (gai_errno != 0)
|
||||
{
|
||||
/*
|
||||
For DBUG we are keeping the right message but for client we default to
|
||||
historical error message.
|
||||
*/
|
||||
DBUG_PRINT("info",("IPV6 getaddrinfo error %d", gai_errno));
|
||||
set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
|
||||
ER(CR_UNKNOWN_HOST), host, errno);
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
A hostname might map to multiple IP addresses (IPv4/IPv6). Go over the
|
||||
list of IP addresses until a successful connection can be established.
|
||||
*/
|
||||
DBUG_PRINT("info", ("Try connect on all addresses for host."));
|
||||
for (t_res= res_lst; t_res; t_res= t_res->ai_next)
|
||||
{
|
||||
DBUG_PRINT("info", ("Create socket, family: %d type: %d proto: %d",
|
||||
t_res->ai_family, t_res->ai_socktype,
|
||||
t_res->ai_protocol));
|
||||
sock= socket(t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol);
|
||||
if (sock == SOCKET_ERROR)
|
||||
{
|
||||
saved_error= socket_errno;
|
||||
continue;
|
||||
}
|
||||
|
||||
DBUG_PRINT("info", ("Connect socket"));
|
||||
status= my_connect(sock, t_res->ai_addr, t_res->ai_addrlen,
|
||||
mysql->options.connect_timeout);
|
||||
/*
|
||||
Here we rely on my_connect() to return success only if the
|
||||
connect attempt was really successful. Otherwise we would stop
|
||||
trying another address, believing we were successful.
|
||||
*/
|
||||
if (!status)
|
||||
break;
|
||||
|
||||
/*
|
||||
Save value as socket errno might be overwritten due to
|
||||
calling a socket function below.
|
||||
*/
|
||||
saved_error= socket_errno;
|
||||
|
||||
DBUG_PRINT("info", ("No success, close socket, try next address."));
|
||||
closesocket(sock);
|
||||
}
|
||||
DBUG_PRINT("info",
|
||||
("End of connect attempts, sock: %d status: %d error: %d",
|
||||
sock, status, saved_error));
|
||||
|
||||
freeaddrinfo(res_lst);
|
||||
|
||||
if (sock == SOCKET_ERROR)
|
||||
{
|
||||
set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
|
||||
ER(CR_IPSOCK_ERROR), socket_errno);
|
||||
ER(CR_IPSOCK_ERROR), saved_error);
|
||||
goto error;
|
||||
}
|
||||
net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
|
||||
bzero((char*) &sock_addr,sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_port = (ushort) htons((ushort) port);
|
||||
|
||||
/*
|
||||
The server name may be a host name or IP address
|
||||
*/
|
||||
|
||||
if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
|
||||
{
|
||||
memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
|
||||
status= my_connect(sock, (struct sockaddr *) &sock_addr,
|
||||
sizeof(sock_addr), mysql->options.connect_timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, tmp_errno;
|
||||
struct hostent tmp_hostent,*hp;
|
||||
char buff2[GETHOSTBYNAME_BUFF_SIZE];
|
||||
hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2),
|
||||
&tmp_errno);
|
||||
|
||||
/*
|
||||
Don't attempt to connect to non IPv4 addresses as the client could
|
||||
end up sending information to a unknown server. For example, a IPv6
|
||||
address might be returned from gethostbyname depending on options
|
||||
set via the RES_OPTIONS environment variable.
|
||||
*/
|
||||
if (!hp || (hp->h_addrtype != AF_INET))
|
||||
{
|
||||
my_gethostbyname_r_free();
|
||||
set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
|
||||
ER(CR_UNKNOWN_HOST), host, tmp_errno);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i= 0; status && hp->h_addr_list[i]; i++)
|
||||
{
|
||||
char ipaddr[18] __attribute__((unused));
|
||||
memcpy(&sock_addr.sin_addr, hp->h_addr_list[i],
|
||||
min(sizeof(sock_addr.sin_addr), (size_t) hp->h_length));
|
||||
DBUG_PRINT("info",("Trying %s...",
|
||||
(my_inet_ntoa(sock_addr.sin_addr, ipaddr), ipaddr)));
|
||||
/*
|
||||
Here we rely on my_connect() to return success only if the
|
||||
connect attempt was really successful. Otherwise we would stop
|
||||
trying another address, believing we were successful.
|
||||
*/
|
||||
status= my_connect(sock, (struct sockaddr *) &sock_addr,
|
||||
sizeof(sock_addr), mysql->options.connect_timeout);
|
||||
}
|
||||
|
||||
my_gethostbyname_r_free();
|
||||
}
|
||||
|
||||
if (status)
|
||||
{
|
||||
DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,
|
||||
host));
|
||||
DBUG_PRINT("error",("Got error %d on connect to '%s'", saved_error, host));
|
||||
set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
|
||||
ER(CR_CONN_HOST_ERROR), host, socket_errno);
|
||||
ER(CR_CONN_HOST_ERROR), host, saved_error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
|
||||
if (! net->vio )
|
||||
{
|
||||
DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol));
|
||||
set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
|
||||
closesocket(sock);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_PRINT("info", ("net->vio: %p", net->vio));
|
||||
if (!net->vio)
|
||||
{
|
||||
DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol));
|
||||
|
@ -2640,14 +2684,14 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
if (client_flag & CLIENT_MULTI_STATEMENTS)
|
||||
client_flag|= CLIENT_MULTI_RESULTS;
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
|
||||
if (mysql->options.ssl_key || mysql->options.ssl_cert ||
|
||||
mysql->options.ssl_ca || mysql->options.ssl_capath ||
|
||||
mysql->options.ssl_cipher)
|
||||
mysql->options.use_ssl= 1;
|
||||
if (mysql->options.use_ssl)
|
||||
client_flag|=CLIENT_SSL;
|
||||
#endif /* HAVE_OPENSSL */
|
||||
#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/
|
||||
if (db)
|
||||
client_flag|=CLIENT_CONNECT_WITH_DB;
|
||||
|
||||
|
@ -2676,7 +2720,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
}
|
||||
mysql->client_flag=client_flag;
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
|
||||
if (client_flag & CLIENT_SSL)
|
||||
{
|
||||
/* Do the SSL layering. */
|
||||
|
@ -2727,7 +2771,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
}
|
||||
|
||||
}
|
||||
#endif /* HAVE_OPENSSL */
|
||||
#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
|
||||
|
||||
DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu",
|
||||
mysql->server_version,mysql->server_capabilities,
|
||||
|
|
|
@ -30,10 +30,6 @@
|
|||
#define set_sigpipe(mysql)
|
||||
#define reset_sigpipe(mysql)
|
||||
#define read_user_name(A) {}
|
||||
#define mysql_rpl_query_type(A,B) MYSQL_RPL_ADMIN
|
||||
#define mysql_master_send_query(A, B, C) 1
|
||||
#define mysql_slave_send_query(A, B, C) 1
|
||||
#define mysql_rpl_probe(mysql) 0
|
||||
#undef HAVE_SMEM
|
||||
#undef _CUSTOMCONFIG_
|
||||
|
||||
|
|
617
sql/hostname.cc
617
sql/hostname.cc
|
@ -18,10 +18,10 @@
|
|||
@file
|
||||
|
||||
@brief
|
||||
Get hostname for an IP.
|
||||
Get hostname for an IP address.
|
||||
|
||||
Hostnames are checked with reverse name lookup and
|
||||
checked that they doesn't resemble an ip.
|
||||
Hostnames are checked with reverse name lookup and checked that they
|
||||
doesn't resemble an IP address.
|
||||
*/
|
||||
|
||||
#include "mysql_priv.h"
|
||||
|
@ -34,24 +34,54 @@ extern "C" { // Because of SCO 3.2V4.2
|
|||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#include <netdb.h>
|
||||
#include <sys/utsname.h>
|
||||
#endif // __WIN__
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
HOST_ENTRY_KEY_SIZE -- size of IP address string in the hash cache.
|
||||
*/
|
||||
|
||||
class host_entry :public hash_filo_element
|
||||
#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
|
||||
{
|
||||
public:
|
||||
char ip[sizeof(((struct in_addr *) 0)->s_addr)];
|
||||
uint errors;
|
||||
char *hostname;
|
||||
/**
|
||||
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;
|
||||
|
||||
/**
|
||||
One of the host names for the IP address. May be NULL.
|
||||
*/
|
||||
const char *hostname;
|
||||
};
|
||||
|
||||
static hash_filo *hostname_cache;
|
||||
static pthread_mutex_t LOCK_hostname;
|
||||
|
||||
void hostname_cache_refresh()
|
||||
{
|
||||
|
@ -60,219 +90,468 @@ void hostname_cache_refresh()
|
|||
|
||||
bool hostname_cache_init()
|
||||
{
|
||||
host_entry tmp;
|
||||
uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp);
|
||||
if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset,
|
||||
sizeof(struct in_addr),NULL,
|
||||
(my_hash_free_key) free,
|
||||
&my_charset_bin)))
|
||||
Host_entry tmp;
|
||||
uint key_offset= (uint) ((char*) (&tmp.ip_key) - (char*) &tmp);
|
||||
|
||||
if (!(hostname_cache= new hash_filo(HOST_CACHE_SIZE,
|
||||
key_offset, HOST_ENTRY_KEY_SIZE,
|
||||
NULL, (my_hash_free_key) free,
|
||||
&my_charset_bin)))
|
||||
return 1;
|
||||
|
||||
hostname_cache->clear();
|
||||
(void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hostname_cache_free()
|
||||
{
|
||||
if (hostname_cache)
|
||||
delete hostname_cache;
|
||||
hostname_cache= NULL;
|
||||
}
|
||||
|
||||
static void prepare_hostname_cache_key(const char *ip_string,
|
||||
char *ip_key)
|
||||
{
|
||||
int ip_string_length= strlen(ip_string);
|
||||
DBUG_ASSERT(ip_string_length < HOST_ENTRY_KEY_SIZE);
|
||||
|
||||
memset(ip_key, 0, HOST_ENTRY_KEY_SIZE);
|
||||
memcpy_fixed(ip_key, ip_string, ip_string_length);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
memcpy_fixed(&entry->ip_key, ip_key, HOST_ENTRY_KEY_SIZE);
|
||||
|
||||
if (hostname_size)
|
||||
{
|
||||
(void) pthread_mutex_destroy(&LOCK_hostname);
|
||||
delete hostname_cache;
|
||||
hostname_cache= 0;
|
||||
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));
|
||||
}
|
||||
else
|
||||
{
|
||||
hostname_copy= NULL;
|
||||
|
||||
DBUG_PRINT("info", ("Adding '%s' -> NULL to the hostname cache...'",
|
||||
(const char *) ip_key));
|
||||
}
|
||||
|
||||
entry->hostname= hostname_copy;
|
||||
entry->connect_errors= 0;
|
||||
|
||||
return hostname_cache->add(entry);
|
||||
}
|
||||
|
||||
static bool add_hostname(const char *ip_key, const char *hostname)
|
||||
{
|
||||
if (specialflag & SPECIAL_NO_HOST_CACHE)
|
||||
return FALSE;
|
||||
|
||||
pthread_mutex_lock(&hostname_cache->lock);
|
||||
|
||||
bool err_status= add_hostname_impl(ip_key, hostname);
|
||||
|
||||
pthread_mutex_unlock(&hostname_cache->lock);
|
||||
|
||||
return err_status;
|
||||
}
|
||||
|
||||
void inc_host_errors(const char *ip_string)
|
||||
{
|
||||
if (!ip_string)
|
||||
return;
|
||||
|
||||
char ip_key[HOST_ENTRY_KEY_SIZE];
|
||||
prepare_hostname_cache_key(ip_string, ip_key);
|
||||
|
||||
pthread_mutex_lock(&hostname_cache->lock);
|
||||
|
||||
Host_entry *entry= hostname_cache_search(ip_key);
|
||||
|
||||
if (entry)
|
||||
entry->connect_errors++;
|
||||
|
||||
pthread_mutex_unlock(&hostname_cache->lock);
|
||||
}
|
||||
|
||||
|
||||
static void add_hostname(struct in_addr *in,const char *name)
|
||||
void reset_host_errors(const char *ip_string)
|
||||
{
|
||||
if (!(specialflag & SPECIAL_NO_HOST_CACHE))
|
||||
{
|
||||
pthread_mutex_lock(&hostname_cache->lock);
|
||||
host_entry *entry;
|
||||
if (!(entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
|
||||
if (!ip_string)
|
||||
return;
|
||||
|
||||
char ip_key[HOST_ENTRY_KEY_SIZE];
|
||||
prepare_hostname_cache_key(ip_string, ip_key);
|
||||
|
||||
pthread_mutex_lock(&hostname_cache->lock);
|
||||
|
||||
Host_entry *entry= hostname_cache_search(ip_key);
|
||||
|
||||
if (entry)
|
||||
entry->connect_errors= 0;
|
||||
|
||||
pthread_mutex_unlock(&hostname_cache->lock);
|
||||
}
|
||||
|
||||
|
||||
static inline bool is_ip_loopback(const struct sockaddr *ip)
|
||||
{
|
||||
switch (ip->sa_family) {
|
||||
case AF_INET:
|
||||
{
|
||||
uint length=name ? (uint) strlen(name) : 0;
|
||||
|
||||
if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1)))
|
||||
{
|
||||
char *new_name;
|
||||
memcpy_fixed(&entry->ip, &in->s_addr, sizeof(in->s_addr));
|
||||
if (length)
|
||||
memcpy(new_name= (char *) (entry+1), name, length+1);
|
||||
else
|
||||
new_name=0;
|
||||
entry->hostname=new_name;
|
||||
entry->errors=0;
|
||||
(void) hostname_cache->add(entry);
|
||||
}
|
||||
/* Check for IPv4 127.0.0.1. */
|
||||
struct in_addr *ip4= &((struct sockaddr_in *) ip)->sin_addr;
|
||||
return ntohl(ip4->s_addr) == INADDR_LOOPBACK;
|
||||
}
|
||||
pthread_mutex_unlock(&hostname_cache->lock);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
case AF_INET6:
|
||||
{
|
||||
/* Check for IPv6 ::1. */
|
||||
struct in6_addr *ip6= &((struct sockaddr_in6 *) ip)->sin6_addr;
|
||||
return IN6_IS_ADDR_LOOPBACK(ip6);
|
||||
}
|
||||
#endif /* HAVE_IPV6 */
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void add_wrong_ip(struct in_addr *in)
|
||||
static inline bool is_hostname_valid(const char *hostname)
|
||||
{
|
||||
add_hostname(in,NullS);
|
||||
/*
|
||||
A hostname is invalid if it starts with a number followed by a dot
|
||||
(IPv4 address).
|
||||
*/
|
||||
|
||||
if (!my_isdigit(&my_charset_latin1, hostname[0]))
|
||||
return TRUE;
|
||||
|
||||
const char *p= hostname + 1;
|
||||
|
||||
while (my_isdigit(&my_charset_latin1, *p))
|
||||
++p;
|
||||
|
||||
return *p != '.';
|
||||
}
|
||||
|
||||
void inc_host_errors(struct in_addr *in)
|
||||
{
|
||||
pthread_mutex_lock(&hostname_cache->lock);
|
||||
host_entry *entry;
|
||||
if ((entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
|
||||
entry->errors++;
|
||||
pthread_mutex_unlock(&hostname_cache->lock);
|
||||
}
|
||||
/**
|
||||
Resolve IP-address to host name.
|
||||
|
||||
void reset_host_errors(struct in_addr *in)
|
||||
{
|
||||
pthread_mutex_lock(&hostname_cache->lock);
|
||||
host_entry *entry;
|
||||
if ((entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
|
||||
entry->errors=0;
|
||||
pthread_mutex_unlock(&hostname_cache->lock);
|
||||
}
|
||||
This function does the following things:
|
||||
- resolves IP-address;
|
||||
- employs Forward Confirmed Reverse DNS technique to validate IP-address;
|
||||
- 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.
|
||||
|
||||
/* Deal with systems that don't defined INADDR_LOOPBACK */
|
||||
#ifndef INADDR_LOOPBACK
|
||||
#define INADDR_LOOPBACK 0x7f000001UL
|
||||
#endif
|
||||
NOTE: connect_errors are counted (are supported) only for the clients
|
||||
where IP-address can be resolved and FCrDNS check is passed.
|
||||
|
||||
char * ip_to_hostname(struct in_addr *in, uint *errors)
|
||||
@param [in] ip_storage IP address (sockaddr). Must be set.
|
||||
@param [in] ip_string IP address (string). Must be set.
|
||||
@param [out] hostname
|
||||
@param [out] connect_errors
|
||||
|
||||
@return Error status
|
||||
@retval FALSE Success
|
||||
@retval TRUE Error
|
||||
|
||||
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)
|
||||
{
|
||||
uint i;
|
||||
host_entry *entry;
|
||||
const struct sockaddr *ip= (const sockaddr *) ip_storage;
|
||||
int err_code;
|
||||
bool err_status;
|
||||
|
||||
DBUG_ENTER("ip_to_hostname");
|
||||
*errors=0;
|
||||
DBUG_PRINT("info", ("IP address: '%s'; family: %d.",
|
||||
(const char *) ip_string,
|
||||
(int) ip->sa_family));
|
||||
|
||||
/* We always treat the loopback address as "localhost". */
|
||||
if (in->s_addr == htonl(INADDR_LOOPBACK)) // is expanded inline by gcc
|
||||
DBUG_RETURN((char *)my_localhost);
|
||||
/* 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. */
|
||||
*hostname= (char *) my_localhost;
|
||||
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
/* Prepare host name cache key. */
|
||||
|
||||
char ip_key[HOST_ENTRY_KEY_SIZE];
|
||||
prepare_hostname_cache_key(ip_string, ip_key);
|
||||
|
||||
/* Check first if we have host name in the cache. */
|
||||
|
||||
/* Check first if we have name in cache */
|
||||
if (!(specialflag & SPECIAL_NO_HOST_CACHE))
|
||||
{
|
||||
pthread_mutex_lock(&hostname_cache->lock);
|
||||
if ((entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
|
||||
|
||||
Host_entry *entry= hostname_cache_search(ip_key);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
char *name;
|
||||
if (!entry->hostname)
|
||||
name=0; // Don't allow connection
|
||||
else
|
||||
name=my_strdup(entry->hostname,MYF(0));
|
||||
*errors= entry->errors;
|
||||
*connect_errors= entry->connect_errors;
|
||||
*hostname= NULL;
|
||||
|
||||
if (entry->hostname)
|
||||
*hostname= my_strdup(entry->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));
|
||||
|
||||
pthread_mutex_unlock(&hostname_cache->lock);
|
||||
DBUG_RETURN(name);
|
||||
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&hostname_cache->lock);
|
||||
}
|
||||
|
||||
struct hostent *hp, *check;
|
||||
char *name;
|
||||
LINT_INIT(check);
|
||||
#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
|
||||
char buff[GETHOSTBYADDR_BUFF_SIZE],buff2[GETHOSTBYNAME_BUFF_SIZE];
|
||||
int tmp_errno;
|
||||
struct hostent tmp_hostent, tmp_hostent2;
|
||||
#ifdef HAVE_purify
|
||||
bzero(buff,sizeof(buff)); // Bug in purify
|
||||
#endif
|
||||
if (!(hp=gethostbyaddr_r((char*) in,sizeof(*in),
|
||||
AF_INET,
|
||||
&tmp_hostent,buff,sizeof(buff),&tmp_errno)))
|
||||
/*
|
||||
Resolve host name. Return an error if a host name can not be resolved
|
||||
(instead of returning the numeric form of the host name).
|
||||
*/
|
||||
|
||||
char hostname_buffer[NI_MAXHOST];
|
||||
|
||||
DBUG_PRINT("info", ("Resolving '%s'...", (const char *) ip_key));
|
||||
|
||||
err_code= vio_getnameinfo(ip, hostname_buffer, NI_MAXHOST, NULL, 0,
|
||||
NI_NAMEREQD);
|
||||
|
||||
if (err_code == EAI_NONAME)
|
||||
{
|
||||
DBUG_PRINT("error",("gethostbyaddr_r returned %d",tmp_errno));
|
||||
return 0;
|
||||
}
|
||||
if (!(check=my_gethostbyname_r(hp->h_name,&tmp_hostent2,buff2,sizeof(buff2),
|
||||
&tmp_errno)))
|
||||
{
|
||||
DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno));
|
||||
/*
|
||||
Don't cache responses when the DSN server is down, as otherwise
|
||||
There is no reverse address mapping for the IP address. A host name
|
||||
can not be resolved.
|
||||
*/
|
||||
|
||||
DBUG_PRINT("error", ("IP address '%s' could not be resolved: "
|
||||
"no reverse address mapping.",
|
||||
(const char *) ip_key));
|
||||
|
||||
sql_print_warning("IP address '%s' could not be resolved: "
|
||||
"no reverse address mapping.",
|
||||
(const char *) ip_key);
|
||||
|
||||
err_status= add_hostname(ip_key, NULL);
|
||||
|
||||
*hostname= NULL;
|
||||
*connect_errors= 0; /* New IP added to the cache. */
|
||||
|
||||
DBUG_RETURN(err_status);
|
||||
}
|
||||
else if (err_code)
|
||||
{
|
||||
DBUG_PRINT("error", ("IP address '%s' could not be resolved: "
|
||||
"getnameinfo() returned %d.",
|
||||
(const char *) ip_key,
|
||||
(int) err_code));
|
||||
|
||||
sql_print_warning("IP address '%s' could not be resolved: "
|
||||
"getnameinfo() returned error (code: %d).",
|
||||
(const char *) ip_key,
|
||||
(int) err_code);
|
||||
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
DBUG_PRINT("info", ("IP '%s' resolved to '%s'.",
|
||||
(const char *) ip_key,
|
||||
(const char *) hostname_buffer));
|
||||
|
||||
/*
|
||||
Validate hostname: the server does not accept host names, which
|
||||
resemble IP addresses.
|
||||
|
||||
The thing is that theoretically, a host name can be in a form of IPv4
|
||||
address (123.example.org, or 1.2 or even 1.2.3.4). We have to deny such
|
||||
host names because ACL-systems is not designed to work with them.
|
||||
|
||||
For example, it is possible to specify a host name mask (like
|
||||
192.168.1.%) for an ACL rule. Then, if IPv4-like hostnames are allowed,
|
||||
there is a security hole: instead of allowing access for
|
||||
192.168.1.0/255 network (which was assumed by the user), the access
|
||||
will be allowed for host names like 192.168.1.example.org.
|
||||
*/
|
||||
|
||||
if (!is_hostname_valid(hostname_buffer))
|
||||
{
|
||||
DBUG_PRINT("error", ("IP address '%s' has been resolved "
|
||||
"to the host name '%s', which resembles "
|
||||
"IPv4-address itself.",
|
||||
(const char *) ip_key,
|
||||
(const char *) hostname_buffer));
|
||||
|
||||
sql_print_warning("IP address '%s' has been resolved "
|
||||
"to the host name '%s', which resembles "
|
||||
"IPv4-address itself.",
|
||||
(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. */
|
||||
|
||||
DBUG_RETURN(err_status);
|
||||
}
|
||||
|
||||
/* Get IP-addresses for the resolved host name (FCrDNS technique). */
|
||||
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *addr_info_list;
|
||||
|
||||
memset(&hints, 0, sizeof (struct addrinfo));
|
||||
hints.ai_flags= AI_PASSIVE;
|
||||
hints.ai_socktype= SOCK_STREAM;
|
||||
hints.ai_family= AF_UNSPEC;
|
||||
|
||||
DBUG_PRINT("info", ("Getting IP addresses for hostname '%s'...",
|
||||
(const char *) hostname_buffer));
|
||||
|
||||
err_code= getaddrinfo(hostname_buffer, NULL, &hints, &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.
|
||||
*/
|
||||
if (tmp_errno == HOST_NOT_FOUND || tmp_errno == NO_DATA)
|
||||
add_wrong_ip(in);
|
||||
my_gethostbyname_r_free();
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
if (!hp->h_name[0])
|
||||
{
|
||||
DBUG_PRINT("error",("Got an empty hostname"));
|
||||
add_wrong_ip(in);
|
||||
my_gethostbyname_r_free();
|
||||
DBUG_RETURN(0); // Don't allow empty hostnames
|
||||
}
|
||||
if (!(name=my_strdup(hp->h_name,MYF(0))))
|
||||
{
|
||||
my_gethostbyname_r_free();
|
||||
DBUG_RETURN(0); // out of memory
|
||||
}
|
||||
my_gethostbyname_r_free();
|
||||
#else
|
||||
pthread_mutex_lock(&LOCK_hostname);
|
||||
if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET)))
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_hostname);
|
||||
DBUG_PRINT("error",("gethostbyaddr returned %d",errno));
|
||||
|
||||
if (errno == HOST_NOT_FOUND || errno == NO_DATA)
|
||||
goto add_wrong_ip_and_return;
|
||||
/* Failure, don't cache responce */
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
if (!hp->h_name[0]) // Don't allow empty hostnames
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_hostname);
|
||||
DBUG_PRINT("error",("Got an empty hostname"));
|
||||
goto add_wrong_ip_and_return;
|
||||
}
|
||||
if (!(name=my_strdup(hp->h_name,MYF(0))))
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_hostname);
|
||||
DBUG_RETURN(0); // out of memory
|
||||
}
|
||||
check=gethostbyname(name);
|
||||
pthread_mutex_unlock(&LOCK_hostname);
|
||||
if (!check)
|
||||
{
|
||||
DBUG_PRINT("error",("gethostbyname returned %d",errno));
|
||||
my_free(name,MYF(0));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#endif
|
||||
err_status= add_hostname(ip_key, NULL);
|
||||
|
||||
/* Don't accept hostnames that starts with digits because they may be
|
||||
false ip:s */
|
||||
if (my_isdigit(&my_charset_latin1,name[0]))
|
||||
*hostname= NULL;
|
||||
*connect_errors= 0; /* New IP added to the cache. */
|
||||
|
||||
DBUG_RETURN(err_status);
|
||||
}
|
||||
else if (err_code)
|
||||
{
|
||||
char *pos;
|
||||
for (pos= name+1 ; my_isdigit(&my_charset_latin1,*pos); pos++) ;
|
||||
if (*pos == '.')
|
||||
DBUG_PRINT("error", ("getaddrinfo() failed with error code %d.", err_code));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
/* Check that getaddrinfo() returned the used IP (FCrDNS technique). */
|
||||
|
||||
DBUG_PRINT("info", ("The following IP addresses found for '%s':",
|
||||
(const char *) hostname_buffer));
|
||||
|
||||
for (struct addrinfo *addr_info= addr_info_list;
|
||||
addr_info; addr_info= addr_info->ai_next)
|
||||
{
|
||||
char ip_buffer[HOST_ENTRY_KEY_SIZE];
|
||||
|
||||
{
|
||||
DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
|
||||
my_free(name,MYF(0));
|
||||
goto add_wrong_ip_and_return;
|
||||
err_status=
|
||||
vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
|
||||
ip_buffer, sizeof (ip_buffer));
|
||||
DBUG_ASSERT(!err_status);
|
||||
}
|
||||
|
||||
DBUG_PRINT("info", (" - '%s'", (const char *) ip_buffer));
|
||||
|
||||
if (strcmp(ip_key, ip_buffer) == 0)
|
||||
{
|
||||
/* Copy host name string to be stored in the cache. */
|
||||
|
||||
*hostname= my_strdup(hostname_buffer, MYF(0));
|
||||
|
||||
if (!*hostname)
|
||||
{
|
||||
DBUG_PRINT("error", ("Out of memory."));
|
||||
|
||||
freeaddrinfo(addr_info_list);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that 'gethostbyname' returned the used ip */
|
||||
for (i=0; check->h_addr_list[i]; i++)
|
||||
/* Log resolved IP-addresses if no match was found. */
|
||||
|
||||
if (!*hostname)
|
||||
{
|
||||
if (*(uint32*)(check->h_addr_list)[i] == in->s_addr)
|
||||
sql_print_information("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);
|
||||
|
||||
for (struct addrinfo *addr_info= addr_info_list;
|
||||
addr_info; addr_info= addr_info->ai_next)
|
||||
{
|
||||
add_hostname(in,name);
|
||||
DBUG_RETURN(name);
|
||||
char ip_buffer[HOST_ENTRY_KEY_SIZE];
|
||||
|
||||
err_status=
|
||||
vio_get_normalized_ip_string(addr_info->ai_addr, addr_info->ai_addrlen,
|
||||
ip_buffer, sizeof (ip_buffer));
|
||||
DBUG_ASSERT(!err_status);
|
||||
|
||||
sql_print_information(" - %s\n", (const char *) ip_buffer);
|
||||
}
|
||||
}
|
||||
DBUG_PRINT("error",("Couldn't verify hostname with gethostbyname"));
|
||||
my_free(name,MYF(0));
|
||||
|
||||
add_wrong_ip_and_return:
|
||||
add_wrong_ip(in);
|
||||
DBUG_RETURN(0);
|
||||
/* Free the result of getaddrinfo(). */
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,9 @@
|
|||
#include "sql_array.h"
|
||||
#include "sql_plugin.h"
|
||||
#include "scheduler.h"
|
||||
#ifndef __WIN__
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
class Parser_state;
|
||||
|
||||
|
@ -2235,10 +2238,11 @@ uint build_table_shadow_filename(char *buff, size_t bufflen,
|
|||
#define FRM_ONLY (1 << 3)
|
||||
|
||||
/* from hostname.cc */
|
||||
struct in_addr;
|
||||
char * ip_to_hostname(struct in_addr *in,uint *errors);
|
||||
void inc_host_errors(struct in_addr *in);
|
||||
void reset_host_errors(struct in_addr *in);
|
||||
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);
|
||||
bool hostname_cache_init();
|
||||
void hostname_cache_free();
|
||||
void hostname_cache_refresh(void);
|
||||
|
|
118
sql/mysqld.cc
118
sql/mysqld.cc
|
@ -106,7 +106,6 @@ extern "C" { // Because of SCO 3.2V4.2
|
|||
#ifdef HAVE_SYS_UN_H
|
||||
# include <sys/un.h>
|
||||
#endif
|
||||
#include <netdb.h>
|
||||
#ifdef HAVE_SELECT_H
|
||||
# include <select.h>
|
||||
#endif
|
||||
|
@ -176,7 +175,7 @@ static void registerwithneb();
|
|||
static void getvolumename();
|
||||
static void getvolumeID(BYTE *volumeName);
|
||||
#endif /* __NETWARE__ */
|
||||
|
||||
|
||||
|
||||
#ifdef _AIX41
|
||||
int initgroups(const char *,unsigned int);
|
||||
|
@ -390,7 +389,6 @@ static my_bool opt_short_log_format= 0;
|
|||
static uint kill_cached_threads, wake_thread;
|
||||
static ulong killed_threads, thread_created;
|
||||
static ulong max_used_connections;
|
||||
static ulong my_bind_addr; /**< the address we bind to */
|
||||
static volatile ulong cached_thread_count= 0;
|
||||
static const char *sql_mode_str= "OFF";
|
||||
/* Text representation for OPTIMIZER_SWITCH_DEFAULT */
|
||||
|
@ -1635,17 +1633,18 @@ static void set_root(const char *path)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void network_init(void)
|
||||
{
|
||||
struct sockaddr_in IPaddr;
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
struct sockaddr_un UNIXaddr;
|
||||
#endif
|
||||
int arg=1;
|
||||
int arg;
|
||||
int ret;
|
||||
uint waited;
|
||||
uint this_wait;
|
||||
uint retry;
|
||||
char port_buf[NI_MAXSERV];
|
||||
DBUG_ENTER("network_init");
|
||||
LINT_INIT(ret);
|
||||
|
||||
|
@ -1656,26 +1655,65 @@ static void network_init(void)
|
|||
|
||||
if (mysqld_port != 0 && !opt_disable_networking && !opt_bootstrap)
|
||||
{
|
||||
struct addrinfo *ai, *a;
|
||||
struct addrinfo hints;
|
||||
int error;
|
||||
DBUG_PRINT("general",("IP Socket is %d",mysqld_port));
|
||||
ip_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
bzero(&hints, sizeof (hints));
|
||||
hints.ai_flags= AI_PASSIVE;
|
||||
hints.ai_socktype= SOCK_STREAM;
|
||||
hints.ai_family= AF_UNSPEC;
|
||||
|
||||
my_snprintf(port_buf, NI_MAXSERV, "%d", mysqld_port);
|
||||
error= getaddrinfo(my_bind_addr_str, port_buf, &hints, &ai);
|
||||
if (error != 0)
|
||||
{
|
||||
DBUG_PRINT("error",("Got error: %d from getaddrinfo()", error));
|
||||
sql_perror(ER(ER_IPSOCK_ERROR)); /* purecov: tested */
|
||||
unireg_abort(1); /* purecov: tested */
|
||||
}
|
||||
|
||||
for (a= ai; a != NULL; a= a->ai_next)
|
||||
{
|
||||
ip_sock= socket(a->ai_family, a->ai_socktype, a->ai_protocol);
|
||||
if (ip_sock != INVALID_SOCKET)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ip_sock == INVALID_SOCKET)
|
||||
{
|
||||
DBUG_PRINT("error",("Got error: %d from socket()",socket_errno));
|
||||
sql_perror(ER(ER_IPSOCK_ERROR)); /* purecov: tested */
|
||||
unireg_abort(1); /* purecov: tested */
|
||||
}
|
||||
bzero((char*) &IPaddr, sizeof(IPaddr));
|
||||
IPaddr.sin_family = AF_INET;
|
||||
IPaddr.sin_addr.s_addr = my_bind_addr;
|
||||
IPaddr.sin_port = (unsigned short) htons((unsigned short) mysqld_port);
|
||||
|
||||
#ifndef __WIN__
|
||||
/*
|
||||
We should not use SO_REUSEADDR on windows as this would enable a
|
||||
user to open two mysqld servers with the same TCP/IP port.
|
||||
*/
|
||||
arg= 1;
|
||||
(void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg));
|
||||
#endif /* __WIN__ */
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
/*
|
||||
For interoperability with older clients, IPv6 socket should
|
||||
listen on both IPv6 and IPv4 wildcard addresses.
|
||||
Turn off IPV6_V6ONLY option.
|
||||
|
||||
NOTE: this will work starting from Windows Vista only.
|
||||
On Windows XP dual stack is not available, so it will not
|
||||
listen on the corresponding IPv4-address.
|
||||
*/
|
||||
if (a->ai_family == AF_INET6)
|
||||
{
|
||||
arg= 0;
|
||||
(void) setsockopt(ip_sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
|
||||
sizeof(arg));
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
Sometimes the port is not released fast enough when stopping and
|
||||
restarting the server. This happens quite often with the test suite
|
||||
|
@ -1686,8 +1724,7 @@ static void network_init(void)
|
|||
*/
|
||||
for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
|
||||
{
|
||||
if (((ret= bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
|
||||
sizeof(IPaddr))) >= 0) ||
|
||||
if (((ret= bind(ip_sock, a->ai_addr, a->ai_addrlen)) >= 0 ) ||
|
||||
(socket_errno != SOCKET_EADDRINUSE) ||
|
||||
(waited >= mysqld_port_timeout))
|
||||
break;
|
||||
|
@ -1695,6 +1732,7 @@ static void network_init(void)
|
|||
this_wait= retry * retry / 3 + 1;
|
||||
sleep(this_wait);
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
if (ret < 0)
|
||||
{
|
||||
DBUG_PRINT("error",("Got error: %d from bind",socket_errno));
|
||||
|
@ -1716,7 +1754,6 @@ static void network_init(void)
|
|||
if (Service.IsNT() && mysqld_unix_port[0] && !opt_bootstrap &&
|
||||
opt_enable_named_pipe)
|
||||
{
|
||||
|
||||
strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\",
|
||||
mysqld_unix_port, NullS);
|
||||
bzero((char*) &saPipeSecurity, sizeof(saPipeSecurity));
|
||||
|
@ -1782,6 +1819,7 @@ static void network_init(void)
|
|||
UNIXaddr.sun_family = AF_UNIX;
|
||||
strmov(UNIXaddr.sun_path, mysqld_unix_port);
|
||||
(void) unlink(mysqld_unix_port);
|
||||
arg= 1;
|
||||
(void) setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,
|
||||
sizeof(arg));
|
||||
umask(0);
|
||||
|
@ -4850,7 +4888,7 @@ static bool read_init_file(char *file_name)
|
|||
|
||||
When we enter this function, LOCK_thread_count is hold!
|
||||
*/
|
||||
|
||||
|
||||
void handle_connection_in_main_thread(THD *thd)
|
||||
{
|
||||
safe_mutex_assert_owner(&LOCK_thread_count);
|
||||
|
@ -4933,7 +4971,6 @@ void create_thread_to_handle_connection(THD *thd)
|
|||
|
||||
static void create_new_thread(THD *thd)
|
||||
{
|
||||
NET *net=&thd->net;
|
||||
DBUG_ENTER("create_new_thread");
|
||||
|
||||
/*
|
||||
|
@ -5003,6 +5040,7 @@ inline void kill_broken_server()
|
|||
/* Handle new connections and spawn new process to handle them */
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
|
||||
void handle_connections_sockets()
|
||||
{
|
||||
my_socket sock,new_sock;
|
||||
|
@ -5010,7 +5048,7 @@ void handle_connections_sockets()
|
|||
uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1);
|
||||
fd_set readFDs,clientFDs;
|
||||
THD *thd;
|
||||
struct sockaddr_in cAddr;
|
||||
struct sockaddr_storage cAddr;
|
||||
int ip_flags=0,socket_flags=0,flags;
|
||||
st_vio *vio_tmp;
|
||||
DBUG_ENTER("handle_connections_sockets");
|
||||
|
@ -5084,9 +5122,9 @@ void handle_connections_sockets()
|
|||
#endif /* NO_FCNTL_NONBLOCK */
|
||||
for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++)
|
||||
{
|
||||
size_socket length=sizeof(struct sockaddr_in);
|
||||
new_sock = accept(sock, my_reinterpret_cast(struct sockaddr *) (&cAddr),
|
||||
&length);
|
||||
size_socket length= sizeof(struct sockaddr_storage);
|
||||
new_sock= accept(sock, (struct sockaddr *)(&cAddr),
|
||||
&length);
|
||||
#ifdef __NETWARE__
|
||||
// TODO: temporary fix, waiting for TCP/IP fix - DEFECT000303149
|
||||
if ((new_sock == INVALID_SOCKET) && (socket_errno == EINVAL))
|
||||
|
@ -5157,9 +5195,10 @@ void handle_connections_sockets()
|
|||
|
||||
{
|
||||
size_socket dummyLen;
|
||||
struct sockaddr dummy;
|
||||
dummyLen = sizeof(struct sockaddr);
|
||||
if (getsockname(new_sock,&dummy, &dummyLen) < 0)
|
||||
struct sockaddr_storage dummy;
|
||||
dummyLen = sizeof(dummy);
|
||||
if ( getsockname(new_sock,(struct sockaddr *)&dummy,
|
||||
(SOCKET_SIZE_TYPE *)&dummyLen) < 0 )
|
||||
{
|
||||
sql_perror("Error on new connection socket");
|
||||
(void) shutdown(new_sock, SHUT_RDWR);
|
||||
|
@ -5505,7 +5544,7 @@ errorconn:
|
|||
NullS);
|
||||
sql_perror(buff);
|
||||
}
|
||||
if (handle_client_file_map)
|
||||
if (handle_client_file_map)
|
||||
CloseHandle(handle_client_file_map);
|
||||
if (handle_client_map)
|
||||
UnmapViewOfFile(handle_client_map);
|
||||
|
@ -7786,7 +7825,6 @@ static int mysql_init_variables(void)
|
|||
strmov(server_version, MYSQL_SERVER_VERSION);
|
||||
myisam_recover_options_str= sql_mode_str= "OFF";
|
||||
myisam_stats_method_str= "nulls_unequal";
|
||||
my_bind_addr = htonl(INADDR_ANY);
|
||||
threads.empty();
|
||||
thread_cache.empty();
|
||||
key_caches.empty();
|
||||
|
@ -8226,27 +8264,25 @@ mysqld_get_one_option(int optid,
|
|||
my_use_symdir=0;
|
||||
break;
|
||||
case (int) OPT_BIND_ADDRESS:
|
||||
if ((my_bind_addr= (ulong) inet_addr(argument)) == INADDR_NONE)
|
||||
{
|
||||
struct hostent *ent;
|
||||
if (argument[0])
|
||||
ent=gethostbyname(argument);
|
||||
else
|
||||
struct addrinfo *res_lst, hints;
|
||||
|
||||
bzero(&hints, sizeof(struct addrinfo));
|
||||
hints.ai_socktype= SOCK_STREAM;
|
||||
hints.ai_protocol= IPPROTO_TCP;
|
||||
|
||||
if (getaddrinfo(argument, NULL, &hints, &res_lst) != 0)
|
||||
{
|
||||
char myhostname[255];
|
||||
if (gethostname(myhostname,sizeof(myhostname)) < 0)
|
||||
{
|
||||
sql_perror("Can't start server: cannot get my own hostname!");
|
||||
return 1;
|
||||
}
|
||||
ent=gethostbyname(myhostname);
|
||||
}
|
||||
if (!ent)
|
||||
{
|
||||
sql_perror("Can't start server: cannot resolve hostname!");
|
||||
sql_print_error("Can't start server: cannot resolve hostname!");
|
||||
return 1;
|
||||
}
|
||||
my_bind_addr = (ulong) ((in_addr*)ent->h_addr_list[0])->s_addr;
|
||||
|
||||
if (res_lst->ai_next)
|
||||
{
|
||||
sql_print_error("Can't start server: bind-address refers to multiple interfaces!");
|
||||
return 1;
|
||||
}
|
||||
freeaddrinfo(res_lst);
|
||||
}
|
||||
break;
|
||||
case (int) OPT_PID_FILE:
|
||||
|
|
|
@ -1785,24 +1785,83 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
|
|||
(ip && !wild_compare(ip, host->hostname, 0)));
|
||||
}
|
||||
|
||||
/**
|
||||
Check if the given host name needs to be resolved or not.
|
||||
Host name has to be resolved if it actually contains *name*.
|
||||
|
||||
For example:
|
||||
192.168.1.1 --> FALSE
|
||||
192.168.1.0/255.255.255.0 --> FALSE
|
||||
% --> FALSE
|
||||
192.168.1.% --> FALSE
|
||||
AB% --> FALSE
|
||||
|
||||
AAAAFFFF --> TRUE (Hostname)
|
||||
AAAA:FFFF:1234:5678 --> FALSE
|
||||
::1 --> FALSE
|
||||
|
||||
This function does not check if the given string is a valid host name or
|
||||
not. It assumes that the argument is a valid host name.
|
||||
|
||||
@param hostname the string to check.
|
||||
|
||||
@return a flag telling if the argument needs to be resolved or not.
|
||||
@retval TRUE the argument is a host name and needs to be resolved.
|
||||
@retval FALSE the argument is either an IP address, or a patter and
|
||||
should not be resolved.
|
||||
*/
|
||||
|
||||
bool hostname_requires_resolving(const char *hostname)
|
||||
{
|
||||
char cur;
|
||||
if (!hostname)
|
||||
return FALSE;
|
||||
size_t namelen= strlen(hostname);
|
||||
size_t lhlen= strlen(my_localhost);
|
||||
if ((namelen == lhlen) &&
|
||||
!my_strnncoll(system_charset_info, (const uchar *)hostname, namelen,
|
||||
(const uchar *)my_localhost, strlen(my_localhost)))
|
||||
return FALSE;
|
||||
for (; (cur=*hostname); hostname++)
|
||||
|
||||
/* Check if hostname is the localhost. */
|
||||
|
||||
size_t hostname_len= strlen(hostname);
|
||||
size_t localhost_len= strlen(my_localhost);
|
||||
|
||||
if (hostname == my_localhost ||
|
||||
(hostname_len == localhost_len &&
|
||||
!my_strnncoll(system_charset_info,
|
||||
(const uchar *) hostname, hostname_len,
|
||||
(const uchar *) my_localhost, strlen(my_localhost))))
|
||||
{
|
||||
if ((cur != '%') && (cur != '_') && (cur != '.') && (cur != '/') &&
|
||||
((cur < '0') || (cur > '9')))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
If the string contains any of {':', '%', '_', '/'}, it is definitely
|
||||
not a host name:
|
||||
- ':' means that the string is an IPv6 address;
|
||||
- '%' or '_' means that the string is a pattern;
|
||||
- '/' means that the string is an IPv4 network address;
|
||||
*/
|
||||
|
||||
for (const char *p= hostname; *p; ++p)
|
||||
{
|
||||
switch (*p) {
|
||||
case ':':
|
||||
case '%':
|
||||
case '_':
|
||||
case '/':
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Now we have to tell a host name (ab.cd, 12.ab) from an IPv4 address
|
||||
(12.34.56.78). The assumption is that if the string contains only
|
||||
digits and dots, it is an IPv4 address. Otherwise -- a host name.
|
||||
*/
|
||||
|
||||
for (const char *p= hostname; *p; ++p)
|
||||
{
|
||||
if (*p != '.' && !my_isdigit(&my_charset_latin1, *p))
|
||||
return TRUE; /* a "letter" has been found. */
|
||||
}
|
||||
|
||||
return FALSE; /* all characters are either dots or digits. */
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1238,7 +1238,6 @@ public:
|
|||
HASH user_vars; // hash for user variables
|
||||
String packet; // dynamic buffer for network I/O
|
||||
String convert_buffer; // buffer for charset conversions
|
||||
struct sockaddr_in remote; // client socket address
|
||||
struct rand_struct rand; // used for authentication
|
||||
struct system_variables variables; // Changeable local variables
|
||||
struct system_status_var status_var; // Per thread statistic vars
|
||||
|
|
|
@ -377,7 +377,8 @@ check_user(THD *thd, enum enum_server_command command,
|
|||
if (send_old_password_request(thd) ||
|
||||
my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
inc_host_errors(thd->main_security_ctx.ip);
|
||||
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
@ -498,9 +499,9 @@ check_user(THD *thd, enum enum_server_command command,
|
|||
thd->main_security_ctx.host_or_ip,
|
||||
passwd_len ? ER(ER_YES) : ER(ER_NO));
|
||||
/*
|
||||
log access denied messages to the error log when log-warnings = 2
|
||||
Log access denied messages to the error log when log-warnings = 2
|
||||
so that the overhead of the general query log is not required to track
|
||||
failed connections
|
||||
failed connections.
|
||||
*/
|
||||
if (global_system_variables.log_warnings > 1)
|
||||
{
|
||||
|
@ -666,9 +667,9 @@ static int check_connection(THD *thd)
|
|||
|
||||
if (!thd->main_security_ctx.host) // If TCP/IP connection
|
||||
{
|
||||
char ip[30];
|
||||
char ip[NI_MAXHOST];
|
||||
|
||||
if (vio_peer_addr(net->vio, ip, &thd->peer_port))
|
||||
if (vio_peer_addr(net->vio, ip, &thd->peer_port, NI_MAXHOST))
|
||||
{
|
||||
my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
return 1;
|
||||
|
@ -676,12 +677,15 @@ static int check_connection(THD *thd)
|
|||
if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
|
||||
return 1; /* The error is set by my_strdup(). */
|
||||
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
|
||||
vio_in_addr(net->vio,&thd->remote.sin_addr);
|
||||
if (!(specialflag & SPECIAL_NO_RESOLVE))
|
||||
{
|
||||
vio_in_addr(net->vio,&thd->remote.sin_addr);
|
||||
thd->main_security_ctx.host=
|
||||
ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
|
||||
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), ip);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Cut very long hostnames to avoid possible overflows */
|
||||
if (thd->main_security_ctx.host)
|
||||
{
|
||||
|
@ -714,7 +718,7 @@ static int check_connection(THD *thd)
|
|||
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
|
||||
thd->main_security_ctx.ip= 0;
|
||||
/* Reset sin_addr */
|
||||
bzero((char*) &thd->remote, sizeof(thd->remote));
|
||||
bzero((char*) &net->vio->remote, sizeof(net->vio->remote));
|
||||
}
|
||||
vio_keepalive(net->vio, TRUE);
|
||||
|
||||
|
@ -769,7 +773,8 @@ static int check_connection(THD *thd)
|
|||
(pkt_len= my_net_read(net)) == packet_error ||
|
||||
pkt_len < MIN_HANDSHAKE_SIZE)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
inc_host_errors(thd->main_security_ctx.ip);
|
||||
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0),
|
||||
thd->main_security_ctx.host_or_ip);
|
||||
return 1;
|
||||
|
@ -779,7 +784,7 @@ static int check_connection(THD *thd)
|
|||
#include "_cust_sql_parse.h"
|
||||
#endif
|
||||
if (connect_errors)
|
||||
reset_host_errors(&thd->remote.sin_addr);
|
||||
reset_host_errors(thd->main_security_ctx.ip);
|
||||
if (thd->packet.alloc(thd->variables.net_buffer_length))
|
||||
return 1; /* The error is set by alloc(). */
|
||||
|
||||
|
@ -813,7 +818,7 @@ static int check_connection(THD *thd)
|
|||
/* Do the SSL layering. */
|
||||
if (!ssl_acceptor_fd)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
inc_host_errors(thd->main_security_ctx.ip);
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
return 1;
|
||||
}
|
||||
|
@ -821,7 +826,8 @@ static int check_connection(THD *thd)
|
|||
if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
|
||||
{
|
||||
DBUG_PRINT("error", ("Failed to accept new SSL connection"));
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
inc_host_errors(thd->main_security_ctx.ip);
|
||||
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
return 1;
|
||||
}
|
||||
|
@ -831,7 +837,8 @@ static int check_connection(THD *thd)
|
|||
{
|
||||
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
|
||||
pkt_len));
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
inc_host_errors(thd->main_security_ctx.ip);
|
||||
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
return 1;
|
||||
}
|
||||
|
@ -840,7 +847,8 @@ static int check_connection(THD *thd)
|
|||
|
||||
if (end >= (char*) net->read_pos+ pkt_len +2)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
inc_host_errors(thd->main_security_ctx.ip);
|
||||
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
return 1;
|
||||
}
|
||||
|
@ -878,7 +886,8 @@ static int check_connection(THD *thd)
|
|||
|
||||
if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
inc_host_errors(thd->main_security_ctx.ip);
|
||||
|
||||
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -78,7 +78,6 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
|
|||
vio->was_interrupted=vio_was_interrupted;
|
||||
vio->vioclose =vio_close_pipe;
|
||||
vio->peer_addr =vio_peer_addr;
|
||||
vio->in_addr =vio_in_addr;
|
||||
vio->vioblocking =vio_blocking;
|
||||
vio->is_blocking =vio_is_blocking;
|
||||
|
||||
|
@ -108,7 +107,6 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
|
|||
vio->was_interrupted=vio_was_interrupted;
|
||||
vio->vioclose =vio_close_shared_memory;
|
||||
vio->peer_addr =vio_peer_addr;
|
||||
vio->in_addr =vio_in_addr;
|
||||
vio->vioblocking =vio_blocking;
|
||||
vio->is_blocking =vio_is_blocking;
|
||||
|
||||
|
@ -136,7 +134,6 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
|
|||
vio->was_interrupted=vio_was_interrupted;
|
||||
vio->vioclose =vio_ssl_close;
|
||||
vio->peer_addr =vio_peer_addr;
|
||||
vio->in_addr =vio_in_addr;
|
||||
vio->vioblocking =vio_ssl_blocking;
|
||||
vio->is_blocking =vio_is_blocking;
|
||||
vio->timeout =vio_timeout;
|
||||
|
@ -156,7 +153,6 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
|
|||
vio->was_interrupted=vio_was_interrupted;
|
||||
vio->vioclose =vio_close;
|
||||
vio->peer_addr =vio_peer_addr;
|
||||
vio->in_addr =vio_in_addr;
|
||||
vio->vioblocking =vio_blocking;
|
||||
vio->is_blocking =vio_is_blocking;
|
||||
vio->timeout =vio_timeout;
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
#include <m_string.h>
|
||||
#include <violite.h>
|
||||
|
||||
#ifndef _WIN_
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
void vio_win32_timeout(Vio *vio, uint which, uint timeout);
|
||||
#endif
|
||||
|
|
260
vio/viosocket.c
260
vio/viosocket.c
|
@ -300,53 +300,209 @@ my_socket vio_fd(Vio* vio)
|
|||
return vio->sd;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert a sock-address (AF_INET or AF_INET6) into the "normalized" form,
|
||||
which is the IPv4 form for IPv4-mapped or IPv4-compatible IPv6 addresses.
|
||||
|
||||
my_bool vio_peer_addr(Vio * vio, char *buf, uint16 *port)
|
||||
@note Background: when IPv4 and IPv6 are used simultaneously, IPv4
|
||||
addresses may be written in a form of IPv4-mapped or IPv4-compatible IPv6
|
||||
addresses. That means, one address (a.b.c.d) can be written in three forms:
|
||||
- IPv4: a.b.c.d;
|
||||
- IPv4-compatible IPv6: ::a.b.c.d;
|
||||
- IPv4-mapped IPv4: ::ffff:a.b.c.d;
|
||||
|
||||
Having three forms of one address makes it a little difficult to compare
|
||||
addresses with each other (the IPv4-compatible IPv6-address of foo.bar
|
||||
will be different from the IPv4-mapped IPv6-address of foo.bar).
|
||||
|
||||
@note This function can be made public when it's needed.
|
||||
|
||||
@param src [in] source IP address (AF_INET or AF_INET6).
|
||||
@param src_length [in] length of the src.
|
||||
@param dst [out] a buffer to store normalized IP address
|
||||
(sockaddr_storage).
|
||||
@param dst_length [out] actual length of the normalized IP address.
|
||||
*/
|
||||
static void vio_get_normalized_ip(const struct sockaddr *src,
|
||||
int src_length,
|
||||
struct sockaddr *dst,
|
||||
int *dst_length)
|
||||
{
|
||||
switch (src->sa_family) {
|
||||
case AF_INET:
|
||||
memcpy(dst, src, src_length);
|
||||
*dst_length= src_length;
|
||||
break;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
case AF_INET6:
|
||||
{
|
||||
const struct sockaddr_in6 *src_addr6= (const struct sockaddr_in6 *) src;
|
||||
const struct in6_addr *src_ip6= &(src_addr6->sin6_addr);
|
||||
const uint32 *src_ip6_int32= (uint32 *) src_ip6->s6_addr;
|
||||
|
||||
if (IN6_IS_ADDR_V4MAPPED(src_ip6) || IN6_IS_ADDR_V4COMPAT(src_ip6))
|
||||
{
|
||||
struct sockaddr_in *dst_ip4= (struct sockaddr_in *) dst;
|
||||
|
||||
/*
|
||||
This is an IPv4-mapped or IPv4-compatible IPv6 address. It should
|
||||
be converted to the IPv4 form.
|
||||
*/
|
||||
|
||||
*dst_length= sizeof (struct sockaddr_in);
|
||||
|
||||
memset(dst_ip4, 0, *dst_length);
|
||||
dst_ip4->sin_family= AF_INET;
|
||||
dst_ip4->sin_port= src_addr6->sin6_port;
|
||||
|
||||
/*
|
||||
In an IPv4 mapped or compatible address, the last 32 bits represent
|
||||
the IPv4 address. The byte orders for IPv6 and IPv4 addresses are
|
||||
the same, so a simple copy is possible.
|
||||
*/
|
||||
dst_ip4->sin_addr.s_addr= src_ip6_int32[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a "native" IPv6 address. */
|
||||
|
||||
memcpy(dst, src, src_length);
|
||||
*dst_length= src_length;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif /* HAVE_IPV6 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Return the normalized IP address string for a sock-address.
|
||||
|
||||
The idea is to return an IPv4-address for an IPv4-mapped and
|
||||
IPv4-compatible IPv6 address.
|
||||
|
||||
The function writes the normalized IP address to the given buffer.
|
||||
The buffer should have enough space, otherwise error flag is returned.
|
||||
The system constant INET6_ADDRSTRLEN can be used to reserve buffers of
|
||||
the right size.
|
||||
|
||||
@param addr [in] sockaddr object (AF_INET or AF_INET6).
|
||||
@param addr_length [in] length of the addr.
|
||||
@param ip_string [out] buffer to write normalized IP address.
|
||||
@param ip_string_size [in] size of the ip_string.
|
||||
|
||||
@return Error status.
|
||||
@retval TRUE in case of error (the ip_string buffer is not enough).
|
||||
@retval FALSE on success.
|
||||
*/
|
||||
|
||||
my_bool vio_get_normalized_ip_string(const struct sockaddr *addr,
|
||||
int addr_length,
|
||||
char *ip_string,
|
||||
size_t ip_string_size)
|
||||
{
|
||||
struct sockaddr_storage norm_addr_storage;
|
||||
struct sockaddr *norm_addr= (struct sockaddr *) &norm_addr_storage;
|
||||
int norm_addr_length;
|
||||
int err_code;
|
||||
|
||||
vio_get_normalized_ip(addr, addr_length, norm_addr, &norm_addr_length);
|
||||
|
||||
err_code= vio_getnameinfo(norm_addr, ip_string, ip_string_size, NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
|
||||
if (!err_code)
|
||||
return FALSE;
|
||||
|
||||
DBUG_PRINT("error", ("getnameinfo() failed with %d (%s).",
|
||||
(int) err_code,
|
||||
(const char *) gai_strerror(err_code)));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Return IP address and port of a VIO client socket.
|
||||
|
||||
The function returns an IPv4 address if IPv6 support is disabled.
|
||||
|
||||
The function returns an IPv4 address if the client socket is associated
|
||||
with an IPv4-compatible or IPv4-mapped IPv6 address. Otherwise, the native
|
||||
IPv6 address is returned.
|
||||
*/
|
||||
|
||||
my_bool vio_peer_addr(Vio *vio, char *ip_buffer, uint16 *port,
|
||||
size_t ip_buffer_size)
|
||||
{
|
||||
DBUG_ENTER("vio_peer_addr");
|
||||
DBUG_PRINT("enter", ("sd: %d", vio->sd));
|
||||
DBUG_PRINT("enter", ("Client socked fd: %d", (int) vio->sd));
|
||||
|
||||
if (vio->localhost)
|
||||
{
|
||||
strmov(buf,"127.0.0.1");
|
||||
/*
|
||||
Initialize vio->remote and vio->addLen. Set vio->remote to IPv4 loopback
|
||||
address.
|
||||
*/
|
||||
struct in_addr *ip4= &((struct sockaddr_in *) &(vio->remote))->sin_addr;
|
||||
|
||||
vio->remote.ss_family= AF_INET;
|
||||
vio->addrLen= sizeof (struct sockaddr_in);
|
||||
|
||||
ip4->s_addr= htonl(INADDR_LOOPBACK);
|
||||
|
||||
/* Initialize ip_buffer and port. */
|
||||
|
||||
strmov(ip_buffer, "127.0.0.1");
|
||||
*port= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_socket addrLen = sizeof(vio->remote);
|
||||
if (getpeername(vio->sd, (struct sockaddr *) (&vio->remote),
|
||||
&addrLen) != 0)
|
||||
int err_code;
|
||||
char port_buffer[NI_MAXSERV];
|
||||
|
||||
struct sockaddr_storage addr_storage;
|
||||
struct sockaddr *addr= (struct sockaddr *) &addr_storage;
|
||||
size_socket addr_length= sizeof (addr_storage);
|
||||
|
||||
/* Get sockaddr by socked fd. */
|
||||
|
||||
err_code= getpeername(vio->sd, addr, &addr_length);
|
||||
|
||||
if (err_code)
|
||||
{
|
||||
DBUG_PRINT("exit", ("getpeername gave error: %d", socket_errno));
|
||||
DBUG_RETURN(1);
|
||||
DBUG_PRINT("exit", ("getpeername() gave error: %d", socket_errno));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
my_inet_ntoa(vio->remote.sin_addr,buf);
|
||||
*port= ntohs(vio->remote.sin_port);
|
||||
|
||||
/* Normalize IP address. */
|
||||
|
||||
vio_get_normalized_ip(addr, addr_length,
|
||||
(struct sockaddr *) &vio->remote, &vio->addrLen);
|
||||
|
||||
/* Get IP address & port number. */
|
||||
|
||||
err_code= vio_getnameinfo((struct sockaddr *) &vio->remote,
|
||||
ip_buffer, ip_buffer_size,
|
||||
port_buffer, NI_MAXSERV,
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
if (err_code)
|
||||
{
|
||||
DBUG_PRINT("exit", ("getnameinfo() gave error: %s",
|
||||
gai_strerror(err_code)));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
*port= (uint16) strtol(port_buffer, NULL, 10);
|
||||
}
|
||||
DBUG_PRINT("exit", ("addr: %s", buf));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get in_addr for a TCP/IP connection
|
||||
|
||||
SYNOPSIS
|
||||
vio_in_addr()
|
||||
vio vio handle
|
||||
in put in_addr here
|
||||
|
||||
NOTES
|
||||
one must call vio_peer_addr() before calling this one
|
||||
*/
|
||||
|
||||
void vio_in_addr(Vio *vio, struct in_addr *in)
|
||||
{
|
||||
DBUG_ENTER("vio_in_addr");
|
||||
if (vio->localhost)
|
||||
bzero((char*) in, sizeof(*in));
|
||||
else
|
||||
*in=vio->remote.sin_addr;
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_PRINT("exit", ("Client IP address: %s; port: %d",
|
||||
(const char *) ip_buffer,
|
||||
(int) *port));
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -377,7 +533,8 @@ static my_bool socket_poll_read(my_socket sd, uint timeout)
|
|||
FD_ZERO(&errorfds);
|
||||
FD_SET(fd, &readfds);
|
||||
FD_SET(fd, &errorfds);
|
||||
if ((res= select(fd, &readfds, NULL, &errorfds, &tm) <= 0))
|
||||
/* The first argument is ignored on Windows, so a conversion to int is OK */
|
||||
if ((res= select((int) fd, &readfds, NULL, &errorfds, &tm) <= 0))
|
||||
{
|
||||
DBUG_RETURN(res < 0 ? 0 : 1);
|
||||
}
|
||||
|
@ -879,3 +1036,36 @@ ssize_t vio_pending(Vio *vio)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This is a wrapper for the system getnameinfo(), because different OS
|
||||
differ in the getnameinfo() implementation. For instance, Solaris 10
|
||||
requires that the 2nd argument (salen) must match the actual size of the
|
||||
struct sockaddr_storage passed to it.
|
||||
*/
|
||||
|
||||
int vio_getnameinfo(const struct sockaddr *sa,
|
||||
char *hostname, size_t hostname_size,
|
||||
char *port, size_t port_size,
|
||||
int flags)
|
||||
{
|
||||
int sa_length= 0;
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
sa_length= sizeof (struct sockaddr_in);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
case AF_INET6:
|
||||
sa_length= sizeof (struct sockaddr_in6);
|
||||
break;
|
||||
#endif /* HAVE_IPV6 */
|
||||
}
|
||||
|
||||
return getnameinfo(sa, sa_length,
|
||||
hostname, hostname_size,
|
||||
port, port_size,
|
||||
flags);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue