diff options
Diffstat (limited to 'server.c')
-rw-r--r-- | server.c | 124 |
1 files changed, 102 insertions, 22 deletions
diff --git a/server.c b/server.c index 20d94e3..9d7be14 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,10 +12,22 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this Program, or any covered work, by linking or + * combining it with OpenSSL (or a modified version of that library), + * containing parts covered by the terms of the OpenSSL License and the + * original SSLeay license, the licensors of this Program grant you + * additional permission to convey the resulting work. Corresponding + * Source for a non-source form of such a combination shall include the + * source code for the parts of OpenSSL used as well as that of the + * covered work. */ #include <assert.h> #include <err.h> +#include <limits.h> #include <netdb.h> #include <netinet/in.h> #include <stdarg.h> @@ -30,29 +42,47 @@ #include "bounce.h" static struct tls *client; +static struct tls_config *config; -void serverConfig(bool insecure, const char *cert, const char *priv) { - struct tls_config *config = tls_config_new(); +void serverConfig( + bool insecure, const char *trust, const char *cert, const char *priv +) { + int error = 0; + char buf[PATH_MAX]; + config = tls_config_new(); if (!config) errx(EX_SOFTWARE, "tls_config_new"); - int error = tls_config_set_ciphers(config, "compat"); - if (error) { - errx(EX_SOFTWARE, "tls_config_set_ciphers: %s", tls_config_error(config)); - } - if (insecure) { tls_config_insecure_noverifycert(config); tls_config_insecure_noverifyname(config); } + if (trust) { + tls_config_insecure_noverifyname(config); + for (int i = 0; configPath(buf, sizeof(buf), trust, i); ++i) { + error = tls_config_set_ca_file(config, buf); + if (!error) break; + } + if (error) errx(EX_NOINPUT, "%s: %s", trust, tls_config_error(config)); + } + if (cert) { - error = tls_config_set_keypair_file(config, cert, (priv ? priv : cert)); - if (error) { - errx( - EX_SOFTWARE, "tls_config_set_keypair_file: %s", - tls_config_error(config) - ); + for (int i = 0; configPath(buf, sizeof(buf), cert, i); ++i) { + if (priv) { + error = tls_config_set_cert_file(config, buf); + } else { + error = tls_config_set_keypair_file(config, buf, buf); + } + if (!error) break; + } + if (error) errx(EX_NOINPUT, "%s: %s", cert, tls_config_error(config)); + } + if (priv) { + for (int i = 0; configPath(buf, sizeof(buf), priv, i); ++i) { + error = tls_config_set_key_file(config, buf); + if (!error) break; } + if (error) errx(EX_NOINPUT, "%s: %s", priv, tls_config_error(config)); } client = tls_client(); @@ -60,7 +90,6 @@ void serverConfig(bool insecure, const char *cert, const char *priv) { error = tls_configure(client, config); if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client)); - tls_config_free(config); } int serverConnect(const char *bindHost, const char *host, const char *port) { @@ -114,21 +143,32 @@ int serverConnect(const char *bindHost, const char *host, const char *port) { if (sock < 0) err(EX_UNAVAILABLE, "%s:%s", host, port); freeaddrinfo(head); - int yes = 1; - error = setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &yes, sizeof(yes)); - if (error) err(EX_OSERR, "setsockopt"); - error = tls_connect_socket(client, sock, host); if (error) errx(EX_PROTOCOL, "tls_connect: %s", tls_error(client)); - error = tls_handshake(client); + do { + error = tls_handshake(client); + } while (error == TLS_WANT_POLLIN || error == TLS_WANT_POLLOUT); if (error) errx(EX_PROTOCOL, "tls_handshake: %s", tls_error(client)); + tls_config_clear_keys(config); return sock; } +void serverClose(void) { + tls_close(client); + tls_free(client); +} + +void serverPrintCert(void) { + size_t len; + const byte *pem = tls_peer_cert_chain_pem(client, &len); + printf("subject= %s\n", tls_peer_cert_subject(client)); + fwrite(pem, len, 1, stdout); +} + void serverSend(const char *ptr, size_t len) { - if (verbose) fprintf(stderr, "\x1B[31m%.*s\x1B[m", (int)len, ptr); + verboseLog("<<", ptr, len); while (len) { ssize_t ret = tls_write(client, ptr, len); if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) continue; @@ -148,6 +188,46 @@ void serverFormat(const char *format, ...) { serverSend(buf, len); } +enum { QueueCap = 256 }; +static struct { + size_t enq; + size_t deq; + char *msgs[QueueCap]; +} queue; + +void serverDequeue(void) { + if (queue.enq - queue.deq) { + char *msg = queue.msgs[queue.deq++ % QueueCap]; + serverSend(msg, strlen(msg)); + free(msg); + } else { + struct itimerval timer = { .it_value = {0} }; + int error = setitimer(ITIMER_REAL, &timer, NULL); + if (error) err(EX_OSERR, "setitimer"); + } +} + +struct timeval serverQueueInterval = { .tv_usec = 1000 * 200 }; + +void serverEnqueue(const char *format, ...) { + if (queue.enq - queue.deq == QueueCap) { + warnx("server send queue full"); + serverDequeue(); + } else if (queue.enq == queue.deq) { + struct itimerval timer = { + .it_interval = serverQueueInterval, + .it_value = { .tv_usec = 1 }, + }; + int error = setitimer(ITIMER_REAL, &timer, NULL); + if (error) err(EX_OSERR, "setitimer"); + } + va_list ap; + va_start(ap, format); + int len = vasprintf(&queue.msgs[queue.enq++ % QueueCap], format, ap); + va_end(ap); + if (len < 0) err(EX_OSERR, "vasprintf"); +} + void serverRecv(void) { static char buf[MessageCap]; static size_t len; @@ -164,7 +244,7 @@ void serverRecv(void) { crlf = memmem(line, &buf[len] - line, "\r\n", 2); if (!crlf) break; crlf[0] = '\0'; - if (verbose) fprintf(stderr, "\x1B[32m%s\x1B[m\n", line); + verboseLog(">>", line, crlf - line); const char *ping = line; if (ping[0] == '@') { ping += strcspn(ping, " "); |