]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
socket: add support for binding sockets to device
authorMiroslav Lichvar <mlichvar@redhat.com>
Tue, 30 Jun 2020 08:21:45 +0000 (10:21 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Wed, 1 Jul 2020 14:19:44 +0000 (16:19 +0200)
As a Linux-specific feature, allow sockets to be bound to a device using
the SO_BINDTODEVICE socket option. The CAP_NET_RAW capability is
required for setting the option.

client.c
cmdmon.c
ntp_io.c
ntp_io_linux.c
nts_ke_client.c
nts_ke_server.c
socket.c
socket.h
sys_linux.c

index 41527e7ad3c6339d161a7c1302f8a3173e56fdef..3ac0b865b0c02ec657b0920480326c42c3080da7 100644 (file)
--- a/client.c
+++ b/client.c
@@ -222,7 +222,7 @@ open_socket(struct Address *addr)
 
   switch (addr->type) {
     case SCK_ADDR_IP:
-      sock_fd = SCK_OpenUdpSocket(&addr->addr.ip, NULL, 0);
+      sock_fd = SCK_OpenUdpSocket(&addr->addr.ip, NULL, NULL, 0);
       break;
     case SCK_ADDR_UNIX:
       /* Construct path of our socket.  Use the same directory as the server
index 8e9764aab24305b301a90d7c8e47f4c4657439d1..d5dbe710608a007969d17c82ce63ae5128b3cce5 100644 (file)
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -173,7 +173,7 @@ open_socket(int family)
         SCK_GetLoopbackIPAddress(family, &local_addr.ip_addr);
       local_addr.port = port;
 
-      sock_fd = SCK_OpenUdpSocket(NULL, &local_addr, SCK_FLAG_RX_DEST_ADDR);
+      sock_fd = SCK_OpenUdpSocket(NULL, &local_addr, NULL, SCK_FLAG_RX_DEST_ADDR);
       if (sock_fd < 0) {
         LOG(LOGS_ERR, "Could not open command socket on %s",
             UTI_IPSockAddrToString(&local_addr));
index ed5568717d71bc1c0b277195ab33d7fae1300ef1..9c1b686a271d9c59ca498a1997e55cba61e92c3c 100644 (file)
--- a/ntp_io.c
+++ b/ntp_io.c
@@ -103,7 +103,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, sock_flags);
+  sock_fd = SCK_OpenUdpSocket(remote_addr, &local_addr, NULL, sock_flags);
   if (sock_fd < 0) {
     if (!client_only)
       LOG(LOGS_ERR, "Could not open NTP socket on %s", UTI_IPSockAddrToString(&local_addr));
index 634ccb0807951f553b1731c754fee00ab2533194..bfe9f996f567b4213c6240b78d2b641b7c20baff 100644 (file)
@@ -125,7 +125,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
       return 1;
   }
 
-  sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
+  sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
   if (sock_fd < 0)
     return 0;
 
@@ -285,7 +285,7 @@ update_interface_speed(struct Interface *iface)
   struct ifreq req;
   int sock_fd, link_speed;
 
-  sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
+  sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
   if (sock_fd < 0)
     return;
 
@@ -320,7 +320,7 @@ check_timestamping_option(int option)
 {
   int sock_fd;
 
-  sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
+  sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
   if (sock_fd < 0)
     return 0;
 
@@ -341,7 +341,7 @@ open_dummy_socket(void)
 {
   int sock_fd, events = 0;
 
-  sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
+  sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
   if (sock_fd < 0)
     return INVALID_SOCK_FD;
 
index f37d76828e67a94e11141f3fe79929321ade70ed..967e0147d7ec4acdd468c83a545596cc4215b7b2 100644 (file)
@@ -325,7 +325,7 @@ NKC_Start(NKC_Instance inst)
 
   local_addr.port = 0;
 
-  sock_fd = SCK_OpenTcpSocket(&inst->address, &local_addr, 0);
+  sock_fd = SCK_OpenTcpSocket(&inst->address, &local_addr, NULL, 0);
   if (sock_fd < 0)
     return 0;
 
index a4b1e2d95cd7936c01091e9b5cffae3780addccb..2b94b9bca69dc45c4b1a2f85eab2983df0aea534 100644 (file)
@@ -268,7 +268,7 @@ open_socket(int family, int port)
 
   local_addr.port = port;
 
-  sock_fd = SCK_OpenTcpSocket(NULL, &local_addr, 0);
+  sock_fd = SCK_OpenTcpSocket(NULL, &local_addr, NULL, 0);
   if (sock_fd < 0) {
     LOG(LOGS_ERR, "Could not open NTS-KE socket on %s", UTI_IPSockAddrToString(&local_addr));
     return INVALID_SOCK_FD;
index 325ef199f31f42f4dcfbb8b8339dd3c1d6ccebea..9eaf9fda256378c367ee9437e551693b87793b18 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -336,6 +336,23 @@ is_any_address(IPAddr *addr)
 
 /* ================================================== */
 
+static int
+bind_device(int sock_fd, const char *iface)
+{
+#ifdef SO_BINDTODEVICE
+  if (setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1) < 0) {
+    DEBUG_LOG("Could not bind socket to %s : %s", iface, strerror(errno));
+    return 0;
+  }
+  return 1;
+#else
+  DEBUG_LOG("Could not bind socket to %s : %s", "Not supported");
+  return 0;
+#endif
+}
+
+/* ================================================== */
+
 static int
 bind_ip_address(int sock_fd, IPSockAddr *addr, int flags)
 {
@@ -403,7 +420,8 @@ connect_ip_address(int sock_fd, IPSockAddr *addr)
 /* ================================================== */
 
 static int
-open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int type, int flags)
+open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *iface,
+               int type, int flags)
 {
   int domain, family, sock_fd;
 
@@ -442,6 +460,9 @@ open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int type, int fl
   if (!set_ip_options(sock_fd, family, flags))
     goto error;
 
+  if (iface && !bind_device(sock_fd, iface))
+    goto error;
+
   /* Bind the socket if a non-any local address/port was specified */
   if (local_addr && local_addr->ip_addr.family != IPADDR_UNSPEC &&
       (local_addr->port != 0 || !is_any_address(&local_addr->ip_addr)) &&
@@ -1213,17 +1234,17 @@ SCK_SetPrivBind(int (*function)(int sock_fd, struct sockaddr *address,
 /* ================================================== */
 
 int
-SCK_OpenUdpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int flags)
+SCK_OpenUdpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *iface, int flags)
 {
-  return open_ip_socket(remote_addr, local_addr, SOCK_DGRAM, flags);
+  return open_ip_socket(remote_addr, local_addr, iface, SOCK_DGRAM, flags);
 }
 
 /* ================================================== */
 
 int
-SCK_OpenTcpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int flags)
+SCK_OpenTcpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *iface, int flags)
 {
-  return open_ip_socket(remote_addr, local_addr, SOCK_STREAM, flags);
+  return open_ip_socket(remote_addr, local_addr, iface, SOCK_STREAM, flags);
 }
 
 /* ================================================== */
