From 70086d295a129ad93fb56fdd5a2ce5d226779556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Gallou=C3=ABt?= Date: Tue, 16 Jan 2018 16:37:01 +0000 Subject: [PATCH] Add a simple unix controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Adrien Gallouët --- Makefile.am | 16 ++++++++- meson.build | 22 ++++++++---- src/common.h | 8 +++++ src/ctl.c | 79 +++++++++++++++++++++++++++++++++++++++++++ src/ctl.h | 19 +++++++++++ src/main.c | 73 +++++++++++++++++++++++++++++----------- src/mainctl.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 284 insertions(+), 26 deletions(-) create mode 100644 src/ctl.c create mode 100644 src/ctl.h create mode 100644 src/mainctl.c diff --git a/Makefile.am b/Makefile.am index 4e6741c..ec13872 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ACLOCAL_AMFLAGS = -I m4 --install -bin_PROGRAMS = glorytun +bin_PROGRAMS = glorytun glorytunctl glorytun_CFLAGS = $(libsodium_CFLAGS) glorytun_LDADD = $(libsodium_LIBS) @@ -9,6 +9,8 @@ glorytun_SOURCES = \ src/common.c \ src/ip.h \ src/str.h \ + src/ctl.c \ + src/ctl.h \ src/main.c \ src/option.c \ src/option.h \ @@ -19,6 +21,18 @@ glorytun_SOURCES = \ mud/mud.h \ mud/mud.c +glorytunctl_CFLAGS = +glorytunctl_LDADD = +glorytunctl_SOURCES = \ + src/common.h \ + src/common.c \ + src/str.h \ + src/ctl.c \ + src/ctl.h \ + src/mainctl.c \ + src/option.c \ + src/option.h + EXTRA_DIST = \ LICENSE \ README.md \ diff --git a/meson.build b/meson.build index a80d5cf..a4723ed 100644 --- a/meson.build +++ b/meson.build @@ -12,21 +12,31 @@ conf_data.set('prefix', prefix) conf_data.set('bindir', bindir) add_global_arguments('-DPACKAGE_VERSION="'+meson.project_version()+'"', language : 'c') +add_global_arguments('-DPACKAGE_NAME="'+meson.project_name()+'"', language : 'c') -src = [ +executable('glorytun', install: true, + sources: [ 'src/common.c', 'src/iface.c', 'src/option.c', 'src/tun.c', + 'src/ctl.c', 'mud/mud.c', 'src/main.c' -] - -deps = [ + ], + dependencies: [ dependency('libsodium', version : '>=1.0.4') -] + ] +) -executable('glorytun', install: true, sources: src, dependencies: deps) +executable('glorytunctl', install: true, + sources: [ + 'src/common.c', + 'src/option.c', + 'src/ctl.c', + 'src/mainctl.c' + ] +) systemd = dependency('systemd', required: false) diff --git a/src/common.h b/src/common.h index 79f13fa..fa14795 100644 --- a/src/common.h +++ b/src/common.h @@ -6,6 +6,14 @@ #include #include +#ifndef PACKAGE_NAME +#define PACKAGE_NAME "glorytun" +#endif + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "0.0.0" +#endif + #define COUNT(x) (sizeof(x)/sizeof(x[0])) #define ALIGN_SIZE (1<<4) diff --git a/src/ctl.c b/src/ctl.c new file mode 100644 index 0000000..d83e505 --- /dev/null +++ b/src/ctl.c @@ -0,0 +1,79 @@ +#include "common.h" + +#include "ctl.h" +#include "str.h" + +#include +#include +#include +#include + +int +ctl_init(const char *dir, const char *file) +{ + if (str_empty(dir) || str_empty(file)) { + errno = EINVAL; + return -1; + } + + if (mkdir(dir, 0700) == -1 && errno != EEXIST) { + perror("mkdir"); + return -1; + } + + const char *strs[] = {dir, "/", file}; + char *path = str_cat(strs, 3); + + if (!path) + return -1; + + int fd = socket(AF_UNIX, SOCK_DGRAM, 0); + + if (fd == -1) { + int err = errno; + free(path); + errno = err; + return -1; + } + + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + }; + + str_cpy(sun.sun_path, path, sizeof(sun.sun_path) - 1); + free(path); + unlink(sun.sun_path); + + if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + int err = errno; + close(fd); + errno = err; + return -1; + } + + return fd; +} + +int +ctl_connect(int fd, const char *dir, const char *file) +{ + if (fd < 0 || str_empty(dir) || str_empty(file)) { + errno = EINVAL; + return -1; + } + + const char *strs[] = {dir, "/", file}; + char *path = str_cat(strs, 3); + + if (!path) + return -1; + + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + }; + + str_cpy(sun.sun_path, path, sizeof(sun.sun_path) - 1); + free(path); + + return connect(fd, (struct sockaddr *)&sun, sizeof(sun)); +} diff --git a/src/ctl.h b/src/ctl.h new file mode 100644 index 0000000..b4593d3 --- /dev/null +++ b/src/ctl.h @@ -0,0 +1,19 @@ +#pragma once + +enum ctl_type { + CTL_UNKNOWN, + CTL_PING, + CTL_PONG, +}; + +struct ctl_msg { + enum ctl_type type; + union { + struct { + enum ctl_type type; + } unknown; + }; +}; + +int ctl_init (const char *, const char *); +int ctl_connect (int, const char *, const char *); diff --git a/src/main.c b/src/main.c index 3d2cb84..d1d852a 100644 --- a/src/main.c +++ b/src/main.c @@ -1,24 +1,17 @@ #include "common.h" -#include "db.h" +#include "ctl.h" +#include "iface.h" #include "ip.h" #include "option.h" #include "str.h" #include "tun.h" -#include "iface.h" #include -#include -#include +#include #include #include #include -#include -#include -#include - -#include -#include #include "../mud/mud.h" @@ -26,10 +19,6 @@ #define O_CLOEXEC 0 #endif -#ifndef PACKAGE_VERSION -#define PACKAGE_VERSION "unknown" -#endif - #define GT_MTU(X) ((X)-28) static struct { @@ -79,6 +68,9 @@ fd_set_nonblock(int fd) { int ret; + if (fd == -1) + return; + do { ret = fcntl(fd, F_GETFL, 0); } while (ret == -1 && errno == EINTR); @@ -377,24 +369,31 @@ main(int argc, char **argv) gt_setup_mtu(mud, tun_name); + int ctl_fd = ctl_init("/run/" PACKAGE_NAME, tun_name); + + if (ctl_fd == -1) { + perror("gt_setup_ctl"); + return 1; + } + int mud_fd = mud_get_fd(mud); fd_set_nonblock(tun_fd); fd_set_nonblock(mud_fd); - - if (icmp_fd != -1) - fd_set_nonblock(icmp_fd); + fd_set_nonblock(icmp_fd); + fd_set_nonblock(ctl_fd); gt_log("running...\n"); fd_set rfds; FD_ZERO(&rfds); - int last_fd = 1 + MAX(tun_fd, MAX(mud_fd, icmp_fd)); + int last_fd = 1 + MAX(tun_fd, MAX(mud_fd, MAX(ctl_fd, icmp_fd))); while (!gt.quit) { FD_SET(tun_fd, &rfds); FD_SET(mud_fd, &rfds); + FD_SET(ctl_fd, &rfds); if (icmp_fd != -1) FD_SET(icmp_fd, &rfds); @@ -407,11 +406,13 @@ main(int argc, char **argv) } if (icmp_fd != -1 && FD_ISSET(icmp_fd, &rfds)) { + struct ip_common ic; struct sockaddr_storage ss; socklen_t sl = sizeof(ss); + ssize_t r = recvfrom(icmp_fd, gt.buf.data, gt.buf.size, 0, (struct sockaddr *)&ss, &sl); - struct ip_common ic; + if (!ip_get_common(&ic, gt.buf.data, r)) { int mtu = ip_get_mtu(&ic, gt.buf.data, r); if (mtu > 0) { @@ -421,6 +422,40 @@ main(int argc, char **argv) } } + if (FD_ISSET(ctl_fd, &rfds)) { + struct ctl_msg msg; + struct ctl_msg reply; + + struct sockaddr_storage ss; + socklen_t sl = sizeof(ss); + + ssize_t r = recvfrom(ctl_fd, &msg, sizeof(msg), 0, + (struct sockaddr *)&ss, &sl); + + if (r == (ssize_t)sizeof(msg)) { + switch (msg.type) { + case CTL_PING: + reply = (struct ctl_msg){ + .type = CTL_PONG, + }; + break; + default: + reply = (struct ctl_msg){ + .type = CTL_UNKNOWN, + .unknown = { + .type = msg.type, + }, + }; + break; + } + if (sendto(ctl_fd, &reply, sizeof(reply), 0, + (const struct sockaddr *)&ss, sl) == -1) + perror("sendto(ctl)"); + } else if (r == -1 && errno != EAGAIN) { + perror("recvfrom(ctl)"); + } + } + if (FD_ISSET(tun_fd, &rfds)) { size_t size = 0; diff --git a/src/mainctl.c b/src/mainctl.c new file mode 100644 index 0000000..0f7fd1a --- /dev/null +++ b/src/mainctl.c @@ -0,0 +1,93 @@ +#include "common.h" + +#include "ctl.h" +#include "option.h" +#include "str.h" + +#include +#include + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +static struct { + char *dev; + int version; +} gt = {}; + +static int +gt_setup_option(int argc, char **argv) +{ + // clang-format off + + struct option opts[] = { + { "dev", >.dev, option_str }, + { "version", NULL, option_option }, + { NULL }, + }; + + // clang-format on + + if (option(opts, argc, argv)) + return 1; + + gt.version = option_is_set(opts, "version"); + + return 0; +} + +int +main(int argc, char **argv) +{ + if (gt_setup_option(argc, argv)) + return 1; + + if (gt.version) { + gt_print(PACKAGE_VERSION "\n"); + return 0; + } + + int ctl_fd = ctl_init("/run/" PACKAGE_NAME, "client"); + + if (ctl_fd == -1) { + perror("ctl_init"); + return 1; + } + + if (ctl_connect(ctl_fd, "/run/" PACKAGE_NAME, gt.dev) == -1) { + perror("ctl_connect"); + return 1; + } + + struct ctl_msg msg = { + .type = CTL_PING, + }; + + if (send(ctl_fd, &msg, sizeof(msg), 0) == -1) { + perror("send"); + return 1; + } + + struct ctl_msg reply; + + if (recv(ctl_fd, &reply, sizeof(reply), 0) == -1) { + perror("recv"); + return 1; + } + + switch (reply.type) { + case CTL_PONG: + gt_print("PONG!\n"); + break; + case CTL_UNKNOWN: + gt_print("Unknown command: %i\n", reply.unknown.type); + break; + default: + gt_print("Bad reply from server: %i\n", reply.type); + } + + close(ctl_fd); + + return 0; +}