0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-10-18 09:58:43 +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.
For passive UNIX socket the filesystem entry is considered as part of the
resource and hence is unlinked in rfree.
This commit is contained in:
Vojtech Vilimek 2024-07-17 12:05:13 +02:00
parent 08ff0af898
commit ad23b465f8
4 changed files with 109 additions and 45 deletions

View File

@ -43,7 +43,7 @@ typedef struct birdsock {
int subtype; /* Socket subtype */ int subtype; /* Socket subtype */
void *data; /* User data */ void *data; /* User data */
ip_addr saddr, daddr; /* IPA_NONE = unspecified */ 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) */ uint sport, dport; /* 0 = unspecified (for IP: protocol type) */
int tos; /* TOS / traffic class, -1 = default */ int tos; /* TOS / traffic class, -1 = default */
int priority; /* Local socket priority, -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_ipv4(sock *s); /* True if socket is IPv4 */
int sk_is_ipv6(sock *s); /* True if socket is IPv6 */ 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) static inline int sk_tx_buffer_empty(sock *sk)
{ return sk->tbuf == sk->tpos; } { 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_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_ipv6_checksum(sock *s, int offset);
int sk_set_icmp6_filter(sock *s, int p1, int p2); 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); void sk_log_error(sock *s, const char *p);
byte * sk_rx_buffer(sock *s, int *len); /* Temporary */ 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_UDP 3 /* ? ? ? ? ? ? ? */
#define SK_IP 5 /* ? - ? * ? ? ? */ #define SK_IP 5 /* ? - ? * ? ? ? */
#define SK_MAGIC 7 /* Internal use by sysdep code */ #define SK_MAGIC 7 /* Internal use by sysdep code */
#define SK_UNIX_PASSIVE 8 #define SK_UNIX_PASSIVE 8 /* - - * - - - - DA = host */
#define SK_UNIX 9 #define SK_UNIX_ACTIVE 9 /* - - * - - - - DA = host */
#define SK_SSH_ACTIVE 10 /* - - * * - ? - DA = host */ #define SK_UNIX 10
#define SK_SSH 11 #define SK_SSH_ACTIVE 11 /* - - * * - ? - DA = host */
#define SK_SSH 12
/* /*
* Socket subtypes * 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 * 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 * available in some corner cases). The first way is used when SKF_BIND is
* specified, the second way is used otherwise. * 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 #endif

View File

@ -566,6 +566,21 @@ sk_setup_multicast(sock *s)
return sk_setup_multicast6(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 * sk_join_group - join multicast group for given socket
* @s: socket * @s: socket
@ -831,6 +846,10 @@ sk_free(resource *r)
sk_ssh_free(s); sk_ssh_free(s);
#endif #endif
if (s->host && s->type == SK_UNIX_PASSIVE)
/* Return value intentionally ignored */
(void) unlink(s->host);
if (s->fd < 0) if (s->fd < 0)
return; return;
@ -898,7 +917,7 @@ static void
sk_dump(resource *r) sk_dump(resource *r)
{ {
sock *s = (sock *) 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", debug("(%s, ud=%p, sa=%I, sp=%d, da=%I, dp=%d, tos=%d, ttl=%d, if=%s)\n",
sk_type_names[s->type], sk_type_names[s->type],
@ -955,6 +974,12 @@ sk_setup(sock *s)
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
ERR("O_NONBLOCK"); 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) if (!s->af)
return 0; return 0;
@ -1089,6 +1114,14 @@ sk_tcp_connected(sock *s)
s->tx_hook(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 #ifdef HAVE_LIBSSH
static void static void
sk_ssh_connected(sock *s) sk_ssh_connected(sock *s)
@ -1114,6 +1147,7 @@ sk_passive_connected(sock *s, int type)
return 0; return 0;
} }
/* Do not copy UNIX address in s->host. */
sock *t = sk_new(s->pool); sock *t = sk_new(s->pool);
t->type = type; t->type = type;
t->data = s->data; t->data = s->data;
@ -1367,6 +1401,9 @@ sk_open(sock *s)
int bind_port = 0; int bind_port = 0;
ip_addr bind_addr = IPA_NONE; ip_addr bind_addr = IPA_NONE;
sockaddr sa; sockaddr sa;
struct sockaddr_un un;
struct sockaddr *addr;
socklen_t len;
if (s->type <= SK_IP) if (s->type <= SK_IP)
{ {
@ -1439,6 +1476,15 @@ sk_open(sock *s)
fd = s->fd; fd = s->fd;
break; 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: default:
bug("sk_open() called for invalid sock type %d", s->type); bug("sk_open() called for invalid sock type %d", s->type);
} }
@ -1479,8 +1525,21 @@ sk_open(sock *s)
if (sk_set_freebind(s) < 0) if (sk_set_freebind(s) < 0)
log(L_WARN "Socket error: %s%#m", s->err); log(L_WARN "Socket error: %s%#m", s->err);
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); sockaddr_fill(&sa, s->af, bind_addr, s->iface, bind_port);
if (bind(fd, &sa.sa, SA_LEN(sa)) < 0) addr = &sa.sa;
len = SA_LEN(sa);
}
if (bind(fd, addr, len) < 0)
ERR2("bind"); ERR2("bind");
} }
@ -1511,6 +1570,21 @@ sk_open(sock *s)
sk_alloc_bufs(s); sk_alloc_bufs(s);
break; 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_SSH_ACTIVE:
case SK_MAGIC: case SK_MAGIC:
break; break;
@ -1530,38 +1604,6 @@ err:
return -1; 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, \ #define CMSG_RX_SPACE MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \
CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL) CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL)
@ -1985,6 +2027,20 @@ sk_write_noflush(sock *s)
return 0; 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 #ifdef HAVE_LIBSSH
case SK_SSH_ACTIVE: case SK_SSH_ACTIVE:
{ {
@ -2031,6 +2087,9 @@ int sk_is_ipv4(sock *s)
int sk_is_ipv6(sock *s) int sk_is_ipv6(sock *s)
{ return s->af == AF_INET6; } { return s->af == AF_INET6; }
int sk_is_unix(sock *s)
{ return s->af == AF_UNIX; }
void void
sk_err(sock *s, int revents) sk_err(sock *s, int revents)
{ {

View File

@ -553,6 +553,7 @@ cli_listen(struct cli_config *cf)
l->config = cf; l->config = cf;
sock *s = l->s = sk_new(cli_pool); sock *s = l->s = sk_new(cli_pool);
s->type = SK_UNIX_PASSIVE; s->type = SK_UNIX_PASSIVE;
s->host = cf->name;
s->rx_hook = cli_connect; s->rx_hook = cli_connect;
s->err_hook = cli_connect_err; s->err_hook = cli_connect_err;
s->data = l; s->data = l;
@ -560,9 +561,9 @@ cli_listen(struct cli_config *cf)
s->fast_rx = 1; s->fast_rx = 1;
/* Return value intentionally ignored */ /* 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); log(L_ERR "Cannot create control socket %s: %m", cf->name);
return NULL; return NULL;
@ -590,7 +591,6 @@ static void
cli_deafen(struct cli_listener *l) cli_deafen(struct cli_listener *l)
{ {
rfree(l->s); rfree(l->s);
unlink(l->config->name);
cli_listener_rem_node(&cli_listeners, l); cli_listener_rem_node(&cli_listeners, l);
mb_free(l); mb_free(l);
} }

View File

@ -53,7 +53,6 @@ typedef struct sockaddr_bird {
} sockaddr; } sockaddr;
/* This is sloppy hack, it should be detected by configure script */ /* This is sloppy hack, it should be detected by configure script */
/* Linux systems have it defined so this is definition for BSD systems */ /* Linux systems have it defined so this is definition for BSD systems */
#ifndef s6_addr32 #ifndef s6_addr32
@ -107,7 +106,6 @@ extern volatile sig_atomic_t async_shutdown_flag;
void io_init(void); void io_init(void);
void io_loop(void); void io_loop(void);
void io_log_dump(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_open(struct pool *, const char *name, const char *mode);
struct rfile *rf_fdopen(pool *p, int fd, const char *mode); struct rfile *rf_fdopen(pool *p, int fd, const char *mode);
void *rf_file(struct rfile *f); void *rf_file(struct rfile *f);