2 * Copyright (c) 2021, 2024 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.
20 #include <sys/types.h>
21 #include <sys/socket.h>
24 #include <netinet/in.h>
44 #include "telescope.h"
47 static struct imsgev *iev_ui;
58 /* a pending request */
61 enum conn_state state;
79 struct addrinfo *servinfo, *p;
85 TAILQ_ENTRY(req) reqs;
88 static struct req *req_by_id(uint32_t);
90 static void die(void) __attribute__((__noreturn__));
92 static void close_with_err(struct req*, const char*);
93 static void close_with_errf(struct req*, const char*, ...)
94 __attribute__((format(printf, 2, 3)));
96 static int try_to_connect(struct req *);
97 static int gemini_parse_reply(struct req *, const char *);
98 static void net_ev(int, int, void *);
99 static void handle_dispatch_imsg(int, int, void*);
101 static int net_send_ui(int, uint32_t, const void *, uint16_t);
103 /* TODO: making this customizable */
104 struct timeval timeout_for_handshake = { 5, 0 };
106 TAILQ_HEAD(, req) reqhead;
109 req_by_id(uint32_t id)
113 TAILQ_FOREACH(r, &reqhead, reqs) {
121 static void __attribute__((__noreturn__))
128 req_bio_ev(struct req *req)
133 ev = bufio_ev(&req->bio);
134 if (ev & BUFIO_WANT_READ)
136 if (ev & BUFIO_WANT_WRITE)
142 close_conn(int fd, int ev, void *d)
146 if (req->state != CONN_ERROR)
147 req->state = CONN_CLOSE;
156 if (req->timer != 0) {
157 ev_timer_cancel(req->timer);
161 if (req->state == CONN_CLOSE &&
163 bufio_close(&req->bio) == -1 &&
165 ev_add(req->fd, req_bio_ev(req), close_conn, req);
170 freeaddrinfo(req->servinfo);
172 bufio_free(&req->bio);
174 if (req->ccert != NULL) {
175 munmap(req->ccert, req->ccert_len);
176 close(req->ccert_fd);
183 TAILQ_REMOVE(&reqhead, req, reqs);
192 close_with_err(struct req *req, const char *err)
194 req->state = CONN_ERROR;
195 net_send_ui(IMSG_ERR, req->id, err, strlen(err)+1);
196 close_conn(0, 0, req);
200 close_with_errf(struct req *req, const char *fmt, ...)
206 if (vasprintf(&s, fmt, ap) == -1)
210 close_with_err(req, s);
216 req_resolve(int fd, int ev, void *d)
219 struct addrinfo hints;
220 struct asr_result ar;
223 if (req->q == NULL) {
224 memset(&hints, 0, sizeof(hints));
225 hints.ai_family = AF_UNSPEC;
226 hints.ai_socktype = SOCK_STREAM;
228 req->q = getaddrinfo_async(req->host, req->port, &hints, NULL);
229 if (req->q == NULL) {
230 close_with_errf(req, "getaddrinfo_async: %s",
239 ev_timer_cancel(req->timer);
243 if (asr_run(req->q, &ar) == 0) {
245 if (ar.ar_cond & ASR_WANT_READ)
247 if (ar.ar_cond & ASR_WANT_WRITE)
250 req->ar_fd = ar.ar_fd;
251 if (ev_add(req->ar_fd, ev, req_resolve, req) == -1) {
252 close_with_errf(req, "ev_add failure: %s",
257 tv.tv_sec = ar.ar_timeout / 1000;
258 tv.tv_usec = (ar.ar_timeout % 1000) * 1000;
259 req->timer = ev_timer(&tv, req_resolve, req);
261 close_with_errf(req, "ev_timer failure: %s",
269 if (ar.ar_gai_errno) {
270 close_with_errf(req, "failed to resolve %s: %s",
271 req->host, gai_strerror(ar.ar_gai_errno));
275 req->servinfo = ar.ar_addrinfo;
277 req->p = req->servinfo;
278 net_ev(-1, EV_READ, req);
282 req_resolve(int fd, int ev, struct req *req)
284 struct addrinfo hints;
287 memset(&hints, 0, sizeof(hints));
288 hints.ai_family = AF_UNSPEC;
289 hints.ai_socktype = SOCK_STREAM;
291 s = getaddrinfo(req->host, req->port, &hints, &req->servinfo);
293 close_with_errf(req, "failed to resolve %s: %s",
294 req->host, gai_strerror(s));
299 req->p = req->servinfo;
300 net_ev(-1, EV_READ, req);
305 try_to_connect(struct req *req)
308 socklen_t len = sizeof(error);
315 if (getsockopt(req->fd, SOL_SOCKET, SO_ERROR, &error,
317 req->conn_error = errno;
318 req->cause = "getsockopt";
322 if (error == 0) /* connected */
325 req->conn_error = error;
326 req->cause = "connect";
329 req->p = req->p->ai_next;
333 req->fd = socket(req->p->ai_family, req->p->ai_socktype,
334 req->p->ai_protocol);
336 req->conn_error = errno;
337 req->cause = "socket";
338 req->p = req->p->ai_next;
342 if (!mark_nonblock_cloexec(req->fd)) {
343 req->conn_error = errno;
344 req->cause = "setsockopt";
348 if (connect(req->fd, req->p->ai_addr, req->p->ai_addrlen) == 0)
355 gemini_parse_reply(struct req *req, const char *header)
361 if (!isdigit(header[0]) || !isdigit(header[1]))
364 code = (header[0] - '0')*10 + (header[1] - '0');
365 if (header[2] != ' ')
369 len = strlen(header) + 1;
371 if ((ibuf = imsg_create(&iev_ui->ibuf, IMSG_REPLY, req->id, 0,
372 sizeof(code) + len)) == NULL)
374 if (imsg_add(ibuf, &code, sizeof(code)) == -1 ||
375 imsg_add(ibuf, header, len) == -1)
377 imsg_close(&iev_ui->ibuf, ibuf);
378 imsg_event_add(iev_ui);
380 /* pause until we've told go go ahead */
387 net_send_req(struct req *req)
389 return (bufio_compose(&req->bio, req->req, req->len));
393 net_ev(int fd, int ev, void *d)
395 static char buf[4096];
403 if (ev == EV_TIMEOUT) {
404 close_with_err(req, "Timeout loading page");
408 if (req->state == CONN_CONNECTING) {
410 if (try_to_connect(req) == -1) {
411 if (req->fd != -1 && errno == EAGAIN) {
412 ev_add(req->fd, EV_WRITE, net_ev, req);
415 close_with_errf(req, "failed to connect to %s"
416 " (%s: %s)", req->host, req->cause,
417 strerror(req->conn_error));
421 bufio_set_fd(&req->bio, req->fd);
423 switch (req->proto) {
426 /* finger and gopher don't have a header nor TLS */
427 req->state = CONN_BODY;
428 if (net_send_req(req) == -1) {
429 close_with_err(req, "failed to send request");
434 req->state = CONN_HANDSHAKE;
435 if (bufio_starttls(&req->bio, req->host, 1,
436 req->ccert, req->ccert_len,
437 req->ccert, req->ccert_len) == -1) {
438 close_with_err(req, "failed to setup TLS");
441 req->timer = ev_timer(&timeout_for_handshake,
443 if (req->timer == 0) {
444 close_with_err(req, "failed to setup"
452 if (req->state == CONN_HANDSHAKE) {
453 if (bufio_handshake(&req->bio) == -1 && errno == EAGAIN) {
454 ev_add(req->fd, req_bio_ev(req), net_ev, req);
458 ev_timer_cancel(req->timer);
461 req->state = CONN_HEADER;
463 /* pause until we've told the certificate is OK */
466 hash = tls_peer_cert_hash(req->bio.ctx);
468 close_with_errf(req, "handshake failed: %s",
469 tls_error(req->bio.ctx));
473 net_send_ui(IMSG_CHECK_CERT, req->id, hash, strlen(hash)+1);
478 read = bufio_read(&req->bio);
479 if (read == -1 && errno != EAGAIN) {
480 close_with_errf(req, "Read error");
487 if ((ev & EV_WRITE) && bufio_write(&req->bio) == -1 &&
489 close_with_errf(req, "bufio_write: %s", strerror(errno));
493 if (req->state == CONN_HEADER) {
494 header = buf_getdelim(&req->bio.rbuf, "\r\n", &len);
495 if (header == NULL && req->bio.rbuf.len >= 1024) {
496 close_with_err(req, "Invalid gemini reply (too long)");
499 if (header == NULL && req->eof) {
500 close_with_err(req, "Invalid gemini reply.");
503 if (header == NULL) {
504 ev_add(req->fd, req_bio_ev(req), net_ev, req);
507 req->state = CONN_BODY;
508 r = gemini_parse_reply(req, header);
509 buf_drain(&req->bio.rbuf, len);
511 close_with_err(req, "Malformed gemini reply");
514 if (r < 20 || r >= 30)
515 close_conn(0, 0, req);
520 * Split data into chunks before sending. imsg can't handle
521 * message that are "too big".
524 if ((len = bufio_drain(&req->bio, buf, sizeof(buf))) == 0)
526 net_send_ui(IMSG_BUF, req->id, buf, len);
530 net_send_ui(IMSG_EOF, req->id, NULL, 0);
531 close_conn(0, 0, req);
535 ev_add(req->fd, req_bio_ev(req), net_ev, req);
539 load_cert(struct imsg *imsg, struct req *req)
544 if ((fd = imsg_get_fd(imsg)) == -1)
547 if (fstat(fd, &sb) == -1)
551 if (sb.st_size >= (off_t)SIZE_MAX) {
557 req->ccert = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
558 if (req->ccert == MAP_FAILED) {
564 req->ccert_len = sb.st_size;
571 handle_dispatch_imsg(int fd, int event, void *d)
573 struct imsgev *iev = d;
574 struct imsgbuf *ibuf = &iev->ibuf;
581 if (event & EV_READ) {
582 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
585 err(1, "connection closed");
587 if (event & EV_WRITE) {
588 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
589 err(1, "msgbuf_write");
591 err(1, "connection closed");
595 if ((n = imsg_get(ibuf, &imsg)) == -1)
599 switch (imsg_get_type(&imsg)) {
601 if (imsg_get_data(&imsg, &r, sizeof(r)) == -1 ||
602 r.host[sizeof(r.host) - 1] != '\0' ||
603 r.port[sizeof(r.port) - 1] != '\0' ||
604 r.req[sizeof(r.req) - 1] != '\0')
606 if (r.proto != PROTO_FINGER &&
607 r.proto != PROTO_GEMINI &&
608 r.proto != PROTO_GOPHER)
611 if ((req = calloc(1, sizeof(*req))) == NULL)
619 req->id = imsg_get_id(&imsg);
620 TAILQ_INSERT_HEAD(&reqhead, req, reqs);
622 if ((req->host = strdup(r.host)) == NULL)
624 if ((req->port = strdup(r.port)) == NULL)
626 if ((req->req = strdup(r.req)) == NULL)
628 if (load_cert(&imsg, req) == -1)
630 if (bufio_init(&req->bio) == -1)
633 req->len = strlen(req->req);
634 req->proto = r.proto;
635 req_resolve(-1, 0, req);
638 case IMSG_CERT_STATUS:
639 if ((req = req_by_id(imsg_get_id(&imsg))) == NULL)
642 if (imsg_get_data(&imsg, &certok, sizeof(certok)) ==
646 close_conn(0, 0, req);
650 if (net_send_req(req) == -1) {
651 close_with_err(req, "failed to send request");
655 if (ev_add(req->fd, EV_WRITE, net_ev, req) == -1) {
657 "failed to register event.");
663 if ((req = req_by_id(imsg_get_id(&imsg))) == NULL)
665 ev_add(req->fd, EV_READ, net_ev, req);
666 net_ev(req->fd, 0, req);
670 if ((req = req_by_id(imsg_get_id(&imsg))) == NULL)
672 close_conn(0, 0, req);
681 errx(1, "got unknown imsg %d", imsg_get_type(&imsg));
691 net_send_ui(int type, uint32_t peerid, const void *data,
694 return imsg_compose_event(iev_ui, type, peerid, 0, -1,
703 TAILQ_INIT(&reqhead);
708 /* Setup pipe and event handler to the main process */
709 if ((iev_ui = malloc(sizeof(*iev_ui))) == NULL)
711 imsg_init(&iev_ui->ibuf, 3);
712 iev_ui->handler = handle_dispatch_imsg;
713 iev_ui->events = EV_READ;
714 ev_add(iev_ui->ibuf.fd, iev_ui->events, iev_ui->handler, iev_ui);
716 sandbox_net_process();
720 msgbuf_clear(&iev_ui->ibuf.w);
721 close(iev_ui->ibuf.fd);