Compare commits

..

2 Commits

Author SHA1 Message Date
Barra Ó Catháin 2d6b194c26 Added basic command-line options to server.
* source/server/main.c
(checkRequestedHostname): Added function to check if client SNI hostname is the same as specified by the server.
(main): Added command-line options for binding to ports, hostnames, and interfaces.
2024-03-18 03:14:50 +00:00
Barra Ó Catháin 24f8e2688a Added address iteration and graceful TLS failures.
* source/client/main.c (main):
- Added iteration through found addresses from getaddrinfo.
- Added graceful failures for TLS errors.
2024-03-18 03:10:59 +00:00
2 changed files with 110 additions and 21 deletions

View File

@ -21,23 +21,24 @@
#include "client-drawing.h" #include "client-drawing.h"
#include "receiving-thread.h" #include "receiving-thread.h"
static char serverPort[HOST_NAME_MAX] = "5050";
static char serverHostname[HOST_NAME_MAX] = "127.0.0.1";
static bool hostSpecified = false, portSpecified = false;
int main (int argc, char ** argv) int main (int argc, char ** argv)
{ {
static char serverPort[HOST_NAME_MAX] = "5050";
static char serverHostname[HOST_NAME_MAX] = "127.0.0.1";
struct addrinfo * serverInformation;
// Print a welcome message: // Print a welcome message:
printf("SilverMUD Client - Starting Now.\n" printf("SilverMUD Client - Starting Now.\n"
"================================\n"); "================================\n");
struct addrinfo * serverInformation;
// Configure command-line options: // Configure command-line options:
static struct option longOptions[] = static struct option longOptions[] =
{ {
{"host", required_argument, 0, 'h' }, {"host", required_argument, 0, 'h' },
{"port", required_argument, 0, 'p' } {"port", required_argument, 0, 'p' }
}; };
bool hostSpecified = false, portSpecified = false;
// Parse command-line options: // Parse command-line options:
int selectedOption = 0, optionIndex = 0; int selectedOption = 0, optionIndex = 0;
@ -78,13 +79,22 @@ int main (int argc, char ** argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Connect to the server: // Connect to the server, iterating through addresses until we get SilverMUD:
if (connect(serverSocket, serverInformation->ai_addr, serverInformation->ai_addrlen) != 0) struct addrinfo * currentAddress;
for (currentAddress = serverInformation; currentAddress != NULL; currentAddress = currentAddress->ai_next)
{
if (connect(serverSocket, serverInformation->ai_addr, serverInformation->ai_addrlen) != -1)
{
break;
}
}
if (currentAddress == NULL)
{ {
printf("Failed to connect to the server. Aborting.\n"); printf("Failed to connect to the server. Aborting.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
freeaddrinfo(serverInformation);
// Set up a GnuTLS session and handshake with the server: // Set up a GnuTLS session and handshake with the server:
gnutls_session_t tlsSession = NULL; gnutls_session_t tlsSession = NULL;
if (gnutls_init(&tlsSession, GNUTLS_CLIENT) < 0) if (gnutls_init(&tlsSession, GNUTLS_CLIENT) < 0)
@ -94,20 +104,31 @@ int main (int argc, char ** argv)
gnutls_anon_client_credentials_t clientKey = NULL; gnutls_anon_client_credentials_t clientKey = NULL;
gnutls_anon_allocate_client_credentials(&clientKey); gnutls_anon_allocate_client_credentials(&clientKey);
gnutls_credentials_set(tlsSession, GNUTLS_CRD_ANON, &clientKey);
gnutls_transport_set_int(tlsSession, serverSocket); gnutls_transport_set_int(tlsSession, serverSocket);
gnutls_priority_set_direct(tlsSession, "PERFORMANCE:+ANON-ECDH:+ANON-DH", NULL); gnutls_credentials_set(tlsSession, GNUTLS_CRD_ANON, &clientKey);
gnutls_handshake_set_timeout(tlsSession, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); gnutls_handshake_set_timeout(tlsSession, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
gnutls_priority_set_direct(tlsSession, "PERFORMANCE:+ANON-ECDH:+ANON-DH", NULL);
gnutls_server_name_set(tlsSession, GNUTLS_NAME_DNS, serverHostname, strlen(serverHostname));
int returnValue = -1; int returnValue = -1, connectionAttempts = 0;
do do
{ {
returnValue = gnutls_handshake(tlsSession); returnValue = gnutls_handshake(tlsSession);
connectionAttempts++;
if (connectionAttempts == 50)
{
printf("Failed to establish a TLS session. Aborting.\n");
exit(EXIT_FAILURE);
}
} }
while (returnValue < 0 && gnutls_error_is_fatal(returnValue) == 0); while (returnValue < 0 && gnutls_error_is_fatal(returnValue) == 0);
if (returnValue < 0)
{
printf("Failed to establish a TLS session. Aborting.\n");
exit(EXIT_FAILURE);
}
// Initialize ncurses: // Initialize ncurses:
initscr(); initscr();
keypad(stdscr, TRUE); keypad(stdscr, TRUE);

View File

@ -9,6 +9,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h>
#include <stdbool.h> #include <stdbool.h>
#include <pthread.h> #include <pthread.h>
#include <libguile.h> #include <libguile.h>
@ -24,8 +25,31 @@
#include "../messages.h" #include "../messages.h"
#include "scheme-integration.h" #include "scheme-integration.h"
static const int PORT = 5000;
static const int CONCURRENT_PLAYER_COUNT = 256; static const int CONCURRENT_PLAYER_COUNT = 256;
static char serverPort[HOST_NAME_MAX] = "5050";
static char serverHostname[HOST_NAME_MAX] = "";
static char serverInterface[HOST_NAME_MAX] = "";
static char clientRequestedHost[HOST_NAME_MAX] = "";
static size_t clientRequestedHostLength = HOST_NAME_MAX;
static bool portSpecified = false, hostSpecified = false, interfaceSpecified = false;
// Check what the client intends to connect to:
int checkRequestedHostname(gnutls_session_t session)
{
// Get the hostname the client is using to connect:
clientRequestedHostLength = HOST_NAME_MAX;
gnutls_server_name_get(session, (void *)clientRequestedHost, &clientRequestedHostLength, &(unsigned int){GNUTLS_NAME_DNS}, 0);
clientRequestedHost[HOST_NAME_MAX - 1] = '\0';
printf("Client is connecting to: %s\n", clientRequestedHost);
// Check that it's a valid hostname for SilverMUD:
if (hostSpecified == true && strncmp(serverHostname, clientRequestedHost, HOST_NAME_MAX) != 0)
{
return GNUTLS_E_UNRECOGNIZED_NAME;
}
return 0;
}
int main (int argc, char ** argv) int main (int argc, char ** argv)
{ {
@ -33,6 +57,46 @@ int main (int argc, char ** argv)
printf("SilverMUD Server - Starting Now.\n" printf("SilverMUD Server - Starting Now.\n"
"================================\n"); "================================\n");
// Configure command-line options:
static struct option longOptions[] =
{
{"port", required_argument, 0, 'p' },
{"host", required_argument, 0, 'h' },
{"interface", required_argument, 0, 'i' }
};
// Parse command-line options:
int selectedOption = 0, optionIndex = 0;
while ((selectedOption = getopt_long(argc, argv, "p:h:i:", longOptions, &optionIndex)) != -1)
{
switch (selectedOption)
{
case 'p':
{
printf("Using port: %s\n", optarg);
portSpecified = true;
strncpy(serverPort, optarg, HOST_NAME_MAX);
break;
}
case 'h':
{
printf("Using hostname: %s\n", optarg);
hostSpecified = true;
strncpy(serverHostname, optarg, HOST_NAME_MAX);
break;
}
case 'i':
{
printf("Using interface address: %s\n", optarg);
interfaceSpecified = true;
strncpy(serverInterface, optarg, HOST_NAME_MAX);
break;
}
}
}
// Initialize Scheme: // Initialize Scheme:
scm_init_guile(); scm_init_guile();
@ -59,8 +123,10 @@ int main (int argc, char ** argv)
// Assign the IP address and port to the server address struct: // Assign the IP address and port to the server address struct:
serverAddress.sin_family = AF_INET; serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_addr.s_addr = (interfaceSpecified) ?
serverAddress.sin_port = htons(PORT); inet_addr(serverInterface) : htonl(INADDR_ANY);
serverAddress.sin_port = (portSpecified) ?
htons(atoi(serverPort)) : htons(5050);
// Bind the master socket to the server address: // Bind the master socket to the server address:
if ((bind(masterSocket, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in))) != 0) if ((bind(masterSocket, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in))) != 0)
@ -109,6 +175,8 @@ int main (int argc, char ** argv)
//pthread_t schemeREPLThread; //pthread_t schemeREPLThread;
//pthread_create(&schemeREPLThread, NULL, schemeREPLHandler, NULL); //pthread_create(&schemeREPLThread, NULL, schemeREPLHandler, NULL);
size_t * clientRequestedHostLength = calloc(1, sizeof(size_t));
while (true) while (true)
{ {
do do
@ -133,22 +201,22 @@ int main (int argc, char ** argv)
gnutls_priority_set_direct(*tlsSession, "NORMAL:+ANON-ECDH:+ANON-DH", NULL); gnutls_priority_set_direct(*tlsSession, "NORMAL:+ANON-ECDH:+ANON-DH", NULL);
gnutls_credentials_set(*tlsSession, GNUTLS_CRD_ANON, serverKey); gnutls_credentials_set(*tlsSession, GNUTLS_CRD_ANON, serverKey);
gnutls_handshake_set_timeout(*tlsSession, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); gnutls_handshake_set_timeout(*tlsSession, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
gnutls_handshake_set_post_client_hello_function(*tlsSession, checkRequestedHostname);
// Accept the connection: // Accept the connection:
int newSocket = accept(masterSocket, NULL, NULL); int newSocket = accept(masterSocket, NULL, NULL);
gnutls_transport_set_int(*tlsSession, newSocket); gnutls_transport_set_int(*tlsSession, newSocket);
// Perform a TLS handshake: // Perform a TLS handshake:
int handshakeReturnValue = 0; int handshakeReturnValue = 0;
do do
{ {
handshakeReturnValue = gnutls_handshake(*tlsSession); handshakeReturnValue = gnutls_handshake(*tlsSession);
} while (handshakeReturnValue < 0 && gnutls_error_is_fatal(handshakeReturnValue) == 0); } while (handshakeReturnValue < 0 && gnutls_error_is_fatal(handshakeReturnValue) == 0);
// If the handshake was unsuccessful, close the connection: // If the handshake was unsuccessful, close the connection:
if (handshakeReturnValue < 0) if (handshakeReturnValue < 0)
{ {
printf("%d", handshakeReturnValue); fprintf(stderr, "TLS Failure: %d\n", handshakeReturnValue);
fflush(stdout); fflush(stdout);
gnutls_bye(*tlsSession, 2); gnutls_bye(*tlsSession, 2);
shutdown(newSocket, 2); shutdown(newSocket, 2);