Blob


1 /*
2 * Copyright (c) 2021, 2024 Omar Polo <op@omarpolo.com>
3 *
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.
7 *
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.
15 */
17 #include "compat.h"
19 #include <sys/mman.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/stat.h>
24 #include <netinet/in.h>
26 #include <assert.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <netdb.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <tls.h>
35 #include <unistd.h>
37 #if HAVE_ASR_RUN
38 # include <asr.h>
39 #endif
41 #include "bufio.h"
42 #include "ev.h"
43 #include "imsgev.h"
44 #include "telescope.h"
45 #include "utils.h"
47 static struct imsgev *iev_ui;
49 enum conn_state {
50 CONN_CONNECTING,
51 CONN_HANDSHAKE,
52 CONN_HEADER,
53 CONN_BODY,
54 CONN_CLOSE,
55 CONN_ERROR,
56 };
58 /* a pending request */
59 struct req {
60 uint32_t id;
61 enum conn_state state;
62 int proto;
63 int fd;
64 char *host;
65 char *port;
66 char *req;
67 size_t len;
68 void *ccert;
69 size_t ccert_len;
70 int ccert_fd;
72 int eof;
73 unsigned int timer;
74 struct bufio bio;
76 int conn_error;
77 const char *cause;
79 struct addrinfo *servinfo, *p;
80 #if HAVE_ASR_RUN
81 struct asr_query *q;
82 int ar_fd;
83 #endif
85 TAILQ_ENTRY(req) reqs;
86 };
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 *, size_t);
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;
108 static struct req *
109 req_by_id(uint32_t id)
111 struct req *r;
113 TAILQ_FOREACH(r, &reqhead, reqs) {
114 if (r->id == id)
115 return r;
118 return NULL;
121 static void __attribute__((__noreturn__))
122 die(void)
124 abort(); /* TODO */
127 static inline int
128 req_bio_ev(struct req *req)
130 int ret, ev;
132 ret = 0;
133 ev = bufio_ev(&req->bio);
134 if (ev & BUFIO_WANT_READ)
135 ret |= EV_READ;
136 if (ev & BUFIO_WANT_WRITE)
137 ret |= EV_WRITE;
138 return (ret);
141 static void
142 close_conn(int fd, int ev, void *d)
144 struct req *req = d;
146 if (req->state != CONN_ERROR)
147 req->state = CONN_CLOSE;
149 #if HAVE_ASR_RUN
150 if (req->q) {
151 asr_abort(req->q);
152 ev_del(req->ar_fd);
154 #endif
156 if (req->timer != 0) {
157 ev_timer_cancel(req->timer);
158 req->timer = 0;
161 if (req->state == CONN_CLOSE &&
162 req->fd != -1 &&
163 bufio_close(&req->bio) == -1 &&
164 errno == EAGAIN) {
165 ev_add(req->fd, req_bio_ev(req), close_conn, req);
166 return;
169 if (req->servinfo)
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);
179 free(req->host);
180 free(req->port);
181 free(req->req);
183 TAILQ_REMOVE(&reqhead, req, reqs);
184 if (req->fd != -1) {
185 ev_del(req->fd);
186 close(req->fd);
188 free(req);
191 static void
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);
199 static void
200 close_with_errf(struct req *req, const char *fmt, ...)
202 va_list ap;
203 char *s;
205 va_start(ap, fmt);
206 if (vasprintf(&s, fmt, ap) == -1)
207 abort();
208 va_end(ap);
210 close_with_err(req, s);
211 free(s);
214 #if HAVE_ASR_RUN
215 static void
216 req_resolve(int fd, int ev, void *d)
218 struct req *req = d;
219 struct addrinfo hints;
220 struct asr_result ar;
221 struct timeval tv;
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",
231 strerror(errno));
232 return;
236 if (fd != -1)
237 ev_del(fd);
238 if (req->timer) {
239 ev_timer_cancel(req->timer);
240 req->timer = 0;
243 if (asr_run(req->q, &ar) == 0) {
244 ev = 0;
245 if (ar.ar_cond & ASR_WANT_READ)
246 ev |= EV_READ;
247 if (ar.ar_cond & ASR_WANT_WRITE)
248 ev |= EV_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",
253 strerror(errno));
254 return;
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);
260 if (req->timer == 0)
261 close_with_errf(req, "ev_timer failure: %s",
262 strerror(errno));
263 return;
266 req->ar_fd = -1;
267 req->q = NULL;
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));
272 return;
275 req->servinfo = ar.ar_addrinfo;
277 req->p = req->servinfo;
278 net_ev(-1, EV_READ, req);
280 #else
281 static void
282 req_resolve(int fd, int ev, struct req *req)
284 struct addrinfo hints;
285 int s;
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);
292 if (s != 0) {
293 close_with_errf(req, "failed to resolve %s: %s",
294 req->host, gai_strerror(s));
295 return;
298 req->fd = -1;
299 req->p = req->servinfo;
300 net_ev(-1, EV_READ, req);
302 #endif
304 static int
305 try_to_connect(struct req *req)
307 int error;
308 socklen_t len = sizeof(error);
310 again:
311 if (req->p == NULL)
312 return (-1);
314 if (req->fd != -1) {
315 if (getsockopt(req->fd, SOL_SOCKET, SO_ERROR, &error,
316 &len) == -1) {
317 req->conn_error = errno;
318 req->cause = "getsockopt";
319 return (-1);
322 if (error == 0) /* connected */
323 return (0);
325 req->conn_error = error;
326 req->cause = "connect";
327 close(req->fd);
328 req->fd = -1;
329 req->p = req->p->ai_next;
330 goto again;
333 req->fd = socket(req->p->ai_family, req->p->ai_socktype,
334 req->p->ai_protocol);
335 if (req->fd == -1) {
336 req->conn_error = errno;
337 req->cause = "socket";
338 req->p = req->p->ai_next;
339 goto again;
342 if (!mark_nonblock_cloexec(req->fd)) {
343 req->conn_error = errno;
344 req->cause = "setsockopt";
345 return (-1);
348 if (connect(req->fd, req->p->ai_addr, req->p->ai_addrlen) == 0)
349 return (0);
350 errno = EAGAIN;
351 return (-1);
354 static int
355 gemini_parse_reply(struct req *req, const char *header, size_t len)
357 struct ibuf *ibuf;
358 int code;
359 const char *t;
361 if (len < 4)
362 return 0;
364 if (!isdigit(header[0]) || !isdigit(header[1]))
365 return 0;
367 code = (header[0] - '0')*10 + (header[1] - '0');
368 if (header[2] != ' ')
369 return 0;
371 t = header + 3;
372 len = strlen(t) + 1;
374 if ((ibuf = imsg_create(&iev_ui->ibuf, IMSG_REPLY, req->id, 0,
375 sizeof(code) + len)) == NULL)
376 die();
377 if (imsg_add(ibuf, &code, sizeof(code)) == -1 ||
378 imsg_add(ibuf, t, len) == -1)
379 die();
380 imsg_close(&iev_ui->ibuf, ibuf);
381 imsg_event_add(iev_ui);
383 /* pause until we've told go go ahead */
384 ev_del(req->fd);
386 return code;
389 static inline int
390 net_send_req(struct req *req)
392 return (bufio_compose(&req->bio, req->req, req->len));
395 static void
396 net_ev(int fd, int ev, void *d)
398 static char buf[4096];
399 struct req *req = d;
400 const char *hash;
401 ssize_t read;
402 size_t len;
403 char *header, *endl;
404 int r;
406 if (ev == EV_TIMEOUT) {
407 close_with_err(req, "Timeout loading page");
408 return;
411 if (req->state == CONN_CONNECTING) {
412 ev_del(req->fd);
413 if (try_to_connect(req) == -1) {
414 if (req->fd != -1 && errno == EAGAIN) {
415 ev_add(req->fd, EV_WRITE, net_ev, req);
416 return;
418 close_with_errf(req, "failed to connect to %s"
419 " (%s: %s)", req->host, req->cause,
420 strerror(req->conn_error));
421 return;
424 bufio_set_fd(&req->bio, req->fd);
426 switch (req->proto) {
427 case PROTO_FINGER:
428 case PROTO_GOPHER:
429 /* finger and gopher don't have a header nor TLS */
430 req->state = CONN_BODY;
431 if (net_send_req(req) == -1) {
432 close_with_err(req, "failed to send request");
433 return;
435 break;
436 case PROTO_GEMINI:
437 req->state = CONN_HANDSHAKE;
438 if (bufio_starttls(&req->bio, req->host, 1,
439 req->ccert, req->ccert_len,
440 req->ccert, req->ccert_len) == -1) {
441 close_with_err(req, "failed to setup TLS");
442 return;
444 req->timer = ev_timer(&timeout_for_handshake,
445 net_ev, req);
446 if (req->timer == 0) {
447 close_with_err(req, "failed to setup"
448 " handshake timer");
449 return;
451 break;
455 if (req->state == CONN_HANDSHAKE) {
456 if (bufio_handshake(&req->bio) == -1 && errno == EAGAIN) {
457 ev_add(req->fd, req_bio_ev(req), net_ev, req);
458 return;
461 ev_timer_cancel(req->timer);
462 req->timer = 0;
464 req->state = CONN_HEADER;
466 /* pause until we've told the certificate is OK */
467 ev_del(req->fd);
469 hash = tls_peer_cert_hash(req->bio.ctx);
470 if (hash == NULL) {
471 close_with_errf(req, "handshake failed: %s",
472 tls_error(req->bio.ctx));
473 return;
476 net_send_ui(IMSG_CHECK_CERT, req->id, hash, strlen(hash)+1);
477 return;
480 if (ev & EV_READ) {
481 read = bufio_read(&req->bio);
482 if (read == -1 && errno != EAGAIN) {
483 close_with_errf(req, "Read error");
484 return;
486 if (read == 0)
487 req->eof = 1;
490 if ((ev & EV_WRITE) && bufio_write(&req->bio) == -1 &&
491 errno != EAGAIN) {
492 close_with_errf(req, "bufio_write: %s", strerror(errno));
493 return;
496 if (req->state == CONN_HEADER) {
497 header = req->bio.rbuf.buf;
498 endl = memmem(header, req->bio.rbuf.len, "\r\n", 2);
499 if (endl == NULL && req->bio.rbuf.len >= 1024) {
500 close_with_err(req, "Invalid gemini reply (too long)");
501 return;
503 if (endl == NULL && req->eof) {
504 close_with_err(req, "Invalid gemini reply.");
505 return;
507 if (endl == NULL) {
508 ev_add(req->fd, req_bio_ev(req), net_ev, req);
509 return;
511 *endl = '\0';
512 req->state = CONN_BODY;
513 r = gemini_parse_reply(req, header, strlen(header));
514 buf_drain(&req->bio.rbuf, endl - header + 2);
515 if (r == 0) {
516 close_with_err(req, "Malformed gemini reply");
517 return;
519 if (r < 20 || r >= 30)
520 close_conn(0, 0, req);
521 return;
524 /*
525 * Split data into chunks before sending. imsg can't handle
526 * message that are "too big".
527 */
528 for (;;) {
529 if ((len = bufio_drain(&req->bio, buf, sizeof(buf))) == 0)
530 break;
531 net_send_ui(IMSG_BUF, req->id, buf, len);
534 if (req->eof) {
535 net_send_ui(IMSG_EOF, req->id, NULL, 0);
536 close_conn(0, 0, req);
537 return;
540 ev_add(req->fd, req_bio_ev(req), net_ev, req);
543 static int
544 load_cert(struct imsg *imsg, struct req *req)
546 struct stat sb;
547 int fd;
549 if ((fd = imsg_get_fd(imsg)) == -1)
550 return (0);
552 if (fstat(fd, &sb) == -1)
553 return (-1);
555 #if 0
556 if (sb.st_size >= (off_t)SIZE_MAX) {
557 close(fd);
558 return (-1);
560 #endif
562 req->ccert = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
563 if (req->ccert == MAP_FAILED) {
564 req->ccert = NULL;
565 close(fd);
566 return (-1);
569 req->ccert_len = sb.st_size;
570 req->ccert_fd = fd;
572 return (0);
575 static void
576 handle_dispatch_imsg(int fd, int event, void *d)
578 struct imsgev *iev = d;
579 struct imsgbuf *ibuf = &iev->ibuf;
580 struct imsg imsg;
581 struct req *req;
582 struct get_req r;
583 ssize_t n;
584 int certok;
586 if (event & EV_READ) {
587 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
588 err(1, "imsg_read");
589 if (n == 0)
590 err(1, "connection closed");
592 if (event & EV_WRITE) {
593 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
594 err(1, "msgbuf_write");
595 if (n == 0)
596 err(1, "connection closed");
599 for (;;) {
600 if ((n = imsg_get(ibuf, &imsg)) == -1)
601 err(1, "imsg_get");
602 if (n == 0)
603 break;
604 switch (imsg_get_type(&imsg)) {
605 case IMSG_GET:
606 if (imsg_get_data(&imsg, &r, sizeof(r)) == -1 ||
607 r.host[sizeof(r.host) - 1] != '\0' ||
608 r.port[sizeof(r.port) - 1] != '\0' ||
609 r.req[sizeof(r.req) - 1] != '\0')
610 die();
611 if (r.proto != PROTO_FINGER &&
612 r.proto != PROTO_GEMINI &&
613 r.proto != PROTO_GOPHER)
614 die();
616 if ((req = calloc(1, sizeof(*req))) == NULL)
617 die();
619 req->fd = -1;
620 #if HAVE_ASR_RUN
621 req->ar_fd = -1;
622 #endif
623 req->ccert_fd = -1;
624 req->id = imsg_get_id(&imsg);
625 TAILQ_INSERT_HEAD(&reqhead, req, reqs);
627 if ((req->host = strdup(r.host)) == NULL)
628 die();
629 if ((req->port = strdup(r.port)) == NULL)
630 die();
631 if ((req->req = strdup(r.req)) == NULL)
632 die();
633 if (load_cert(&imsg, req) == -1)
634 die();
635 if (bufio_init(&req->bio) == -1)
636 die();
638 req->len = strlen(req->req);
639 req->proto = r.proto;
640 req_resolve(-1, 0, req);
641 break;
643 case IMSG_CERT_STATUS:
644 if ((req = req_by_id(imsg_get_id(&imsg))) == NULL)
645 break;
647 if (imsg_get_data(&imsg, &certok, sizeof(certok)) ==
648 -1)
649 die();
650 if (!certok) {
651 close_conn(0, 0, req);
652 break;
655 if (net_send_req(req) == -1) {
656 close_with_err(req, "failed to send request");
657 break;
660 if (ev_add(req->fd, EV_WRITE, net_ev, req) == -1) {
661 close_with_err(req,
662 "failed to register event.");
663 break;
665 break;
667 case IMSG_PROCEED:
668 if ((req = req_by_id(imsg_get_id(&imsg))) == NULL)
669 break;
670 ev_add(req->fd, EV_READ, net_ev, req);
671 net_ev(req->fd, 0, req);
672 break;
674 case IMSG_STOP:
675 if ((req = req_by_id(imsg_get_id(&imsg))) == NULL)
676 break;
677 close_conn(0, 0, req);
678 break;
680 case IMSG_QUIT:
681 ev_break();
682 imsg_free(&imsg);
683 return;
685 default:
686 errx(1, "got unknown imsg %d", imsg_get_type(&imsg));
689 imsg_free(&imsg);
692 imsg_event_add(iev);
695 static int
696 net_send_ui(int type, uint32_t peerid, const void *data,
697 uint16_t datalen)
699 return imsg_compose_event(iev_ui, type, peerid, 0, -1,
700 data, datalen);
703 int
704 net_main(void)
706 setproctitle("net");
708 TAILQ_INIT(&reqhead);
710 if (ev_init() == -1)
711 exit(1);
713 /* Setup pipe and event handler to the main process */
714 if ((iev_ui = malloc(sizeof(*iev_ui))) == NULL)
715 die();
716 imsg_init(&iev_ui->ibuf, 3);
717 iev_ui->handler = handle_dispatch_imsg;
718 iev_ui->events = EV_READ;
719 ev_add(iev_ui->ibuf.fd, iev_ui->events, iev_ui->handler, iev_ui);
721 sandbox_net_process();
723 ev_loop();
725 msgbuf_clear(&iev_ui->ibuf.w);
726 close(iev_ui->ibuf.fd);
727 free(iev_ui);
729 return 0;