stun

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

commit cd801d3eefc9654dd2f56d4944eaa245eb581c9f
parent 965324af5e5e7826cf87d5c760e8298f5e47161e
Author: sin <sin@2f30.org>
Date:   Tue, 12 Apr 2016 16:52:04 +0100

split out client/server code

Diffstat:
MMakefile | 6+++---
Aclient.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Aserver.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mstun.c | 186++++++++++++++++++-------------------------------------------------------------
Mstun.h | 10++++++++++
5 files changed, 182 insertions(+), 148 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,9 +1,9 @@ include config.mk DISTFILES = Makefile README WHATSNEW UNLICENSE arg.h auth.c \ - config.mk crypto.c dev_bsd.c dev_linux.c log.c \ - netpkt.c stun.8 stun.c stun.h util.c -OBJ = $(EXTRAOBJ) auth.o crypto.o log.o netpkt.o stun.o util.o + client.c config.mk crypto.c dev_bsd.c dev_linux.c log.c \ + netpkt.c server.c stun.8 stun.c stun.h util.c +OBJ = $(EXTRAOBJ) auth.o client.o crypto.o log.o netpkt.o server.o stun.o util.o BIN = stun all: $(BIN) diff --git a/client.c b/client.c @@ -0,0 +1,53 @@ +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#include "stun.h" + +int +clientconnect(char *host, char *port) +{ + struct addrinfo hints, *ai, *p; + int ret, netfd; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + if ((ret = getaddrinfo(host, port, &hints, &ai))) + logerr("getaddrinfo: %s", gai_strerror(ret)); + + for (p = ai; p; p = p->ai_next) { + if ((netfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + continue; + if (connect(netfd, p->ai_addr, p->ai_addrlen) < 0) { + close(netfd); + continue; + } + break; + } + freeaddrinfo(ai); + if (!p) { + close(netfd); + logwarn("failed to connect to %s:%s", host, port); + return -1; + } + + setnonblock(netfd, 1); + setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, (int []){1}, sizeof(int)); + setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int)); + + if (response(netfd) < 0 || challenge(netfd) < 0) { + close(netfd); + logwarn("challenge-response failed"); + return -1; + } + return netfd; +} diff --git a/server.c b/server.c @@ -0,0 +1,75 @@ +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <errno.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#include "stun.h" + +int +serverinit(char *host, char *port) +{ + struct addrinfo hints, *ai, *p; + int ret, listenfd; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + if ((ret = getaddrinfo(host, port, &hints, &ai))) + logerr("getaddrinfo: %s", gai_strerror(ret)); + + for (p = ai; p; p = p->ai_next) { + if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + continue; + setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (int []){1}, + sizeof(int)); + if (bind(listenfd, p->ai_addr, p->ai_addrlen) < 0) { + close(listenfd); + continue; + } + if (listen(listenfd, 5) < 0) { + close(listenfd); + continue; + } + break; + } + if (!p) + logerr("failed to bind socket"); + freeaddrinfo(ai); + return listenfd; +} + +int +serveraccept(int listenfd) +{ + struct sockaddr_in remote; + int netfd; + + netfd = accept(listenfd, (struct sockaddr *)&remote, + (socklen_t []){sizeof(remote)}); + if (netfd < 0) { + if (errno != ECONNABORTED) + logwarn("accept failed"); + return -1; + } + + setnonblock(netfd, 1); + setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, (int []){1}, sizeof(int)); + setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int)); + + if (challenge(netfd) < 0 || response(netfd) < 0) { + close(netfd); + logwarn("challenge-response failed"); + return -1; + } + return netfd; +} diff --git a/stun.c b/stun.c @@ -41,17 +41,8 @@ * */ -#include <sys/types.h> #include <sys/resource.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include <errno.h> -#include <fcntl.h> #include <poll.h> #include <signal.h> #include <stdio.h> @@ -106,124 +97,6 @@ tunnel(int netfd, int devfd) return 0; } -int -serversetup(int devfd) -{ - struct addrinfo hints, *ai, *p; - struct sockaddr_in remote; - int ret, netfd, listenfd; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - - if ((ret = getaddrinfo(bindaddr, port, &hints, &ai))) - logerr("getaddrinfo: %s", gai_strerror(ret)); - - for (p = ai; p; p = p->ai_next) { - if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - continue; - setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (int []){1}, - sizeof(int)); - if (bind(listenfd, p->ai_addr, p->ai_addrlen) < 0) { - close(listenfd); - continue; - } - if (listen(listenfd, 5) < 0) { - close(listenfd); - continue; - } - break; - } - if (!p) - logerr("failed to bind socket"); - freeaddrinfo(ai); - - revokeprivs(); -#if defined(__OpenBSD__) - if (pledge("stdio inet", NULL) < 0) - logerr("pledge failed"); -#endif - - for (;;) { - netfd = accept(listenfd, (struct sockaddr *)&remote, - (socklen_t []){sizeof(remote)}); - if (netfd < 0) { - if (errno != ECONNABORTED) - logwarn("accept failed"); - continue; - } - if (debug) - logdbg("remote peer connected: %s", - inet_ntoa(remote.sin_addr)); - - setnonblock(netfd, 1); - setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, (int []){1}, sizeof(int)); - setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int)); - - if (challenge(netfd) < 0 || response(netfd) < 0) { - logwarn("challenge-response failed"); - goto err; - } - - tunnel(netfd, devfd); -err: - netreset(); - close(netfd); - if (debug) - logdbg("remote peer disconnected: %s", - inet_ntoa(remote.sin_addr)); - } -} - -int -clientsetup(int devfd) -{ - struct addrinfo hints, *ai, *p; - int ret, netfd; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - if ((ret = getaddrinfo(host, port, &hints, &ai))) - logerr("getaddrinfo: %s", gai_strerror(ret)); - - for (p = ai; p; p = p->ai_next) { - if ((netfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - continue; - if (connect(netfd, p->ai_addr, p->ai_addrlen) < 0) { - close(netfd); - continue; - } - break; - } - freeaddrinfo(ai); - if (!p) { - close(netfd); - logwarn("failed to connect to %s:%s", host, port); - return -1; - } - if (debug) - logdbg("connected to %s:%s", host, port); - - setnonblock(netfd, 1); - setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, (int []){1}, sizeof(int)); - setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int)); - - if (response(netfd) < 0 || challenge(netfd) < 0) { - logwarn("challenge-response failed"); - goto err; - } - - tunnel(netfd, devfd); -err: - netreset(); - close(netfd); - logwarn("connection to %s:%s dropped", host, port); - return -1; -} - void usage(void) { @@ -237,7 +110,7 @@ main(int argc, char *argv[]) { struct rlimit rlim; char *arg, *pw; - int devfd; + int devfd, listenfd, netfd; ARGBEGIN { case 'd': @@ -274,37 +147,60 @@ main(int argc, char *argv[]) if (argc != 1 || !(sflag ^ (host != NULL))) usage(); + /* disable core dumps as memory contains the pre-shared key */ + rlim.rlim_cur = rlim.rlim_max = 0; + if (setrlimit(RLIMIT_CORE, &rlim) < 0) + logerr("failed to disable core dumps"); + signal(SIGPIPE, SIG_IGN); if (!debug) daemon(0, 0); loginit("stun"); - devfd = devopen(argv[0]); - /* disable core dumps as memory contains the pre-shared key */ - rlim.rlim_cur = rlim.rlim_max = 0; - if (setrlimit(RLIMIT_CORE, &rlim) < 0) - logerr("failed to disable core dumps"); + /* initialize tun/tap device */ + devfd = devopen(argv[0]); + /* initialize crypto engine */ if (!(pw = getenv("STUNPW"))) logerr("STUNPW is not set"); cryptoinit(pw); memset(pw, 0, strlen(pw)); + /* initialize networking engine */ netinit(); - - if (sflag) - return serversetup(devfd); - - revokeprivs(); + if (sflag) { + listenfd = serverinit(bindaddr, port); + revokeprivs(); #if defined(__OpenBSD__) - if (pledge("stdio dns inet", NULL) < 0) - logerr("pledge failed"); + if (pledge("stdio inet", NULL) < 0) + logerr("pledge failed"); #endif - - /* auto-reconnect client */ - for (;;) { - clientsetup(devfd); - sleep(RECONNECTTIMEO); + for (;;) { + if ((netfd = serveraccept(listenfd)) < 0) { + netreset(); + continue; + } + tunnel(netfd, devfd); + close(netfd); + netreset(); + } + } else { + revokeprivs(); +#if defined(__OpenBSD__) + if (pledge("stdio dns inet", NULL) < 0) + logerr("pledge failed"); +#endif + for (;;) { + if ((netfd = clientconnect(host, port)) < 0) { + netreset(); + sleep(RECONNECTTIMEO); + continue; + } + tunnel(netfd, devfd); + close(netfd); + netreset(); + sleep(RECONNECTTIMEO); + } } return 0; } diff --git a/stun.h b/stun.h @@ -26,6 +26,9 @@ extern char *cipher; int challenge(int); int response(int); +/* client.c */ +int clientconnect(char *, char *); + /* crypto.c */ void cryptoinit(char *); size_t cryptononcelen(void); @@ -54,6 +57,13 @@ int netread(int, unsigned char *, size_t, size_t *); void netreset(void); void netinit(void); +/* server.c */ +int serverinit(char *, char *); +int serveraccept(int); + +/* stun.c */ +int tunnel(int, int); + /* util.c */ void pack16(unsigned char *, uint16_t); uint16_t unpack16(unsigned char *);