]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Additional CLI and TCP control sockets mq-tcp-control-socket
authorMaria Matejka <mq@ucw.cz>
Mon, 5 Jun 2023 15:57:53 +0000 (17:57 +0200)
committerMaria Matejka <mq@ucw.cz>
Mon, 5 Jun 2023 16:18:01 +0000 (18:18 +0200)
conf/conf.h
conf/confbase.Y
doc/bird.sgml
sysdep/unix/conf.h [new file with mode: 0644]
sysdep/unix/config.Y
sysdep/unix/io.c
sysdep/unix/main.c
sysdep/unix/unix.h

index d40f955eb903904c8f6a8923044a337a3a18a0b5..4c28aae035abf2cd99051151ca5c9d51936fef7a 100644 (file)
@@ -14,6 +14,9 @@
 #include "lib/hash.h"
 #include "lib/resource.h"
 #include "lib/timer.h"
+#include "lib/tlists.h"
+
+#include "sysdep/unix/conf.h"
 
 /* Configuration structure */
 
@@ -31,6 +34,8 @@ struct config {
   struct rtable_config *def_tables[NET_MAX]; /* Default routing tables for each network */
   struct iface_patt *router_id_from;   /* Configured list of router ID iface patterns */
 
+  TLIST_LIST(control_socket_config) control_socket;    /* Control socket definitions */
+
   u32 router_id;                       /* Our Router ID */
   u32 proto_default_debug;             /* Default protocol debug mask */
   u32 proto_default_mrtdump;           /* Default protocol mrtdump mask */
index 3e8f580744e0f120a9c9b21cc87a85b276c4091a..ade8ea8a26a79fa7a284dfa4e33354bac41f7a38 100644 (file)
@@ -95,6 +95,7 @@ CF_DECLS
   struct timeformat *tf;
   mpls_label_stack *mls;
   struct bytestring *bs;
+  struct control_socket_config *control_socket_config;
 }
 
 %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
index 8041faa90b219fdcc72f273e85e747644f67c74e..0451795a1706bed97745b4fb7a990be80486e91d 100644 (file)
@@ -179,7 +179,8 @@ BIRD executable by configuring out routing protocols you don't use, and
 
        <tag><label id="argv-socket">-s <m/name of communication socket/</tag>
        use given filename for a socket for communications with the client,
-       default is <it/prefix/<file>/var/run/bird.ctl</file>.
+       default is <it/prefix/<file>/var/run/bird.ctl</file>. See also
+       <ref id="opt-commands" name="commands config option">.
 
        <tag><label id="argv-user">-u <m/user/</tag>
        drop privileges and use that user ID, see the next section for details.
@@ -471,6 +472,11 @@ ipv6 table
 include "tablename.conf";;
 </code>
 
+       <tag><label id="opt-commands">commands [ restrict ] "<m/filename/" | <m/ip/ port <m/port/;</tag>
+       Open an additional UNIX or TCP control socket for client communication.
+       When <cf>restrict</cf> is specified, the socket is restricted as if <tt/-r/
+       was always given to <tt/birdc/.
+
        <tag><label id="opt-log">log "<m/filename/" [<m/limit/ "<m/backup/"] | syslog [name <m/name/] | stderr all|{ <m/list of classes/ }</tag>
        Set logging of messages having the given class (either <cf/all/ or <cf>{
        error|trace [, <m/.../] }</cf> etc.) into selected destination - a file
