MXS-1220: Allow binding to a specific address
The admin interface can now bind to a specific network interface.
This commit is contained in:
@ -172,6 +172,12 @@ write or modify the data in the backend server. The default is 2 seconds.
|
|||||||
auth_write_timeout=10
|
auth_write_timeout=10
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `admin_host`
|
||||||
|
|
||||||
|
The network interface where the HTTP admin interface listens on. The default
|
||||||
|
value is the IPv6 address `::` which listens on all available network
|
||||||
|
interfaces.
|
||||||
|
|
||||||
#### `admin_port`
|
#### `admin_port`
|
||||||
|
|
||||||
The port where the HTTP admin interface listens on. The default value is port
|
The port where the HTTP admin interface listens on. The default value is port
|
||||||
|
@ -28,10 +28,12 @@ MXS_BEGIN_DECLS
|
|||||||
|
|
||||||
/** Default port where the REST API listens */
|
/** Default port where the REST API listens */
|
||||||
#define DEFAULT_ADMIN_HTTP_PORT 8989
|
#define DEFAULT_ADMIN_HTTP_PORT 8989
|
||||||
|
#define DEFAULT_ADMIN_HOST "::"
|
||||||
|
|
||||||
#define _RELEASE_STR_LENGTH 256 /**< release len */
|
#define _RELEASE_STR_LENGTH 256 /**< release len */
|
||||||
#define MAX_ADMIN_USER_LEN 1024
|
#define MAX_ADMIN_USER_LEN 1024
|
||||||
#define MAX_ADMIN_PW_LEN 1024
|
#define MAX_ADMIN_PW_LEN 1024
|
||||||
|
#define MAX_ADMIN_HOST_LEN 1024
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common configuration parameters names
|
* Common configuration parameters names
|
||||||
@ -42,6 +44,7 @@ MXS_BEGIN_DECLS
|
|||||||
*/
|
*/
|
||||||
extern const char CN_ADDRESS[];
|
extern const char CN_ADDRESS[];
|
||||||
extern const char CN_ADMIN_AUTH[];
|
extern const char CN_ADMIN_AUTH[];
|
||||||
|
extern const char CN_ADMIN_HOST[];
|
||||||
extern const char CN_ADMIN_PASSWORD[];
|
extern const char CN_ADMIN_PASSWORD[];
|
||||||
extern const char CN_ADMIN_PORT[];
|
extern const char CN_ADMIN_PORT[];
|
||||||
extern const char CN_ADMIN_USER[];
|
extern const char CN_ADMIN_USER[];
|
||||||
@ -156,6 +159,7 @@ typedef struct
|
|||||||
char* qc_args; /**< Arguments for the query classifier */
|
char* qc_args; /**< Arguments for the query classifier */
|
||||||
char admin_user[MAX_ADMIN_USER_LEN]; /**< Admin interface user */
|
char admin_user[MAX_ADMIN_USER_LEN]; /**< Admin interface user */
|
||||||
char admin_password[MAX_ADMIN_PW_LEN]; /**< Admin interface password */
|
char admin_password[MAX_ADMIN_PW_LEN]; /**< Admin interface password */
|
||||||
|
char admin_host[MAX_ADMIN_HOST_LEN]; /**< Admin interface host */
|
||||||
uint16_t admin_port; /**< Admin interface port */
|
uint16_t admin_port; /**< Admin interface port */
|
||||||
bool admin_auth; /**< Admin interface authentication */
|
bool admin_auth; /**< Admin interface authentication */
|
||||||
} MXS_CONFIG;
|
} MXS_CONFIG;
|
||||||
|
@ -11,11 +11,17 @@
|
|||||||
* Public License.
|
* Public License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file The embedded HTTP protocol administrative interface
|
||||||
|
*/
|
||||||
#include "maxscale/admin.hh"
|
#include "maxscale/admin.hh"
|
||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <microhttpd.h>
|
#include <microhttpd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
#include <maxscale/atomic.h>
|
#include <maxscale/atomic.h>
|
||||||
#include <maxscale/debug.h>
|
#include <maxscale/debug.h>
|
||||||
@ -180,16 +186,64 @@ int handle_client(void *cls,
|
|||||||
return client->process(url, method, upload_data, upload_data_size);
|
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()
|
bool mxs_admin_init()
|
||||||
{
|
{
|
||||||
http_daemon = MHD_start_daemon(MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY | MHD_USE_DUAL_STACK,
|
struct sockaddr_storage addr;
|
||||||
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;
|
|
||||||
|
|
||||||
|
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()
|
void mxs_admin_shutdown()
|
||||||
|
@ -53,6 +53,7 @@ using std::string;
|
|||||||
|
|
||||||
const char CN_ADDRESS[] = "address";
|
const char CN_ADDRESS[] = "address";
|
||||||
const char CN_ADMIN_AUTH[] = "admin_auth";
|
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_PASSWORD[] = "admin_password";
|
||||||
const char CN_ADMIN_PORT[] = "admin_port";
|
const char CN_ADMIN_PORT[] = "admin_port";
|
||||||
const char CN_ADMIN_USER[] = "admin_user";
|
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);
|
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)
|
else if (strcmp(name, CN_ADMIN_AUTH) == 0)
|
||||||
{
|
{
|
||||||
gateway.admin_auth = config_truth_value(value);
|
gateway.admin_auth = config_truth_value(value);
|
||||||
@ -1746,6 +1751,7 @@ global_defaults()
|
|||||||
gateway.skip_permission_checks = false;
|
gateway.skip_permission_checks = false;
|
||||||
gateway.admin_port = DEFAULT_ADMIN_HTTP_PORT;
|
gateway.admin_port = DEFAULT_ADMIN_HTTP_PORT;
|
||||||
gateway.admin_auth = false;
|
gateway.admin_auth = false;
|
||||||
|
strcpy(gateway.admin_host, DEFAULT_ADMIN_HOST);
|
||||||
strcpy(gateway.admin_user, INET_DEFAULT_USERNAME);
|
strcpy(gateway.admin_user, INET_DEFAULT_USERNAME);
|
||||||
strcpy(gateway.admin_password, INET_DEFAULT_PASSWORD);
|
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());
|
MXS_NOTICE("MaxScale started with %d server threads.", config_threadcount());
|
||||||
/**
|
/**
|
||||||
* Successful start, notify the parent process that it can exit.
|
* 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);
|
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.
|
* Run worker 0 in the main thread.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user