]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
IO: Changes in socket API
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Wed, 17 Jul 2024 10:05:13 +0000 (12:05 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Wed, 21 Aug 2024 08:40:58 +0000 (10:40 +0200)
Support for active UNIX sockets is added. UNIX socket are now created with
sk_open. The socket name/path is passes in host, the same way as SSH address.
For passive UNIX socket the filesystem entry is considered as part of the
resource and hence is unlinked in rfree.

lib/socket.h
sysdep/unix/io.c
sysdep/unix/main.c
sysdep/unix/unix.h

index 3417423f6091c15e283cc55fa7d7ff4f209ca660..2802dd5ccd943eb82ebad008a0d7afb7da158aa6 100644 (file)
@@ -43,7 +43,7 @@ typedef struct birdsock {
   int subtype;                         /* Socket subtype */
   void *data;                          /* User data */
   ip_addr saddr, daddr;                        /* IPA_NONE = unspecified */
-  const char *host;                    /* Alternative to daddr, NULL = unspecified */
+  const char *host;                    /* Alternative to daddr especially for UNIX sockets, NULL = unspecified */
   uint sport, dport;                   /* 0 = unspecified (for IP: protocol type) */
   int tos;                             /* TOS / traffic class, -1 = default */
   int priority;                                /* Local socket priority, -1 = default */
@@ -96,6 +96,7 @@ void sk_dump_all(void);
 
 int sk_is_ipv4(sock *s);               /* True if socket is IPv4 */
 int sk_is_ipv6(sock *s);               /* True if socket is IPv6 */
+int sk_is_unix(sock *s);               /* True if socket is UNIX socket */
 
 static inline int sk_tx_buffer_empty(sock *sk)
 { return sk->tbuf == sk->tpos; }
@@ -109,6 +110,7 @@ int sk_set_min_ttl(sock *s, int ttl);       /* Set minimal accepted TTL for given sock
 int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey);
 int sk_set_ipv6_checksum(sock *s, int offset);
 int sk_set_icmp6_filter(sock *s, int p1, int p2);
+int sk_check_unix(const char *path);
 void sk_log_error(sock *s, const char *p);
 
 byte * sk_rx_buffer(sock *s, int *len);        /* Temporary */
@@ -143,10 +145,11 @@ extern int sk_priority_control;           /* Suggested priority for control traffic, shou
 #define SK_UDP         3          /* ?  ?  ?  ?  ?  ?   ?      */
 #define SK_IP          5          /* ?  -  ?  *  ?  ?   ?      */
 #define SK_MAGIC       7          /* Internal use by sysdep code */
-#define SK_UNIX_PASSIVE        8
-#define SK_UNIX                9
-#define SK_SSH_ACTIVE  10         /* -  -  *  *  -  ?   -      DA = host */
-#define SK_SSH         11
+#define SK_UNIX_PASSIVE        8          /* -  -  *  -  -  -   -      DA = host */
+#define SK_UNIX_ACTIVE 9          /* -  -  *  -  -  -   -      DA = host */
+#define SK_UNIX                10
+#define SK_SSH_ACTIVE  11         /* -  -  *  *  -  ?   -      DA = host */
+#define SK_SSH         12
 
 /*
  *     Socket subtypes
@@ -177,6 +180,10 @@ extern int sk_priority_control;            /* Suggested priority for control traffic, shou
  * per-packet basis using platform dependent options (but these are not
  * available in some corner cases). The first way is used when SKF_BIND is
  * specified, the second way is used otherwise.
+ *
+ * For UNIX sockets (SK_UNIX_PASSIVE, SK_UNIX_ACTIVE), path is passed in host
+ * string. If the path does not fit into the sockaddr_un sun_path array, the
+ * sk_open will fail. One can check path length with sk_check_unix.
  */
 
 #endif
index 59b33ef1804e71ac62f98c21a54bc26a621e658a..cc742a280dcf1785e4cedec40d7935acaf03c717 100644 (file)
@@ -600,6 +600,21 @@ sk_setup_multicast(sock *s)
     return sk_setup_multicast6(s);
 }
 
+/**
+ * sk_check_unix - check path length
+ * @path: filesystem path
+ *
+ * Check if path fits into the sockaddr_un sun_path array.
+ *
+ * Result: 0 for success, -1 for an error.
+ */
+
+int
+sk_check_unix(const char *path)
+{
+  return -(strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path));
+}
+
 /**
  * sk_join_group - join multicast group for given socket
  * @s: socket
@@ -865,6 +880,10 @@ sk_free(resource *r)
     sk_ssh_free(s);
 #endif
 
+  if (s->host && s->type == SK_UNIX_PASSIVE)
+    /* Return value intentionally ignored */
+    (void) unlink(s->host);
+
   if (s->fd < 0)
     return;
 