diff --git a/sysdep/unix/conf.h b/sysdep/unix/conf.h
new file mode 100644 (file)
index 0000000..5abbcde
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *     BIRD -- Unix Port Config Structures
+ *
+ *     (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ *     (c) 2023       Maria Matejka <mq@jmq.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_UNIX_CONFIG_H_
+#define _BIRD_UNIX_CONFIG_H_
+
+#include "lib/tlists.h"
+
+#define TLIST_PREFIX control_socket_config
+#define TLIST_TYPE struct control_socket_config
+#define TLIST_ITEM n
+#define TLIST_WANT_WALK
+#define TLIST_WANT_ADD_TAIL
+
+struct control_socket_config {
+  TLIST_DEFAULT_NODE;
+  struct config *config;
+  struct control_socket *cs;
+
+  ip_addr addr;
+  uint port;
+
+  const char *unix;
+  uid_t uid;
+  gid_t gid;
+  u8 restricted;
+};
+
+#include "lib/tlists.h"
+
+struct log_config {
+  node n;
+  uint mask;                           /* Classes to log */
+  void *fh;                            /* FILE to log to, NULL=syslog */
+  struct rfile *rf;                    /* Resource for log file */
+  const char *filename;                        /* Log filename */
+  const char *backup;                  /* Secondary filename (for log rotation) */
+  off_t pos;                           /* Position/size of current log */
+  off_t limit;                         /* Log size limit */
+  int terminal_flag;
+};
+
+#endif
index 5c4b5beff936cb4b2509e13575d445b0b64f14f8..d385b034e62691c434688b0eebef5a86e0260c41 100644 (file)
@@ -25,6 +25,7 @@ CF_KEYWORDS(GRACEFUL, RESTART)
 %type <t> cfg_name
 %type <tf> timeformat_which
 %type <t> syslog_name
+%type <control_socket_config> control_socket_listen
 
 CF_GRAMMAR
 
@@ -101,6 +102,32 @@ mrtdump_base:
  ;
 
 
+conf: control_socket ';' ;
+
+control_socket:
+   COMMANDS control_socket_listen {
+     control_socket_config_add_tail(&new_config->control_socket, $2);
+   }
+ | COMMANDS RESTRICT control_socket_listen {
+     $3->restricted = 1;
+     control_socket_config_add_tail(&new_config->control_socket, $3);
+   }
+;
+
+control_socket_listen:
+   ipa PORT expr {
+     $$ = cfg_allocz(sizeof(struct control_socket_config));
+     $$->config = new_config;
+     $$->addr = $1;
+     $$->port = $3;
+   }
+ | text {
+     $$ = cfg_allocz(sizeof(struct control_socket_config));
+     $$->config = new_config;
+     $$->unix = $1;
+   }
+ ;
+
 conf: debug_unix ;
 
 debug_unix:
index 6aedcfb669191ae60c198d6b3620a9123afc8e9a..0b7b731737ccbc768ec47049b50ca64d7357ce3b 100644 (file)
@@ -1498,7 +1498,7 @@ err:
 }
 
 int
-sk_open_unix(sock *s, char *name)
+sk_open_unix(sock *s, const char *name)
 {
   struct sockaddr_un sa;
   int fd;
@@ -2401,7 +2401,7 @@ io_loop(void)
 }
 
 void
-test_old_bird(char *path)
+test_old_bird(const char *path)
 {
   int fd;
   struct sockaddr_un sa;
index 0d3ec0c07b500ec1b5b39334c4e18feed94bb05b..2ee4f135a6f2e07d9bfc37a561138a1d0d2f4afa 100644 (file)
@@ -198,10 +198,22 @@ sysdep_preconfig(struct config *c)
 #endif
 }
 
+static int control_socket_open(struct control_socket_config *csc);
+static void control_socket_close(struct control_socket_config *csc);
+
 int
-sysdep_commit(struct config *new, struct config *old UNUSED)
+sysdep_commit(struct config *new, struct config *old)
 {
   log_switch(0, &new->logfiles, new->syslog_name);
+
+  WALK_TLIST(control_socket_config, csc, &new->control_socket)
+    control_socket_open(csc);
+
+  if (old)
+    WALK_TLIST(control_socket_config, csc, &old->control_socket)
+      if (csc->cs)
+       control_socket_close(csc);
+
   return 0;
 }
 
@@ -394,9 +406,24 @@ cmd_reconfig_status(void)
  *     Command-Line Interface
  */
 
-static sock *cli_sk;
-static char *path_control_socket = PATH_CONTROL_SOCKET;
+#define TLIST_PREFIX control_socket
+#define TLIST_TYPE struct control_socket
+#define TLIST_ITEM n
+#define TLIST_WANT_WALK
+#define TLIST_WANT_ADD_TAIL
 
