MXS-1220: Allow binding to a specific address
The admin interface can now bind to a specific network interface.
This commit is contained in:
@ -11,11 +11,17 @@
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file The embedded HTTP protocol administrative interface
|
||||
*/
|
||||
#include "maxscale/admin.hh"
|
||||
|
||||
#include <climits>
|
||||
#include <new>
|
||||
#include <microhttpd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <maxscale/atomic.h>
|
||||
#include <maxscale/debug.h>
|
||||
@ -180,16 +186,64 @@ int handle_client(void *cls,
|
||||
return client->process(url, method, upload_data, upload_data_size);
|
||||
}
|
||||
|
||||
static bool host_to_sockaddr(const char* host, uint16_t port, struct sockaddr_storage* addr)
|
||||
{
|
||||
struct addrinfo *ai = NULL, hint = {};
|
||||
int rc;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
hint.ai_family = AF_UNSPEC;
|
||||
hint.ai_flags = AI_ALL;
|
||||
|
||||
if ((rc = getaddrinfo(host, NULL, &hint, &ai)) != 0)
|
||||
{
|
||||
MXS_ERROR("Failed to obtain address for host %s: %s", host, gai_strerror(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Take the first one */
|
||||
if (ai)
|
||||
{
|
||||
memcpy(addr, ai->ai_addr, ai->ai_addrlen);
|
||||
|
||||
if (addr->ss_family == AF_INET)
|
||||
{
|
||||
struct sockaddr_in *ip = (struct sockaddr_in*)addr;
|
||||
ip->sin_port = htons(port);
|
||||
}
|
||||
else if (addr->ss_family == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 *ip = (struct sockaddr_in6*)addr;
|
||||
ip->sin6_port = htons(port);
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mxs_admin_init()
|
||||
{
|
||||
http_daemon = MHD_start_daemon(MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY | MHD_USE_DUAL_STACK,
|
||||
config_get_global_options()->admin_port,
|
||||
NULL, NULL,
|
||||
handle_client, NULL,
|
||||
MHD_OPTION_NOTIFY_COMPLETED, close_client, NULL,
|
||||
MHD_OPTION_END);
|
||||
return http_daemon != NULL;
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
if (host_to_sockaddr(config_get_global_options()->admin_host,
|
||||
config_get_global_options()->admin_port,
|
||||
&addr))
|
||||
{
|
||||
int options = MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY;
|
||||
|
||||
if (addr.ss_family == AF_INET6)
|
||||
{
|
||||
options |= MHD_USE_DUAL_STACK;
|
||||
}
|
||||
|
||||
// The port argument is ignored and the port in the struct sockaddr is used instead
|
||||
http_daemon = MHD_start_daemon(options, 0, NULL, NULL, handle_client, NULL,
|
||||
MHD_OPTION_NOTIFY_COMPLETED, close_client, NULL,
|
||||
MHD_OPTION_SOCK_ADDR, &addr,
|
||||
MHD_OPTION_END);
|
||||
}
|
||||
|
||||
return http_daemon != NULL;
|
||||
}
|
||||
|
||||
void mxs_admin_shutdown()
|
||||
|
@ -53,6 +53,7 @@ using std::string;
|
||||
|
||||
const char CN_ADDRESS[] = "address";
|
||||
const char CN_ADMIN_AUTH[] = "admin_auth";
|
||||
const char CN_ADMIN_HOST[] = "admin_host";
|
||||
const char CN_ADMIN_PASSWORD[] = "admin_password";
|
||||
const char CN_ADMIN_PORT[] = "admin_port";
|
||||
const char CN_ADMIN_USER[] = "admin_user";
|
||||
@ -1520,6 +1521,10 @@ handle_global_item(const char *name, const char *value)
|
||||
{
|
||||
gateway.admin_port = atoi(value);
|
||||
}
|
||||
else if (strcmp(name, CN_ADMIN_HOST) == 0)
|
||||
{
|
||||
strcpy(gateway.admin_host, value);
|
||||
}
|
||||
else if (strcmp(name, CN_ADMIN_AUTH) == 0)
|
||||
{
|
||||
gateway.admin_auth = config_truth_value(value);
|
||||
@ -1746,6 +1751,7 @@ global_defaults()
|
||||
gateway.skip_permission_checks = false;
|
||||
gateway.admin_port = DEFAULT_ADMIN_HTTP_PORT;
|
||||
gateway.admin_auth = false;
|
||||
strcpy(gateway.admin_host, DEFAULT_ADMIN_HOST);
|
||||
strcpy(gateway.admin_user, INET_DEFAULT_USERNAME);
|
||||
strcpy(gateway.admin_password, INET_DEFAULT_PASSWORD);
|
||||
|
||||
|
@ -1982,6 +1982,18 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (mxs_admin_init())
|
||||
{
|
||||
MXS_NOTICE("Started REST API on [%s]:%u", cnf->admin_host, cnf->admin_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* logerr = "Failed to initialize admin interface";
|
||||
print_log_n_stderr(true, true, logerr, logerr, 0);
|
||||
rc = MAXSCALE_INTERNALERROR;
|
||||
goto return_main;
|
||||
}
|
||||
|
||||
MXS_NOTICE("MaxScale started with %d server threads.", config_threadcount());
|
||||
/**
|
||||
* Successful start, notify the parent process that it can exit.
|
||||
@ -1992,14 +2004,6 @@ int main(int argc, char **argv)
|
||||
write_child_exit_code(daemon_pipe[1], rc);
|
||||
}
|
||||
|
||||
if (!mxs_admin_init())
|
||||
{
|
||||
const char* logerr = "Failed to initialize admin interface";
|
||||
print_log_n_stderr(true, true, logerr, logerr, 0);
|
||||
rc = MAXSCALE_INTERNALERROR;
|
||||
goto return_main;
|
||||
}
|
||||
|
||||
/*<
|
||||
* Run worker 0 in the main thread.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user