diff options
Diffstat (limited to 'ostp.d/net')
-rw-r--r-- | ostp.d/net/otd_listen.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/ostp.d/net/otd_listen.c b/ostp.d/net/otd_listen.c new file mode 100644 index 0000000..87744c2 --- /dev/null +++ b/ostp.d/net/otd_listen.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/select.h> +#include <arpa/inet.h> +#include <net/stpsession.h> +#include <crypto/ecdh.h> +#include <defs.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <string.h> + +#define LISTEN_PORT 5352 +#define KEY_BYTE_WIDTH 32 +#define MAX_BACKLOG 4 +#define MAX_CLIENTS 32 + +static int serv_sock; +static int clients[MAX_CLIENTS] = {0}; + +static void +signal_handle(int sig) +{ + printf("Cleaning up... goodbye!\n"); + + for (int i = 0; i < MAX_CLIENTS; ++i) { + close(clients[i]); + } + + close(serv_sock); + exit(0); +} + +static void +log_pubkey(char pubkey[KEY_BYTE_WIDTH]) +{ + for (size_t i = 0; i < KEY_BYTE_WIDTH; ++i) { + printf("%02X ", pubkey[i] & 0xFF); + if (i != 0 && i % 4 == 0) { + printf("\n"); + } + } +} + +static int +handle_client(struct sockaddr_in *caddr, int clientno) +{ + struct session_request srq; + struct x25519_keypair keypair; + ssize_t nread; + int client_fd; + + client_fd = clients[clientno]; + + /* Try to read in the session request */ + if ((nread = read(client_fd, &srq, sizeof(srq))) < 0) { + printf("Read failure...\n"); + close(client_fd); + clients[clientno] = -1; + return -1; + } + + if (nread == 0) { + printf("Connection closed by peer\n"); + close(client_fd); + clients[clientno] = -1; + return -1; + } + + /* Is this even a session request? */ + if (nread != sizeof(srq)) { + printf("Rejecting data - not a session request...\n"); + close(client_fd); + clients[clientno] = -1; + return -1; + } + + printf("Got public key from peer: \n"); + log_pubkey(srq.pubkey); + printf("Generating keys...\n"); + + if (gen_x25519_keypair(&keypair) < 0) { + printf("Key generation failed!\n"); + close(client_fd); + clients[clientno] = -1; + return -1; + } + + return 0; +} + +static void +read_clients(void) +{ + struct sockaddr_in caddr; + fd_set fds; + socklen_t caddr_len; + int client_sock, error = 0; + char *ip; + + memset(clients, -1, sizeof(clients)); + clients[0] = serv_sock; + + while (1) { + FD_ZERO(&fds); + + for (int i = 0; i < MAX_CLIENTS; ++i) { + if (clients[i] >= 0) + FD_SET(clients[i], &fds); + } + + if (select(1024, &fds, NULL, NULL, NULL) < 0) { + perror("select"); + continue; + } + + /* Check if the servers socket has new connections */ + if (FD_ISSET(serv_sock, &fds)) { + caddr_len = sizeof(caddr); + client_sock = accept(serv_sock, (struct sockaddr *)&caddr, + &caddr_len); + + if (client_sock < 0) { + perror("accept"); + continue; + } + + for (int i = 0; i < MAX_CLIENTS; ++i) { + if (clients[i] < 0) { + clients[i] = client_sock; + ip = inet_ntoa(caddr.sin_addr); + printf("Incoming connection from %s\n", ip); + break; + } + } + } + + /* Handle from data from clients */ + for (int i = 1; i < MAX_CLIENTS; ++i) { + if (clients[i] <= 0) + continue; + if (FD_ISSET(clients[i], &fds) <= 0) + continue; + + handle_client(&caddr, i); + break; + } + } + + close(client_sock); + close(serv_sock); +} + +int +main(void) +{ + struct sockaddr_in saddr; + int error; + + signal(SIGTERM, signal_handle); + signal(SIGINT, signal_handle); + + serv_sock = socket(AF_INET, SOCK_STREAM, 0); + if (serv_sock < 0) { + perror("Failed to create socket\n"); + return -1; + } + + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = INADDR_ANY; + saddr.sin_port = htons(LISTEN_PORT); + error = bind(serv_sock, (struct sockaddr *)&saddr, sizeof(saddr)); + if (error < -1) { + perror("Failed to bind socket\n"); + close(serv_sock); + return error; + } + + if ((error = listen(serv_sock, MAX_BACKLOG)) < -1) { + perror("Failed to listen"); + return error; + } + + read_clients(); + return 0; +} |