+struct control_socket {
+  TLIST_DEFAULT_NODE;
+  struct control_socket_config *cf;
+  sock *s;
+};
+
+#include "lib/tlists.h"
+
+static TLIST_LIST(control_socket) control_sockets;
+static struct control_socket_config args_control_socket = {
+  .unix = PATH_CONTROL_SOCKET,
+};
 
 static void
 cli_write(cli *c)
@@ -503,6 +530,8 @@ cli_connect_err(sock *s UNUSED, int err)
 static int
 cli_connect(sock *s, uint size UNUSED)
 {
+  struct control_socket_config *csc = s->data;
+
   cli *c;
 
   if (config->cli_debug)
@@ -514,37 +543,136 @@ cli_connect(sock *s, uint size UNUSED)
   s->pool = c->pool;           /* We need to have all the socket buffers allocated in the cli pool */
   s->fast_rx = 1;
   c->rx_pos = c->rx_buf;
+  c->restricted = csc->restricted;
   rmove(s, c->pool);
   return 1;
 }
 
-static void
-cli_init_unix(uid_t use_uid, gid_t use_gid)
+static int
+control_socket_open(struct control_socket_config *csc)
 {
-  sock *s;
+  /* Find existing socket */
+  WALK_TLIST(control_socket, cs, &control_sockets)
+  {
+    if (ipa_equal(cs->cf->addr, csc->addr) &&
+       (cs->cf->port == csc->port) &&
+       (!cs->cf->unix && !csc->unix || !strcmp(cs->cf->unix, csc->unix)))
+    {
+      if (!cs->cf->config)
+      {
+       log(L_ERR "Can't configure the same control socket in config and args: %s", cs->cf->unix);
+       return 0;
+      }
 
-  cli_init();
-  s = cli_sk = sk_new(cli_pool);
-  s->type = SK_UNIX_PASSIVE;
-  s->rx_hook = cli_connect;
-  s->err_hook = cli_connect_err;
-  s->rbsize = 1024;
-  s->fast_rx = 1;
+      if (cs->cf->config == csc->config)
+      {
+       if (csc->unix)
+         log(L_ERR "Duplicate control socket config: %s", csc->unix);
+       else
+         log(L_ERR "Duplicate control socket config: %I port %d", csc->addr, csc->port);
+       return 0;
+      }
+
+      cs->cf->cs = NULL;
+      cs->cf = csc;
+      csc->cs = cs;
+      return 1;
+    }
+  }
+
+  struct control_socket *cs = mb_allocz(cli_pool, sizeof(struct control_socket));
+  cs->s = sk_new(cli_pool);
+  cs->s->data = csc;
+
+  cs->s->rx_hook = cli_connect;
+  cs->s->err_hook = cli_connect_err;
+  cs->s->rbsize = 1024;
+  cs->s->fast_rx = 1;
+
+  if (csc->unix)
+  {
+    cs->s->type = SK_UNIX_PASSIVE;
+    int ok = 0;
+    do {
+      /* Just a cleanup, no need to check the return value */
+      unlink(csc->unix);
+
+      if (sk_open_unix(cs->s, csc->unix) < 0)
+      {
+       log(L_ERR "Cannot create control socket %s: %m", csc->unix);
+       break;
+      }
+
+      if (csc->uid || csc->gid)
+       if (chown(csc->unix, csc->uid, csc->gid) < 0)
+       {
+         log(L_ERR "Cannot chown control socket %s: %m", csc->unix);
+         break;
+       }
+
+      if (chmod(csc->unix, 0660) < 0)
+      {
+       log(L_ERR "Cannot chmod control socket %s: %m", csc->unix);
+       break;
+      }
+
+      ok = 1;
+    } while (0);
+
+    if (!ok)
+    {
+      rfree(cs->s);
+      mb_free(cs);
+      return 0;
+    }
+  }
+  else
+  {
+    cs->s->type = SK_TCP_PASSIVE;
+    cs->s->saddr = csc->addr;
+    cs->s->sport = csc->port;
+
+    if (sk_open(cs->s) < 0)
+    {
+      log(L_ERR "Cannot open control socket at %I port %d", csc->addr, csc->port);
+      rfree(cs->s);
+      mb_free(cs);
+      return 0;
+    }
+  }
+
+  cs->cf = csc;
+  csc->cs = cs;
+  return 1;
+}
+
+static void
+control_socket_close(struct control_socket_config *csc)
+{
+  ASSERT_DIE(csc->cs);
+  if (!csc->cs)
+    return;
 
-  /* Return value intentionally ignored */
-  unlink(path_control_socket);
+  if (csc->unix)
+    unlink(csc->unix);
 
-  if (sk_open_unix(s, path_control_socket) < 0)
-    die("Cannot create control socket %s: %m", path_control_socket);
+  rfree(csc->cs->s);
+  mb_free(csc->cs);
+  csc->cs = NULL;
+}
 
