summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--daemon.c91
-rw-r--r--macro.h43
-rw-r--r--main.c44
-rw-r--r--tunnel.c120
-rw-r--r--tunnel.h7
-rw-r--r--utils.c14
-rw-r--r--utils.h8
8 files changed, 262 insertions, 71 deletions
diff --git a/Makefile b/Makefile
index 365d550..822c6f4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
PROGNAME = tunnel
-CFLAGS = -Wall -Wextra
+CFLAGS = -Wall -Wextra -Werror
LDFLAGS =
include libevent.mk
@@ -9,10 +9,10 @@ SOURCES = $(wildcard *.c)
OBJECTS = $(patsubst %.c,%.o,$(SOURCES))
$(PROGNAME): $(OBJECTS)
- gcc $(LDFLAGS) -o $@ $^
+ gcc -o $@ $^ $(LDFLAGS)
%.o: %.c
- gcc $(CFLAGS) -c -o $@ $<
+ gcc -c -o $@ $< $(CFLAGS)
clean:
@echo cleaning...
diff --git a/daemon.c b/daemon.c
index 305755d..0f25181 100644
--- a/daemon.c
+++ b/daemon.c
@@ -3,44 +3,109 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
+#include <time.h>
#include <err.h>
#include "tunnel.h"
#include "macro.h"
+#include "utils.h"
-static void sighandler(int signo __unused)
+static time_t since;
+
+static void tunnel_daemon_atexit(void)
{
unlink(TUNNEL_SOCK_PATH);
+}
+
+static void sighandler(int signo __unused)
+{
exit(EXIT_FAILURE);
}
+static char **parse_args(char *buf, int len)
+{
+ char **args = NULL;
+
+ while (len) {
+ addv(&args, buf);
+
+ char *p = memchr(buf, '\0', len);
+ if (!p)
+ break;
+
+ len -= p - buf + 1;
+ buf = p + 1;
+ }
+
+ return args;
+}
+
+static void echo(FILE *fp, char **args)
+{
+ for (int n = 0; args[n]; n++)
+ fprintf(fp, "%s%s", n ? " " : "", args[n]);
+}
+
static void tunnel_daemon_loop(int sock)
{
- for (;;) {
+ bool alive = true;
+
+ while (alive) {
+ char msg[1024];
+ int len;
+
int fd = accept(sock, NULL, NULL);
if (fd < 0) {
warn("accept");
continue;
}
- FILE *fp = fdopen(fd, "w");
- if (fp) {
- fprintf(fp, "hello from %d", getpid());
- fclose(fp);
+ len = read(fd, msg, sizeof(msg) - 1);
+ if (len < 0) {
+ warn("read");
+ close(fd);
+ continue;
+ }
+
+ if (! len) {
+ close(fd);
+ continue;
+ }
+
+ msg[len] = '\0';
+
+ char **args = parse_args(msg, len);
+
+ let (fp, fdopen(fd, "w"), fclose) {
+ char *cmd = *args;
+
+ if (strequal(cmd, "echo"))
+ echo(fp, args + 1);
+ else if (strequal(cmd, "hello"))
+ fprintf(fp, "hello from %d", getpid());
+ else if (strequal(cmd, "alive"))
+ fprintf(fp, "since %s", ctime(&since));
+ else if (strequal(cmd, "stop")) {
+ fprintf(fp, "ok");
+ alive = false;
+ } else
+ fprintf(fp, "what do you want?");
}
+
+ free(args);
}
}
-int tunnel_daemon(int sock)
+bool tunnel_daemon(int sock)
{
switch (fork()) {
case -1:
warn("fork");
- return -1;
+ return false;
case 0:
break;
default:
- return 0;
+ return true;
}
if (setsid() < 0)
@@ -68,7 +133,13 @@ int tunnel_daemon(int sock)
close(fd);
#endif
+ time(&since);
+
+ atexit(tunnel_daemon_atexit);
+
tunnel_daemon_loop(sock);
- return 0;
+ exit(EXIT_SUCCESS);
+
+ return true;
}
diff --git a/macro.h b/macro.h
index c91b8cf..5a55e10 100644
--- a/macro.h
+++ b/macro.h
@@ -4,7 +4,7 @@
#include <stdlib.h>
#include <string.h>
-#define _new(t) memset(malloc(sizeof(t)), 0, sizeof(t))
+#define _new(T, ...) ({ T __v = { __VA_ARGS__ }; _copy(&__v); })
#define _copy(p, ...) _copy_(p, ## __VA_ARGS__, sizeof(*p))
#define _copy_(p, n, ...) memcpy(malloc(n), p, n)
@@ -22,4 +22,45 @@
int UNIQ(defer_var) __cleanup(UNIQ(defer_func)); \
void UNIQ(defer_func)(int *p __unused)
+static __unused void __let_nothing(void)
+{
+}
+
+#define let(p, e, ...) let_(p, e, ## __VA_ARGS__, __let_nothing)
+#define let_(p, e, f, ...) \
+ for (int step = 1; step; ) \
+ for (typeof(e) p = e; step; f(p), step = 0)
+
+static inline int lenv(void **pp)
+{
+ int count = 0;
+
+ if (pp) {
+ for (; *pp; pp++)
+ count++;
+ }
+
+ return count;
+}
+
+#define lenv(v) lenv((void **) v)
+
+static inline void **addv(void ***v, void *p)
+{
+ if (! v) {
+ *v = calloc(2, sizeof(*v));
+ **v = p;
+ } else {
+ int len = lenv(*v);
+
+ *v = realloc(*v, sizeof(*v) * (len + 2));
+ (*v)[len] = p;
+ (*v)[len + 1] = NULL;
+ }
+
+ return *v;
+}
+
+#define addv(v, p) addv((void ***) v, p)
+
#endif
diff --git a/main.c b/main.c
index 5a43f51..e8b0026 100644
--- a/main.c
+++ b/main.c
@@ -5,25 +5,51 @@
#include "tunnel.h"
#include "macro.h"
+#include "utils.h"
-int main(int argc __unused, char *argv[] __unused)
+static void sendcmd(int sock, int argc, char *argv[])
{
-#if 0
- if (geteuid() != 0)
- errx(EXIT_FAILURE, "running as root required");
-#endif
+ char *buf = NULL;
+ size_t len = 0;
+
+ let (fp, open_memstream(&buf, &len), fclose) {
+ for (int n = 0; n < argc; n++) {
+ if (n)
+ fputc('\0', fp);
+
+ fprintf(fp, "%s", argv[n]);
+ }
+ }
+
+ if (write(sock, buf, len) < 0)
+ err(EXIT_FAILURE, "write");
+
+ free(buf);
+}
+
+int main(int argc, char *argv[])
+{
+ char reply[1024];
+
+ if (argc == 1)
+ errx(EXIT_FAILURE, "bad usage");
int sock = tunnel_client();
if (sock < 0)
- errx(EXIT_FAILURE, "tunnel_connect failed");
+ errx(EXIT_FAILURE, "tunnel_client failed");
- char buf[512];
+ sendcmd(sock, argc - 1, argv + 1);
- int n = read(sock, buf, sizeof(buf));
+ int n = read(sock, reply, sizeof(reply));
if (n < 0)
err(EXIT_FAILURE, "read");
- printf("%.*s\n", n, buf);
+ if (n) {
+ if (reply[n - 1] == '\n')
+ printf("%.*s", n, reply);
+ else
+ printf("%.*s\n", n, reply);
+ }
close(sock);
diff --git a/tunnel.c b/tunnel.c
index 56bdcdd..2e0718e 100644
--- a/tunnel.c
+++ b/tunnel.c
@@ -2,6 +2,7 @@
#include <sys/stat.h>
#include <sys/un.h>
+#include <stdbool.h>
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
@@ -12,12 +13,45 @@
#include "tunnel.h"
#include "macro.h"
-int tunnel_socket(struct sockaddr **sa, socklen_t *salen)
+struct socket {
+ int fd;
+ struct sockaddr *sa;
+ socklen_t salen;
+};
+
+static bool socket_connect(struct socket *sock)
+{
+ if (connect(sock->fd, sock->sa, sock->salen) < 0)
+ return false;
+
+ return true;
+}
+
+static void socket_free(struct socket *sock)
+{
+ if (sock) {
+ if (sock->fd >= 0)
+ close(sock->fd);
+ free(sock->sa);
+ free(sock);
+ }
+}
+
+static int socket_detach_fd(struct socket *sock)
+{
+ int fd = sock->fd;
+
+ sock->fd = -1;
+
+ return fd;
+}
+
+struct socket *tunnel_socket(void)
{
- int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
- if (sock < 0) {
+ int fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+ if (fd < 0) {
warn("socket");
- return -1;
+ return NULL;
}
struct sockaddr_un sun = {
@@ -31,86 +65,78 @@ int tunnel_socket(struct sockaddr **sa, socklen_t *salen)
if (len > sizeof(sun)) {
warnx("too large unix path");
- close(sock);
- return -1;
+ close(fd);
+ return NULL;
}
- *sa = _copy(&sun, len);
- *salen = len;
+ struct socket *sock = _new(struct socket,
+ .fd = fd,
+ .salen = len,
+ .sa = _copy(&sun, len),
+ );
return sock;
}
-int tunnel_listen(int sock, struct sockaddr *sa, socklen_t salen)
+bool tunnel_listen(struct socket *sock)
{
- if (bind(sock, sa, salen) < 0) {
+ if (bind(sock->fd, sock->sa, sock->salen) < 0) {
warn("bind");
- return -1;
+ return false;
}
- if (listen(sock, 0) < 0) {
+ if (listen(sock->fd, 0) < 0) {
warn("listen");
- return -1;
+ return false;
}
- return 0;
+ return true;
}
-int tunnel_server(void)
+bool tunnel_server(void)
{
- struct sockaddr *sa = NULL;
- socklen_t salen = 0;
+ struct socket *sock = tunnel_socket();
+ if (!sock)
+ return false;
- int sock = tunnel_socket(&sa, &salen);
- if (sock < 0)
- return -1;
+ defer { socket_free(sock); }
- defer {
- close(sock);
- free(sa);
- }
+ if (! tunnel_listen(sock))
+ return false;
- if (tunnel_listen(sock, sa, salen) < 0)
- return -1;
-
- if (tunnel_daemon(sock) < 0)
- return -1;
+ if (! tunnel_daemon(sock->fd))
+ return false;
- return 0;
+ return true;
}
-int tunnel_connect(int sock, struct sockaddr *sa, socklen_t salen)
+bool tunnel_connect(struct socket *sock)
{
- if (connect(sock, sa, salen) < 0) {
+ if (! socket_connect(sock)) {
if (errno == ENOENT) {
- if (tunnel_server() < 0)
- return -1;
+ if (! tunnel_server())
+ return false;
}
- if (errno != ENOENT || connect(sock, sa, salen) < 0) {
+ if (errno != ENOENT || ! socket_connect(sock)) {
warn("connect");
- return -1;
+ return false;
}
}
- return 0;
+ return true;
}
int tunnel_client(void)
{
- struct sockaddr *sa = NULL;
- socklen_t salen = 0;
-
- int sock = tunnel_socket(&sa, &salen);
- if (sock < 0)
+ struct socket *sock = tunnel_socket();
+ if (! sock)
return -1;
- defer { free(sa); }
+ defer { socket_free(sock); }
- if (tunnel_connect(sock, sa, salen) < 0) {
- close(sock);
+ if (! tunnel_connect(sock))
return -1;
- }
- return sock;
+ return socket_detach_fd(sock);
}
diff --git a/tunnel.h b/tunnel.h
index d04bde5..a62f1b8 100644
--- a/tunnel.h
+++ b/tunnel.h
@@ -1,9 +1,14 @@
#ifndef __TUNNEL_H__
#define __TUNNEL_H__
+#include <stdbool.h>
+
#define TUNNEL_SOCK_PATH "/tmp/tunnel.sock"
+bool tunnel_alive(bool *alive);
+
int tunnel_client(void);
-int tunnel_daemon(int sock);
+
+bool tunnel_daemon(int sock);
#endif
diff --git a/utils.c b/utils.c
new file mode 100644
index 0000000..62fb0b2
--- /dev/null
+++ b/utils.c
@@ -0,0 +1,14 @@
+#include <string.h>
+
+#include "utils.h"
+
+bool strequal(const char *a, const char *b)
+{
+ if (!a && !b)
+ return true;
+
+ if (!a || !b)
+ return false;
+
+ return !strcmp(a, b);
+}
diff --git a/utils.h b/utils.h
new file mode 100644
index 0000000..bea66d9
--- /dev/null
+++ b/utils.h
@@ -0,0 +1,8 @@
+#ifndef __TUNNEL_UTILS_H__
+#define __TUNNEL_UTILS_H__
+
+#include <stdbool.h>
+
+bool strequal(const char *a, const char *b);
+
+#endif