@@ -935,7 +954,7 @@ static void
 sk_dump(resource *r)
 {
   sock *s = (sock *) r;
-  static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", NULL, "IP", NULL, "MAGIC", "UNIX<", "UNIX", "SSH>", "SSH", "DEL!" };
+  static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", NULL, "IP", NULL, "MAGIC", "UNIX<", "UNIX>", "UNIX", "SSH>", "SSH", "DEL!" };
 
   debug("(%s, ud=%p, sa=%I, sp=%d, da=%I, dp=%d, tos=%d, ttl=%d, if=%s)\n",
        sk_type_names[s->type],
@@ -992,6 +1011,12 @@ sk_setup(sock *s)
   if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
     ERR("O_NONBLOCK");
 
+  if (s->type == SK_UNIX_ACTIVE || s->type == SK_UNIX_PASSIVE)
+    return sk_check_unix(s->host);
+
+  if (s->type == SK_UNIX)
+    return 0;
+
   if (!s->af)
     return 0;
 
@@ -1130,6 +1155,14 @@ sk_tcp_connected(sock *s)
   s->tx_hook(s);
 }
 
+static void
+sk_unix_connected(sock *s)
+{
+  s->type = SK_UNIX;
+  sk_alloc_bufs(s);
+  s->tx_hook(s);
+}
+
 #ifdef HAVE_LIBSSH
 static void
 sk_ssh_connected(sock *s)
@@ -1155,6 +1188,7 @@ sk_passive_connected(sock *s, int type)
     return 0;
   }
 
+  /* Do not copy UNIX address in s->host. */
   sock *t = sk_new(s->pool);
   t->type = type;
   t->data = s->data;
@@ -1408,6 +1442,9 @@ sk_open(sock *s)
   int bind_port = 0;
   ip_addr bind_addr = IPA_NONE;
   sockaddr sa;
+  struct sockaddr_un un;
+  struct sockaddr *addr;
+  socklen_t len;
 
   if (s->type <= SK_IP)
   {
@@ -1480,6 +1517,15 @@ sk_open(sock *s)
     fd = s->fd;
     break;
 
+  case SK_UNIX_ACTIVE:
+    s->ttx = "";
+    /* Fall thru */
+  case SK_UNIX_PASSIVE:
+    af = AF_UNIX;
+    fd = socket(af, SOCK_STREAM, 0);
+    do_bind = s->type == SK_UNIX_PASSIVE;
+    break;
+
   default:
     bug("sk_open() called for invalid sock type %d", s->type);
   }
@@ -1520,8 +1566,21 @@ sk_open(sock *s)
       if (sk_set_freebind(s) < 0)
         log(L_WARN "Socket error: %s%#m", s->err);
 
-    sockaddr_fill(&sa, s->af, bind_addr, s->iface, bind_port);
-    if (bind(fd, &sa.sa, SA_LEN(sa)) < 0)
+    if (s->type == SK_UNIX_PASSIVE)
+    {
+      un.sun_family = AF_UNIX;
+      strcpy(un.sun_path, s->host);
+      addr = (struct sockaddr *) &un;
+      len = SUN_LEN(&un);
+    }
+    else
+    {
+      sockaddr_fill(&sa, s->af, bind_addr, s->iface, bind_port);
+      addr = &sa.sa;
+      len = SA_LEN(sa);
+    }
+
+    if (bind(fd, addr, len) < 0)
       ERR2("bind");
   }
 
@@ -1552,6 +1611,21 @@ sk_open(sock *s)
     sk_alloc_bufs(s);
     break;
 
+  case SK_UNIX_ACTIVE:
+    un.sun_family = AF_UNIX;
+    strcpy(un.sun_path, s->host);
+
+    if (connect(s->fd, (struct sockaddr *) &un, SUN_LEN(&un)) >= 0)
+      sk_unix_connected(s);
+    else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS)
+      ERR2("connect");
+    break;
+
+  case SK_UNIX_PASSIVE:
+    if (listen(fd, 8) < 0)
+      ERR2("listen");
+    break;
+
   case SK_SSH_ACTIVE:
   case SK_MAGIC:
     break;
