Implemented hostname resolving, added IPv6

This commit is contained in:
Max 2024-01-14 18:14:52 +01:00
parent 07cde8f676
commit 6b5dfdc8d4
4 changed files with 171 additions and 23 deletions

View File

@ -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

View File

@ -5,7 +5,6 @@
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#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;
}
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;
}

View File

@ -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();

View File

@ -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);
}