diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index c869b9d95..8ea5ce799 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -10,6 +10,8 @@ #define EXPMARIA +#define BUFLEN 256 + extern const CHARSET_INFO * proxysql_find_charset_name(const char * const name); extern MySQL_Authentication *GloMyAuth; @@ -1736,13 +1738,22 @@ __get_pkts_from_client: default: proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Statuses: WAITING_CLIENT_DATA - STATE_UNKNOWN\n"); { - char buf[256]; - if (client_myds->client_addr->sa_family==AF_INET) { - struct sockaddr_in * ipv4addr=(struct sockaddr_in *)client_myds->client_addr; - sprintf(buf,"%s:%d", inet_ntoa(ipv4addr->sin_addr), htons(ipv4addr->sin_port)); - } else { - sprintf(buf,"localhost"); - } + char buf[BUFLEN]; + switch (client_myds->client_addr->sa_family) { + case AF_INET: { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)client_myds->client_addr; + inet_ntop(client_myds->client_addr->sa_family, &ipv4->sin_addr, buf, BUFLEN); + break; + } + case AF_INET6: { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)client_myds->client_addr; + inet_ntop(client_myds->client_addr->sa_family, &ipv6->sin6_addr, buf, BUFLEN); + break; + } + default: + sprintf(buf, "localhost"); + break; + } proxy_error("Unexpected packet from client %s . Session_status: %d , client_status: %d Disconnecting it\n", buf, status, client_myds->status); } return -1; diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index f55192bf7..edf497e59 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -10,18 +10,7 @@ MySQL_Session *sess_stopat; #define PROXYSQL_LISTEN_LEN 1024 #define MIN_THREADS_FOR_MAINTENANCE 8 - -/* -// qsort int comparison function -static int int_cmp(const void *a, const void *b) { - const int *ia = (const int *)a; // casting pointer types - const int *ib = (const int *)b; - return *ia - *ib; - // integer comparison: returns negative if b > a - // and positive if a > b -} -*/ - +#define BUFLEN 256 extern Query_Processor *GloQPro; extern MySQL_Authentication *GloMyAuth; @@ -107,8 +96,24 @@ int MySQL_Listeners_Manager::add(const char *iface, unsigned int num_threads, in } } char *address=NULL; char *port=NULL; - c_split_2(iface, ":" , &address, &port); - int s=-1; + int s = -1; + char *h = NULL; + + if (*(char *)iface == '[') { + char *p = strchr((char *)iface, ']'); + if (p == NULL) { + proxy_error("Invalid IPv6 address: %s\n", iface); + return -1; + } + h = (char *)++iface; // remove first '[' + *p = '\0'; + iface = p++; // remove last ']' + address = h; + port = ++p; // remove ':' + } else { + c_split_2(iface, ":" , &address, &port); + } + #ifdef SO_REUSEPORT if (GloVars.global.reuseport==false) { s = ( atoi(port) ? listen_on_port(address, atoi(port), PROXYSQL_LISTEN_LEN) : listen_on_unix(address, PROXYSQL_LISTEN_LEN)); @@ -2846,13 +2851,29 @@ void MySQL_Thread::listener_handle_new_connection(MySQL_Data_Stream *myds, unsig } sess->client_myds->client_addrlen=addrlen; sess->client_myds->client_addr=addr; - if (sess->client_myds->client_addr->sa_family==AF_INET) { - struct sockaddr_in * ipv4addr=(struct sockaddr_in *)sess->client_myds->client_addr; - sess->client_myds->addr.addr=strdup(inet_ntoa(ipv4addr->sin_addr)); - sess->client_myds->addr.port=htons(ipv4addr->sin_port); - } else { - sess->client_myds->addr.addr=strdup("localhost"); - } + + switch (sess->client_myds->client_addr->sa_family) { + case AF_INET: { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)sess->client_myds->client_addr; + char buf[BUFLEN]; + inet_ntop(sess->client_myds->client_addr->sa_family, &ipv4->sin_addr, buf, BUFLEN); + sess->client_myds->addr.addr = strdup(buf); + sess->client_myds->addr.port = htons(ipv4->sin_port); + break; + } + case AF_INET6: { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)sess->client_myds->client_addr; + char buf[BUFLEN]; + inet_ntop(sess->client_myds->client_addr->sa_family, &ipv6->sin6_addr, buf, BUFLEN); + sess->client_myds->addr.addr = strdup(buf); + sess->client_myds->addr.port = htons(ipv6->sin6_port); + break; + } + default: + sess->client_myds->addr.addr = strdup("localhost"); + break; + } + iface_info *ifi=NULL; ifi=GloMTH->MLM_find_iface_from_fd(myds->fd); // here we try to get the info about the proxy bind address if (ifi) { @@ -3114,6 +3135,7 @@ void MySQL_Threads_Handler::Get_Memory_Stats() { SQLite3_result * MySQL_Threads_Handler::SQL3_Processlist() { const int colnum=14; + char port[NI_MAXSERV]; proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 4, "Dumping MySQL Processlist\n"); SQLite3_result *result=new SQLite3_result(colnum); result->add_column_definition(SQLITE_TEXT,"ThreadID"); @@ -3173,15 +3195,31 @@ SQLite3_result * MySQL_Threads_Handler::SQL3_Processlist() { pta[3]=strdup(ui->schemaname); } } - if (sess->mirror==false && sess->client_myds->client_addr->sa_family==AF_INET) { - struct sockaddr_in * ipv4addr=(struct sockaddr_in *)sess->client_myds->client_addr; - pta[4]=strdup(inet_ntoa(ipv4addr->sin_addr)); - sprintf(buf,"%d", htons(ipv4addr->sin_port)); - pta[5]=strdup(buf); - } else { - pta[4]=strdup("localhost"); - pta[5]=NULL; - } + + if (sess->mirror==false) { + switch (sess->client_myds->client_addr->sa_family) { + case AF_INET: { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)sess->client_myds->client_addr; + inet_ntop(sess->client_myds->client_addr->sa_family, &ipv4->sin_addr, buf, BUFLEN); + pta[4] = strdup(buf); + sprintf(port, "%d", ntohs(ipv4->sin_port)); + pta[5] = strdup(port); + break; + } + case AF_INET6: { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)sess->client_myds->client_addr; + inet_ntop(sess->client_myds->client_addr->sa_family, &ipv6->sin6_addr, buf, BUFLEN); + pta[4] = strdup(buf); + sprintf(port, "%d", ntohs(ipv6->sin6_port)); + pta[5] = strdup(port); + break; + } + default: + pta[4] = strdup("localhost"); + pta[5] = NULL; + break; + } + } sprintf(buf,"%d", sess->current_hostgroup); pta[6]=strdup(buf); if (sess->mybe && sess->mybe->server_myds && sess->mybe->server_myds->myconn) { @@ -3194,15 +3232,28 @@ SQLite3_result * MySQL_Threads_Handler::SQL3_Processlist() { int rc; rc=getsockname(mc->fd, &addr, &addr_len); if (rc==0) { - if (addr.sa_family==AF_INET) { - struct sockaddr_in * ipv4addr=(struct sockaddr_in *)&addr; - pta[7]=strdup(inet_ntoa(ipv4addr->sin_addr)); - sprintf(buf,"%d", htons(ipv4addr->sin_port)); - pta[8]=strdup(buf); - } else { - pta[7]=strdup("localhost"); - pta[8]=NULL; - } + switch (addr.sa_family) { + case AF_INET: { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)&addr; + inet_ntop(addr.sa_family, &ipv4->sin_addr, buf, BUFLEN); + pta[7] = strdup(buf); + sprintf(port, "%d", ntohs(ipv4->sin_port)); + pta[8] = strdup(port); + break; + } + case AF_INET6: { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&addr; + inet_ntop(addr.sa_family, &ipv6->sin6_addr, buf, BUFLEN); + pta[7] = strdup(buf); + sprintf(port, "%d", ntohs(ipv6->sin6_port)); + pta[8] = strdup(port); + break; + } + default: + pta[7] = strdup("localhost"); + pta[8] = NULL; + break; + } } else { pta[7]=NULL; pta[8]=NULL; diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index 402f62282..c876f67a6 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -2353,7 +2353,22 @@ __end_while_pool: i=0; j=0; for (j=0; jifaces->len; j++) { char *add=NULL; char *port=NULL; char *sn=(char *)S_amll.ifaces_mysql->ifaces->index(j); - c_split_2(sn, ":" , &add, &port); + + char *h = NULL; + if (*sn == '[') { + char *p = strchr(sn, ']'); + if (p == NULL) + proxy_error("Invalid IPv6 address: %s\n", sn); + + h = ++sn; // remove first '[' + *p = '\0'; + sn = p++; // remove last ']' + add = h; + port = ++p; // remove ':' + } else { + c_split_2(sn, ":" , &add, &port); + } + int s = ( atoi(port) ? listen_on_port(add, atoi(port), 128) : listen_on_unix(add, 128)); if (s>0) { fds[nfds].fd=s; fds[nfds].events=POLLIN; fds[nfds].revents=0; callback_func[nfds]=0; socket_names[nfds]=strdup(sn); nfds++; } } diff --git a/lib/network.cpp b/lib/network.cpp index d2d12963c..9dc38447b 100644 --- a/lib/network.cpp +++ b/lib/network.cpp @@ -5,51 +5,63 @@ * returns the socket */ int listen_on_port(char *ip, uint16_t port, int backlog, bool reuseport) { - int rc, arg_on=1; - struct sockaddr_in addr; - int sd; - - // create a socket - if ( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) { - proxy_error("Error on creating socket\n"); - close(sd); - return -1; - } - - // set SO_REUSEADDR - rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&arg_on, sizeof(arg_on)); - if (rc < 0) { - proxy_error("setsockopt() failed\n"); - } + int arg_on = 1; + struct addrinfo hints = { + .ai_flags = AI_PASSIVE, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + struct addrinfo *next, *ai; + char port_string[NI_MAXSERV]; + int sd = -1; + + snprintf(port_string, sizeof(port_string), "%d", port); + if (getaddrinfo(ip, port_string, &hints, &ai) != 0) { + proxy_error("getaddrinfo(): %s\n", gai_strerror(errno)); + return -1; + } + + for (next = ai; next != NULL; next = next->ai_next) { + if ((sd = socket(next->ai_family, next->ai_socktype, next->ai_protocol)) == -1) + continue; +#ifdef IPV6_V6ONLY + if (next->ai_family == AF_INET6) { + if(setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&arg_on, sizeof(arg_on)) == -1) + proxy_error("setsockopt() IPV6_V6ONLY: %d\n", gai_strerror(errno)); + } +#endif + + if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&arg_on, sizeof(arg_on)) == -1) { + proxy_error("setsockopt() SO_REUSEADDR: %s\n", gai_strerror(errno)); + close(sd); + freeaddrinfo(ai); + return -1; + } #ifdef SO_REUSEPORT - // set SO_REUSEPORT - if (reuseport) { - rc = setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, (char *)&arg_on, sizeof(arg_on)); - if (rc < 0) { - proxy_error("setsockopt() failed\n"); + if (reuseport) { + if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, (char *)&arg_on, sizeof(arg_on)) == -1) { + proxy_error("setsockopt() SO_REUSEPORT: %d\n", gai_strerror(errno)); + } } - } #endif /* SO_REUSEPORT */ - // define addr with the specified IP and port - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = inet_addr(ip); - - // call bind() to bind the socket on the specified address - if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) { - proxy_error("Error on Bind , address %s:%d\n", ip, port); - close(sd); - return -1; - } - - // define the backlog - if ( listen(sd, backlog) != 0 ) { - proxy_error("Error on Listen , address %s:%d\n", ip, port); - close(sd); - return -1; - } + if (bind(sd, next->ai_addr, next->ai_addrlen) == -1) { + if (errno != EADDRINUSE) { + proxy_error("bind(): %s\n", gai_strerror(errno)); + close(sd); + freeaddrinfo(ai); + return -1; + } + } else { + if (listen(sd, backlog) == -1) { + proxy_error("listen(): %s\n", gai_strerror(errno)); + close(sd); + freeaddrinfo(ai); + return -1; + } + } + } // return the socket return sd;