Last active
July 12, 2017 22:42
-
-
Save tokenrove/c1af799c84e9fa644a5abc9c64854f23 to your computer and use it in GitHub Desktop.
sending fds over unix domain sockets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Opens a Unix domain socket and cats any fds passed over it. | |
*/ | |
#include <err.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <sysexits.h> | |
#include <unistd.h> | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <sys/un.h> | |
#include <sys/wait.h> | |
void cat(int fd) | |
{ | |
char buf[4096]; | |
while (true) { | |
ssize_t n = read(fd, buf, sizeof(buf)); | |
if (n == 0) { | |
close(fd); | |
return; | |
} | |
if (n < 0) | |
err(EX_IOERR, "read(%d)", fd); | |
if (n != write(1, buf, n)) | |
err(EX_IOERR, "write"); | |
} | |
__builtin_unreachable(); | |
} | |
int main(int argc, char **argv) | |
{ | |
if (2 != argc) | |
errx(EX_USAGE, "takes path to UDS to create"); | |
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); | |
if (sockfd < 0) | |
err(EX_OSERR, "socket"); | |
struct sockaddr_un name = { .sun_family = AF_UNIX }; | |
char *path = argv[1]; | |
if (strlen(path) > sizeof(name.sun_path)-1) | |
errx(EX_USAGE, "UDS pathnames can't be longer than %zu (yours is %zu)", | |
sizeof(name.sun_path)-1, strlen(path)); | |
strncpy(name.sun_path, path, sizeof(name.sun_path)-1); | |
if (bind(sockfd, (const struct sockaddr *)&name, sizeof(name))) | |
err(EX_OSERR, "bind(%s)", path); | |
pid_t child = fork(); | |
if (child < 0) | |
err(EX_OSERR, "fork"); | |
if (child) { | |
sigaction(SIGINT, | |
&(struct sigaction){ .sa_handler = SIG_IGN, | |
.sa_flags = SA_RESETHAND }, | |
NULL); | |
do { waitpid(child, NULL, 0); } while (!kill(child, 0)); | |
unlink(path); | |
return 0; | |
} | |
while (true) { | |
char buf[CMSG_LEN(sizeof(int))] | |
__attribute__((aligned(__alignof__(struct cmsghdr)))); | |
struct msghdr msg = { | |
// NB: can't receive any data | |
.msg_control = buf, | |
.msg_controllen = sizeof(buf), | |
}; | |
if (recvmsg(sockfd, &msg, 0) < 0) | |
err(EX_IOERR, "recvmsg"); | |
struct cmsghdr *c; | |
for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) { | |
if (c->cmsg_level == SOL_SOCKET && | |
c->cmsg_type == SCM_RIGHTS) | |
cat(*(int *)CMSG_DATA(c)); | |
} | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Send stdin on a Unix domain socket. | |
* | |
* You can use the shell to redirect arbitrary fds into this program. | |
*/ | |
#include <assert.h> | |
#include <err.h> | |
#include <string.h> | |
#include <sysexits.h> | |
#include <unistd.h> | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <sys/un.h> | |
static void usage(void) | |
{ | |
errx(EX_USAGE, "takes path to Unix domain socket; sends fd 0"); | |
} | |
int main(int argc, char **argv) | |
{ | |
if (2 != argc) | |
usage(); | |
if (isatty(0)) /* NB: try removing this and see what happens */ | |
errx(EX_USAGE, "you probably don't want to send your tty."); | |
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); | |
if (sockfd < 0) | |
err(EX_OSERR, "socket"); | |
struct sockaddr_un name = { .sun_family = AF_UNIX }; | |
char *path = argv[1]; | |
if (strlen(path) > sizeof(name.sun_path)-1) | |
errx(EX_USAGE, "UDS pathnames can't be longer than %zu (yours is %zu)", | |
sizeof(name.sun_path)-1, strlen(path)); | |
strncpy(name.sun_path, path, sizeof(name.sun_path)-1); | |
char buf[CMSG_LEN(sizeof(int))]; | |
struct msghdr msg = { | |
.msg_name = &name, | |
.msg_namelen = sizeof(name), | |
.msg_control = buf, | |
.msg_controllen = CMSG_LEN(sizeof(int)), | |
}; | |
struct cmsghdr *cmsg; | |
cmsg = CMSG_FIRSTHDR(&msg); | |
assert(cmsg); | |
cmsg->cmsg_level = SOL_SOCKET; | |
cmsg->cmsg_type = SCM_RIGHTS; | |
cmsg->cmsg_len = sizeof(buf); | |
*(int *)CMSG_DATA(cmsg) = 0; | |
if (sendmsg(sockfd, &msg, 0) < 0) | |
err(EX_IOERR, "sendmsg"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment