TLS: use wrapper functions - sacc - sacc(omys), simple console gopher client | |
git clone git://bitreich.org/sacc/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65… | |
Log | |
Files | |
Refs | |
Tags | |
LICENSE | |
--- | |
commit 5a5611b3293eaac0b26832a54b845c6822736b65 | |
parent e3535c1405eac56a658886023b057944b4b91bc0 | |
Author: Quentin Rameau <[email protected]> | |
Date: Sat, 10 Apr 2021 15:56:05 +0200 | |
TLS: use wrapper functions | |
Diffstat: | |
M Makefile | 8 ++++---- | |
M config.mk | 12 ++++++++---- | |
A io.h | 17 +++++++++++++++++ | |
A io_clr.c | 63 +++++++++++++++++++++++++++++… | |
A io_tls.c | 129 +++++++++++++++++++++++++++++… | |
M sacc.c | 173 ++++++++---------------------… | |
6 files changed, 264 insertions(+), 138 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
@@ -6,7 +6,7 @@ include config.mk | |
BIN = sacc | |
MAN = $(BIN).1 | |
-OBJ = $(BIN:=.o) ui_$(UI).o | |
+OBJ = $(BIN:=.o) ui_$(UI).o io_$(IO).o | |
all: $(BIN) | |
@@ -14,9 +14,9 @@ config.h: | |
cp config.def.h config.h | |
$(BIN): $(OBJ) | |
- $(CC) $(OBJ) $(LDFLAGS) $(LIBS) $(TLSLIBS) -o $@ | |
+ $(CC) $(OBJ) $(LDFLAGS) $(IOLIBS) $(LIBS) -o $@ | |
-$(OBJ): config.h config.mk common.h | |
+$(OBJ): config.h config.mk common.h io.h | |
clean: | |
rm -f $(BIN) $(OBJ) | |
@@ -33,7 +33,7 @@ uninstall: | |
# Stock FLAGS | |
SACCCFLAGS = -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D_GNU_SOURCE… | |
- $(TLSCFLAGS) $(CFLAGS) | |
+ $(IOCFLAGS) $(CFLAGS) | |
.c.o: | |
$(CC) $(SACCCFLAGS) -c $< | |
diff --git a/config.mk b/config.mk | |
@@ -9,10 +9,14 @@ MANDIR = $(PREFIX)/share/man/man1 | |
UI=ti | |
LIBS=-lcurses | |
+# IO type | |
+# clr (clear) | |
+#IO = clr | |
+# tls (Transport Layer Security) | |
+IO = tls | |
+IOLIBS = -ltls | |
+IOCFLAGS = -DUSE_TLS | |
+ | |
# Define NEED_ASPRINTF and/or NEED_STRCASESTR in your cflags if your system do… | |
# not provide asprintf() or strcasestr(), respectively. | |
#CFLAGS = -DNEED_ASPRINTF -DNEED_STRCASESTR | |
- | |
-# gophers (gopher over TLS) support | |
-TLSCFLAGS = -DUSE_TLS | |
-TLSLIBS = -ltls | |
diff --git a/io.h b/io.h | |
@@ -0,0 +1,17 @@ | |
+#include <netdb.h> | |
+ | |
+struct cnx { | |
+#ifdef USE_TLS | |
+ struct tls *tls; | |
+#endif | |
+ int sock; | |
+}; | |
+ | |
+extern int tls; | |
+ | |
+extern int (*ioclose)(struct cnx *); | |
+extern int (*ioconnect)(struct cnx *, struct addrinfo *, const char *); | |
+extern void (*ioconnerr)(struct cnx *, const char *, const char *, int); | |
+extern char *(*ioparseurl)(char *); | |
+extern ssize_t (*ioread)(struct cnx *, void *, size_t); | |
+extern ssize_t (*iowrite)(struct cnx *, void *, size_t); | |
diff --git a/io_clr.c b/io_clr.c | |
@@ -0,0 +1,63 @@ | |
+#include <string.h> | |
+#include <unistd.h> | |
+#include <netdb.h> | |
+ | |
+#include <sys/socket.h> | |
+ | |
+#include "common.h" | |
+#include "io.h" | |
+ | |
+static int | |
+close_clr(struct cnx *c) | |
+{ | |
+ return close(c->sock); | |
+} | |
+ | |
+static int | |
+connect_clr(struct cnx *c, struct addrinfo *ai, const char *host) | |
+{ | |
+ return connect(c->sock, ai->ai_addr, ai->ai_addrlen); | |
+} | |
+ | |
+static void | |
+connerr_clr(struct cnx *c, const char *host, const char *port, int err) | |
+{ | |
+ if (c->sock == -1) | |
+ diag("Can't open socket: %s", strerror(err)); | |
+ else | |
+ diag("Can't connect to: %s:%s: %s", host, port, strerror(err)); | |
+} | |
+ | |
+static char * | |
+parseurl_clr(char *url) | |
+{ | |
+ char *p; | |
+ | |
+ if (p = strstr(url, "://")) { | |
+ if (strncmp(url, "gopher", p - url)) | |
+ die("Protocol not supported: %.*s", p - url, url); | |
+ | |
+ url = p + 3; | |
+ } | |
+ | |
+ return url; | |
+} | |
+ | |
+static ssize_t | |
+read_clr(struct cnx *c, void *buf, size_t bs) | |
+{ | |
+ return read(c->sock, buf, bs); | |
+} | |
+ | |
+static ssize_t | |
+write_clr(struct cnx *c, void *buf, size_t bs) | |
+{ | |
+ return write(c->sock, buf, bs); | |
+} | |
+ | |
+int (*ioclose)(struct cnx *) = close_clr; | |
+int (*ioconnect)(struct cnx *, struct addrinfo *, const char *) = connect_clr; | |
+void (*ioconnerr)(struct cnx *, const char *, const char *, int) = connerr_clr; | |
+char *(*ioparseurl)(char *) = parseurl_clr; | |
+ssize_t (*ioread)(struct cnx *, void *, size_t) = read_clr; | |
+ssize_t (*iowrite)(struct cnx *, void *, size_t) = write_clr; | |
diff --git a/io_tls.c b/io_tls.c | |
@@ -0,0 +1,129 @@ | |
+#include <string.h> | |
+#include <unistd.h> | |
+#include <netdb.h> | |
+ | |
+#include <sys/socket.h> | |
+ | |
+#include <tls.h> | |
+ | |
+#include "common.h" | |
+#include "io.h" | |
+ | |
+int tls; | |
+ | |
+static int | |
+close_tls(struct cnx *c) | |
+{ | |
+ int r; | |
+ | |
+ if (tls) { | |
+ if (c->tls) { | |
+ do { | |
+ r = tls_close(c->tls); | |
+ } while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT… | |
+ } | |
+ tls_free(c->tls); | |
+ } | |
+ | |
+ return close(c->sock); | |
+} | |
+ | |
+static int | |
+connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) | |
+{ | |
+ struct tls *t; | |
+ int s; | |
+ | |
+ c->tls = NULL; | |
+ s = c->sock; | |
+ | |
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1) | |
+ return -1; | |
+ | |
+ if (tls) { | |
+ if ((t = tls_client()) == NULL) | |
+ return -1; | |
+ if (tls_connect_socket(t, s, host) == -1) | |
+ return -1; | |
+ | |
+ c->tls = t; | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+static void | |
+connerr_tls(struct cnx *c, const char *host, const char *port, int err) | |
+{ | |
+ if (c->sock == -1) { | |
+ diag("Can't open socket: %s", strerror(err)); | |
+ } else { | |
+ if (tls && c->tls) { | |
+ diag("Can't establish TLS with \"%s\": %s", | |
+ host, tls_error(c->tls)); | |
+ } else { | |
+ diag("Can't connect to: %s:%s: %s", host, port, | |
+ strerror(err)); | |
+ } | |
+ } | |
+} | |
+ | |
+static char * | |
+parseurl_tls(char *url) | |
+{ | |
+ char *p; | |
+ | |
+ if (p = strstr(url, "://")) { | |
+ if (!strncmp(url, "gopher", p - url)) { | |
+ if (tls) | |
+ diag("Switching from gophers to gopher"); | |
+ tls = 0; | |
+ } else if (!strncmp(url, "gophers", p - url)) { | |
+ tls = 1; | |
+ } else { | |
+ die("Protocol not supported: %.*s", p - url, url); | |
+ } | |
+ url = p + 3; | |
+ } | |
+ | |
+ return url; | |
+} | |
+ | |
+static ssize_t | |
+read_tls(struct cnx *c, void *buf, size_t bs) | |
+{ | |
+ ssize_t n; | |
+ | |
+ if (tls && c->tls) { | |
+ do { | |
+ n = tls_read(c->tls, buf, bs); | |
+ } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT); | |
+ } else { | |
+ n = read(c->sock, buf, bs); | |
+ } | |
+ | |
+ return n; | |
+} | |
+ | |
+static ssize_t | |
+write_tls(struct cnx *c, void *buf, size_t bs) | |
+{ | |
+ ssize_t n; | |
+ | |
+ if (tls) { | |
+ do { | |
+ n = tls_write(c->tls, buf, bs); | |
+ } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT); | |
+ } else { | |
+ n = write(c->sock, buf, bs); | |
+ } | |
+ | |
+ return n; | |
+} | |
+ | |
+int (*ioclose)(struct cnx *) = close_tls; | |
+int (*ioconnect)(struct cnx *, struct addrinfo *, const char *) = connect_tls; | |
+void (*ioconnerr)(struct cnx *, const char *, const char *, int) = connerr_tls; | |
+char *(*ioparseurl)(char *) = parseurl_tls; | |
+ssize_t (*ioread)(struct cnx *, void *, size_t) = read_tls; | |
+ssize_t (*iowrite)(struct cnx *, void *, size_t) = write_tls; | |
diff --git a/sacc.c b/sacc.c | |
@@ -18,26 +18,15 @@ | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
-#ifdef USE_TLS | |
-#include <tls.h> | |
-#endif | |
- | |
#include "common.h" | |
+#include "io.h" | |
#include "config.h" | |
-struct cnx { | |
-#ifdef USE_TLS | |
- struct tls *tls; | |
-#endif | |
- int sock; | |
-}; | |
- | |
static char *mainurl; | |
static Item *mainentry; | |
static int devnullfd; | |
static int parent = 1; | |
static int interactive; | |
-static int tls; | |
static void (*diag)(char *fmt, ...); | |
@@ -429,7 +418,7 @@ molddiritem(char *raw) | |
} | |
static char * | |
-getrawitem(struct cnx *cnx) | |
+getrawitem(struct cnx *c) | |
{ | |
char *raw, *buf; | |
size_t bn, bs; | |
@@ -458,17 +447,7 @@ getrawitem(struct cnx *cnx) | |
bs = BUFSIZ; | |
} | |
-#ifdef USE_TLS | |
- if (tls) { | |
- do { | |
- n = tls_read(cnx->tls, buf, bs); | |
- } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT… | |
- } else | |
-#endif | |
- { | |
- n = read(cnx->sock, buf, bs); | |
- } | |
- } while (n > 0); | |
+ } while ((n = ioread(c, buf, bs)) > 0); | |
*buf = '\0'; | |
@@ -481,7 +460,7 @@ getrawitem(struct cnx *cnx) | |
} | |
static int | |
-sendselector(struct cnx *cnx, const char *selector) | |
+sendselector(struct cnx *c, const char *selector) | |
{ | |
char *msg, *p; | |
size_t ln; | |
@@ -491,21 +470,10 @@ sendselector(struct cnx *cnx, const char *selector) | |
msg = p = xmalloc(ln); | |
snprintf(msg, ln--, "%s\r\n", selector); | |
- do { | |
-#ifdef USE_TLS | |
- if (tls) { | |
- do { | |
- n = tls_write(cnx->tls, p, ln); | |
- } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT… | |
- } else | |
-#endif | |
- { | |
- n = write(cnx->sock, p, ln); | |
- } | |
- | |
+ while ((n = iowrite(c, p, ln)) > 0) { | |
ln -= n; | |
p += n; | |
- } while (n > 0); | |
+ }; | |
free(msg); | |
if (n == -1) | |
@@ -514,20 +482,8 @@ sendselector(struct cnx *cnx, const char *selector) | |
return n; | |
} | |
-static void | |
-closecnx(struct cnx *cnx) | |
-{ | |
-#ifdef USE_TLS | |
- if (tls) { | |
- tls_close(cnx->tls); | |
- tls_free(cnx->tls); | |
- } | |
-#endif | |
- close(cnx->sock); | |
-} | |
- | |
static int | |
-connectto(const char *host, const char *port, struct cnx *cnx) | |
+connectto(const char *host, const char *port, struct cnx *c) | |
{ | |
sigset_t set, oset; | |
static const struct addrinfo hints = { | |
@@ -536,7 +492,7 @@ connectto(const char *host, const char *port, struct cnx *c… | |
.ai_protocol = IPPROTO_TCP, | |
}; | |
struct addrinfo *addrs, *addr; | |
- int r, sock = -1; | |
+ int r, err; | |
sigemptyset(&set); | |
sigaddset(&set, SIGWINCH); | |
@@ -548,86 +504,54 @@ connectto(const char *host, const char *port, struct cnx … | |
goto err; | |
} | |
+ r = -1; | |
for (addr = addrs; addr; addr = addr->ai_next) { | |
- if ((sock = socket(addr->ai_family, addr->ai_socktype, | |
- addr->ai_protocol)) == -1) | |
- continue; | |
- | |
- r = connect(sock, addr->ai_addr, addr->ai_addrlen); | |
- if (r == -1) { | |
- close(sock); | |
+ if ((c->sock = socket(addr->ai_family, addr->ai_socktype, | |
+ addr->ai_protocol)) == -1) { | |
+ err = errno; | |
continue; | |
} | |
-#ifdef USE_TLS | |
- if (tls) { | |
- if ((cnx->tls = tls_client()) == NULL) { | |
- diag("Can't establish TLS with \"%s\": %s", | |
- host, tls_error(cnx->tls)); | |
- close(sock); | |
- continue; | |
- } | |
- r = tls_connect_socket(cnx->tls, sock, host); | |
- } | |
-#endif | |
- break; | |
- } | |
- freeaddrinfo(addrs); | |
+ if ((r = ioconnect(c, addr, host)) == 0) | |
+ break; | |
- if (sock == -1) { | |
- diag("Can't open socket: %s", strerror(errno)); | |
- goto err; | |
- } | |
- if (r == -1) { | |
- diag("Can't connect to: %s:%s: %s", | |
- host, port, strerror(errno)); | |
- goto err; | |
+ err = errno; | |
+ close(c->sock); | |
} | |
- sigprocmask(SIG_SETMASK, &oset, NULL); | |
- | |
- cnx->sock = sock; | |
+ freeaddrinfo(addrs); | |
- return 0; | |
+ if (r == -1) | |
+ ioconnerr(c, host, port, err); | |
err: | |
sigprocmask(SIG_SETMASK, &oset, NULL); | |
- return -1; | |
+ | |
+ return r; | |
} | |
static int | |
download(Item *item, int dest) | |
{ | |
char buf[BUFSIZ]; | |
- struct cnx cnx; | |
+ struct cnx c; | |
ssize_t r, w; | |
- int src; | |
- if (!item->tag) { | |
- if (connectto(item->host, item->port, &cnx) == -1 || | |
- sendselector(&cnx, item->selector) == -1) | |
+ if (item->tag == NULL) { | |
+ if (connectto(item->host, item->port, &c) == -1 || | |
+ sendselector(&c, item->selector) == -1) | |
+ return 0; | |
+ } else { | |
+ if ((c.sock = open(item->tag, O_RDONLY)) == -1) { | |
+ printf("Can't open source file %s: %s", | |
+ item->tag, strerror(errno)); | |
+ errno = 0; | |
return 0; | |
- src = cnx.sock; | |
- } else if ((src = open(item->tag, O_RDONLY)) == -1) { | |
- printf("Can't open source file %s: %s", | |
- item->tag, strerror(errno)); | |
- errno = 0; | |
- return 0; | |
- } | |
- | |
- for (w = 0; w != -1;) { | |
-#ifdef USE_TLS | |
- if (tls) { | |
- do { | |
- r = tls_read(cnx.tls, buf, sizeof(buf)); | |
- } while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT… | |
- } else | |
-#endif | |
- { | |
- r = read(src, buf, sizeof(buf)); | |
} | |
- if (r <= 0) | |
- break; | |
+ c.tls = NULL; | |
+ } | |
+ w = 0; | |
+ while ((r = ioread(&c, buf, BUFSIZ)) > 0) { | |
while ((w = write(dest, buf, r)) > 0) | |
r -= w; | |
} | |
@@ -638,7 +562,8 @@ download(Item *item, int dest) | |
errno = 0; | |
} | |
- closecnx(&cnx); | |
+ close(dest); | |
+ ioclose(&c); | |
return (r == 0 && w == 0); | |
} | |
@@ -693,15 +618,15 @@ cleanup: | |
static int | |
fetchitem(Item *item) | |
{ | |
- struct cnx cnx; | |
+ struct cnx c; | |
char *raw; | |
- if (connectto(item->host, item->port, &cnx) == -1 || | |
- sendselector(&cnx, item->selector) == -1) | |
+ if (connectto(item->host, item->port, &c) == -1 || | |
+ sendselector(&c, item->selector) == -1) | |
return 0; | |
- raw = getrawitem(&cnx); | |
- closecnx(&cnx); | |
+ raw = getrawitem(&c); | |
+ ioclose(&c); | |
if (raw == NULL || !*raw) { | |
diag("Empty response from server"); | |
@@ -985,19 +910,7 @@ moldentry(char *url) | |
char *p, *host = url, *port = "70", *gopherpath = "1"; | |
int parsed, ipv6; | |
- if (p = strstr(url, "://")) { | |
- if (strncmp(url, "gopher", p - url) == 0) { | |
- if (tls) { | |
- diag("Switching from gophers to gopher"); | |
- tls = 0; | |
- } | |
- } else if (strncmp(url, "gophers", p - url) == 0) { | |
- tls = 1; | |
- } else { | |
- die("Protocol not supported: %.*s", p - url, url); | |
- } | |
- host = p + 3; | |
- } | |
+ host = ioparseurl(url); | |
if (*host == '[') { | |
ipv6 = 1; |