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; +}  | 
