conf: add directives to specify interfaces for binding sockets

Add binddevice, bindacqdevice, and bindcmddevice directive to specify
the interface for binding the NTP server, NTP client, and command socket
respectively.
This commit is contained in:
Miroslav Lichvar 2020-06-30 12:27:10 +02:00
parent 4ef944b734
commit c4a2550518
6 changed files with 96 additions and 12 deletions

View file

@ -157,8 +157,8 @@ static void read_from_cmd_socket(int sock_fd, int event, void *anything);
static int
open_socket(int family)
{
const char *local_path, *iface;
IPSockAddr local_addr;
const char *local_path;
int sock_fd, port;
switch (family) {
@ -173,7 +173,9 @@ open_socket(int family)
SCK_GetLoopbackIPAddress(family, &local_addr.ip_addr);
local_addr.port = port;
sock_fd = SCK_OpenUdpSocket(NULL, &local_addr, NULL, SCK_FLAG_RX_DEST_ADDR);
iface = CNF_GetBindCommandInterface();
sock_fd = SCK_OpenUdpSocket(NULL, &local_addr, iface, SCK_FLAG_RX_DEST_ADDR);
if (sock_fd < 0) {
LOG(LOGS_ERR, "Could not open command socket on %s",
UTI_IPSockAddrToString(&local_addr));

38
conf.c
View file

@ -192,6 +192,11 @@ static IPAddr bind_acq_address4, bind_acq_address6;
the loopback address will be used */
static IPAddr bind_cmd_address4, bind_cmd_address6;
/* Interface names to bind the NTP server, NTP client, and command socket */
static char *bind_ntp_iface = NULL;
static char *bind_acq_iface = NULL;
static char *bind_cmd_iface = NULL;
/* Path to the Unix domain command socket. */
static char *bind_cmd_path = NULL;
@ -422,6 +427,9 @@ CNF_Finalise(void)
Free(keys_file);
Free(leapsec_tz);
Free(logdir);
Free(bind_ntp_iface);
Free(bind_acq_iface);
Free(bind_cmd_iface);
Free(bind_cmd_path);
Free(ntp_signd_socket);
Free(pidfile);
@ -511,10 +519,16 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_authselectmode(p);
} else if (!strcasecmp(command, "bindacqaddress")) {
parse_bindacqaddress(p);
} else if (!strcasecmp(command, "bindacqdevice")) {
parse_string(p, &bind_acq_iface);
} else if (!strcasecmp(command, "bindaddress")) {
parse_bindaddress(p);
} else if (!strcasecmp(command, "bindcmdaddress")) {
parse_bindcmdaddress(p);
} else if (!strcasecmp(command, "bindcmddevice")) {
parse_string(p, &bind_cmd_iface);
} else if (!strcasecmp(command, "binddevice")) {
parse_string(p, &bind_ntp_iface);
} else if (!strcasecmp(command, "broadcast")) {
parse_broadcast(p);
} else if (!strcasecmp(command, "clientloglimit")) {
@ -2228,6 +2242,30 @@ CNF_GetBindAcquisitionAddress(int family, IPAddr *addr)
/* ================================================== */
char *
CNF_GetBindNtpInterface(void)
{
return bind_ntp_iface;
}
/* ================================================== */
char *
CNF_GetBindAcquisitionInterface(void)
{
return bind_acq_iface;
}
/* ================================================== */
char *
CNF_GetBindCommandInterface(void)
{
return bind_cmd_iface;
}
/* ================================================== */
char *
CNF_GetBindCommandPath(void)
{

3
conf.h
View file

@ -79,6 +79,9 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
extern void CNF_GetBindAddress(int family, IPAddr *addr);
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
extern char *CNF_GetBindNtpInterface(void);
extern char *CNF_GetBindAcquisitionInterface(void);
extern char *CNF_GetBindCommandInterface(void);
extern char *CNF_GetBindCommandPath(void);
extern char *CNF_GetNtpSigndSocket(void);
extern char *CNF_GetPidFile(void);

View file

@ -630,7 +630,7 @@ This would change the source port used for client requests to UDP port 1123.
You could then persuade the firewall administrator to open that port.
[[bindacqaddress]]*bindacqaddress* _address_::
The *bindacqaddress* directive sets the network interface to which
The *bindacqaddress* directive specifies a local IP address to which
*chronyd* will bind its NTP client sockets. The syntax is similar to the
<<bindaddress,*bindaddress*>> and <<bindcmdaddress,*bindcmdaddress*>>
directives.
@ -638,6 +638,19 @@ directives.
For each of the IPv4 and IPv6 protocols, only one *bindacqaddress* directive
can be specified.
[[bindacqdevice]]*bindacqdevice* _interface_::
The *bindacqdevice* directive binds the client sockets to a network device
specified by the interface name. This can be useful when the local address is
dynamic, or to enable an NTP source specified with a link-local IPv6 address.
This directive can specify only one interface and it is supported on Linux
only.
+
An example of the directive is:
+
----
bindacqdevice eth0
----
[[dumpdir]]*dumpdir* _directory_::
To compute the rate of gain or loss of time, *chronyd* has to store a
measurement history for each of the time sources it uses.
@ -1336,6 +1349,17 @@ Currently, for each of the IPv4 and IPv6 protocols, only one *bindaddress*
directive can be specified. Therefore, it is not useful on computers which
should serve NTP on multiple network interfaces.
[[binddevice]]*binddevice* _interface_::
The *binddevice* directive binds the NTP server sockets to a network device
specified by the interface name. This directive can specify only one interface
and it is supported on Linux only.
+
An example of the directive is:
+
----
binddevice eth0
----
[[broadcast]]*broadcast* _interval_ _address_ [_port_]::
The *broadcast* directive is used to declare a broadcast address to which
chronyd should send packets in the NTP broadcast mode (i.e. make *chronyd* act
@ -1664,8 +1688,8 @@ smoothtime 50000 0.01
=== Command and monitoring access
[[bindcmdaddress]]*bindcmdaddress* _address_::
The *bindcmdaddress* directive allows you to specify an IP address of an
interface on which *chronyd* will listen for monitoring command packets (issued
The *bindcmdaddress* directive specifies a local IP address to which *chronyd*
will bind the UDP socket listening for monitoring command packets (issued
by *chronyc*). On systems other than Linux, the address of the interface needs
to be already configured when *chronyd* is started.
+
@ -1676,9 +1700,10 @@ directory will be created on start if it does not exist. The compiled-in default
path of the socket is _@CHRONYRUNDIR@/chronyd.sock_. The socket can be
disabled by setting the path to _/_.
+
By default, *chronyd* binds to the loopback interface (with addresses
_127.0.0.1_ and _::1_). This blocks all access except from localhost. To listen
for command packets on all interfaces, you can add the lines:
By default, *chronyd* binds the UDP sockets to the addresses _127.0.0.1_ and
_::1_ (i.e. the loopback interface). This blocks all access except from
localhost. To listen for command packets on all interfaces, you can add the
lines:
+
----
bindcmdaddress 0.0.0.0
@ -1696,6 +1721,17 @@ An example that sets the path of the Unix domain command socket is:
bindcmdaddress /var/run/chrony/chronyd.sock
----
[[bindcmddevice]]*bindcmddevice* _interface_::
The *bindcmddevice* directive binds the UDP command sockets to a network device
specified by the interface name. This directive can specify only one interface
and it is supported on Linux only.
+
An example of the directive is:
+
----
bindcmddevice eth0
----
[[cmdallow]]*cmdallow* [*all*] [_subnet_]::
This is similar to the <<allow,*allow*>> directive, except that it allows
monitoring access (rather than NTP client access) to a particular subnet or

View file

@ -85,14 +85,18 @@ open_socket(int family, int local_port, int client_only, IPSockAddr *remote_addr
{
int sock_fd, sock_flags, events = SCH_FILE_INPUT;
IPSockAddr local_addr;
char *iface;
if (!SCK_IsIpFamilyEnabled(family))
return INVALID_SOCK_FD;
if (!client_only)
if (!client_only) {
CNF_GetBindAddress(family, &local_addr.ip_addr);
else
iface = CNF_GetBindNtpInterface();
} else {
CNF_GetBindAcquisitionAddress(family, &local_addr.ip_addr);
iface = CNF_GetBindAcquisitionInterface();
}
if (local_addr.ip_addr.family != family)
SCK_GetAnyLocalIPAddress(family, &local_addr.ip_addr);
@ -103,7 +107,7 @@ open_socket(int family, int local_port, int client_only, IPSockAddr *remote_addr
if (!client_only)
sock_flags |= SCK_FLAG_BROADCAST;
sock_fd = SCK_OpenUdpSocket(remote_addr, &local_addr, NULL, sock_flags);
sock_fd = SCK_OpenUdpSocket(remote_addr, &local_addr, iface, sock_flags);
if (sock_fd < 0) {
if (!client_only)
LOG(LOGS_ERR, "Could not open NTP socket on %s", UTI_IPSockAddrToString(&local_addr));

View file

@ -442,7 +442,8 @@ SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control)
Keep CAP_SYS_TIME if the clock control is enabled. */
if (snprintf(cap_text, sizeof (cap_text), "%s %s %s",
CNF_GetNTPPort() ? "cap_net_bind_service=ep" : "",
0 ? "cap_net_raw=ep" : "",
CNF_GetBindNtpInterface() || CNF_GetBindAcquisitionInterface() ?
"cap_net_raw=ep" : "",
clock_control ? "cap_sys_time=ep" : "") >= sizeof (cap_text))
assert(0);