stun

simple point to point tunnel
git clone git://git.2f30.org/stun
Log | Files | Refs | README

commit cbb100cc21f32be5fc6d99607251c6186a5f53c8
parent d6e781f2935dd7786ecc83e17a452f92a62b4252
Author: sin <sin@2f30.org>
Date:   Tue, 22 Mar 2016 11:36:17 +0000

add syslog + daemonization support

Diffstat:
Mstun.c | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 124 insertions(+), 37 deletions(-)

diff --git a/stun.c b/stun.c @@ -15,14 +15,16 @@ #include <arpa/inet.h> #include <netdb.h> -#include <err.h> #include <errno.h> #include <fcntl.h> #include <poll.h> +#include <signal.h> +#include <stdarg.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <syslog.h> #include <unistd.h> #include <openssl/aes.h> @@ -39,8 +41,58 @@ char *argv0; char *host; char *port = "12080"; int debug; +int foreground; int sflag; +void +logdbg(char *msg, ...) +{ + va_list ap; + + if (debug) { + va_start(ap, msg); + if (foreground) { + vfprintf(stderr, msg, ap); + fputc('\n', stderr); + } else { + vsyslog(LOG_DAEMON | LOG_DEBUG, msg, ap); + } + va_end(ap); + } +} + +void +logwarn(char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + if (foreground) { + vfprintf(stderr, msg, ap); + fputc('\n', stderr); + } else { + vsyslog(LOG_DAEMON | LOG_WARNING, msg, ap); + } + va_end(ap); +} + +void +logerr(char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + if (foreground) { + fputs("stun: ", stderr); + vfprintf(stderr, msg, ap); + fputc('\n', stderr); + } else { + vsyslog(LOG_DAEMON | LOG_ERR, msg, ap); + } + va_end(ap); + exit(1); +} + int aesinit(unsigned char *pw, int pwlen, EVP_CIPHER_CTX *ectx, EVP_CIPHER_CTX *dctx) { @@ -50,7 +102,7 @@ aesinit(unsigned char *pw, int pwlen, EVP_CIPHER_CTX *ectx, EVP_CIPHER_CTX *dctx ret = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), NULL, pw, pwlen, nrounds, key, iv); if (ret != 32) - errx(1, "wrong key size: %d\n", ret); + logerr("wrong key size: %d", ret); EVP_CIPHER_CTX_init(ectx); EVP_EncryptInit_ex(ectx, EVP_aes_256_cbc(), NULL, key, iv); EVP_CIPHER_CTX_init(dctx); @@ -123,7 +175,7 @@ opentun(char *tundev) fd = open("/dev/net/tun", O_RDWR); if (fd < 0) - err(1, "open %s", "/dev/net/tun"); + logerr("failed to open %s", "/dev/net/tun"); memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; @@ -131,23 +183,23 @@ opentun(char *tundev) ifr.ifr_name[IFNAMSIZ - 1] = '\0'; ret = ioctl(fd, TUNSETIFF, &ifr); if (ret < 0) - err(1, "ioctl: TUNSETIFF %s", tundev); + logerr("failed to set TUNSETIFF on %s", tundev); /* dummy socket so we can manipulate the params */ s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) - err(1, "socket"); + logerr("failed to create socket"); ret = ioctl(s, SIOCGIFFLAGS, &ifr); if (ret < 0) - err(1, "ioctl: SIOCGIFFLAGS %s", tundev); + logerr("failed to set SIOCGIFFLAGS on %s", tundev); ifr.ifr_flags |= IFF_UP | IFF_RUNNING | IFF_POINTOPOINT; ret = ioctl(s, SIOCSIFFLAGS, &ifr); if (ret < 0) - err(1, "ioctl: SIOCSIFFLAGS %s", tundev); + logerr(1, "failed to set SIOCSIFFLAGS on %s", tundev); ifr.ifr_mtu = MTU; ret = ioctl(s, SIOCSIFMTU, &ifr); if (ret < 0) - err(1, "ioctl: SIOCSIFMTU %s", tundev); + logerr(1, "failed to set MTU on %s", tundev); close(s); return fd; @@ -173,14 +225,14 @@ opentun(char *tundev) fd = open(tundev, O_RDWR); if (fd < 0) - err(1, "open %s", tundev); + logerr("failed to open %s", tundev); if (ioctl(fd, TUNSIFMODE, &mode) < 0) - err(1, "ioctl: TUNSIFMODE %s", tundev); + logerr("failed to set TUNSIFMODE on %s", tundev); if (ioctl(fd, TUNGIFINFO, &ti) < 0) - err(1, "ioctl: TUNGIFINFO %s", tundev); + logerr("failed to set TUNGIFINFO on %s", tundev); ti.mtu = MTU; if (ioctl(fd, TUNSIFINFO, &ti) < 0) - err(1, "ioctl: TUNSIFINFO %s", tundev); + logerr("failed to set TUNSIFINFO on %s", tundev); return fd; } @@ -197,7 +249,7 @@ writetun(int fd, unsigned char *buf, int len) iov[1].iov_len = len; n = writev(fd, iov, 2); if (n < 0) - err(1, "writev"); + logerr("writev failed"); else if (n > 0) return n - sizeof(type); return n; @@ -216,7 +268,7 @@ readtun(int fd, unsigned char *buf, int len) iov[1].iov_len = len; n = readv(fd, iov, 2); if (n < 0) - err(1, "readv"); + logerr("readv failed"); else if (n > 0) return n - sizeof(type); return n; @@ -260,7 +312,7 @@ writeall(int fd, void *buf, int len) while (len > 0) { n = write(fd, p + total, len); if (n < 0) { - warn("write"); + logwarn("write failed"); total = -1; break; } else if (n == 0) { @@ -293,7 +345,7 @@ readall(int fd, void *buf, int len) while (len > 0) { n = read(fd, p + total, len); if (n < 0) { - warn("read"); + logwarn("read failed"); total = -1; break; } else if (n == 0) { @@ -318,7 +370,7 @@ readnet(int fd, unsigned char *buf, int len) return n; pktlen = unpack16(hdr); if (pktlen < 0 || pktlen > MTU + AES_BLOCK_SIZE) { - warnx("bogus payload length: %d", pktlen); + logwarn("bogus payload length: %d", pktlen); return -1; } n = readall(fd, encbuf, pktlen); @@ -345,10 +397,10 @@ challenge(int netfd) ret = poll(pfd, 1, CHALLENGETIMEO); switch (ret) { case -1: - warn("poll"); + logwarn("poll failed"); return -1; case 0: - warnx("challenge-response timed out"); + logwarn("challenge-response timed out"); return -1; default: if (pfd[0].revents & (POLLIN | POLLHUP)) { @@ -390,10 +442,10 @@ tunnel(int netfd, int tunfd) for (;;) { ret = poll(pfd, 2, -1); if (ret < 0) - err(1, "poll"); + logerr("poll failed"); if (pfd[0].revents & (POLLERR | POLLNVAL) || pfd[1].revents & (POLLERR | POLLNVAL)) - errx(1, "bad fd"); + logerr("bad fd in poll set"); if (pfd[0].revents & (POLLIN | POLLHUP)) if ((n = readnet(netfd, buf, MTU)) <= 0 || (n = writetun(tunfd, buf, n)) <= 0) @@ -420,7 +472,7 @@ serversetup(int tunfd) ret = getaddrinfo(NULL, port, &hints, &ai); if (ret != 0) - errx(1, "getaddrinfo: %s", gai_strerror(ret)); + logerr("getaddrinfo: %s", gai_strerror(ret)); for (p = ai; p; p = p->ai_next) { listenfd = socket(AF_INET, SOCK_STREAM, 0); @@ -436,28 +488,27 @@ serversetup(int tunfd) break; } if (!p) - errx(1, "failed to bind socket"); + logerr("failed to bind socket"); freeaddrinfo(ai); ret = listen(listenfd, 5); if (ret < 0) - err(1, "listen"); + logerr("listen failed"); for (;;) { netfd = accept(listenfd, (struct sockaddr *)&remote, (socklen_t []){sizeof(remote)}); if (netfd < 0) - err(1, "accept"); + logerr("accept failed"); if (debug) - printf("remote peer connected: %s\n", + logdbg("remote peer connected: %s", inet_ntoa(remote.sin_addr)); setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int)); ret = challenge(netfd); if (ret < 0) { - if (debug) - warnx("challenge-response failed"); + logwarn("challenge-response failed"); close(netfd); continue; } @@ -465,7 +516,7 @@ serversetup(int tunfd) tunnel(netfd, tunfd); close(netfd); if (debug) - printf("remote peer disconnected: %s\n", + logdbg("remote peer disconnected: %s", inet_ntoa(remote.sin_addr)); } } @@ -481,7 +532,7 @@ clientsetup(int tunfd) hints.ai_socktype = SOCK_STREAM; ret = getaddrinfo(host, port, &hints, &ai); if (ret != 0) - errx(1, "getaddrinfo: %s", gai_strerror(ret)); + logerr("getaddrinfo: %s", gai_strerror(ret)); for (p = ai; p; p = p->ai_next) { netfd = socket(AF_INET, SOCK_STREAM, 0); @@ -495,26 +546,55 @@ clientsetup(int tunfd) break; } if (!p) - errx(1, "failed to connect to %s", host); + logerr("failed to connect to %s", host); freeaddrinfo(ai); setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int)); ret = response(netfd); if (ret < 0) - errx(1, "failed to respond to challenge"); + logerr("failed to respond to challenge"); ret = tunnel(netfd, tunfd); - warnx("connection to %s:%s dropped", host, port); + logwarn("connection to %s:%s dropped", host, port); close(netfd); return ret; } +int +daemonize(void) +{ + int fd; + + if (foreground) + return 0; + switch (fork()) { + case -1: + return -1; + case 0: + break; + default: + _exit(0); + } + if (setsid() < 0) + return -1; + chdir("/"); + fd = open("/dev/null", O_RDWR); + if (fd != -1) { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) + close(fd); + } + return 0; +} + void usage(void) { - fprintf(stderr, "usage: %s [-d] -s [-p port] interface\n", argv0); - fprintf(stderr, " %s [-d] -h host [-p port] interface\n", argv0); + fprintf(stderr, "usage: stun [-df] -s [-p port] interface\n"); + fprintf(stderr, " stun [-df] -h host [-p port] interface\n"); exit(1); } @@ -528,6 +608,9 @@ main(int argc, char *argv[]) case 'd': debug = 1; break; + case 'f': + foreground = 1; + break; case 's': sflag = 1; break; @@ -544,13 +627,17 @@ main(int argc, char *argv[]) if (argc != 1 || !(sflag ^ (host != NULL))) usage(); + signal(SIGPIPE, SIG_IGN); + daemonize(); + openlog("stun", LOG_PID | LOG_NDELAY, LOG_DAEMON); + tunfd = opentun(argv[0]); pw = getenv("STUNPW"); if (!pw) - errx(1, "STUNPW is not set"); + logerr("STUNPW is not set"); if (aesinit((unsigned char *)pw, strlen(pw), &enc, &dec) < 0) - errx(1, "couldn't initialize AES cipher"); + logerr("couldn't initialize AES cipher"); explicit_bzero(pw, strlen(pw)); if (sflag)