From 6b5dfdc8d4f3e17a8d59ae76687afe9d38b7ba7c Mon Sep 17 00:00:00 2001 From: Max <51083570+DRdrProfessor@users.noreply.github.com> Date: Sun, 14 Jan 2024 18:14:52 +0100 Subject: [PATCH] Implemented hostname resolving, added IPv6 --- src/net/include/netex.h | 20 +++++- src/net/netex.c | 152 ++++++++++++++++++++++++++++++++++++---- src/server/main.c | 2 +- src/server/server.c | 20 ++++-- 4 files changed, 171 insertions(+), 23 deletions(-) diff --git a/src/net/include/netex.h b/src/net/include/netex.h index dd28848..5c7c056 100644 --- a/src/net/include/netex.h +++ b/src/net/include/netex.h @@ -8,9 +8,25 @@ #define WARN(msg, args...) fprintf(stdout, "[Warning]: " msg "\n", ##args) #define ERROR(msg, args...) fprintf(stderr, "[ERROR]: " msg "\n", ##args) +typedef enum socket_ipv +{ + IPv4, + IPv6, + Double +} SOCKET_IPV_TYPE; + +typedef struct host_info +{ + char* ip; + struct sockaddr* address; + size_t addrlen; + SOCKET_IPV_TYPE ipv_type; +} HOST_INFO; + + void netex_init(void); void netex_shutdown(void); -// Creates a socket and bind to that socket on the given port and hostname. If done with the socket close it with 'close()' -int setup_socket(int port, const char* hostname); +int setup_socket(int port, const char* hostname, SOCKET_IPV_TYPE ipv_type); +HOST_INFO* resolve_host(const char* hostname, int port, SOCKET_IPV_TYPE ipv_type); #endif //NETEX_H \ No newline at end of file diff --git a/src/net/netex.c b/src/net/netex.c index 4105a7d..81f2688 100644 --- a/src/net/netex.c +++ b/src/net/netex.c @@ -5,7 +5,6 @@ #include #include #include -#include #include "netex.h" #include "config.h" @@ -21,6 +20,7 @@ void netex_init(void) SSL_library_init(); OpenSSL_add_all_algorithms(); } + void netex_shutdown(void) { // OpenSSL @@ -28,24 +28,146 @@ void netex_shutdown(void) EVP_cleanup(); } -int setup_socket(const int port, const char* hostname) +int setup_socket(const int port, const char* hostname, const SOCKET_IPV_TYPE ipv_type) { - struct sockaddr_in sockaddr_in; - const int sock_fd = socket(AF_INET, SOCK_STREAM, 0); - if (sock_fd < 0) + HOST_INFO* resolved_host = resolve_host(hostname, port, ipv_type); + if (resolved_host == NULL) + return -1; + int socket_fd; + switch (resolved_host->ipv_type) { - ERROR("Failed to created socket"); + default: + case IPv4: + PRINT_LINE("Creating IPv4 socket..."); + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd < 0) + { + ERROR("Failed to created socket (IPv4)"); + free(resolved_host); + return -1; + } + break; + case Double: + case IPv6: + PRINT_LINE("Creating IPv6 socket..."); + socket_fd = socket(AF_INET6, SOCK_STREAM, 0); + if (socket_fd < 0) + { + ERROR("Failed to create socket (IPv6)"); + free(resolved_host); + return -1; + } + break; + } + if (socket_fd == 0) + { + WARN("Failed to set socket!"); + free(resolved_host); return -1; } - sockaddr_in.sin_family = AF_INET; - sockaddr_in.sin_port = htons(port); - sockaddr_in.sin_addr.s_addr = inet_addr(hostname); - const int bind_result = bind(sock_fd, (struct sockaddr*)&sockaddr_in, sizeof(sockaddr_in)); + const int bind_result = bind(socket_fd, resolved_host->address, resolved_host->addrlen); if (bind_result != 0) { - ERROR("Could not bind!"); - close(sock_fd); - return -1; + const int bind_error = errno; + ERROR("Could not bind! Error: %i", bind_error); + close(socket_fd); } - return sock_fd; -} \ No newline at end of file + free(resolved_host); + return socket_fd; +} + +HOST_INFO* resolve_host(const char* hostname, const int port, const SOCKET_IPV_TYPE ipv_type) +{ + struct addrinfo *resolved, *next, hints; + + const char* p_port = NULL; + char port_str[PORT_NUM_LENGHT]; + if (port != 0) + { + const int print_result = snprintf(port_str, PORT_NUM_LENGHT, "%d", port); + if (print_result < 0) + { + ERROR("Failed to convert port to string!"); + return NULL; + } + p_port = (char*)&port_str; + } + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = 0; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + switch (ipv_type) + { + default: + case IPv4: + hints.ai_family = AF_INET; + break; + case IPv6: + hints.ai_family = AF_INET6; + break; + case Double: + hints.ai_family = AF_UNSPEC; + break; + } + if (getaddrinfo(hostname, p_port, &hints, &resolved) != 0) + { + ERROR("Failed to get addres info for hostname '%s'", hostname); + return NULL; + } + for (next = resolved; next != NULL; next = next->ai_next) + { + const int sock_fd = socket(next->ai_family, next->ai_socktype, next->ai_protocol); + if (sock_fd == -1) + continue; + if (bind(sock_fd, next->ai_addr, next->ai_addrlen) == 0) + break; // Succesfull bind + if (connect(sock_fd, next->ai_addr, next->ai_addrlen) == 0) + break; + close(sock_fd); + } + if (next == NULL) + { + freeaddrinfo(resolved); + return NULL; + } + HOST_INFO* host_info = malloc(sizeof(HOST_INFO)); + if (host_info == NULL) + { + const int malloc_error = errno; + ERROR("Failed to allocate object, error: %i", malloc_error); + return NULL; + } + switch (next->ai_family) + { + case AF_INET: + host_info->ipv_type = IPv4; + break; + case AF_INET6: + host_info->ipv_type = IPv6; + break; + default: + ERROR("Invalid net family encounterd!"); + free(host_info); + freeaddrinfo(resolved); + return NULL; + } + char host[NI_MAXHOST]; + getnameinfo(next->ai_addr, next->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST); + host_info->ip = strdup(host); + host_info->addrlen = next->ai_addrlen; + host_info->address = malloc(next->ai_addrlen); + if (host_info->address != NULL) + { + if (memcpy(host_info->address, next->ai_addr, next->ai_addrlen) == NULL) + { + WARN("Failed to copy addrinfo over!"); + } + } + freeaddrinfo(resolved); + return host_info; +} diff --git a/src/server/main.c b/src/server/main.c index 2b34bbd..54bb7c6 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -14,7 +14,7 @@ int main(int argc, char *argv[]) const int init_result = initialize_server(argc, argv); if (init_result) { - WARN("Failed to initialize server, error: %i. Exiting...", init_result); + WARN("Failed to initialize server. Exiting..."); return init_result; } return server_execute(); diff --git a/src/server/server.c b/src/server/server.c index e7c2102..9070c60 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -32,7 +32,8 @@ int initialize_server(int argc, char* argv[]) WARN("Fallback to default config!"); srv_configuration = config_create(); config_set_int(srv_configuration, "Connection.Port", 6920); - config_set_string(srv_configuration, "Connection.Host", "localhost"); + config_set_string(srv_configuration, "Connection.BindIP", "0.0.0.0"); + config_set_string(srv_configuration, "Connection.IPv", "Double"); config_set_string(srv_configuration, "Connection.Crypto.CertPath", "cert.pem"); if (config_save_to_path(srv_configuration, CONFIG_PATH) != 0) { @@ -43,9 +44,18 @@ int initialize_server(int argc, char* argv[]) // Socket const int64_t portnum = config_get_int(srv_configuration, "Connection.Port"); - char* hostname = config_get_string(srv_configuration, "Connection.Host"); - server_sockfd = setup_socket(portnum, hostname); + char* hostname = config_get_string(srv_configuration, "Connection.BindIP"); + char* ipv = config_get_string(srv_configuration, "Connection.IPv"); + SOCKET_IPV_TYPE ipv_t = IPv4; + if (strcmp(ipv, "Double") == 0) + ipv_t = Double; + else if (strcmp(ipv, "4") == 0) + ipv_t = IPv4; + else if (strcmp(ipv, "6") == 0) + ipv_t = IPv6; + server_sockfd = setup_socket(portnum, hostname, ipv_t); free(hostname); + free(ipv); if (server_sockfd <= 0) { WARN("Could not create server sockedfd!"); @@ -56,7 +66,7 @@ int initialize_server(int argc, char* argv[]) int server_execute(void) { - const int thread_create_result = pthread_create(&listen_thread, NULL, server_listen, NULL); + const int thread_create_result = pthread_create(&listen_thread, NULL, (void*)server_listen, NULL); if (thread_create_result != 0) { ERROR("Failed to create main listening thread, pthread error: %i", thread_create_result); @@ -99,5 +109,5 @@ void server_listen() close(accepted_fd); //TODO: Send client to thread that will handle further connection things. } - pthread_exit((void*)some_return_code); + pthread_exit(&some_return_code); } \ No newline at end of file