index a51a67cebc938ea22f3529ac8c3b65172a16fbaa..9207a43c6cf7bc1097b5ba3cc13f3d1cfdc183ad 100644 (file)
--- a/socket.h
+++ b/socket.h
@@ -92,9 +92,11 @@ extern void SCK_GetLoopbackIPAddress(int family, IPAddr *local_addr);
 extern void SCK_SetPrivBind(int (*function)(int sock_fd, struct sockaddr *address,
                                             socklen_t address_len));
 
-/* Open socket */
-extern int SCK_OpenUdpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int flags);
-extern int SCK_OpenTcpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int flags);
+/* Open a socket (addresses and iface may be NULL) */
+extern int SCK_OpenUdpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr,
+                             const char *iface, int flags);
+extern int SCK_OpenTcpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr,
+                             const char *iface, int flags);
 extern int SCK_OpenUnixDatagramSocket(const char *remote_addr, const char *local_addr,
                                       int flags);
 extern int SCK_OpenUnixStreamSocket(const char *remote_addr, const char *local_addr,
index f74e323af36872ae7676b461539063b9208ee946..8c41259f0d65ccf2d20003e6e3d60ffc43e97c4a 100644 (file)
@@ -437,10 +437,12 @@ SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control)
   
   UTI_DropRoot(uid, gid);
 
-  /* Keep CAP_NET_BIND_SERVICE only if a server NTP port can be opened
-     and keep CAP_SYS_TIME only if the clock control is enabled */
-  if (snprintf(cap_text, sizeof (cap_text), "%s %s",
+  /* Keep CAP_NET_BIND_SERVICE if the NTP server sockets may need to be bound.
+     Keep CAP_NET_RAW if an NTP socket may need to be bound to a device.
+     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" : "",
                clock_control ? "cap_sys_time=ep" : "") >= sizeof (cap_text))
     assert(0);