2021-01-23 17:56:24 +01:00
|
|
|
/*
|
|
|
|
* 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 <string.h>
|
|
|
|
|
|
|
|
#include "gmid.h"
|
|
|
|
|
2021-01-27 15:48:23 +01:00
|
|
|
int flag2, flag3, bflag, cflag, hflag, Nflag, Vflag, vflag;
|
|
|
|
|
2021-01-23 17:56:24 +01:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct iri iri;
|
|
|
|
struct tls_config *conf;
|
|
|
|
struct tls *ctx;
|
2021-01-23 18:45:56 +01:00
|
|
|
char iribuf[GEMINI_URL_LEN], buf[GEMINI_URL_LEN];
|
2021-01-23 17:56:24 +01:00
|
|
|
const char *parse_err = "unknown error", *port = "1965";
|
2021-01-27 15:48:23 +01:00
|
|
|
const char *hostname;
|
2021-01-23 17:56:24 +01:00
|
|
|
char *t;
|
2021-01-27 15:48:23 +01:00
|
|
|
int ch;
|
|
|
|
int handshake;
|
2021-01-23 17:56:24 +01:00
|
|
|
ssize_t len;
|
|
|
|
|
2021-01-27 15:48:23 +01:00
|
|
|
hostname = NULL;
|
|
|
|
while ((ch = getopt(argc, argv, "23cbH:hNVv")) != -1) {
|
2021-01-23 17:56:24 +01:00
|
|
|
switch (ch) {
|
|
|
|
case '2':
|
|
|
|
flag2 = 1;
|
|
|
|
break;
|
|
|
|
case '3':
|
|
|
|
flag3 = 1;
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
bflag = 1;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
cflag = 1;
|
|
|
|
break;
|
2021-01-27 15:48:23 +01:00
|
|
|
case 'H':
|
|
|
|
hostname = optarg;
|
|
|
|
break;
|
2021-01-23 17:56:24 +01:00
|
|
|
case 'h':
|
|
|
|
hflag = 1;
|
|
|
|
break;
|
|
|
|
case 'N':
|
|
|
|
Nflag = 1;
|
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
Vflag = 1;
|
|
|
|
break;
|
2021-01-27 15:48:23 +01:00
|
|
|
case 'v':
|
|
|
|
vflag = 1;
|
|
|
|
break;
|
2021-01-23 17:56:24 +01:00
|
|
|
default:
|
2021-01-27 15:48:23 +01:00
|
|
|
fprintf(stderr, "USAGE: %s [-23cbhNVv] [-H hostname]\n",
|
|
|
|
*argv);
|
2021-01-23 17:56:24 +01:00
|
|
|
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 (argc != 1)
|
|
|
|
errx(1, "missing IRI");
|
|
|
|
|
|
|
|
if (strlcpy(iribuf, argv[0], sizeof(iribuf)) >= sizeof(iribuf))
|
|
|
|
errx(1, "request too long: %s", argv[0]);
|
2021-01-23 18:45:56 +01:00
|
|
|
if (strlcpy(buf, argv[0], sizeof(buf)) >= sizeof(iribuf))
|
2021-01-23 17:56:24 +01:00
|
|
|
errx(1, "request too long: %s", argv[0]);
|
2021-01-23 18:45:56 +01:00
|
|
|
if (strlcat(buf, "\r\n", sizeof(buf)) >= sizeof(buf))
|
2021-01-23 17:56:24 +01:00
|
|
|
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 ((ctx = tls_client()) == NULL)
|
|
|
|
errx(1, "tls_client creation failed");
|
|
|
|
|
|
|
|
if (tls_configure(ctx, conf) == -1)
|
|
|
|
errx(1, "tls_configure: %s", tls_error(ctx));
|
|
|
|
|
2021-01-23 18:07:52 +01:00
|
|
|
if (*iri.port != '\0')
|
|
|
|
port = iri.port;
|
2021-01-27 15:48:23 +01:00
|
|
|
|
|
|
|
if (hostname == NULL)
|
|
|
|
hostname = iri.host;
|
|
|
|
|
|
|
|
if (tls_connect_servername(ctx, iri.host, port, hostname) == -1)
|
2021-01-23 17:56:24 +01:00
|
|
|
errx(1, "tls_connect: %s", tls_error(ctx));
|
|
|
|
|
2021-01-27 15:48:23 +01:00
|
|
|
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));
|
2021-01-23 17:56:24 +01:00
|
|
|
|
|
|
|
for (;;) {
|
2021-01-23 18:43:04 +01:00
|
|
|
switch (len = tls_read(ctx, buf, sizeof(buf))) {
|
|
|
|
case 0:
|
|
|
|
case -1:
|
|
|
|
goto end;
|
|
|
|
case TLS_WANT_POLLIN:
|
|
|
|
case TLS_WANT_POLLOUT:
|
|
|
|
continue;
|
|
|
|
}
|
2021-01-23 17:56:24 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2021-01-23 18:43:04 +01:00
|
|
|
end:
|
2021-01-23 17:56:24 +01:00
|
|
|
|
|
|
|
tls_close(ctx);
|
|
|
|
tls_free(ctx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|