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:
M | config.mk | | | 4 | ++++ |
M | sacc.c | | | 72 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- |
A | tls.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