diff options
author | Omar Polo <op@omarpolo.com> | 2021-05-24 13:48:55 +0000 |
---|---|---|
committer | Omar Polo <op@omarpolo.com> | 2021-05-24 13:48:55 +0000 |
commit | f48e3b85a97ab6dbf808559c2231d0ab6344ba66 (patch) | |
tree | 9a9401326f29498c60ea22ccfb2cfb76e45d2a83 /regress | |
parent | 0d047efcb40ec311da407e0b705a92f764c96338 (diff) |
move gg to regress
Diffstat (limited to 'regress')
-rw-r--r-- | regress/Makefile | 7 | ||||
-rw-r--r-- | regress/gg.1 | 70 | ||||
-rw-r--r-- | regress/gg.c | 200 | ||||
-rwxr-xr-x | regress/runtime | 6 |
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() { |