2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 int flag2, flag3, bflag, cflag, hflag, Nflag, Vflag, vflag;
22 const char *cert, *key;
27 dprintf(2, "%s: timer expired\n", getprogname());
32 main(int argc, char **argv)
35 struct tls_config *conf;
37 char iribuf[GEMINI_URL_LEN], buf[GEMINI_URL_LEN];
38 const char *parse_err = "unknown error", *port = "1965", *errstr;
41 int ch, handshake, timer;
45 while ((ch = getopt(argc, argv, "23C:cbH:hK:NT:Vv")) != -1) {
75 timer = strtonum(optarg, 1, 1000, &errstr);
77 errx(1, "timeout is %s: %s", errstr, optarg);
78 signal(SIGALRM, timeout);
88 fprintf(stderr, "USAGE: %s [-23cbhNVv] [-H hostname]\n",
96 if ((bflag + cflag + hflag + Vflag) > 1)
97 errx(1, "only one of bchr flags can be used.");
99 if (flag2 + flag3 > 1)
100 errx(1, "only -2 or -3 can be specified at the same time.");
102 if ((cert != NULL && key == NULL) || (cert == NULL && key != NULL))
103 errx(1, "missing certificate or key");
106 errx(1, "missing IRI");
108 if (strlcpy(iribuf, argv[0], sizeof(iribuf)) >= sizeof(iribuf))
109 errx(1, "request too long: %s", argv[0]);
110 if (strlcpy(buf, argv[0], sizeof(buf)) >= sizeof(iribuf))
111 errx(1, "request too long: %s", argv[0]);
112 if (strlcat(buf, "\r\n", sizeof(buf)) >= sizeof(buf))
113 errx(1, "request too long: %s", argv[0]);
115 if (!parse_iri(iribuf, &iri, &parse_err))
116 errx(1, "invalid IRI: %s", parse_err);
121 if ((conf = tls_config_new()) == NULL)
122 errx(1, "tls_config_new");
124 tls_config_insecure_noverifycert(conf);
126 tls_config_insecure_noverifyname(conf);
128 if (flag2 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_2) == -1)
129 errx(1, "cannot set TLSv1.2");
130 if (flag3 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_3) == -1)
131 errx(1, "cannot set TLSv1.3");
133 if (cert != NULL && tls_config_set_keypair_file(conf, cert, key))
134 errx(1, "couldn't load cert: %s", cert);
136 if ((ctx = tls_client()) == NULL)
137 errx(1, "tls_client creation failed");
139 if (tls_configure(ctx, conf) == -1)
140 errx(1, "tls_configure: %s", tls_error(ctx));
142 if (*iri.port != '\0')
145 if (hostname == NULL)
148 if (tls_connect_servername(ctx, iri.host, port, hostname) == -1)
149 errx(1, "tls_connect: %s", tls_error(ctx));
151 for (handshake = 0; !handshake;) {
152 switch (tls_handshake(ctx)) {
162 if (tls_write(ctx, buf, strlen(buf)) == -1)
163 errx(1, "tls_write: %s", tls_error(ctx));
166 switch (len = tls_read(ctx, buf, sizeof(buf))) {
170 case TLS_WANT_POLLIN:
171 case TLS_WANT_POLLOUT:
177 if ((t = strchr(buf, '\r')) != NULL)
179 else if ((t = strchr(buf, '\n')) != NULL)
195 t = strchr(buf, '\r');
197 t = strchr(buf, '\n');
200 write(1, buf, t - buf);