Description:
On line 245 of sql/hostname.cc, memcmp is used to compare a struct sockaddr_storage* (in) to a struct sockaddr* (t_res->ai_addr). I believe this is invalid, because of the following code I added to debug this problem.
printf("Getaddrinfo result: %0*X\n", t_res->ai_addrlen, t_res->ai_addr);
printf("In: %0*X\n", addrLen, in);
printf("Getaddrinfo result: %0*X\n", 4, ((struct sockaddr_in*)t_res->ai_addr)->sin_addr);
printf("In: %0*X\n", 4, ((struct sockaddr_in*)in)->sin_addr);
printf("Getaddrinfo result: %p\n", &((struct sockaddr_in*)t_res->ai_addr)->sin_addr);
printf("In: %p\n", &((struct sockaddr_in*)in)->sin_addr);
This code prints (for example):
Getaddrinfo result: 0000000008062110
In: 0000000008047B84
Getaddrinfo result: FC5F5582
In: FC5F5582
Getaddrinfo result: 8062114
In: 8047b88
This shows that because t_res->ai_addr (a struct sockaddr*) has a pointer as part of its structure, using memcmp() to compare the contents of "t_res->ai_addr" and "in" is invalid.
The attached patch *should* fix the problem... but it doesn't.
How to repeat:
Build mysql-cluster-gpl-7.0.6 on Solaris (or install the precompiled binaries). Add a GRANT like:
GRANT ALL ON *.* to 'user'@'chasca.cs.umbc.edu';
Try to connect from the specified user and host. Get an error like this:
Access denied for user 'user'@'::ffff:130.85.95.252'
Suggested fix:
--- mysql-cluster-gpl-7.0.6/sql/hostname.cc Tue May 26 10:34:43 2009
+++ mysql-cluster-gpl-7.0.6-mod//sql/hostname.cc Tue Jul 28 17:22:14 2009
@@ -137,6 +148,18 @@
char * ip_to_hostname(struct sockaddr_storage *in, int addrLen, uint *errors)
{
char *name= NULL;
+ if (in->ss_family == AF_INET6)
+ {
+ if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)in)->sin6_addr))
+ {
+ struct sockaddr_in foo;
+ bzero(&foo, sizeof(struct sockaddr));
+ foo.sin_family = AF_INET;
+ foo.sin_port = ((struct sockaddr_in6*)in)->sin6_port;
+ memcpy(&foo.sin_addr.s_addr, &((struct sockaddr_in6*)in)->sin6_addr.s6_addr[12], 4);
+ in = (struct sockaddr_storage*)&foo;
+ }
+ }
struct addrinfo hints,*res_lst= NULL,*t_res;
int gxi_error;
@@ -149,7 +172,7 @@
/* Historical comparison for 127.0.0.1 */
gxi_error= getnameinfo((struct sockaddr *)in, addrLen,
hostname_buff, NI_MAXHOST,
- NULL, 0, NI_NUMERICHOST);
+ NULL, 0, 0);
if (gxi_error)
{
DBUG_PRINT("error",("getnameinfo returned %d", gxi_error));
@@ -242,8 +265,16 @@
/* Check that 'getaddrinfo' returned the used ip */
for (t_res= res_lst; t_res; t_res=t_res->ai_next)
{
- if (!memcmp(&(t_res->ai_addr), in,
- sizeof(struct sockaddr_storage) ) )
+ if ((in->ss_family == t_res->ai_addr->sa_family) &&
+ (((in->ss_family == AF_INET) &&
+ (((struct sockaddr_in*)in)->sin_addr.s_addr ==
+ ((struct sockaddr_in*)t_res->ai_addr)->sin_addr.s_addr))
+ ||
+ ((in->ss_family == AF_INET6) &&
+ (!memcmp(
+ (void*)&((struct sockaddr_in6*)in)->sin6_addr,
+ (void*)&((struct sockaddr_in6*)t_res->ai_addr)->sin6_addr,
+ sizeof(struct in6_addr))))))
{
add_hostname(in,name);
freeaddrinfo(res_lst);
Description: On line 245 of sql/hostname.cc, memcmp is used to compare a struct sockaddr_storage* (in) to a struct sockaddr* (t_res->ai_addr). I believe this is invalid, because of the following code I added to debug this problem. printf("Getaddrinfo result: %0*X\n", t_res->ai_addrlen, t_res->ai_addr); printf("In: %0*X\n", addrLen, in); printf("Getaddrinfo result: %0*X\n", 4, ((struct sockaddr_in*)t_res->ai_addr)->sin_addr); printf("In: %0*X\n", 4, ((struct sockaddr_in*)in)->sin_addr); printf("Getaddrinfo result: %p\n", &((struct sockaddr_in*)t_res->ai_addr)->sin_addr); printf("In: %p\n", &((struct sockaddr_in*)in)->sin_addr); This code prints (for example): Getaddrinfo result: 0000000008062110 In: 0000000008047B84 Getaddrinfo result: FC5F5582 In: FC5F5582 Getaddrinfo result: 8062114 In: 8047b88 This shows that because t_res->ai_addr (a struct sockaddr*) has a pointer as part of its structure, using memcmp() to compare the contents of "t_res->ai_addr" and "in" is invalid. The attached patch *should* fix the problem... but it doesn't. How to repeat: Build mysql-cluster-gpl-7.0.6 on Solaris (or install the precompiled binaries). Add a GRANT like: GRANT ALL ON *.* to 'user'@'chasca.cs.umbc.edu'; Try to connect from the specified user and host. Get an error like this: Access denied for user 'user'@'::ffff:130.85.95.252' Suggested fix: --- mysql-cluster-gpl-7.0.6/sql/hostname.cc Tue May 26 10:34:43 2009 +++ mysql-cluster-gpl-7.0.6-mod//sql/hostname.cc Tue Jul 28 17:22:14 2009 @@ -137,6 +148,18 @@ char * ip_to_hostname(struct sockaddr_storage *in, int addrLen, uint *errors) { char *name= NULL; + if (in->ss_family == AF_INET6) + { + if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)in)->sin6_addr)) + { + struct sockaddr_in foo; + bzero(&foo, sizeof(struct sockaddr)); + foo.sin_family = AF_INET; + foo.sin_port = ((struct sockaddr_in6*)in)->sin6_port; + memcpy(&foo.sin_addr.s_addr, &((struct sockaddr_in6*)in)->sin6_addr.s6_addr[12], 4); + in = (struct sockaddr_storage*)&foo; + } + } struct addrinfo hints,*res_lst= NULL,*t_res; int gxi_error; @@ -149,7 +172,7 @@ /* Historical comparison for 127.0.0.1 */ gxi_error= getnameinfo((struct sockaddr *)in, addrLen, hostname_buff, NI_MAXHOST, - NULL, 0, NI_NUMERICHOST); + NULL, 0, 0); if (gxi_error) { DBUG_PRINT("error",("getnameinfo returned %d", gxi_error)); @@ -242,8 +265,16 @@ /* Check that 'getaddrinfo' returned the used ip */ for (t_res= res_lst; t_res; t_res=t_res->ai_next) { - if (!memcmp(&(t_res->ai_addr), in, - sizeof(struct sockaddr_storage) ) ) + if ((in->ss_family == t_res->ai_addr->sa_family) && + (((in->ss_family == AF_INET) && + (((struct sockaddr_in*)in)->sin_addr.s_addr == + ((struct sockaddr_in*)t_res->ai_addr)->sin_addr.s_addr)) + || + ((in->ss_family == AF_INET6) && + (!memcmp( + (void*)&((struct sockaddr_in6*)in)->sin6_addr, + (void*)&((struct sockaddr_in6*)t_res->ai_addr)->sin6_addr, + sizeof(struct in6_addr)))))) { add_hostname(in,name); freeaddrinfo(res_lst);