sacc

sacc(omys), simple console gopher client (mirror)
git clone https://git.parazyd.org/sacc
Log | Files | Refs | LICENSE

commit c3bb55bb797cb476a5f26b148e1572521e389313
parent eae2a995544b2b48c3a7debcb186a00aa0c400b3
Author: parazyd <parazyd@dyne.org>
Date:   Tue,  6 Apr 2021 13:24:32 +0200

Add support for Gopher over TLS.

This implementation uses libtls and acts on gophers:// URIs.

Diffstat:
Mconfig.mk | 4++++
Msacc.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Atls.h | 15+++++++++++++++
3 files changed, 81 insertions(+), 10 deletions(-)

diff --git a/config.mk b/config.mk @@ -12,3 +12,7 @@ LIBS=-lcurses # Define NEED_ASPRINTF and/or NEED_STRCASESTR in your cflags if your system does # not provide asprintf() or strcasestr(), respectively. #CFLAGS = -DNEED_ASPRINTF -DNEED_STRCASESTR + +# Define USE_TLS if you want Gopher over TLS support as gophers:// URIs +#CFLAGS = -DUSE_TLS +#LIBS = -lcurses -ltls diff --git a/sacc.c b/sacc.c @@ -19,6 +19,7 @@ #include <sys/wait.h> #include "common.h" +#include "tls.h" #include "config.h" @@ -27,6 +28,8 @@ static Item *mainentry; static int devnullfd; static int parent = 1; static int interactive; +static int dotls = 0; +static struct tls *tlsctx = NULL; static void (*diag)(char *fmt, ...); @@ -54,6 +57,40 @@ die(const char *fmt, ...) exit(1); } +static ssize_t +read_wrap(int s, void *buf, size_t bs) +{ + if (tlsctx) { + ssize_t r = TLS_WANT_POLLIN; + while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) + r = tls_read(tlsctx, buf, bs); + return r; + } + return read(s, buf, bs); +} + +static ssize_t +write_wrap(int fd, const void *buf, size_t nbyte) +{ + if (tlsctx) { + ssize_t r = TLS_WANT_POLLIN; + while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) + r = tls_write(tlsctx, buf, nbyte); + return r; + } + return write(fd, buf, nbyte); +} + +static int +close_wrap(int fd) +{ + if (tlsctx) { + tls_close(tlsctx); + tls_reset(tlsctx); + } + return close(fd); +} + #ifdef NEED_ASPRINTF int asprintf(char **s, const char *fmt, ...) @@ -435,18 +472,20 @@ getrawitem(int sock) buf = raw + (bn-1) * BUFSIZ; bs = BUFSIZ; } - } while ((n = read(sock, buf, bs)) > 0); + } while ((n = read_wrap(sock, buf, bs)) > 0); *buf = '\0'; if (n < 0) { - diag("Can't read socket: %s", strerror(errno)); + diag("Can't read socket: %s", + tlsctx ? tls_error(tlsctx) : strerror(errno)); clear(&raw); } return raw; } + static int sendselector(int sock, const char *selector) { @@ -458,14 +497,15 @@ sendselector(int sock, const char *selector) msg = p = xmalloc(ln); snprintf(msg, ln--, "%s\r\n", selector); - while ((n = write(sock, p, ln)) > 0) { + while ((n = write_wrap(sock, p, ln)) > 0) { ln -= n; p += n; } free(msg); if (n == -1) - diag("Can't send message: %s", strerror(errno)); + diag("Can't send message: %s", + tlsctx ? tls_error(tlsctx) : strerror(errno)); return n; } @@ -480,7 +520,7 @@ connectto(const char *host, const char *port) .ai_protocol = IPPROTO_TCP, }; struct addrinfo *addrs, *addr; - int r, sock = -1; + int r, t = 0, sock = -1; sigemptyset(&set); sigaddset(&set, SIGWINCH); @@ -497,9 +537,13 @@ connectto(const char *host, const char *port) addr->ai_protocol)) < 0) continue; if ((r = connect(sock, addr->ai_addr, addr->ai_addrlen)) < 0) { - close(sock); + close_wrap(sock); continue; } + if (dotls) { + tlsctx = tls_client(); + t = tls_connect_socket(tlsctx, sock, host); + } break; } @@ -514,6 +558,10 @@ connectto(const char *host, const char *port) host, port, strerror(errno)); goto err; } + if (t < 0) { + diag("Can't init TLS : %s", tls_error(tlsctx)); + goto err; + } sigprocmask(SIG_SETMASK, &oset, NULL); return sock; @@ -542,7 +590,7 @@ download(Item *item, int dest) } w = 0; - while ((r = read(src, buf, BUFSIZ)) > 0) { + while ((r = read_wrap(src, buf, BUFSIZ)) > 0) { while ((w = write(dest, buf, r)) > 0) r -= w; } @@ -553,7 +601,7 @@ download(Item *item, int dest) errno = 0; } - close(src); + close_wrap(src); return (r == 0 && w == 0); } @@ -615,7 +663,7 @@ fetchitem(Item *item) sendselector(sock, item->selector) < 0) return 0; raw = getrawitem(sock); - close(sock); + close_wrap(sock); if (raw == NULL || !*raw) { diag("Empty response from server"); @@ -900,7 +948,11 @@ moldentry(char *url) int parsed, ipv6; if (p = strstr(url, "://")) { - if (strncmp(url, "gopher", p - url)) + if (!strncmp(url, "gopher", p - url)) + dotls = 0; + else if (!strncmp(url, "gophers", p - url)) + dotls = 1; + else die("Protocol not supported: %.*s", p - url, url); host = p + 3; } diff --git a/tls.h b/tls.h @@ -0,0 +1,15 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef USE_TLS + +#define TLS_WANT_POLLIN 0 +#define TLS_WANT_POLLOUT 0 +#define tls_read(a,b,c) 0 +#define tls_write(a,b,c) 0 +#define tls_close(a) 0 +#define tls_reset(a) 0 +#define tls_error(a) 0 +#define tls_client() 0 +#define tls_connect_socket(a,b,c) 0 +#else +#include <tls.h> +#endif