diff --git a/.gitignore b/.gitignore index c75cf2e..7a43dd2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ **/*.o +**/*.swp +**/*.pem asfur config.h diff --git a/Makefile b/Makefile index d3cdbef..2d4cce3 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,9 @@ include config.mk SRC = main.c\ - password.c -HDR = config.def.h client.h + password.c\ + network.c +HDR = config.def.h client.h password.h network.h OBJ = ${SRC:.c=.o} all: options asfur @@ -18,7 +19,7 @@ options: .c.o: ${CC} -c ${CFLAGS} $< -${OBJ}: config.h client.h +${OBJ}: config.h client.h password.h network.h config.h: cp config.def.h $@ diff --git a/PROTOCOL b/PROTOCOL new file mode 100644 index 0000000..bed9763 --- /dev/null +++ b/PROTOCOL @@ -0,0 +1,20 @@ +for client: +server parses packets from left to right like this: + [u16 length][u8 type][char *data] + + length: the length of the entire packet + type: + PACKET_ERROR = 0 + PACKET_REGISTER = 1 + PACKET_AUTHENTICATE = 2 + PACKET_JOIN = 3 + PACKET_TEXT = 4 + PACKET_LEAVE = 5 + + data: bytes of data, what it could represent depends on the packet type + (following layouts are layouts for data byte array) + PACKET_REGISTER : [char username[20]][char password[20]] + PACKET_AUTHENTICATE : [char username[20]][char password[20]] + PACKET_JOIN : [] + PACKET_TEXT : + PACKET_LEAVE : diff --git a/client.h b/client.h index ef2f89a..d46c3e8 100644 --- a/client.h +++ b/client.h @@ -2,11 +2,15 @@ #define CLIENT_H #include +#include #include #include struct client { uv_tcp_t handle; + SSL *ssl; + BIO *rbio; + BIO *wbio; uint32_t user_id; uint32_t current_room_id; bool is_authenticated; diff --git a/config.def.h b/config.def.h index 6359ca9..5e6a394 100644 --- a/config.def.h +++ b/config.def.h @@ -2,3 +2,5 @@ #define CONFIG_ALLOW_REGISTER true +#define CONFIG_CERT_FILE "cert.pem" +#define CONFIG_KEY_FILE "key.pem" diff --git a/main.c b/main.c index 089a738..f6c5315 100644 --- a/main.c +++ b/main.c @@ -3,46 +3,89 @@ #include #include #include -#include +#include +#include #include "client.h" uv_loop_t *loop; +SSL_CTX *ctx; -void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) +void cleanup_client(uv_handle_t *handle) { - (void)handle; - buf->base = (char*) malloc(suggested_size); - buf->len = suggested_size; + struct client *client = (struct client*) handle; + if (client->ssl) { + SSL_free(client->ssl); + } + free(client); } -void echo_write(uv_write_t *req, int status) +void on_write_end(uv_write_t *req, int status) { - if (status) { + if (status < 0) { fprintf(stderr, "Write error %s\n", uv_strerror(status)); } + free(req->data); free(req); } -void on_close(uv_handle_t *handle) +void flush_ssl_to_socket(struct client *client) { - free(handle); + char buf[4096]; + int pending; + + while ((pending = BIO_pending(client->wbio)) > 0) { + int bytes_read = BIO_read(client->wbio, buf, sizeof(buf)); + if (bytes_read > 0) { + uv_write_t *req = malloc(sizeof(uv_write_t)); + char *send_data = malloc(bytes_read); + memcpy(send_data, buf, bytes_read); + + req->data = send_data; + + uv_buf_t uvbuf = uv_buf_init(send_data, bytes_read); + uv_write(req, (uv_stream_t*)&client->handle, &uvbuf, 1, on_write_end); + } + } } -void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) +void ssl_write_msg(struct client *client, const char *data, size_t len) { + int written = SSL_write(client->ssl, data, len); + if (written > 0) { + flush_ssl_to_socket(client); + } +} + +void on_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) +{ + struct client *client = (struct client*) stream; + if (nread > 0) { - uv_write_t *req = (uv_write_t *) malloc(sizeof(uv_write_t)); - uv_buf_t wrbuf = uv_buf_init(buf->base, nread); - uv_write(req, client, &wrbuf, 1, echo_write); - } - if (nread < 0) { - if (nread != UV_EOF) - fprintf(stderr, "Read error %s\n", uv_err_name(nread)); - uv_close((uv_handle_t*) client, on_close); + BIO_write(client->rbio, buf->base, nread); + + char plain_buf[4096]; + int p; + + while ((p = SSL_read(client->ssl, plain_buf, sizeof(plain_buf))) > 0) { + ssl_write_msg(client, plain_buf, p); + } + + flush_ssl_to_socket(client); + } + else if (nread < 0) { + if (nread != UV_EOF) fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, cleanup_client); } + free(buf->base); } +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) +{ + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + void on_new_connection(uv_stream_t *server, int status) { if (status < 0) { @@ -52,15 +95,43 @@ void on_new_connection(uv_stream_t *server, int status) struct client *client = malloc(sizeof(struct client)); uv_tcp_init(loop, &client->handle); + if (uv_accept(server, (uv_stream_t*) &client->handle) == 0) { + client->ssl = SSL_new(ctx); + client->rbio = BIO_new(BIO_s_mem()); + client->wbio = BIO_new(BIO_s_mem()); + SSL_set_bio(client->ssl, client->rbio, client->wbio); + SSL_set_accept_state(client->ssl); + uv_read_start((uv_stream_t*) &client->handle, alloc_buffer, on_read); } else { - uv_close((uv_handle_t*) &client->handle, on_close); + uv_close((uv_handle_t*) &client->handle, cleanup_client); + } +} + +void init_openssl() +{ + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + ctx = SSL_CTX_new(TLS_server_method()); + if (!ctx) { + perror("Unable to create SSL context"); + ERR_print_errors_fp(stderr); + exit(1); + } + + SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); + + if (SSL_CTX_use_certificate_file(ctx, CONFIG_CERT_FILE, SSL_FILETYPE_PEM) <= 0 || + SSL_CTX_use_PrivateKey_file(ctx, CONFIG_KEY_FILE, SSL_FILETYPE_PEM) <= 0) { + ERR_print_errors_fp(stderr); + exit(1); } } int main() { + init_openssl(); loop = uv_default_loop(); uv_tcp_t server; @@ -76,5 +147,7 @@ int main() fprintf(stderr, "Listen error %s\n", uv_strerror(r)); return 1; } + + printf("server listening on port 7000...\n"); return uv_run(loop, UV_RUN_DEFAULT); } diff --git a/network.c b/network.c new file mode 100644 index 0000000..481dc96 --- /dev/null +++ b/network.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include "network.h" + +void network_parse_packet() +{ + +} diff --git a/network.h b/network.h new file mode 100644 index 0000000..8d8c647 --- /dev/null +++ b/network.h @@ -0,0 +1,11 @@ +#ifndef NETWORK_H +#define NETWORK_H + +#include + +struct packet_header { + uint16_t size; + uint8_t type; +}; + +#endif