diff --git a/lib/socket.h b/lib/socket.h index 0417a5aa..611f528b 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -74,6 +74,9 @@ typedef struct birdsock { uint lifindex; /* local interface that received the datagram */ /* 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 fd; /* System-dependent data */ 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_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) */ @@ -157,6 +163,7 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou #define SK_UNIX 9 #define SK_SSH_ACTIVE 10 /* - - * * - ? - DA = host */ #define SK_SSH 11 +#define SK_UNIX_MSG 12 /* Like SK_UNIX but using sendmsg and recvmsg */ /* * Socket subtypes diff --git a/sysdep/unix/socket.c b/sysdep/unix/socket.c index a497e40f..67dde0e6 100644 --- a/sysdep/unix/socket.c +++ b/sysdep/unix/socket.c @@ -300,6 +300,43 @@ sk_prepare_cmsgs6(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) 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 @@ -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, \ - CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL) -#define CMSG_TX_SPACE MAX(CMSG4_SPACE_PKTINFO,CMSG6_SPACE_PKTINFO) +#define CMSG_RX_SPACE MAX(CMSGU_SPACE_FD, \ + MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \ + CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL)) +#define CMSG_TX_SPACE MAX(MAX(CMSG4_SPACE_PKTINFO,CMSG6_SPACE_PKTINFO),CMSGU_SPACE_FD) static void 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); else 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_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; int flags = 0; - sockaddr_fill(&dst, s->af, s->daddr, s->iface, s->dport); - struct msghdr msg = { - .msg_name = &dst.sa, - .msg_namelen = SA_LEN(dst), .msg_iov = &iov, .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 /* 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). */ @@ -1495,7 +1544,7 @@ sk_sendmsg(sock *s) } #endif - if (s->flags & SKF_PKTINFO) + if (s->flags & (SKF_PKTINFO | SKF_FD_TX)) sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf)); return sendmsg(s->fd, &msg, flags); @@ -1602,6 +1651,7 @@ sk_maybe_write(sock *s) case SK_UDP: case SK_IP: + case SK_UNIX_MSG: { if (s->tbuf == s->tpos) return 1;