0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

Socket: sending filedescriptors over UNIX sockets

This commit is contained in:
Maria Matejka 2024-10-10 11:59:25 +02:00
parent 62bca8e882
commit d0425e8a54
2 changed files with 66 additions and 9 deletions

View File

@ -74,6 +74,9 @@ typedef struct birdsock {
uint lifindex; /* local interface that received the datagram */ uint lifindex; /* local interface that received the datagram */
/* laddr and lifindex are valid only if SKF_LADDR_RX flag is set to request it */ /* laddr and lifindex are valid only if SKF_LADDR_RX flag is set to request it */
/* Filedescriptors to send/receive (UNIX) */
int rxfd, txfd;
int af; /* System-dependend adress family (e.g. AF_INET) */ int af; /* System-dependend adress family (e.g. AF_INET) */
int fd; /* System-dependent data */ int fd; /* System-dependent data */
int index; /* Index in poll buffer */ int index; /* Index in poll buffer */
@ -143,6 +146,9 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
#define SKF_HDRINCL 0x400 /* Used internally */ #define SKF_HDRINCL 0x400 /* Used internally */
#define SKF_PKTINFO 0x800 /* Used internally */ #define SKF_PKTINFO 0x800 /* Used internally */
#define SKF_FD_RX 0x1000 /* Allow receiving filedescriptors (unix sockets) */
#define SKF_FD_TX 0x2000 /* Allow sending filedescriptors (unix sockets) */
/* /*
* Socket types SA SP DA DP IF TTL SendTo (?=may, -=must not, *=must) * Socket types SA SP DA DP IF TTL SendTo (?=may, -=must not, *=must)
*/ */
@ -157,6 +163,7 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
#define SK_UNIX 9 #define SK_UNIX 9
#define SK_SSH_ACTIVE 10 /* - - * * - ? - DA = host */ #define SK_SSH_ACTIVE 10 /* - - * * - ? - DA = host */
#define SK_SSH 11 #define SK_SSH 11
#define SK_UNIX_MSG 12 /* Like SK_UNIX but using sendmsg and recvmsg */
/* /*
* Socket subtypes * Socket subtypes

View File

@ -300,6 +300,43 @@ sk_prepare_cmsgs6(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
msg->msg_controllen = controllen; msg->msg_controllen = controllen;
} }
/*
* UNIX packet control messages
*/
#define CMSGU_SPACE_FD CMSG_SPACE(sizeof (int))
static inline void
sk_prepare_cmsgs_unix(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
{
if (s->txfd < 0)
{
msg->msg_control = NULL;
msg->msg_controllen = 0;
return;
}
msg->msg_control = cbuf;
msg->msg_controllen = cbuflen;
struct cmsghdr *cm = CMSG_FIRSTHDR(msg);
cm->cmsg_level = SOL_SOCKET;
cm->cmsg_type = SCM_RIGHTS;
cm->cmsg_len = CMSG_LEN(sizeof s->txfd);
memcpy(CMSG_DATA(cm), &s->txfd, sizeof s->txfd);
msg->msg_controllen = CMSGU_SPACE_FD;
}
static inline void
sk_process_cmsg_unix_fd(sock *s, struct cmsghdr *cm)
{
if (cm->cmsg_type == SCM_RIGHTS)
memcpy(&s->rxfd, CMSG_DATA(cm), sizeof s->rxfd);
else
s->rxfd = -1;
}
/* /*
* Miscellaneous socket syscalls * Miscellaneous socket syscalls
@ -1420,14 +1457,17 @@ sk_open_unix(sock *s, struct birdloop *loop, const char *name)
} }
#define CMSG_RX_SPACE MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \ #define CMSG_RX_SPACE MAX(CMSGU_SPACE_FD, \
CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL) MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \
#define CMSG_TX_SPACE MAX(CMSG4_SPACE_PKTINFO,CMSG6_SPACE_PKTINFO) CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL))
#define CMSG_TX_SPACE MAX(MAX(CMSG4_SPACE_PKTINFO,CMSG6_SPACE_PKTINFO),CMSGU_SPACE_FD)
static void static void
sk_prepare_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) sk_prepare_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
{ {
if (sk_is_ipv4(s)) if (s->type == SK_UNIX_MSG)
sk_prepare_cmsgs_unix(s, msg, cbuf, cbuflen);
else if (sk_is_ipv4(s))
sk_prepare_cmsgs4(s, msg, cbuf, cbuflen); sk_prepare_cmsgs4(s, msg, cbuf, cbuflen);
else else
sk_prepare_cmsgs6(s, msg, cbuf, cbuflen); sk_prepare_cmsgs6(s, msg, cbuf, cbuflen);
@ -1455,6 +1495,11 @@ sk_process_cmsgs(sock *s, struct msghdr *msg)
sk_process_cmsg6_pktinfo(s, cm); sk_process_cmsg6_pktinfo(s, cm);
sk_process_cmsg6_ttl(s, cm); sk_process_cmsg6_ttl(s, cm);
} }
if ((cm->cmsg_level == SOL_SOCKET) && (s->type == SK_UNIX_MSG))
{
sk_process_cmsg_unix_fd(s, cm);
}
} }
} }
@ -1467,15 +1512,19 @@ sk_sendmsg(sock *s)
sockaddr dst; sockaddr dst;
int flags = 0; int flags = 0;
sockaddr_fill(&dst, s->af, s->daddr, s->iface, s->dport);
struct msghdr msg = { struct msghdr msg = {
.msg_name = &dst.sa,
.msg_namelen = SA_LEN(dst),
.msg_iov = &iov, .msg_iov = &iov,
.msg_iovlen = 1 .msg_iovlen = 1
}; };
if (s->type != SK_UNIX_MSG)
{
sockaddr_fill(&dst, s->af, s->daddr, s->iface, s->dport);
msg.msg_name = &dst.sa;
msg.msg_namelen = SA_LEN(dst);
}
#ifdef CONFIG_DONTROUTE_UNICAST #ifdef CONFIG_DONTROUTE_UNICAST
/* FreeBSD silently changes TTL to 1 when MSG_DONTROUTE is used, therefore we /* FreeBSD silently changes TTL to 1 when MSG_DONTROUTE is used, therefore we
cannot use it for other cases (e.g. when TTL security is used). */ cannot use it for other cases (e.g. when TTL security is used). */
@ -1495,7 +1544,7 @@ sk_sendmsg(sock *s)
} }
#endif #endif
if (s->flags & SKF_PKTINFO) if (s->flags & (SKF_PKTINFO | SKF_FD_TX))
sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf)); sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
return sendmsg(s->fd, &msg, flags); return sendmsg(s->fd, &msg, flags);
@ -1602,6 +1651,7 @@ sk_maybe_write(sock *s)
case SK_UDP: case SK_UDP:
case SK_IP: case SK_IP:
case SK_UNIX_MSG:
{ {
if (s->tbuf == s->tpos) if (s->tbuf == s->tpos)
return 1; return 1;