From 95ff740e8238799cd70d829053704b9c366fc59f Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Sat, 18 May 2019 18:58:41 +0100 Subject: Alert other clients when clients connect, disconnect, authenticate, or fail to authenticate. --- blabouncer.c | 102 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 34 deletions(-) diff --git a/blabouncer.c b/blabouncer.c index 23042c4..287176b 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -10,7 +10,6 @@ // - Check authentication before even getting to the send functions to save unnecessary processing // - Configurable auto channels // - Comma separated channel list in JOINs/PARTs -// - Alert when clients connect/authenticate/disconnect // - Perhaps rename clients.ssl and server_ssl since they may not even be OpenSSL sockets // - Is it possible to replay JOINs/PARTs accurately? @@ -162,36 +161,6 @@ int sendtoclient(int fd, char *strsrc, struct client *clients, struct settings * return 1; } -// Disconnect the client fd "fd" by close()ing it and remove -// it from the array of clients. -// Also set its authentication and registration statuses to 0. -// Also set the pending statuses to 0 -int disconnectclient(int fd, struct client *clients) { - printf("disconnectclient(): disconnecting client fd '%d'\n", fd); - // Remove the client from the clients array - for (int i = 0; i < MAXCLIENTS; i++) { - if (clients[i].fd == fd) { - printf("found and clearing fd %d from clients[%d]\n", fd, i); - clients[i].fd = 0; - clients[i].authed = 0; - clients[i].registered = 0; - clients[i].pendingchannelmode = 0; - clients[i].pendingban = 0; - clients[i].pendingwho = 0; - clients[i].pendinglist = 0; - // Finish up with OpenSSL - SSL_free(clients[i].ssl); - // Close the socket - close(fd); - return 1; - } - } - - // If we got here, we didn't find and clear the client - // TODO - Do something with a failed return code - return 0; -} - // Relay/send message to all clients (optionally except one) // "except" is used to send to all clients _except_ the fd provided (except = 0 (EXCEPT_NONE) avoids this, i.e. sends to all) // "except" is really the "sourcefd" and is also used as part of the authentication check - this is messy and they should perhaps be two separate arguments. @@ -291,6 +260,46 @@ int sendtoserver(SSL *server_ssl, char *strsrc, int str_len, int clientfd, struc return 1; } +// Disconnect the client fd "fd" by close()ing it and remove +// it from the array of clients. +// Also set its authentication and registration statuses to 0. +// Also set the pending statuses to 0 +int disconnectclient(int fd, struct client *clients, struct ircdstrings *ircdstrings, struct settings *settings) { + printf("disconnectclient(): disconnecting client fd '%d'\n", fd); + + // Alert other clients about the disconnection + char alertmsg[MAXDATASIZE]; + if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: client with fd %d has disconnected.", ircdstrings->ircnick, fd)) { + fprintf(stderr, "Error while preparing authentication failure NOTICE!\n"); + exit(1); + } + // "except" 0 since we trust this message + sendtoallclients(clients, alertmsg, 0, settings); + + // Remove the client from the clients array + for (int i = 0; i < MAXCLIENTS; i++) { + if (clients[i].fd == fd) { + printf("found and clearing fd %d from clients[%d]\n", fd, i); + clients[i].fd = 0; + clients[i].authed = 0; + clients[i].registered = 0; + clients[i].pendingchannelmode = 0; + clients[i].pendingban = 0; + clients[i].pendingwho = 0; + clients[i].pendinglist = 0; + // Finish up with OpenSSL + SSL_free(clients[i].ssl); + // Close the socket + close(fd); + return 1; + } + } + + // If we got here, we didn't find and clear the client + // TODO - Do something with a failed return code + return 0; +} + int createchannel(struct channel *channels, char *name, char *topic, char *topicwho, char *topicwhen, char *modes, char *namestype) { printf("createchannel(): given \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", and \"%s\".\n", name, topic, topicwho, topicwhen, modes, namestype); @@ -955,11 +964,27 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli // Found client in array, set to authenticated clients[i].authed = 1; printf("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 with fd %d has successfully authenticated.", ircdstrings->ircnick, sourcefd)) { + fprintf(stderr, "Error while preparing authentication success NOTICE!\n"); + exit(1); + } + // "except" 0 since we trust this message + sendtoallclients(clients, alertmsg, 0, settings); } } } else { printf("Password rejected, disconnecting fd %d.\n", sourcefd); - disconnectclient(sourcefd, clients); + disconnectclient(sourcefd, clients, ircdstrings, settings); + // Alert other clients about the failed authentication + char alertmsg[MAXDATASIZE]; + if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client with fd %d has failed to authenticate.", ircdstrings->ircnick, sourcefd)) { + fprintf(stderr, "Error while preparing authentication failure NOTICE!\n"); + exit(1); + } + // "except" 0 since we trust this message + sendtoallclients(clients, alertmsg, 0, settings); } free(strcopyPtr); @@ -1167,7 +1192,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli // A client has QUIT, so disconnect (close) them and don't do anything else for now - TODO: Let another clients know with a NOTICE or something if (strncmp(tokens[0], "QUIT", strlen(tokens[0])) == 0) { printf("Client QUIT found from fd %d and it is: %s with length %zd! Disconnecting that fd.\n", sourcefd, tokens[0], strlen(tokens[0])); - disconnectclient(sourcefd, clients); + disconnectclient(sourcefd, clients, ircdstrings, settings); free(strcopyPtr); return 1; } @@ -1660,6 +1685,15 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { } // TODO - Handle the "find a free element" loop not finding a free element printf("bouncer-client: new connection from %s on socket %d\n", inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*)&remoteaddr), remoteIP, INET6_ADDRSTRLEN), newfd); + // Alert other clients about the new connection + char alertmsg[MAXDATASIZE]; + if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client connected from %s with fd %d.", ircdstrings.ircnick, + inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*)&remoteaddr), remoteIP, INET6_ADDRSTRLEN), newfd)) { + fprintf(stderr, "Error while preparing new client connection NOTICE!\n"); + exit(1); + } + // "except" 0 since we trust this message + sendtoallclients(clients, alertmsg, 0, settings); printf("bouncer-client: total client connections: %d\n", numclients(clients)); } } else { @@ -1674,7 +1708,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { perror("recv"); } // Disconnect the client - disconnectclient(i, clients); + disconnectclient(i, clients, &ircdstrings, settings); FD_CLR(i, &rfds); // remove from master set - TODO is this needed at the moment since we just add everything from *clientsockfd to fdmax to rfds // TODO - Handle the "remove the client" loop not finding the old fd printf("bouncer-client: total client connections: %d\n", numclients(clients)); -- cgit v1.2.3