0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 01:31:55 +00:00

Additional CLI and TCP control sockets

This commit is contained in:
Maria Matejka 2023-06-05 17:57:53 +02:00
parent a794b2e8c1
commit 1ef65e7a7e
8 changed files with 248 additions and 44 deletions

View 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 */

View 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

View 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

49
sysdep/unix/conf.h Normal file
View File

@ -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

View 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:

View 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;

View 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 int
control_socket_open(struct control_socket_config *csc)
{
/* 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;
}
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;
if (csc->unix)
unlink(csc->unix);
rfree(csc->cs->s);
mb_free(csc->cs);
csc->cs = NULL;
}
static void
cli_init_unix(uid_t use_uid, gid_t use_gid)
{
sock *s;
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;
args_control_socket.uid = use_uid;
args_control_socket.gid = use_gid;
/* Return value intentionally ignored */
unlink(path_control_socket);
if (sk_open_unix(s, path_control_socket) < 0)
die("Cannot create control socket %s: %m", path_control_socket);
if (use_uid || use_gid)
if (chown(path_control_socket, use_uid, use_gid) < 0)
die("chown: %m");
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);
}

View 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