mirror of https://github.com/omar-polo/gmid.git
retire the old gg
This commit is contained in:
parent
7a4ae106ec
commit
a62c63f261
|
@ -6,14 +6,11 @@ include ../Makefile.local
|
|||
|
||||
.PHONY: all data clean regres
|
||||
|
||||
all: data gg puny-test iri_test fcgi-test
|
||||
all: data puny-test iri_test fcgi-test
|
||||
./regress ${TESTS}
|
||||
|
||||
data: testdata cert.pem testca.pem valid.crt invalid.cert.pem
|
||||
|
||||
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}
|
||||
|
@ -72,7 +69,7 @@ clean:
|
|||
rm -f *.o iri_test cert.pem key.pem
|
||||
rm -f localhost.cert.pem localhost.key.pem
|
||||
rm -f testca.* valid.csr valid.key valid.crt invalid.*pem
|
||||
rm -rf testdata fill-file puny-test gg fcgi-test
|
||||
rm -rf testdata fill-file puny-test fcgi-test
|
||||
rm -f gmid.pid
|
||||
|
||||
testdata: fill-file
|
||||
|
|
80
regress/gg.1
80
regress/gg.1
|
@ -1,80 +0,0 @@
|
|||
.\" 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 23bchNOVv
|
||||
.Op Fl C Pa cert.pem Fl K Pa key.pem
|
||||
.Op Fl H Ar hostname
|
||||
.Op Fl T Ar timeout
|
||||
.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 O
|
||||
Require that a valid stapled OCSP response be provided during the TLS
|
||||
handshake.
|
||||
.It Fl T Ar timeout
|
||||
Kill
|
||||
.Nm
|
||||
after
|
||||
.Ar timeout
|
||||
seconds.
|
||||
.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.
|
219
regress/gg.c
219
regress/gg.c
|
@ -1,219 +0,0 @@
|
|||
/*
|
||||
* 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, Oflag, Vflag, vflag;
|
||||
const char *cert, *key;
|
||||
|
||||
static void
|
||||
timeout(int signo)
|
||||
{
|
||||
dprintf(2, "%s: timer expired\n", getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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", *errstr;
|
||||
const char *hostname;
|
||||
char *t;
|
||||
int ch, handshake, timer;
|
||||
ssize_t len;
|
||||
|
||||
hostname = NULL;
|
||||
while ((ch = getopt(argc, argv, "23C:cbH:hK:NOT:Vv")) != -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 'O':
|
||||
Oflag = 1;
|
||||
break;
|
||||
case 'T':
|
||||
timer = strtonum(optarg, 1, 1000, &errstr);
|
||||
if (errstr != NULL)
|
||||
errx(1, "timeout is %s: %s", errstr, optarg);
|
||||
signal(SIGALRM, timeout);
|
||||
alarm(timer);
|
||||
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 (Oflag)
|
||||
tls_config_ocsp_require_stapling(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;
|
||||
}
|
Loading…
Reference in New Issue