tAdd support for Gopher over TLS. - sacc - [fork] customized build of sacc, the simple console gopher client
(HTM) git clone git://src.adamsgaard.dk/sacc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
(DIR) commit 23ed5ec549dc587313402809caf19f0c5ed80282
(DIR) parent 1f92f24f9061cd4e4ecdc72cc86fbda5cd382724
(HTM) 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.
Signed-off-by: Anders Damsgaard <anders@adamsgaard.dk>
Diffstat:
M config.mk | 4 ++++
M sacc.c | 72 ++++++++++++++++++++++++++-----
A tls.h | 15 +++++++++++++++
3 files changed, 81 insertions(+), 10 deletions(-)
---
(DIR) diff --git a/config.mk b/config.mk
t@@ -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
(DIR) diff --git a/sacc.c b/sacc.c
t@@ -19,6 +19,7 @@
#include <sys/wait.h>
#include "common.h"
+#include "tls.h"
#include "config.h"
t@@ -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, ...);
t@@ -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, ...)
t@@ -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)
{
t@@ -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;
}
t@@ -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);
t@@ -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;
}
t@@ -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;
t@@ -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;
}
t@@ -553,7 +601,7 @@ download(Item *item, int dest)
errno = 0;
}
- close(src);
+ close_wrap(src);
return (r == 0 && w == 0);
}
t@@ -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");
t@@ -898,7 +946,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;
}
(DIR) diff --git a/tls.h b/tls.h
t@@ -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