-  if (use_uid || use_gid)
-    if (chown(path_control_socket, use_uid, use_gid) < 0)
-      die("chown: %m");
+static void
+cli_init_unix(uid_t use_uid, gid_t use_gid)
+{
+  cli_init();
+  args_control_socket.uid = use_uid;
+  args_control_socket.gid = use_gid;
 
-  if (chmod(path_control_socket, 0660) < 0)
-    die("chmod: %m");
+  if (!control_socket_open(&args_control_socket))
+    die("Failed to create control socket: %s", args_control_socket.unix);
 }
 
+
 /*
  *     PID file
  */
@@ -622,7 +750,7 @@ void
 sysdep_shutdown_done(void)
 {
   unlink_pid_file();
-  unlink(path_control_socket);
+  control_socket_close(&args_control_socket);
   log_msg(L_FATAL "Shutdown completed");
   exit(0);
 }
@@ -834,7 +962,7 @@ parse_args(int argc, char **argv)
        parse_and_exit = 1;
        break;
       case 's':
-       path_control_socket = optarg;
+       args_control_socket.unix = optarg;
        socket_changed = 1;
        break;
       case 'P':
@@ -853,7 +981,7 @@ parse_args(int argc, char **argv)
        if (!config_changed)
          config_name = xbasename(config_name);
        if (!socket_changed)
-         path_control_socket = xbasename(path_control_socket);
+         args_control_socket.unix = xbasename(args_control_socket.unix);
        break;
       case 'R':
        graceful_restart_recovery();
@@ -903,7 +1031,7 @@ main(int argc, char **argv)
 
   if (!parse_and_exit)
   {
-    test_old_bird(path_control_socket);
+    test_old_bird(args_control_socket.unix);
     cli_init_unix(use_uid, use_gid);
   }
 
index ad85d1ea5fd6dd4849acda381e32202e04525894..976386f87cf7b6b7317e6d5aef56344c589270d5 100644 (file)
@@ -107,11 +107,11 @@ 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, char *name);
+int sk_open_unix(struct birdsock *s, const char *name);
 struct rfile *rf_open(struct pool *, const char *name, const char *mode);
 void *rf_file(struct rfile *f);
 int rf_fileno(struct rfile *f);
-void test_old_bird(char *path);
+void test_old_bird(const char *path);
 
 /* krt.c bits */
 
@@ -123,16 +123,4 @@ void main_thread_init(void);
 void log_init_debug(char *);           /* Initialize debug dump to given file (NULL=stderr, ""=off) */
 void log_switch(int initial, list *l, const char *);
 
-struct log_config {
-  node n;
-  uint mask;                           /* Classes to log */
-  void *fh;                            /* FILE to log to, NULL=syslog */
-  struct rfile *rf;                    /* Resource for log file */
-  const char *filename;                        /* Log filename */
-  const char *backup;                  /* Secondary filename (for log rotation) */
-  off_t pos;                           /* Position/size of current log */
-  off_t limit;                         /* Log size limit */
-  int terminal_flag;
-};
-
 #endif