0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 12:18:42 +00:00

IO: Changes in socket API

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.
This commit is contained in:
Vojtech Vilimek 2024-07-17 12:05:13 +02:00
parent 373b343e0c
commit a059c2c6ff
4 changed files with 104 additions and 43 deletions

View File

@ -44,7 +44,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 */
@ -98,6 +98,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; }
@ -111,6 +112,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

View File

@ -536,6 +536,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
@ -866,7 +881,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],
@ -923,6 +938,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;
@ -1045,6 +1066,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)
@ -1070,6 +1099,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;
@ -1327,6 +1357,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)
{
@ -1399,6 +1432,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);
}
@ -1439,8 +1481,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");
}
@ -1464,6 +1519,21 @@ sk_open(sock *s)
ERR2("listen");
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;
@ -1483,38 +1553,6 @@ err:
return -1;
}
int
sk_open_unix(sock *s, 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;
}
static void
sk_reloop_hook(void *_vs)
{
@ -1971,6 +2009,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:
{
@ -2017,6 +2069,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)
{

View File

@ -515,6 +515,7 @@ cli_init_unix(uid_t use_uid, gid_t use_gid)
cli_init();
s = cli_sk = sk_new(cli_pool);
s->type = SK_UNIX_PASSIVE;
s->host = path_control_socket;
s->rx_hook = cli_connect;
s->err_hook = cli_connect_err;
s->rbsize = 1024;
@ -523,7 +524,7 @@ cli_init_unix(uid_t use_uid, gid_t use_gid)
/* Return value intentionally ignored */
unlink(path_control_socket);
if (sk_open_unix(s, path_control_socket) < 0)
if (sk_open(s) < 0)
die("Cannot create control socket %s: %m", path_control_socket);
if (use_uid || use_gid)

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