#include #include #include #include #include #include #include #include #include #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; }