@@ -1571,38 +1645,6 @@ err:
   return -1;
 }
 
-int
-sk_open_unix(sock *s, const char *name)
-{
-  struct sockaddr_un sa;
-  int fd;
-
-  /* We are sloppy during error (leak fd and not set s->err), but we die anyway */
-
-  fd = socket(AF_UNIX, SOCK_STREAM, 0);
-  if (fd < 0)
-    return -1;
-
-  if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
-    return -1;
-
-  /* Path length checked in test_old_bird() but we may need unix sockets for other reasons in future */
-  ASSERT_DIE(strlen(name) < sizeof(sa.sun_path));
-
-  sa.sun_family = AF_UNIX;
-  strcpy(sa.sun_path, name);
-
-  if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) < 0)
-    return -1;
-
-  if (listen(fd, 8) < 0)
-    return -1;
-
-  s->fd = fd;
-  sk_insert(s);
-  return 0;
-}
-
 
 #define CMSG_RX_SPACE MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \
                          CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL)
@@ -2026,6 +2068,20 @@ sk_write_noflush(sock *s)
       return 0;
     }
 
+  case SK_UNIX_ACTIVE:
+    {
+      struct sockaddr_un un;
+      un.sun_family = AF_UNIX;
+      strcpy(un.sun_path, s->host);
+
+      if (connect(s->fd, (struct sockaddr *) &un, SUN_LEN(&un)) >= 0 || errno == EISCONN)
+       sk_unix_connected(s);
+      else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS)
+       s->err_hook(s, errno);
+
+      return 0;
+    }
+
 #ifdef HAVE_LIBSSH
   case SK_SSH_ACTIVE:
     {
@@ -2072,6 +2128,9 @@ int sk_is_ipv4(sock *s)
 int sk_is_ipv6(sock *s)
 { return s->af == AF_INET6; }
 
+int sk_is_unix(sock *s)
+{ return s->af == AF_UNIX; }
+
 void
 sk_err(sock *s, int revents)
 {
index 880cc3c4aa14c53a221acedc97c2338d6725727a..f8acb5c418b2cf20090948ffef5798d2e0f3822e 100644 (file)
@@ -553,6 +553,7 @@ cli_listen(struct cli_config *cf)
   l->config = cf;
   sock *s = l->s = sk_new(cli_pool);
   s->type = SK_UNIX_PASSIVE;
+  s->host = cf->name;
   s->rx_hook = cli_connect;
   s->err_hook = cli_connect_err;
   s->data = l;
@@ -560,9 +561,9 @@ cli_listen(struct cli_config *cf)
   s->fast_rx = 1;
 
   /* Return value intentionally ignored */
-  unlink(cf->name);
+  (void) unlink(cf->name);
 
-  if (sk_open_unix(s, cf->name) < 0)
+  if (sk_open(s) < 0)
   {
     log(L_ERR "Cannot create control socket %s: %m", cf->name);
     return NULL;
@@ -590,7 +591,6 @@ static void
 cli_deafen(struct cli_listener *l)
 {
   rfree(l->s);
-  unlink(l->config->name);
   cli_listener_rem_node(&cli_listeners, l);
   mb_free(l);
 }
index 33ece06cd9b61027d39b832b308712bf7a8ce6d9..679c3d9318555c5ba5f2814b57ca39e4dc651219 100644 (file)
@@ -53,7 +53,6 @@ typedef struct sockaddr_bird {
 } sockaddr;
 
 
-
 /* This is sloppy hack, it should be detected by configure script */
 /* Linux systems have it defined so this is definition for BSD systems */
 #ifndef s6_addr32
@@ -107,7 +106,6 @@ extern volatile sig_atomic_t async_shutdown_flag;
 void io_init(void);
 void io_loop(void);
 void io_log_dump(void);
-int sk_open_unix(struct birdsock *s, const char *name);
 struct rfile *rf_open(struct pool *, const char *name, const char *mode);
 struct rfile *rf_fdopen(pool *p, int fd, const char *mode);
 void *rf_file(struct rfile *f);