diff options
| author | Mikhail Osipov <mike.osipov@gmail.com> | 2019-10-18 17:43:38 +0300 |
|---|---|---|
| committer | Mikhail Osipov <mike.osipov@gmail.com> | 2019-10-18 17:43:38 +0300 |
| commit | 3b00c7be0e8834402ed93eb42b3a93302076c5ff (patch) | |
| tree | ebf1643f00d2206c80676b1057f6d42d494d5c3a /tunnel.c | |
| parent | 9c05f1c4187de3c43c027f6102b6e161b2f7441c (diff) | |
skel
Diffstat (limited to 'tunnel.c')
| -rw-r--r-- | tunnel.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/tunnel.c b/tunnel.c new file mode 100644 index 0000000..56bdcdd --- /dev/null +++ b/tunnel.c @@ -0,0 +1,116 @@ +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> + +#include <stddef.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <err.h> + +#include "tunnel.h" +#include "macro.h" + +int tunnel_socket(struct sockaddr **sa, socklen_t *salen) +{ + int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (sock < 0) { + warn("socket"); + return -1; + } + + struct sockaddr_un sun = { + .sun_family = AF_UNIX + }; + + const char *path = TUNNEL_SOCK_PATH; + + int n = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", path); + socklen_t len = offsetof(struct sockaddr_un, sun_path) + n + 1; + + if (len > sizeof(sun)) { + warnx("too large unix path"); + close(sock); + return -1; + } + + *sa = _copy(&sun, len); + *salen = len; + + return sock; +} + +int tunnel_listen(int sock, struct sockaddr *sa, socklen_t salen) +{ + if (bind(sock, sa, salen) < 0) { + warn("bind"); + return -1; + } + + if (listen(sock, 0) < 0) { + warn("listen"); + return -1; + } + + return 0; +} + +int tunnel_server(void) +{ + struct sockaddr *sa = NULL; + socklen_t salen = 0; + + int sock = tunnel_socket(&sa, &salen); + if (sock < 0) + return -1; + + defer { + close(sock); + free(sa); + } + + if (tunnel_listen(sock, sa, salen) < 0) + return -1; + + if (tunnel_daemon(sock) < 0) + return -1; + + return 0; +} + +int tunnel_connect(int sock, struct sockaddr *sa, socklen_t salen) +{ + if (connect(sock, sa, salen) < 0) { + if (errno == ENOENT) { + if (tunnel_server() < 0) + return -1; + } + + if (errno != ENOENT || connect(sock, sa, salen) < 0) { + warn("connect"); + return -1; + } + } + + return 0; +} + +int tunnel_client(void) +{ + struct sockaddr *sa = NULL; + socklen_t salen = 0; + + int sock = tunnel_socket(&sa, &salen); + if (sock < 0) + return -1; + + defer { free(sa); } + + if (tunnel_connect(sock, sa, salen) < 0) { + close(sock); + return -1; + } + + return sock; +} |
