diff options
author | Luke Bratch <luke@bratch.co.uk> | 2024-11-09 23:50:46 +0000 |
---|---|---|
committer | Luke Bratch <luke@bratch.co.uk> | 2024-11-09 23:50:46 +0000 |
commit | f55160af3f25fff17d3af4dde50a606c2c78f79b (patch) | |
tree | bc0eb6a581a33d3b81d5b1cf1becf40418c8e9ed | |
parent | 59addf47eca6a0be54e3b07c4ed2b156a8431376 (diff) |
Make NOTICE alerts about client (dis)connection and authentication events optional.
New configuration options added:
- alertconnect
- alertauthfail
- alertauthsuccess
- alertunautheddisconnect
- alertautheddisconnect
-rw-r--r-- | README | 5 | ||||
-rw-r--r-- | TODO | 8 | ||||
-rw-r--r-- | blabouncer.c | 55 | ||||
-rw-r--r-- | blabouncer.conf.example | 15 | ||||
-rw-r--r-- | config.c | 17 | ||||
-rw-r--r-- | functions.c | 86 | ||||
-rw-r--r-- | message.c | 40 | ||||
-rw-r--r-- | structures.h | 5 |
8 files changed, 194 insertions, 37 deletions
@@ -37,6 +37,11 @@ These options can be changed by issuing a BLABOUNCER REHASH command or by sendin - debug - certfile - keyfile + - alertconnect + - alertauthfail + - alertauthsuccess + - alertunautheddisconnect + - alertautheddisconnect == Commands == @@ -51,3 +51,11 @@ Are WALLOPS logged & replayed? QUIT not logged in all channels a person was in? (e.g. Joey Mon 1 Apr 20:49:14 BST 2024) "/whois" with no nick - "No nickname given" goes to all clients - fixable? + +Ability to check for updates (and optional at startup?). + +Absurd CPU usage and duration doing "/BLABOUNCER REPLAY 24:0" approx. 14/09/2024 17:35. + +Send NOTICE about failed authentication before disconnecting. + +Failure to read configuration file suggestion that an upgrade may require new settings. diff --git a/blabouncer.c b/blabouncer.c index 75ce966..56c21a0 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -888,16 +888,18 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { // TODO - Handle the "find a free element" loop not finding a free element debugprint(DEBUG_FULL, "bouncer-client: new connection from %s on socket %d%s\n", remoteip, newfd, opensslfailmsg); - // Alert other clients about the new connection - char alertmsg[MAXDATASIZE]; - if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client connected from %s%s.", ircdstate.ircnick, - remoteip, opensslfailmsg)) { - fprintf(stderr, "Error while preparing new client connection NOTICE!\n"); - debugprint(DEBUG_CRIT, "Error while preparing new client connection NOTICE!\n"); - alertmsg[0] = '\0'; + // Alert other clients about the new connection (if enabled) + if (settings->alertconnect) { + char alertmsg[MAXDATASIZE]; + if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client connected from %s%s.", ircdstate.ircnick, + remoteip, opensslfailmsg)) { + fprintf(stderr, "Error while preparing new client connection NOTICE!\n"); + debugprint(DEBUG_CRIT, "Error while preparing new client connection NOTICE!\n"); + alertmsg[0] = '\0'; + } + // "except" 0 since we trust this message + sendtoallclients(clients, alertmsg, 0, settings); } - // "except" 0 since we trust this message - sendtoallclients(clients, alertmsg, 0, settings); debugprint(DEBUG_FULL, "bouncer-client: total client connections: %d\n", numclients(clients)); } // If using client TLS and still pending SSL_accept() then re-try SSL_accept() (it can't be real client data yet) @@ -1224,6 +1226,41 @@ int main(int argc, char *argv[]) { exit(1); } + // Is alerting (NOTICE) upon a new connection enabled? + settings.alertconnect = getconfint("alertconnect", settings.conffile); + if (errno == ECONFINT) { + printf("main(): error getting 'alertconnect' from configuration file.\n"); + exit(1); + } + + // Is alerting (NOTICE) upon a failed authentication enabled? + settings.alertauthfail = getconfint("alertauthfail", settings.conffile); + if (errno == ECONFINT) { + printf("main(): error getting 'alertauthfail' from configuration file.\n"); + exit(1); + } + + // Is alerting (NOTICE) upon a successful authentication enabled? + settings.alertauthsuccess = getconfint("alertauthsuccess", settings.conffile); + if (errno == ECONFINT) { + printf("main(): error getting 'alertauthsuccess' from configuration file.\n"); + exit(1); + } + + // Is alerting (NOTICE) upon unauthenticated client disconnections enabled? + settings.alertunautheddisconnect = getconfint("alertunautheddisconnect", settings.conffile); + if (errno == ECONFINT) { + printf("main(): error getting 'alertunautheddisconnect' from configuration file.\n"); + exit(1); + } + + // Is alerting (NOTICE) upon authenticated client disconnections enabled? + settings.alertautheddisconnect = getconfint("alertautheddisconnect", settings.conffile); + if (errno == ECONFINT) { + printf("main(): error getting 'alertautheddisconnect' from configuration file.\n"); + exit(1); + } + // How many debug logs should we keep? settings.debugkeep = getconfint("debugkeep", settings.conffile); if (errno == ECONFINT) { diff --git a/blabouncer.conf.example b/blabouncer.conf.example index d77689c..2281806 100644 --- a/blabouncer.conf.example +++ b/blabouncer.conf.example @@ -108,3 +108,18 @@ debug = "2" # Number of debug logs to keep debugkeep = "5" + +# Send NOTICE to all other clients upon new client connections ("1" for yes or "0" for no) +alertconnect = "1" + +# Send NOTICE to all other clients upon clients failing to authenticate ("1" for yes or "0" for no) +alertauthfail = "1" + +# Send NOTICE to all other clients upon clients succesfully authenticating ("1" for yes or "0" for no) +alertauthsuccess = "1" + +# Send NOTICE to all other clients upon unauthenticated client disconnections ("1" for yes or "0" for no) +alertunautheddisconnect = "1" + +# Send NOTICE to all other clients upon authenticated client disconnections ("1" for yes or "0" for no) +alertautheddisconnect = "1" @@ -419,7 +419,22 @@ int createconfigfile(char *filename) { "debug = \"2\"\n" "\n" "# Number of debug logs to keep\n" - "debugkeep = \"5\"\n"; + "debugkeep = \"5\"\n" + "\n" + "# Send NOTICE to all other clients upon new client connections (\"1\" for yes or \"0\" for no)\n" + "alertconnect = \"1\"\n" + "\n" + "# Send NOTICE to all other clients upon clients failing to authenticate (\"1\" for yes or \"0\" for no)\n" + "alertauthfail = \"1\"\n" + "\n" + "# Send NOTICE to all other clients upon clients succesfully authenticating (\"1\" for yes or \"0\" for no)\n" + "alertauthsuccess = \"1\"\n" + "\n" + "# Send NOTICE to all other clients upon unauthenticated client disconnections (\"1\" for yes or \"0\" for no)\n" + "alertunautheddisconnect = \"1\"\n" + "\n" + "# Send NOTICE to all other clients upon authenticated client disconnections (\"1\" for yes or \"0\" for no)\n" + "alertautheddisconnect = \"1\"\n"; // Write complete string to file if ((fprintf(fp, "%s", string)) < 0) { diff --git a/functions.c b/functions.c index d0c0341..c3e9c94 100644 --- a/functions.c +++ b/functions.c @@ -633,13 +633,10 @@ int disconnectclient(int fd, struct client *clients, struct ircdstate *ircdstate } debugprint(DEBUG_SOME, "disconnectclient(): disconnecting client %s with fd '%d'\n", clients[clientindex].remoteip, fd); - // Alert other clients about the disconnection (don't send yet, we haven't removed from the clients array yet) - char alertmsg[MAXDATASIZE]; - if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: client %s has disconnected.", ircdstate->ircnick, clients[clientindex].remoteip)) { - fprintf(stderr, "Error while preparing authentication failure NOTICE!\n"); - debugprint(DEBUG_CRIT, "Error while preparing authentication failure NOTICE!\n"); - alertmsg[0] = '\0'; - } + // Record some properties of the disconnecting client before we remove it from the clients array + int discauthed = clients[clientindex].authed; + char *discremoteip = strdup(clients[clientindex].remoteip); + // Remove the client from the clients array for (int i = 0; i < MAXCLIENTS; i++) { if (clients[i].fd == fd) { @@ -670,20 +667,46 @@ int disconnectclient(int fd, struct client *clients, struct ircdstate *ircdstate // Finish up with OpenSSL if using client TLS SSL_free(clients[i].ssl); } + // Close the socket close(fd); - // Now clients array is cleared, inform all other clients (source "0" since we trust this message) - sendtoallclients(clients, alertmsg, 0, settings); + // If there are now no clients connected, record the time if (numclients(clients) == 0) { ircdstate->clientsnonetime = time(NULL); } + + // Now clients array is cleared, inform all other clients about the disconnection (if enabled) + if (!discauthed && settings->alertunautheddisconnect) { + // Unauthenticated client disconnection alerts enabled and disconnecting client is not authenticated + char alertmsg[MAXDATASIZE]; + if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: unauthenticated client %s has disconnected.", ircdstate->ircnick, discremoteip)) { + fprintf(stderr, "Error while preparing unauthenticated client disconnection NOTICE!\n"); + debugprint(DEBUG_CRIT, "Error while preparing unauthenticated client disconnection NOTICE!\n"); + alertmsg[0] = '\0'; + } + // (source "0" since we trust this message) + sendtoallclients(clients, alertmsg, 0, settings); + } else if (discauthed && settings->alertautheddisconnect) { + // Authenticated client disconnection alerts enabled and disconnecting client is authenticated + char alertmsg[MAXDATASIZE]; + if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: authenticated client %s has disconnected.", ircdstate->ircnick, discremoteip)) { + fprintf(stderr, "Error while preparing authenticated client disconnection NOTICE!\n"); + debugprint(DEBUG_CRIT, "Error while preparing authenticated client disconnection NOTICE!\n"); + alertmsg[0] = '\0'; + } + // (source "0" since we trust this message) + sendtoallclients(clients, alertmsg, 0, settings); + } + + free(discremoteip); return 1; } } // If we got here, we didn't find and clear the client // TODO - Do something with a failed return code + free(discremoteip); return 0; } @@ -1231,6 +1254,51 @@ int rehash(struct settings *settings, char *failuremsg, SSL_CTX *ctx) { configure_openssl_context(ctx, settings->certfile, settings->keyfile); } + // Is alerting (NOTICE) upon a new connection enabled? + int oldalertconnect = settings->alertconnect; + settings->alertconnect = getconfint("alertconnect", settings->conffile); + if (errno == ECONFINT) { + settings->alertconnect = oldalertconnect; + strcpy(failuremsg, "error getting 'alertconnect' from configuration file"); + return 0; + } + + // Is alerting (NOTICE) upon a failed authentication enabled? + int oldalertauthfail = settings->alertauthfail; + settings->alertauthfail = getconfint("alertauthfail", settings->conffile); + if (errno == ECONFINT) { + settings->alertauthfail = oldalertauthfail; + strcpy(failuremsg, "error getting 'alertauthfail' from configuration file"); + return 0; + } + + // Is alerting (NOTICE) upon a successful authentication enabled? + int oldalertauthsuccess = settings->alertauthsuccess; + settings->alertauthsuccess = getconfint("alertauthsuccess", settings->conffile); + if (errno == ECONFINT) { + settings->alertauthsuccess = oldalertauthsuccess; + strcpy(failuremsg, "error getting 'alertauthsuccess' from configuration file"); + return 0; + } + + // Is alerting (NOTICE) upon unauthenticated client disconnections enabled? + int oldalertunautheddisconnect = settings->alertunautheddisconnect; + settings->alertunautheddisconnect = getconfint("alertunautheddisconnect", settings->conffile); + if (errno == ECONFINT) { + settings->alertunautheddisconnect = oldalertunautheddisconnect; + strcpy(failuremsg, "error getting 'alertunautheddisconnect' from configuration file"); + return 0; + } + + // Is alerting (NOTICE) upon authenticated client disconnections enabled? + int oldalertautheddisconnect = settings->alertautheddisconnect; + settings->alertautheddisconnect = getconfint("alertautheddisconnect", settings->conffile); + if (errno == ECONFINT) { + settings->alertautheddisconnect = oldalertautheddisconnect; + strcpy(failuremsg, "error getting 'alertautheddisconnect' from configuration file"); + return 0; + } + // All is good, no failure message, return 1. failuremsg[0] = '\0'; return 1; @@ -905,16 +905,18 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int // Found client in array, set to authenticated clients[i].authed = 1; debugprint(DEBUG_FULL, "Found and authenticated fd in arr_authed.\n"); - // Alert other clients about the successful authentication - char alertmsg[MAXDATASIZE]; - if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client %s has successfully authenticated.", ircdstate->ircnick, - clients[clientindex].remoteip)) { - fprintf(stderr, "Error while preparing authentication success NOTICE!\n"); - debugprint(DEBUG_CRIT, "Error while preparing authentication success NOTICE!\n"); - alertmsg[0] = '\0'; + // Alert other clients about the successful authentication (if enabled) + if (settings->alertauthsuccess) { + char alertmsg[MAXDATASIZE]; + if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client %s has successfully authenticated.", ircdstate->ircnick, + clients[clientindex].remoteip)) { + fprintf(stderr, "Error while preparing authentication success NOTICE!\n"); + debugprint(DEBUG_CRIT, "Error while preparing authentication success NOTICE!\n"); + alertmsg[0] = '\0'; + } + // "except" the current fd - we can use this as "except/sourcefd" since we set them as authed just above + sendtoallclients(clients, alertmsg, sourcefd, settings); } - // "except" the current fd - we can use this as "except/sourcefd" since we set them as authed just above - sendtoallclients(clients, alertmsg, sourcefd, settings); } } } else { @@ -924,15 +926,17 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int strncpy(remoteip, clients[clientindex].remoteip, INET6_ADDRSTRLEN); debugprint(DEBUG_SOME, "Password rejected, disconnecting client %s with fd %d.\n", remoteip, sourcefd); disconnectclient(sourcefd, clients, ircdstate, settings, clientcodes); - // Alert other clients about the failed authentication - char alertmsg[MAXDATASIZE]; - if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client %s failed to authenticate.", ircdstate->ircnick, remoteip)) { - fprintf(stderr, "Error while preparing authentication failure NOTICE!\n"); - debugprint(DEBUG_CRIT, "Error while preparing authentication failure NOTICE!\n"); - alertmsg[0] = '\0'; - } - // "except" 0 since we trust this message - sendtoallclients(clients, alertmsg, 0, settings); + // Alert other clients about the failed authentication (if enabled) + if (settings->alertauthfail) { + char alertmsg[MAXDATASIZE]; + if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client %s failed to authenticate.", ircdstate->ircnick, remoteip)) { + fprintf(stderr, "Error while preparing authentication failure NOTICE!\n"); + debugprint(DEBUG_CRIT, "Error while preparing authentication failure NOTICE!\n"); + alertmsg[0] = '\0'; + } + // "except" 0 since we trust this message + sendtoallclients(clients, alertmsg, 0, settings); + } } return 1; diff --git a/structures.h b/structures.h index d070638..b2585bd 100644 --- a/structures.h +++ b/structures.h @@ -83,6 +83,11 @@ struct settings { int debugkeep; int background; // Whether or not we're running in the background (detached from the terminal as a daemon) int replaydates; // Whether or not to include datestamps when replaying the replay log + int alertconnect; + int alertauthfail; + int alertauthsuccess; + int alertunautheddisconnect; + int alertautheddisconnect; }; // Structure of a connected client, their socket/file descriptors, their authentication status, and their OpenSSL structures |