summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Osipov <mike.osipov@gmail.com>2019-10-18 17:43:38 +0300
committerMikhail Osipov <mike.osipov@gmail.com>2019-10-18 17:43:38 +0300
commit3b00c7be0e8834402ed93eb42b3a93302076c5ff (patch)
treeebf1643f00d2206c80676b1057f6d42d494d5c3a
parent9c05f1c4187de3c43c027f6102b6e161b2f7441c (diff)
skel
-rw-r--r--.gitignore3
-rw-r--r--Makefile19
-rw-r--r--TODO12
-rw-r--r--daemon.c74
-rw-r--r--libevent.mk2
-rw-r--r--macro.h25
-rw-r--r--main.c31
-rw-r--r--tunnel.c116
-rw-r--r--tunnel.h9
9 files changed, 291 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..350c6e0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+tunnel
+*.o
+*~
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..365d550
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+PROGNAME = tunnel
+
+CFLAGS = -Wall -Wextra
+LDFLAGS =
+
+include libevent.mk
+
+SOURCES = $(wildcard *.c)
+OBJECTS = $(patsubst %.c,%.o,$(SOURCES))
+
+$(PROGNAME): $(OBJECTS)
+ gcc $(LDFLAGS) -o $@ $^
+
+%.o: %.c
+ gcc $(CFLAGS) -c -o $@ $<
+
+clean:
+ @echo cleaning...
+ @rm -f *.o *~
diff --git a/TODO b/TODO
index 511a63b..663f2ab 100644
--- a/TODO
+++ b/TODO
@@ -5,3 +5,15 @@ Usage:
tunnel route del ip[/mask]
tunnel route show
tunnel show
+
+ tunnel create http host port name proxy
+ tunnel route add port 80 via proxy
+ tunnel route del port 80 via proxy
+ tunnel route drop via proxy
+
+ tunnel add proxy httpconnect host port
+ tunnel route add proxy port 80
+ tunnel route add proxy port 22
+ tunnel show proxy
+ tunnel del proxy
+ tunnel list
diff --git a/daemon.c b/daemon.c
new file mode 100644
index 0000000..305755d
--- /dev/null
+++ b/daemon.c
@@ -0,0 +1,74 @@
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <err.h>
+
+#include "tunnel.h"
+#include "macro.h"
+
+static void sighandler(int signo __unused)
+{
+ unlink(TUNNEL_SOCK_PATH);
+ exit(EXIT_FAILURE);
+}
+
+static void tunnel_daemon_loop(int sock)
+{
+ for (;;) {
+ 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);
+ }
+ }
+}
+
+int tunnel_daemon(int sock)
+{
+ switch (fork()) {
+ case -1:
+ warn("fork");
+ return -1;
+ case 0:
+ break;
+ default:
+ return 0;
+ }
+
+ if (setsid() < 0)
+ err(EXIT_FAILURE, "setsid");
+
+ chdir("/");
+
+ struct sigaction sa = {
+ .sa_handler = sighandler
+ };
+
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+#if 0
+ int fd = open("/dev/null", O_RDWR);
+ if (fd < 0)
+ err(EXIT_FAILURE, "open /dev/null");
+
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+
+ if (fd > 2)
+ close(fd);
+#endif
+
+ tunnel_daemon_loop(sock);
+
+ return 0;
+}
diff --git a/libevent.mk b/libevent.mk
new file mode 100644
index 0000000..194a525
--- /dev/null
+++ b/libevent.mk
@@ -0,0 +1,2 @@
+CFLAGS += $(shell pkg-config --cflags libevent)
+LDFLAGS += $(shell pkg-config --libs libevent)
diff --git a/macro.h b/macro.h
new file mode 100644
index 0000000..c91b8cf
--- /dev/null
+++ b/macro.h
@@ -0,0 +1,25 @@
+#ifndef __TUNNEL_MACRO_H__
+#define __TUNNEL_MACRO_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+#define _new(t) memset(malloc(sizeof(t)), 0, sizeof(t))
+
+#define _copy(p, ...) _copy_(p, ## __VA_ARGS__, sizeof(*p))
+#define _copy_(p, n, ...) memcpy(malloc(n), p, n)
+
+#define __unused __attribute__((unused))
+#define __cleanup(f) __attribute__((cleanup(f)))
+
+#define CAT(a, b) CAT_(a, b)
+#define CAT_(a, b) a ## b
+
+#define UNIQ(name) CAT(name, __LINE__)
+
+#define defer \
+ auto void UNIQ(defer_func)(int *); \
+ int UNIQ(defer_var) __cleanup(UNIQ(defer_func)); \
+ void UNIQ(defer_func)(int *p __unused)
+
+#endif
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..5a43f51
--- /dev/null
+++ b/main.c
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <err.h>
+
+#include "tunnel.h"
+#include "macro.h"
+
+int main(int argc __unused, char *argv[] __unused)
+{
+#if 0
+ if (geteuid() != 0)
+ errx(EXIT_FAILURE, "running as root required");
+#endif
+
+ int sock = tunnel_client();
+ if (sock < 0)
+ errx(EXIT_FAILURE, "tunnel_connect failed");
+
+ char buf[512];
+
+ int n = read(sock, buf, sizeof(buf));
+ if (n < 0)
+ err(EXIT_FAILURE, "read");
+
+ printf("%.*s\n", n, buf);
+
+ close(sock);
+
+ return 0;
+}
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;
+}
diff --git a/tunnel.h b/tunnel.h
new file mode 100644
index 0000000..d04bde5
--- /dev/null
+++ b/tunnel.h
@@ -0,0 +1,9 @@
+#ifndef __TUNNEL_H__
+#define __TUNNEL_H__
+
+#define TUNNEL_SOCK_PATH "/tmp/tunnel.sock"
+
+int tunnel_client(void);
+int tunnel_daemon(int sock);
+
+#endif