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.
This commit is contained in:
Omar Polo 2021-01-13 18:40:18 +00:00
parent 0d7a38c4ce
commit 9862b637c2
2 changed files with 78 additions and 40 deletions

115
gmid.c
View File

@ -569,51 +569,86 @@ send_dir(char *path, struct pollfd *fds, struct client *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;
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;
}
if (strcmp(iri.schema, "gemini")) {
if (!start_reply(fds, c, PROXY_REFUSED, "won't proxy request"))
return;
goodbye(fds, c);
return;
}
LOGI(c, "GET %s%s%s",
*iri.path ? iri.path : "/",
*iri.query ? "?" : "",
*iri.query ? iri.query : "");
send_file(iri.path, iri.query, fds, c);
}
void
handle(struct pollfd *fds, struct client *client)
{
switch (client->state) {
case S_HANDSHAKE:
handle_handshake(fds, client);
break;
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);
return;
case TLS_WANT_POLLIN:
fds->events = POLLIN;
return;
case TLS_WANT_POLLOUT:
fds->events = POLLOUT;
return;
}
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;
}
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 : "");
send_file(iri.path, iri.query, fds, client);
handle_open_conn(fds, client);
break;
case S_INITIALIZING:
@ -738,7 +773,7 @@ do_accept(int sock, struct tls *ctx, struct pollfd *fds, struct client *clients)
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;

3
gmid.h
View File

@ -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 client*);
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);