]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Socket: sending filedescriptors over UNIX sockets
authorMaria Matejka <mq@ucw.cz>
Thu, 10 Oct 2024 09:59:25 +0000 (11:59 +0200)
committerMaria Matejka <mq@ucw.cz>
Sun, 23 Feb 2025 18:07:30 +0000 (19:07 +0100)
lib/socket.h
sysdep/unix/socket.c

index 85aff84cc28c4b362688f04d8795ae8b7c1592c4..4dcf2880e773d4e8de165c57f4c87e58ab6f76ce 100644 (file)
@@ -74,6 +74,9 @@ typedef struct birdsock {
   uint lifindex;                       /* local interface that received the datagram */
   /* laddr and lifindex are valid only if SKF_LADDR_RX flag is set to request it */
 
+  /* Filedescriptors to send/receive (UNIX) */
+  int rxfd, txfd;
+
   int af;                              /* System-dependend adress family (e.g. AF_INET) */
   int fd;                              /* System-dependent data */
   int index;                           /* Index in poll buffer */
@@ -145,6 +148,9 @@ extern int sk_priority_control;             /* Suggested priority for control traffic, shou
 
 #define SKF_UDP6_NO_CSUM_RX    0x1000  /* Accept zero checksums for received UDPv6 packets */
 
+#define SKF_FD_RX      0x1000  /* Allow receiving filedescriptors (unix sockets) */
+#define SKF_FD_TX      0x2000  /* Allow sending filedescriptors (unix sockets) */
+
 /*
  *     Socket types                 SA SP DA DP IF  TTL SendTo (?=may, -=must not, *=must)
  */
@@ -159,6 +165,7 @@ extern int sk_priority_control;             /* Suggested priority for control traffic, shou
 #define SK_UNIX                9
 #define SK_SSH_ACTIVE  10         /* -  -  *  *  -  ?   -      DA = host */
 #define SK_SSH         11
+#define SK_UNIX_MSG    12         /* Like SK_UNIX but using sendmsg and recvmsg */
 
 /*
  *     Socket subtypes
index c43260214fe5ee613c42d0ac6cb32e914b009c05..6c58f3b2143c787539a11e05453ef4561d2fe443 100644 (file)
@@ -300,6 +300,43 @@ sk_prepare_cmsgs6(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
   msg->msg_controllen = controllen;
 }
 
+/*
+ *     UNIX packet control messages
+ */
+
+#define CMSGU_SPACE_FD CMSG_SPACE(sizeof (int))
+
+static inline void
+sk_prepare_cmsgs_unix(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
+{
+  if (s->txfd < 0)
+  {
+    msg->msg_control = NULL;
+    msg->msg_controllen = 0;
+    return;
+  }
+
+  msg->msg_control = cbuf;
+  msg->msg_controllen = cbuflen;
+
+  struct cmsghdr *cm = CMSG_FIRSTHDR(msg);
+  cm->cmsg_level = SOL_SOCKET;
+  cm->cmsg_type = SCM_RIGHTS;
+  cm->cmsg_len = CMSG_LEN(sizeof s->txfd);
+  memcpy(CMSG_DATA(cm), &s->txfd, sizeof s->txfd);
+
+  msg->msg_controllen = CMSGU_SPACE_FD;
+}
+
+static inline void
+sk_process_cmsg_unix_fd(sock *s, struct cmsghdr *cm)
+{
+  if (cm->cmsg_type == SCM_RIGHTS)
+    memcpy(&s->rxfd, CMSG_DATA(cm), sizeof s->rxfd);
+  else
+    s->rxfd = -1;
+}
+
 
 /*
  *     Miscellaneous socket syscalls
@@ -1465,14 +1502,17 @@ sk_open_unix(sock *s, struct birdloop *loop, const char *name)
 }
 
 
-#define CMSG_RX_SPACE MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \
-                         CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL)
-#define CMSG_TX_SPACE MAX(CMSG4_SPACE_PKTINFO,CMSG6_SPACE_PKTINFO)
+#define CMSG_RX_SPACE MAX(CMSGU_SPACE_FD, \
+                     MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \
+                         CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL))
+#define CMSG_TX_SPACE MAX(MAX(CMSG4_SPACE_PKTINFO,CMSG6_SPACE_PKTINFO),CMSGU_SPACE_FD)
 
 static void
 sk_prepare_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
 {
-  if (sk_is_ipv4(s))
+  if (s->type == SK_UNIX_MSG)
+    sk_prepare_cmsgs_unix(s, msg, cbuf, cbuflen);
+  else if (sk_is_ipv4(s))
     sk_prepare_cmsgs4(s, msg, cbuf, cbuflen);
   else
     sk_prepare_cmsgs6(s, msg, cbuf, cbuflen);
@@ -1500,6 +1540,11 @@ sk_process_cmsgs(sock *s, struct msghdr *msg)
       sk_process_cmsg6_pktinfo(s, cm);
       sk_process_cmsg6_ttl(s, cm);
     }
+
+    if ((cm->cmsg_level == SOL_SOCKET) && (s->type == SK_UNIX_MSG))
+    {
+      sk_process_cmsg_unix_fd(s, cm);
+    }
   }
 }
 
@@ -1512,15 +1557,19 @@ sk_sendmsg(sock *s)
   sockaddr dst;
   int flags = 0;
 
-  sockaddr_fill(&dst, s->af, s->daddr, s->iface, s->dport);
-
   struct msghdr msg = {
-    .msg_name = &dst.sa,
-    .msg_namelen = SA_LEN(dst),
     .msg_iov = &iov,
     .msg_iovlen = 1
   };
 
+  if (s->type != SK_UNIX_MSG)
+  {
+    sockaddr_fill(&dst, s->af, s->daddr, s->iface, s->dport);
+
+    msg.msg_name = &dst.sa;
+    msg.msg_namelen = SA_LEN(dst);
+  }
+
 #ifdef CONFIG_DONTROUTE_UNICAST
   /* FreeBSD silently changes TTL to 1 when MSG_DONTROUTE is used, therefore we
      cannot use it for other cases (e.g. when TTL security is used). */
@@ -1540,7 +1589,7 @@ sk_sendmsg(sock *s)
   }
 #endif
 
-  if (s->flags & SKF_PKTINFO)
+  if (s->flags & (SKF_PKTINFO | SKF_FD_TX))
     sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
 
   return sendmsg(s->fd, &msg, flags);
@@ -1647,6 +1696,7 @@ sk_maybe_write(sock *s)
 
   case SK_UDP:
   case SK_IP:
+  case SK_UNIX_MSG:
     {
       if (s->tbuf == s->tpos)
        return 1;