stun

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

commit 06f762a2c6bed9bd942a92daa2cad841c0f5f93f
parent 7f965011f8e27aaafb8617b0d58b90173121da60
Author: sin <sin@2f30.org>
Date:   Mon, 21 Mar 2016 11:08:59 +0000

add primitive challenge-response auth

server sends an encrypted random integer N and client decrypts it,
adds one and sends the encrypted result back.

Diffstat:
Mstun.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 64 insertions(+), 6 deletions(-)

diff --git a/stun.c b/stun.c @@ -135,18 +135,33 @@ readtun(int fd, unsigned char *buf, int len) } void -pack16(unsigned char *buf, int n) +pack16(unsigned char *buf, uint16_t n) { buf[0] = n >> 8 & 0xff; buf[1] = n & 0xff; } -int +uint16_t unpack16(unsigned char *buf) { return (buf[0] << 8) | buf[1]; } +void +pack32(unsigned char *buf, uint32_t n) +{ + buf[0] = n >> 24 & 0xff; + buf[1] = n >> 16 & 0xff; + buf[2] = n >> 8 & 0xff; + buf[3] = n & 0xff; +} + +uint32_t +unpack32(unsigned char *buf) +{ + return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; +} + /* handles partial writes */ int writeall(int fd, void *buf, int len) @@ -209,6 +224,7 @@ int readnet(int fd, unsigned char *buf, int len) { unsigned char decbuf[MTU + AES_BLOCK_SIZE + HDRLEN]; + unsigned char encbuf[MTU + AES_BLOCK_SIZE + HDRLEN]; unsigned char hdr[HDRLEN]; int n, pktlen; @@ -220,15 +236,44 @@ readnet(int fd, unsigned char *buf, int len) warnx("bogus payload length: %d", pktlen); return -1; } - n = readall(fd, buf, pktlen); + n = readall(fd, encbuf, pktlen); if (n <= 0) return n; - pktlen = aesdec(&dec, decbuf, buf, pktlen); + pktlen = aesdec(&dec, decbuf, encbuf, pktlen); memcpy(buf, decbuf, pktlen); return pktlen; } int +challenge(int netfd) +{ + unsigned char buf[4]; + uint32_t n, reply; + + pack32(buf, n = arc4random()); + if (writenet(netfd, buf, sizeof(buf)) <= 0 || + readnet(netfd, buf, sizeof(buf)) <= 0) + return -1; + reply = unpack32(buf); + return n + 1 == reply; +} + +int +response(int netfd) +{ + unsigned char buf[4]; + uint32_t reply; + + if (readnet(netfd, buf, sizeof(buf)) <= 0) + return -1; + reply = unpack32(buf); + pack32(buf, reply + 1); + if (writenet(netfd, buf, sizeof(buf)) <= 0) + return -1; + return 0; +} + +int loop(int netfd, int tunfd) { unsigned char buf[MTU + AES_BLOCK_SIZE + HDRLEN]; @@ -266,7 +311,9 @@ serversetup(int tunfd) listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd < 0) err(1, "socket"); + setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (int []){1}, sizeof(int)); + memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY); @@ -274,17 +321,24 @@ serversetup(int tunfd) ret = bind(listenfd, (struct sockaddr *)&local, sizeof(local)); if (ret < 0) err(1, "bind"); + ret = listen(listenfd, 5); if (ret < 0) err(1, "listen"); + for (;;) { netfd = accept(listenfd, (struct sockaddr *)&remote, (socklen_t []){sizeof(remote)}); - if (ret < 0) + if (netfd < 0) err(1, "accept"); + setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int)); if (debug) printf("client connected\n"); - setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int)); + ret = challenge(netfd); + if (ret < 0) { + close(netfd); + continue; + } loop(netfd, tunfd); close(netfd); } @@ -298,6 +352,7 @@ clientsetup(int tunfd) netfd = socket(AF_INET, SOCK_STREAM, 0); if (netfd < 0) err(1, "socket"); + memset(&remote, 0, sizeof(remote)); remote.sin_family = AF_INET; remote.sin_addr.s_addr = inet_addr(host); @@ -306,6 +361,9 @@ clientsetup(int tunfd) if (ret < 0) err(1, "connect"); setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int)); + ret = response(netfd); + if (ret < 0) + errx(1, "failed to respond to challenge"); return loop(netfd, tunfd); }