commit - 0d047efcb40ec311da407e0b705a92f764c96338
commit + f48e3b85a97ab6dbf808559c2231d0ab6344ba66
blob - 4d7c6250a5962aa691682a24e88a796da0278bd1
blob + df68f5fe15728c02a7547eefaa8923a40092d37f
--- .gitignore
+++ .gitignore
regress/iri_test
regress/puny-test
regress/*.o
+regress/gg
blob - 521c5b2b4b0603cebeffbf3e66f11a72e61a93ce
blob + 5f91bd7d1cc61800f8d3f469a0d004975abecb3e
--- Makefile
+++ Makefile
gmid: ${OBJS}
${CC} ${OBJS} -o gmid ${LDFLAGS}
-gg: gg.o iri.o utf8.o ${COMPAT}
- ${CC} gg.o iri.o utf8.o ${COMPAT} -o $@ ${LDFLAGS}
-
static: ${OBJS}
${CC} ${OBJS} -o gmid ${LDFLAGS} ${STATIC}
@(etags ${SRCS} || true) 2>/dev/null
clean:
- rm -f *.o compat/*.o lex.yy.c y.tab.c y.tab.h y.output gmid gg
+ rm -f *.o compat/*.o lex.yy.c y.tab.c y.tab.h y.output gmid
rm -f compile_flags.txt
make -C regress clean
-regress: gmid gg
+regress: gmid
make -C regress all
install: gmid
blob - ad47822a9b871beab8e34e4ad26466b12203fa71 (mode 644)
blob + /dev/null
--- gg.1
+++ /dev/null
-.\" 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.
blob - 8a1e7eb445d39a1bc140c48d929f6d0415e3f0c2 (mode 644)
blob + /dev/null
--- gg.c
+++ /dev/null
-/*
- * 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;
-}
blob - b485d6498603cf02baede84cf3178ae0c7b112af
blob + 4f416d36626c56cd952559923fe8d658465648ce
--- regress/Makefile
+++ regress/Makefile
.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}
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
blob - /dev/null
blob + ad47822a9b871beab8e34e4ad26466b12203fa71 (mode 644)
--- /dev/null
+++ regress/gg.1
+.\" 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.
blob - /dev/null
blob + 7eb698f5700f3ad09a243917ce979f3da2e3dc82 (mode 644)
--- /dev/null
+++ regress/gg.c
+/*
+ * 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;
+}
blob - 02cd09b8190a6bee289f07716da2a20e7c8a1476
blob + 098db1a4668faecb1226eae970a097a09e7c26e7
--- regress/runtime
+++ regress/runtime
# 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() {