commit cbb100cc21f32be5fc6d99607251c6186a5f53c8
parent d6e781f2935dd7786ecc83e17a452f92a62b4252
Author: sin <sin@2f30.org>
Date: Tue, 22 Mar 2016 11:36:17 +0000
add syslog + daemonization support
Diffstat:
M | stun.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)