aboutsummaryrefslogtreecommitdiff
path: root/regress
diff options
context:
space:
mode:
authorOmar Polo <op@omarpolo.com>2021-05-24 13:48:55 +0000
committerOmar Polo <op@omarpolo.com>2021-05-24 13:48:55 +0000
commitf48e3b85a97ab6dbf808559c2231d0ab6344ba66 (patch)
tree9a9401326f29498c60ea22ccfb2cfb76e45d2a83 /regress
parent0d047efcb40ec311da407e0b705a92f764c96338 (diff)
move gg to regress
Diffstat (limited to 'regress')
-rw-r--r--regress/Makefile7
-rw-r--r--regress/gg.170
-rw-r--r--regress/gg.c200
-rwxr-xr-xregress/runtime6
4 files changed, 278 insertions, 5 deletions
diff --git a/regress/Makefile b/regress/Makefile
index b485d64..4f416d3 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -2,11 +2,14 @@ include ../Makefile.local
.PHONY: all clean runtime
-all: puny-test testdata iri_test cert.pem testca.pem valid.crt invalid.cert.pem
+all: gg puny-test testdata iri_test cert.pem testca.pem valid.crt invalid.cert.pem
./puny-test
./runtime
./iri_test
+gg: gg.o ../iri.o ../utf8.o ${COMPAT}
+ ${CC} gg.o ../iri.o ../utf8.o ${COMPAT} -o $@ ${LDFLAGS}
+
puny-test: puny-test.o ../puny.o ../utf8.o ../utils.o ../log.o ${COMPAT}
${CC} puny-test.o ../puny.o ../utf8.o ../utils.o ../log.o ${COMPAT} \
-o puny-test ${LDFLAGS}
@@ -59,7 +62,7 @@ invalid.cert.pem: cert.pem
clean:
rm -f *.o iri_test cert.pem key.pem
rm -f testca.* valid.csr valid.key invalid.*pem
- rm -rf testdata fill-file puny-test
+ rm -rf testdata fill-file puny-test gg
testdata: fill-file
mkdir testdata
diff --git a/regress/gg.1 b/regress/gg.1
new file mode 100644
index 0000000..ad47822
--- /dev/null
+++ b/regress/gg.1
@@ -0,0 +1,70 @@
+.\" Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.Dd $Mdocdate: January 23 2021$
+.Dt GG 1
+.Os
+.Sh NAME
+.Nm gg
+.Nd simple Gemini client
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl 23bchNVv
+.Op Fl C Pa cert.pem Fl K Pa key.pem
+.Op Fl H Ar hostname
+.Ar IRI
+.Ek
+.Sh DESCRIPTION
+.Nm
+is a simple Gemini client.
+It fetches the Gemini page given and prints the server response to
+standard output.
+The option are as follows:
+.Bl -tag -width 6m
+.It Fl 2
+Use only TLSv1.2.
+.It Fl 3
+Use only TLSv1.3.
+.It Fl b
+Print only the body of the response.
+.It Fl C Pa cert.pem
+Load the client certificate, must be in PEM format.
+.It Fl c
+Print only the response code.
+.It Fl H Ar hostname
+Use the given
+.Ar hostname
+for SNI, instead of the one extracted from the IRI.
+The IRI hostname will still be used for the DNS resolution.
+.It Fl h
+Print only the response header.
+.It Fl K Pa key.pem
+Load the client certificate key, must be in PEM format.
+.It Fl N
+Don't check whether the peer certificate name matches the requested
+hostname.
+.It Fl V
+Only validate the IRI, don't do the Gemini transaction.
+.It Fl v
+Print also the request.
+.El
+.Pp
+Note that
+.Nm
+won't try to do TOFU (Trust On First Use) or any X.509 certificate
+validation: it will happily accept any certificate it is given.
+.Pp
+By default
+.Nm
+will accept both TLSv1.2 and TLSv1.3 and will always do SNI.
diff --git a/regress/gg.c b/regress/gg.c
new file mode 100644
index 0000000..7eb698f
--- /dev/null
+++ b/regress/gg.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../gmid.h"
+
+#include <string.h>
+
+int flag2, flag3, bflag, cflag, hflag, Nflag, Vflag, vflag;
+const char *cert, *key;
+
+int
+main(int argc, char **argv)
+{
+ struct iri iri;
+ struct tls_config *conf;
+ struct tls *ctx;
+ char iribuf[GEMINI_URL_LEN], buf[GEMINI_URL_LEN];
+ const char *parse_err = "unknown error", *port = "1965";
+ const char *hostname;
+ char *t;
+ int ch;
+ int handshake;
+ ssize_t len;
+
+ hostname = NULL;
+ while ((ch = getopt(argc, argv, "23C:cbH:hK:NVv")) != -1) {
+ switch (ch) {
+ case '2':
+ flag2 = 1;
+ break;
+ case '3':
+ flag3 = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'C':
+ cert = optarg;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'H':
+ hostname = optarg;
+ break;
+ case 'h':
+ hflag = 1;
+ break;
+ case 'K':
+ key = optarg;
+ break;
+ case 'N':
+ Nflag = 1;
+ break;
+ case 'V':
+ Vflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ fprintf(stderr, "USAGE: %s [-23cbhNVv] [-H hostname]\n",
+ *argv);
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if ((bflag + cflag + hflag + Vflag) > 1)
+ errx(1, "only one of bchr flags can be used.");
+
+ if (flag2 + flag3 > 1)
+ errx(1, "only -2 or -3 can be specified at the same time.");
+
+ if ((cert != NULL && key == NULL) || (cert == NULL && key != NULL))
+ errx(1, "missing certificate or key");
+
+ if (argc != 1)
+ errx(1, "missing IRI");
+
+ if (strlcpy(iribuf, argv[0], sizeof(iribuf)) >= sizeof(iribuf))
+ errx(1, "request too long: %s", argv[0]);
+ if (strlcpy(buf, argv[0], sizeof(buf)) >= sizeof(iribuf))
+ errx(1, "request too long: %s", argv[0]);
+ if (strlcat(buf, "\r\n", sizeof(buf)) >= sizeof(buf))
+ errx(1, "request too long: %s", argv[0]);
+
+ if (!parse_iri(iribuf, &iri, &parse_err))
+ errx(1, "invalid IRI: %s", parse_err);
+
+ if (Vflag)
+ errx(0, "IRI: OK");
+
+ if ((conf = tls_config_new()) == NULL)
+ errx(1, "tls_config_new");
+
+ tls_config_insecure_noverifycert(conf);
+ if (Nflag)
+ tls_config_insecure_noverifyname(conf);
+
+ if (flag2 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_2) == -1)
+ errx(1, "cannot set TLSv1.2");
+ if (flag3 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_3) == -1)
+ errx(1, "cannot set TLSv1.3");
+
+ if (cert != NULL && tls_config_set_keypair_file(conf, cert, key))
+ errx(1, "couldn't load cert: %s", cert);
+
+ if ((ctx = tls_client()) == NULL)
+ errx(1, "tls_client creation failed");
+
+ if (tls_configure(ctx, conf) == -1)
+ errx(1, "tls_configure: %s", tls_error(ctx));
+
+ if (*iri.port != '\0')
+ port = iri.port;
+
+ if (hostname == NULL)
+ hostname = iri.host;
+
+ if (tls_connect_servername(ctx, iri.host, port, hostname) == -1)
+ errx(1, "tls_connect: %s", tls_error(ctx));
+
+ for (handshake = 0; !handshake;) {
+ switch (tls_handshake(ctx)) {
+ case 0:
+ case -1:
+ handshake = 1;
+ break;
+ }
+ }
+
+ if (vflag)
+ printf("%s", buf);
+ if (tls_write(ctx, buf, strlen(buf)) == -1)
+ errx(1, "tls_write: %s", tls_error(ctx));
+
+ for (;;) {
+ switch (len = tls_read(ctx, buf, sizeof(buf))) {
+ case 0:
+ case -1:
+ goto end;
+ case TLS_WANT_POLLIN:
+ case TLS_WANT_POLLOUT:
+ continue;
+ }
+
+ if (bflag) {
+ bflag = 0;
+ if ((t = strchr(buf, '\r')) != NULL)
+ t += 2;
+ else if ((t = strchr(buf, '\n')) != NULL)
+ t += 1;
+ else
+ continue;
+ len -= t - buf;
+ write(1, t, len);
+ continue;
+ }
+
+ if (cflag) {
+ write(1, buf, 2);
+ write(1, "\n", 1);
+ break;
+ }
+
+ if (hflag) {
+ t = strchr(buf, '\r');
+ if (t == NULL)
+ t = strchr(buf, '\n');
+ if (t == NULL)
+ t = &buf[len];
+ write(1, buf, t - buf);
+ write(1, "\n", 1);
+ break;
+ }
+
+ write(1, buf, len);
+ }
+end:
+
+ tls_close(ctx);
+ tls_free(ctx);
+
+ return 0;
+}
diff --git a/regress/runtime b/regress/runtime
index 02cd09b..098db1a 100755
--- a/regress/runtime
+++ b/regress/runtime
@@ -27,19 +27,19 @@ checkconf() {
# usage: get <path>
# return the body of the request on stdout
get() {
- ./../gg -b $ggflags "gemini://localhost:10965/$1"
+ ./gg -b $ggflags "gemini://localhost:10965/$1"
}
# usage: head <path>
# return the meta response line on stdout
head() {
- ./../gg -h $ggflags "gemini://localhost:10965/$1"
+ ./gg -h $ggflags "gemini://localhost:10965/$1"
}
# usage: raw <path>
# return both header and body
raw() {
- ./../gg $ggflags "gemini://localhost:10965/$1"
+ ./gg $ggflags "gemini://localhost:10965/$1"
}
run() {