commit 9862b637c2aa97e7e8d148ae9c3f92d0ca758fa7 from: Omar Polo date: Wed Jan 13 18:40:18 2021 UTC track handshakes This alter the current state machine by adding S_HANDSHAKE as the initial state. There, we ensure we did the handshake and we check SNI. ATM we simply continue in S_OPEN, but later we can add virtual host checks there, and skip to S_INITIALIZING with an error state if the client is accessing a wrong host. commit - 0d7a38c4ce99cf5367a242d0a1d41b51d4a742e8 commit + 9862b637c2aa97e7e8d148ae9c3f92d0ca758fa7 blob - ab19646ef28f0d0c0d7c5a4ab18e94d2353629cc blob + 13d49e238fe9957f5d2580fda736d3f50e949676 --- gmid.c +++ gmid.c @@ -569,51 +569,86 @@ send_dir(char *path, struct pollfd *fds, struct client } void -handle(struct pollfd *fds, struct client *client) +handle_handshake(struct pollfd *fds, struct client *c) { + switch (tls_handshake(c->ctx)) { + case 0: /* success */ + case -1: /* already handshaked */ + break; + case TLS_WANT_POLLIN: + fds->events = POLLIN; + return; + case TLS_WANT_POLLOUT: + fds->events = POLLOUT; + return; + default: + /* unreachable */ + abort(); + } + + /* TODO: check SNI here */ + logs(LOG_DEBUG, c, "client wanted to talk to: %s", tls_conn_servername(c->ctx)); + + c->state = S_OPEN; + handle_open_conn(fds, c); +} + +void +handle_open_conn(struct pollfd *fds, struct client *c) +{ char buf[GEMINI_URL_LEN]; - const char *parse_err; + const char *parse_err = "invalid request"; struct iri iri; - switch (client->state) { - case S_OPEN: - bzero(buf, GEMINI_URL_LEN); - switch (tls_read(client->ctx, buf, sizeof(buf)-1)) { - case -1: - LOGE(client, "tls_read: %s", tls_error(client->ctx)); - goodbye(fds, client); + bzero(buf, sizeof(buf)); + + switch (tls_read(c->ctx, buf, sizeof(buf)-1)) { + case -1: + LOGE(c, "tls_read: %s", tls_error(c->ctx)); + goodbye(fds, c); + return; + + case TLS_WANT_POLLIN: + fds->events = POLLIN; + return; + + case TLS_WANT_POLLOUT: + fds->events = POLLOUT; + return; + } + + if (!trim_req_iri(buf) || !parse_iri(buf, &iri, &parse_err)) { + if (!start_reply(fds, c, BAD_REQUEST, parse_err)) return; + goodbye(fds, c); + return; + } - case TLS_WANT_POLLIN: - fds->events = POLLIN; + if (strcmp(iri.schema, "gemini")) { + if (!start_reply(fds, c, PROXY_REFUSED, "won't proxy request")) return; + goodbye(fds, c); + return; + } - case TLS_WANT_POLLOUT: - fds->events = POLLOUT; - return; - } + LOGI(c, "GET %s%s%s", + *iri.path ? iri.path : "/", + *iri.query ? "?" : "", + *iri.query ? iri.query : ""); - parse_err = "invalid request"; - if (!trim_req_iri(buf) || !parse_iri(buf, &iri, &parse_err)) { - if (!start_reply(fds, client, BAD_REQUEST, parse_err)) - return; - goodbye(fds, client); - return; - } + send_file(iri.path, iri.query, fds, c); +} - if (strcmp(iri.schema, "gemini")) { - if (!start_reply(fds, client, PROXY_REFUSED, "won't proxy request")) - return; - goodbye(fds, client); - return; - } - - LOGI(client, "GET %s%s%s", - *iri.path ? iri.path : "/", - *iri.query ? "?" : "", - *iri.query ? iri.query : ""); +void +handle(struct pollfd *fds, struct client *client) +{ + switch (client->state) { + case S_HANDSHAKE: + handle_handshake(fds, client); + break; - send_file(iri.path, iri.query, fds, client); + case S_OPEN: + handle_open_conn(fds, client); break; case S_INITIALIZING: @@ -738,7 +773,7 @@ do_accept(int sock, struct tls *ctx, struct pollfd *fd fds[i].fd = fd; fds[i].events = POLLIN; - clients[i].state = S_OPEN; + clients[i].state = S_HANDSHAKE; clients[i].fd = -1; clients[i].child = -1; clients[i].buf = MAP_FAILED; blob - e145d1a626088989b5738e140f7480da9c5fac93 blob + 570d38cc4b4fc4d38bcdf32cd7af64ceed755f42 --- gmid.h +++ gmid.h @@ -51,6 +51,7 @@ #define MAX_USERS 64 enum { + S_HANDSHAKE, S_OPEN, S_INITIALIZING, S_SENDING, @@ -111,6 +112,8 @@ void cgi_poll_on_client(struct pollfd*, struct clien void handle_cgi(struct pollfd*, struct client*); void send_file(char*, char*, struct pollfd*, struct client*); void send_dir(char*, struct pollfd*, struct client*); +void handle_handshake(struct pollfd*, struct client*); +void handle_open_conn(struct pollfd*, struct client*); void handle(struct pollfd*, struct client*); void mark_nonblock(int);