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 *);
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)
357 struct ibuf *ibuf;
358 size_t len;
359 int code;
361 if (!isdigit(header[0]) || !isdigit(header[1]))
362 return -1;
364 code = (header[0] - '0')*10 + (header[1] - '0');
365 if (header[2] != ' ')
366 return -1;
368 header += 3;
369 len = strlen(header) + 1;
371 if ((ibuf = imsg_create(&iev_ui->ibuf, IMSG_REPLY, req->id, 0,
372 sizeof(code) + len)) == NULL)
373 die();
374 if (imsg_add(ibuf, &code, sizeof(code)) == -1 ||
375 imsg_add(ibuf, header, len) == -1)
376 die();
377 imsg_close(&iev_ui->ibuf, ibuf);
378 imsg_event_add(iev_ui);
379 return code;
382 static inline int
383 net_send_req(struct req *req)
385 return (bufio_compose(&req->bio, req->req, req->len));
388 static void
389 net_ev(int fd, int ev, void *d)
391 static char buf[4096];
392 struct req *req = d;
393 const char *hash;
394 ssize_t read;
395 size_t len;
396 char *header;
397 int code;
399 if (ev == EV_TIMEOUT) {
400 close_with_err(req, "Timeout loading page");
401 return;
404 if (req->state == CONN_CONNECTING) {
405 ev_del(req->fd);
406 if (try_to_connect(req) == -1) {
407 if (req->fd != -1 && errno == EAGAIN) {
408 ev_add(req->fd, EV_WRITE, net_ev, req);
409 return;
411 close_with_errf(req, "failed to connect to %s"
412 " (%s: %s)", req->host, req->cause,
413 strerror(req->conn_error));
414 return;
417 bufio_set_fd(&req->bio, req->fd);
419 switch (req->proto) {
420 case PROTO_FINGER:
421 case PROTO_GOPHER:
422 /* finger and gopher don't have a header nor TLS */
423 req->state = CONN_BODY;
424 if (net_send_req(req) == -1) {
425 close_with_err(req, "failed to send request");
426 return;
428 break;
429 case PROTO_GEMINI:
430 req->state = CONN_HANDSHAKE;
431 if (bufio_starttls(&req->bio, req->host, 1,
432 req->ccert, req->ccert_len,
433 req->ccert, req->ccert_len) == -1) {
434 close_with_err(req, "failed to setup TLS");
435 return;
437 req->timer = ev_timer(&timeout_for_handshake,
438 net_ev, req);
439 if (req->timer == 0) {
440 close_with_err(req, "failed to setup"
441 " handshake timer");
442 return;
444 break;
448 if (req->state == CONN_HANDSHAKE) {
449 if (bufio_handshake(&req->bio) == -1 && errno == EAGAIN) {
450 ev_add(req->fd, req_bio_ev(req), net_ev, req);
451 return;
454 ev_timer_cancel(req->timer);
455 req->timer = 0;
457 req->state = CONN_HEADER;
459 /* pause until we've told the certificate is OK */
460 ev_del(req->fd);
462 hash = tls_peer_cert_hash(req->bio.ctx);
463 if (hash == NULL) {
464 close_with_errf(req, "handshake failed: %s",
465 tls_error(req->bio.ctx));
466 return;
469 net_send_ui(IMSG_CHECK_CERT, req->id, hash, strlen(hash)+1);
470 return;
473 if (ev & EV_READ) {
474 read = bufio_read(&req->bio);
475 if (read == -1 && errno != EAGAIN) {
476 close_with_errf(req, "Read error");
477 return;
479 if (read == 0)
480 req->eof = 1;
483 if ((ev & EV_WRITE) && bufio_write(&req->bio) == -1 &&
484 errno != EAGAIN) {
485 close_with_errf(req, "bufio_write: %s", strerror(errno));
486 return;
489 if (req->state == CONN_HEADER) {
490 header = buf_getdelim(&req->bio.rbuf, "\r\n", &len);
491 if (header == NULL && req->bio.rbuf.len >= 1024) {
492 close_with_err(req, "Invalid gemini reply (too long)");
493 return;
495 if (header == NULL && req->eof) {
496 close_with_err(req, "Invalid gemini reply.");
497 return;
499 if (header == NULL) {
500 ev_add(req->fd, req_bio_ev(req), net_ev, req);
501 return;
503 req->state = CONN_BODY;
504 if ((code = gemini_parse_reply(req, header)) == -1) {
505 close_with_err(req, "Malformed gemini reply");
506 return;
508 if (code < 20 || code >= 30) {
509 close_conn(0, 0, req);
510 return;
513 buf_drain(&req->bio.rbuf, len);
515 /* pause until we've been told to go ahead */
516 ev_del(req->fd);
517 return;
520 /*
521 * Split data into chunks before sending. imsg can't handle
522 * message that are "too big".
523 */
524 for (;;) {
525 if ((len = bufio_drain(&req->bio, buf, sizeof(buf))) == 0)
526 break;
527 net_send_ui(IMSG_BUF, req->id, buf, len);
530 if (req->eof) {
531 net_send_ui(IMSG_EOF, req->id, NULL, 0);
532 close_conn(0, 0, req);
533 return;
536 ev_add(req->fd, req_bio_ev(req), net_ev, req);
539 static int
540 load_cert(struct imsg *imsg, struct req *req)
542 struct stat sb;
543 int fd;
545 if ((fd = imsg_get_fd(imsg)) == -1)
546 return (0);
548 if (fstat(fd, &sb) == -1)
549 return (-1);
551 #if 0
552 if (sb.st_size >= (off_t)SIZE_MAX) {
553 close(fd);
554 return (-1);
556 #endif
558 req->ccert = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
559 if (req->ccert == MAP_FAILED) {
560 req->ccert = NULL;
561 close(fd);
562 return (-1);
565 req->ccert_len = sb.st_size;
566 req->ccert_fd = fd;
568 return (0);
571 static void
572 handle_dispatch_imsg(int fd, int event, void *d)
574 struct imsgev *iev = d;
575 struct imsgbuf *ibuf = &iev->ibuf;
576 struct imsg imsg;
577 struct req *req;
578 struct get_req r;
579 ssize_t n;
580 int certok;
582 if (event & EV_READ) {
583 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
584 err(1, "imsg_read");
585 if (n == 0)
586 err(1, "connection closed");
588 if (event & EV_WRITE) {
589 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
590 err(1, "msgbuf_write");
591 if (n == 0)
592 err(1, "connection closed");
595 for (;;) {
596 if ((n = imsg_get(ibuf, &imsg)) == -1)
597 err(1, "imsg_get");
598 if (n == 0)
599 break;
600 switch (imsg_get_type(&imsg)) {
601 case IMSG_GET:
602 if (imsg_get_data(&imsg, &r, sizeof(r)) == -1 ||
603 r.host[sizeof(r.host) - 1] != '\0' ||
604 r.port[sizeof(r.port) - 1] != '\0' ||
605 r.req[sizeof(r.req) - 1] != '\0')
606 die();
607 if (r.proto != PROTO_FINGER &&
608 r.proto != PROTO_GEMINI &&
609 r.proto != PROTO_GOPHER)
610 die();
612 if ((req = calloc(1, sizeof(*req))) == NULL)
613 die();
615 req->fd = -1;
616 #if HAVE_ASR_RUN
617 req->ar_fd = -1;
618 #endif
619 req->ccert_fd = -1;
620 req->id = imsg_get_id(&imsg);
621 TAILQ_INSERT_HEAD(&reqhead, req, reqs);
623 if ((req->host = strdup(r.host)) == NULL)
624 die();
625 if ((req->port = strdup(r.port)) == NULL)
626 die();
627 if ((req->req = strdup(r.req)) == NULL)
628 die();
629 if (load_cert(&imsg, req) == -1)
630 die();
631 if (bufio_init(&req->bio) == -1)
632 die();
634 req->len = strlen(req->req);
635 req->proto = r.proto;
636 req_resolve(-1, 0, req);
637 break;
639 case IMSG_CERT_STATUS:
640 if ((req = req_by_id(imsg_get_id(&imsg))) == NULL)
641 break;
643 if (imsg_get_data(&imsg, &certok, sizeof(certok)) ==
644 -1)
645 die();
646 if (!certok) {
647 close_conn(0, 0, req);
648 break;
651 if (net_send_req(req) == -1) {
652 close_with_err(req, "failed to send request");
653 break;
656 if (ev_add(req->fd, EV_WRITE, net_ev, req) == -1) {
657 close_with_err(req,
658 "failed to register event.");
659 break;
661 break;
663 case IMSG_PROCEED:
664 if ((req = req_by_id(imsg_get_id(&imsg))) == NULL)
665 break;
666 ev_add(req->fd, EV_READ, net_ev, req);
667 net_ev(req->fd, 0, req);
668 break;
670 case IMSG_STOP:
671 if ((req = req_by_id(imsg_get_id(&imsg))) == NULL)
672 break;
673 close_conn(0, 0, req);
674 break;
676 case IMSG_QUIT:
677 ev_break();
678 imsg_free(&imsg);
679 return;
681 default:
682 errx(1, "got unknown imsg %d", imsg_get_type(&imsg));
685 imsg_free(&imsg);
688 imsg_event_add(iev);
691 static int
692 net_send_ui(int type, uint32_t peerid, const void *data,
693 uint16_t datalen)
695 return imsg_compose_event(iev_ui, type, peerid, 0, -1,
696 data, datalen);
699 int
700 net_main(void)
702 setproctitle("net");
704 TAILQ_INIT(&reqhead);
706 if (ev_init() == -1)
707 exit(1);
709 /* Setup pipe and event handler to the main process */
710 if ((iev_ui = malloc(sizeof(*iev_ui))) == NULL)
711 die();
712 imsg_init(&iev_ui->ibuf, 3);
713 iev_ui->handler = handle_dispatch_imsg;
714 iev_ui->events = EV_READ;
715 ev_add(iev_ui->ibuf.fd, iev_ui->events, iev_ui->handler, iev_ui);
717 sandbox_net_process();
719 ev_loop();
721 msgbuf_clear(&iev_ui->ibuf.w);
722 close(iev_ui->ibuf.fd);
723 free(iev_ui);
725 return 0;