cmdmon: listen on Unix domain socket
In addition to the IPv4/IPv6 command sockets, create also a Unix domain socket to process cmdmon requests. For now, there is no difference for authorized commands, packets from all sockets need to be authenticated. The default path of the socket is /var/run/chrony/chronyd.sock. It can be configured with the bindcmdaddress directive with an address starting with /.
This commit is contained in:
parent
46b7148f3b
commit
0bcd10560a
3 changed files with 87 additions and 28 deletions
64
cmdmon.c
64
cmdmon.c
|
@ -53,15 +53,17 @@
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
union sockaddr_in46 {
|
union sockaddr_all {
|
||||||
struct sockaddr_in in4;
|
struct sockaddr_in in4;
|
||||||
#ifdef FEAT_IPV6
|
#ifdef FEAT_IPV6
|
||||||
struct sockaddr_in6 in6;
|
struct sockaddr_in6 in6;
|
||||||
#endif
|
#endif
|
||||||
struct sockaddr u;
|
struct sockaddr_un un;
|
||||||
|
struct sockaddr sa;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* File descriptors for command and monitoring sockets */
|
/* File descriptors for command and monitoring sockets */
|
||||||
|
static int sock_fdu;
|
||||||
static int sock_fd4;
|
static int sock_fd4;
|
||||||
#ifdef FEAT_IPV6
|
#ifdef FEAT_IPV6
|
||||||
static int sock_fd6;
|
static int sock_fd6;
|
||||||
|
@ -184,7 +186,7 @@ prepare_socket(int family, int port_number)
|
||||||
{
|
{
|
||||||
int sock_fd;
|
int sock_fd;
|
||||||
socklen_t my_addr_len;
|
socklen_t my_addr_len;
|
||||||
union sockaddr_in46 my_addr;
|
union sockaddr_all my_addr;
|
||||||
IPAddr bind_address;
|
IPAddr bind_address;
|
||||||
int on_off = 1;
|
int on_off = 1;
|
||||||
|
|
||||||
|
@ -198,6 +200,7 @@ prepare_socket(int family, int port_number)
|
||||||
/* Close on exec */
|
/* Close on exec */
|
||||||
UTI_FdSetCloexec(sock_fd);
|
UTI_FdSetCloexec(sock_fd);
|
||||||
|
|
||||||
|
if (family != AF_UNIX) {
|
||||||
/* Allow reuse of port number */
|
/* Allow reuse of port number */
|
||||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on_off, sizeof(on_off)) < 0) {
|
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on_off, sizeof(on_off)) < 0) {
|
||||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not set reuseaddr socket options");
|
LOG(LOGS_ERR, LOGF_CmdMon, "Could not set reuseaddr socket options");
|
||||||
|
@ -221,6 +224,7 @@ prepare_socket(int family, int port_number)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
memset(&my_addr, 0, sizeof (my_addr));
|
memset(&my_addr, 0, sizeof (my_addr));
|
||||||
|
|
||||||
|
@ -252,11 +256,19 @@ prepare_socket(int family, int port_number)
|
||||||
my_addr.in6.sin6_addr = in6addr_loopback;
|
my_addr.in6.sin6_addr = in6addr_loopback;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case AF_UNIX:
|
||||||
|
my_addr_len = sizeof (my_addr.un);
|
||||||
|
my_addr.un.sun_family = family;
|
||||||
|
if (snprintf(my_addr.un.sun_path, sizeof (my_addr.un.sun_path), "%s",
|
||||||
|
CNF_GetBindCommandPath()) >= sizeof (my_addr.un.sun_path))
|
||||||
|
LOG_FATAL(LOGF_CmdMon, "Unix socket path too long");
|
||||||
|
unlink(my_addr.un.sun_path);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
|
if (bind(sock_fd, &my_addr.sa, my_addr_len) < 0) {
|
||||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not bind %s command socket : %s",
|
LOG(LOGS_ERR, LOGF_CmdMon, "Could not bind %s command socket : %s",
|
||||||
UTI_SockaddrFamilyToString(family), strerror(errno));
|
UTI_SockaddrFamilyToString(family), strerror(errno));
|
||||||
close(sock_fd);
|
close(sock_fd);
|
||||||
|
@ -302,6 +314,11 @@ CAM_Initialise(int family)
|
||||||
free_replies = NULL;
|
free_replies = NULL;
|
||||||
kept_replies.next = NULL;
|
kept_replies.next = NULL;
|
||||||
|
|
||||||
|
if (CNF_GetBindCommandPath()[0])
|
||||||
|
sock_fdu = prepare_socket(AF_UNIX, 0);
|
||||||
|
else
|
||||||
|
sock_fdu = -1;
|
||||||
|
|
||||||
port_number = CNF_GetCommandPort();
|
port_number = CNF_GetCommandPort();
|
||||||
|
|
||||||
if (port_number && (family == IPADDR_UNSPEC || family == IPADDR_INET4))
|
if (port_number && (family == IPADDR_UNSPEC || family == IPADDR_INET4))
|
||||||
|
@ -332,6 +349,12 @@ CAM_Initialise(int family)
|
||||||
void
|
void
|
||||||
CAM_Finalise(void)
|
CAM_Finalise(void)
|
||||||
{
|
{
|
||||||
|
if (sock_fdu >= 0) {
|
||||||
|
SCH_RemoveInputFileHandler(sock_fdu);
|
||||||
|
close(sock_fdu);
|
||||||
|
unlink(CNF_GetBindCommandPath());
|
||||||
|
}
|
||||||
|
sock_fdu = -1;
|
||||||
if (sock_fd4 >= 0) {
|
if (sock_fd4 >= 0) {
|
||||||
SCH_RemoveInputFileHandler(sock_fd4);
|
SCH_RemoveInputFileHandler(sock_fd4);
|
||||||
close(sock_fd4);
|
close(sock_fd4);
|
||||||
|
@ -680,7 +703,7 @@ token_acknowledged(unsigned long token, struct timeval *now)
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
|
transmit_reply(CMD_Reply *msg, union sockaddr_all *where_to, int auth_len)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
int tx_message_length;
|
int tx_message_length;
|
||||||
|
@ -689,9 +712,9 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
IPAddr ip;
|
IPAddr ip;
|
||||||
|
|
||||||
UTI_SockaddrToIPAndPort(&where_to->u, &ip, &port);
|
UTI_SockaddrToIPAndPort(&where_to->sa, &ip, &port);
|
||||||
|
|
||||||
switch (where_to->u.sa_family) {
|
switch (where_to->sa.sa_family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
sock_fd = sock_fd4;
|
sock_fd = sock_fd4;
|
||||||
addrlen = sizeof (where_to->in4);
|
addrlen = sizeof (where_to->in4);
|
||||||
|
@ -702,13 +725,17 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
|
||||||
addrlen = sizeof (where_to->in6);
|
addrlen = sizeof (where_to->in6);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case AF_UNIX:
|
||||||
|
sock_fd = sock_fdu;
|
||||||
|
addrlen = sizeof (where_to->un);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_message_length = PKL_ReplyLength(msg) + auth_len;
|
tx_message_length = PKL_ReplyLength(msg) + auth_len;
|
||||||
status = sendto(sock_fd, (void *) msg, tx_message_length, 0,
|
status = sendto(sock_fd, (void *) msg, tx_message_length, 0,
|
||||||
&where_to->u, addrlen);
|
&where_to->sa, addrlen);
|
||||||
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
DEBUG_LOG(LOGF_CmdMon, "Could not send to %s:%hu fd %d : %s",
|
DEBUG_LOG(LOGF_CmdMon, "Could not send to %s:%hu fd %d : %s",
|
||||||
|
@ -1497,7 +1524,7 @@ read_from_cmd_socket(void *anything)
|
||||||
CMD_Reply tx_message, *prev_tx_message;
|
CMD_Reply tx_message, *prev_tx_message;
|
||||||
int rx_message_length, tx_message_length;
|
int rx_message_length, tx_message_length;
|
||||||
int sock_fd;
|
int sock_fd;
|
||||||
union sockaddr_in46 where_from;
|
union sockaddr_all where_from;
|
||||||
socklen_t from_length;
|
socklen_t from_length;
|
||||||
IPAddr remote_ip;
|
IPAddr remote_ip;
|
||||||
unsigned short remote_port;
|
unsigned short remote_port;
|
||||||
|
@ -1523,7 +1550,7 @@ read_from_cmd_socket(void *anything)
|
||||||
|
|
||||||
sock_fd = (long)anything;
|
sock_fd = (long)anything;
|
||||||
status = recvfrom(sock_fd, (char *)&rx_message, rx_message_length, flags,
|
status = recvfrom(sock_fd, (char *)&rx_message, rx_message_length, flags,
|
||||||
&where_from.u, &from_length);
|
&where_from.sa, &from_length);
|
||||||
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
LOG(LOGS_WARN, LOGF_CmdMon, "Error [%s] reading from control socket %d",
|
LOG(LOGS_WARN, LOGF_CmdMon, "Error [%s] reading from control socket %d",
|
||||||
|
@ -1539,19 +1566,30 @@ read_from_cmd_socket(void *anything)
|
||||||
/* Get current time cheaply */
|
/* Get current time cheaply */
|
||||||
SCH_GetLastEventTime(&cooked_now, NULL, &now);
|
SCH_GetLastEventTime(&cooked_now, NULL, &now);
|
||||||
|
|
||||||
UTI_SockaddrToIPAndPort(&where_from.u, &remote_ip, &remote_port);
|
UTI_SockaddrToIPAndPort(&where_from.sa, &remote_ip, &remote_port);
|
||||||
|
|
||||||
/* Check if it's a loopback address (127.0.0.1 or ::1) */
|
/* Check if it's from localhost (127.0.0.1, ::1, or Unix domain) */
|
||||||
switch (remote_ip.family) {
|
switch (remote_ip.family) {
|
||||||
case IPADDR_INET4:
|
case IPADDR_INET4:
|
||||||
|
assert(sock_fd == sock_fd4);
|
||||||
localhost = remote_ip.addr.in4 == INADDR_LOOPBACK;
|
localhost = remote_ip.addr.in4 == INADDR_LOOPBACK;
|
||||||
break;
|
break;
|
||||||
#ifdef FEAT_IPV6
|
#ifdef FEAT_IPV6
|
||||||
case IPADDR_INET6:
|
case IPADDR_INET6:
|
||||||
|
assert(sock_fd == sock_fd6);
|
||||||
localhost = !memcmp(remote_ip.addr.in6, &in6addr_loopback,
|
localhost = !memcmp(remote_ip.addr.in6, &in6addr_loopback,
|
||||||
sizeof (in6addr_loopback));
|
sizeof (in6addr_loopback));
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case IPADDR_UNSPEC:
|
||||||
|
/* Unix domain socket */
|
||||||
|
if (where_from.sa.sa_family != AF_UNIX) {
|
||||||
|
DEBUG_LOG(LOGF_CmdMon, "Read command packet with no address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(sock_fd == sock_fdu);
|
||||||
|
localhost = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
@ -1711,7 +1749,7 @@ read_from_cmd_socket(void *anything)
|
||||||
/* Just send this message again */
|
/* Just send this message again */
|
||||||
tx_message_length = PKL_ReplyLength(prev_tx_message);
|
tx_message_length = PKL_ReplyLength(prev_tx_message);
|
||||||
status = sendto(sock_fd, (void *) prev_tx_message, tx_message_length, 0,
|
status = sendto(sock_fd, (void *) prev_tx_message, tx_message_length, 0,
|
||||||
&where_from.u, from_length);
|
&where_from.sa, from_length);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
DEBUG_LOG(LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&remote_ip), remote_port);
|
DEBUG_LOG(LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&remote_ip), remote_port);
|
||||||
}
|
}
|
||||||
|
|
22
conf.c
22
conf.c
|
@ -182,6 +182,9 @@ static IPAddr bind_acq_address4, bind_acq_address6;
|
||||||
the loopback address will be used */
|
the loopback address will be used */
|
||||||
static IPAddr bind_cmd_address4, bind_cmd_address6;
|
static IPAddr bind_cmd_address4, bind_cmd_address6;
|
||||||
|
|
||||||
|
/* Path to the Unix domain command socket. */
|
||||||
|
static char *bind_cmd_path;
|
||||||
|
|
||||||
/* Filename to use for storing pid of running chronyd, to prevent multiple
|
/* Filename to use for storing pid of running chronyd, to prevent multiple
|
||||||
* chronyds being started. */
|
* chronyds being started. */
|
||||||
static char *pidfile;
|
static char *pidfile;
|
||||||
|
@ -320,6 +323,7 @@ CNF_Initialise(int r)
|
||||||
|
|
||||||
dumpdir = Strdup(".");
|
dumpdir = Strdup(".");
|
||||||
logdir = Strdup(".");
|
logdir = Strdup(".");
|
||||||
|
bind_cmd_path = Strdup("/var/run/chrony/chronyd.sock");
|
||||||
pidfile = Strdup("/var/run/chronyd.pid");
|
pidfile = Strdup("/var/run/chronyd.pid");
|
||||||
rtc_device = Strdup("/dev/rtc");
|
rtc_device = Strdup("/dev/rtc");
|
||||||
user = Strdup(DEFAULT_USER);
|
user = Strdup(DEFAULT_USER);
|
||||||
|
@ -349,6 +353,7 @@ CNF_Finalise(void)
|
||||||
Free(keys_file);
|
Free(keys_file);
|
||||||
Free(leapsec_tz);
|
Free(leapsec_tz);
|
||||||
Free(logdir);
|
Free(logdir);
|
||||||
|
Free(bind_cmd_path);
|
||||||
Free(pidfile);
|
Free(pidfile);
|
||||||
Free(rtc_device);
|
Free(rtc_device);
|
||||||
Free(rtc_file);
|
Free(rtc_file);
|
||||||
|
@ -1113,7 +1118,14 @@ parse_bindcmdaddress(char *line)
|
||||||
IPAddr ip;
|
IPAddr ip;
|
||||||
|
|
||||||
check_number_of_args(line, 1);
|
check_number_of_args(line, 1);
|
||||||
if (UTI_StringToIP(line, &ip)) {
|
|
||||||
|
/* Address starting with / is for the Unix domain socket */
|
||||||
|
if (line[0] == '/') {
|
||||||
|
parse_string(line, &bind_cmd_path);
|
||||||
|
/* / disables the socket */
|
||||||
|
if (!strcmp(bind_cmd_path, "/"))
|
||||||
|
bind_cmd_path[0] = '\0';
|
||||||
|
} else if (UTI_StringToIP(line, &ip)) {
|
||||||
if (ip.family == IPADDR_INET4)
|
if (ip.family == IPADDR_INET4)
|
||||||
bind_cmd_address4 = ip;
|
bind_cmd_address4 = ip;
|
||||||
else if (ip.family == IPADDR_INET6)
|
else if (ip.family == IPADDR_INET6)
|
||||||
|
@ -1697,6 +1709,14 @@ CNF_GetBindAcquisitionAddress(int family, IPAddr *addr)
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
char *
|
||||||
|
CNF_GetBindCommandPath(void)
|
||||||
|
{
|
||||||
|
return bind_cmd_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
CNF_GetBindCommandAddress(int family, IPAddr *addr)
|
CNF_GetBindCommandAddress(int family, IPAddr *addr)
|
||||||
{
|
{
|
||||||
|
|
1
conf.h
1
conf.h
|
@ -75,6 +75,7 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
|
||||||
extern void CNF_GetBindAddress(int family, IPAddr *addr);
|
extern void CNF_GetBindAddress(int family, IPAddr *addr);
|
||||||
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
|
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
|
||||||
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
|
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
|
||||||
|
extern char *CNF_GetBindCommandPath(void);
|
||||||
extern char *CNF_GetPidFile(void);
|
extern char *CNF_GetPidFile(void);
|
||||||
extern REF_LeapMode CNF_GetLeapSecMode(void);
|
extern REF_LeapMode CNF_GetLeapSecMode(void);
|
||||||
extern char *CNF_GetLeapSecTimezone(void);
|
extern char *CNF_GetLeapSecTimezone(void);
|
||||||
|
|
Loading…
Reference in a new issue