diff options
author | Luke Bratch <luke@bratch.co.uk> | 2019-05-18 17:24:00 +0100 |
---|---|---|
committer | Luke Bratch <luke@bratch.co.uk> | 2019-05-18 17:24:00 +0100 |
commit | 400b252abe3f585ea2feb98fc110f013f3bef1f1 (patch) | |
tree | 27d7f9b64bc42d637f7da00e28bc0f3f098ba049 | |
parent | fe27073f78cd198d7029a8e81494858d602d8bde (diff) |
Only send certain known responses to the client that requested them. So far implemented channel MODE requests, channel ban requests, WHO requests, and LIST requests.
-rw-r--r-- | blabouncer.c | 123 |
1 files changed, 119 insertions, 4 deletions
diff --git a/blabouncer.c b/blabouncer.c index cbab56b..b996f25 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -11,10 +11,10 @@ // - Check authentication before even getting to the send functions to save unnecessary processing // - Configurable auto channels // - Comma separated channel list in JOINs/PARTs -// - Only send some things to the requesting client (e.g. LIST replies) // - 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? +// - Some/all types of disconnect don't decrement num_clients // // Example WHOIS reply: // BOUNCER-SERVER RECEIVED: :irc.tghost.co.uk 307 blabounce l_bratch :is identified for this nick @@ -115,6 +115,10 @@ struct client { int authed; // Client authentication status - 0 means not authenticated, 1 means authenticated. SSL *ssl; // OpenSSL structures when using TLS, or faked by casting fd ints to SSL* if not. - TODO - Can we drop one of either "int fd" or "SSL *ssl" now? int registered; // Whether the client has finished registering with the bouncer + int pendingchannelmode; // Whether the client is waiting to hear back from a "MODE #channel" command + int pendingban; // Whether the client is waiting to hear back from a "MODE #channel b" command + int pendingwho; // Whether the client is waiting to hear back from a "MODE #channel" command + int pendinglist; // Whether the client is waiting to hear back from a "LIST" command }; // Return index of requested client FD within the clients array. @@ -166,6 +170,7 @@ int sendtoclient(int fd, char *strsrc, struct client *clients, struct settings * // 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); close(fd); // bye! @@ -176,6 +181,10 @@ int disconnectclient(int fd, struct client *clients) { 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; return 1; } } @@ -827,6 +836,75 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli return 1; } + + // Server 324 (RPL_CHANNELMODEIS) received? Send to any clients who requested a channel MODE. + if (strncmp(tokens[1], "324", strlen(tokens[1])) == 0) { + printf("Server 324 (RPL_CHANNELMODEIS) found and it is: %s with length %zd! Sending to clients who are pending this.\n", tokens[1], strlen(tokens[1])); + + // Relay to all pending clients + for (int i = 0; i < MAXCLIENTS; i++) { + if (clients[i].pendingchannelmode == 1) { + sendtoclient(clients[i].fd, str, clients, settings); + // And clear the pending flag + clients[i].pendingchannelmode = 0; + } + } + + return 1; + } + + // Server 368 (RPL_ENDOFBANLIST) received? Send to any clients who requested a ban MODE query. - TODO - Identify and handle start/middle of ban responses. + if (strncmp(tokens[1], "368", strlen(tokens[1])) == 0) { + printf("Server 368 (RPL_ENDOFBANLIST) found and it is: %s with length %zd! Sending to clients who are pending this.\n", tokens[1], strlen(tokens[1])); + + // Relay to all pending clients + for (int i = 0; i < MAXCLIENTS; i++) { + if (clients[i].pendingban == 1) { + sendtoclient(clients[i].fd, str, clients, settings); + // And clear the pending flag + clients[i].pendingban = 0; + } + } + + return 1; + } + + // Server 329 (RPL_CREATIONTIME), 352 (RPL_WHOREPLY), or 315 (RPL_ENDOFWHO) received? Send to any clients who requested a WHO. + if (strncmp(tokens[1], "329", strlen(tokens[1])) == 0 || strncmp(tokens[1], "352", strlen(tokens[1])) == 0 || strncmp(tokens[1], "315", strlen(tokens[1])) == 0) { + printf("Server 329 (RPL_CREATIONTIME), 352 (RPL_WHOREPLY), or 315 (RPL_ENDOFWHO) found and it is: %s with length %zd! Sending to clients who are pending one of these.\n", tokens[1], strlen(tokens[1])); + + // Relay to all pending clients + for (int i = 0; i < MAXCLIENTS; i++) { + if (clients[i].pendingwho == 1 && clients[i].fd) { + sendtoclient(clients[i].fd, str, clients, settings); + // And clear the pending flag if it's 315 (RPL_ENDOFWHO) + if (strncmp(tokens[1], "329", strlen(tokens[1])) == 0) { + clients[i].pendingwho = 0; + } + } + } + + return 1; + } + + // Server 321 (RPL_LISTSTART), 322 (RPL_LIST), or 323 (RPL_LISTEND) received? Send to any clients who requested a WHO. + if (strncmp(tokens[1], "321", strlen(tokens[1])) == 0 || strncmp(tokens[1], "322", strlen(tokens[1])) == 0 || strncmp(tokens[1], "323", strlen(tokens[1])) == 0) { + printf("Server 321 (RPL_LISTSTART), 322 (RPL_LIST), or 323 (RPL_LISTEND) found and it is: %s with length %zd! Sending to clients who are pending one of these.\n", tokens[1], strlen(tokens[1])); + + // Relay to all pending clients + for (int i = 0; i < MAXCLIENTS; i++) { + if (clients[i].pendingwho == 1 && clients[i].fd) { + sendtoclient(clients[i].fd, str, clients, settings); + // And clear the pending flag if it's 323 (RPL_LISTEND) + if (strncmp(tokens[1], "323", strlen(tokens[1])) == 0) { + clients[i].pendingwho = 0; + } + } + } + + return 1; + } + } // Don't return if we got here because this means we didn't process something above @@ -1066,9 +1144,42 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli return 1; } - // Just send MODE to server and let it talk back to clients as required + // Take note of what sort of MODE was requested, mark the client as waiting for the reply (so not all clients get it) + // Send it to the server either way and let it talk back to the requesting client as required if (strncmp(tokens[0], "MODE", strlen(tokens[0])) == 0) { - printf("Client MODE found and it is: %s with length %zd! Sending to server...\n", tokens[0], strlen(tokens[0])); + printf("Client MODE found and it is: %s with length %zd! Analysing...\n", tokens[0], strlen(tokens[0])); + // Is it a ban MODE request (MODE #channel b)? + if (counter >= 3 && strncmp(tokens[2], "b", strlen("b")) == 0) { + printf("Ban MODE request received, marking as pending.\n"); + clients[arrindex(clients, sourcefd)].pendingban = 1; + } else if (counter == 2) { + // Assume a normal channel mode request (MODE #channel) - TODO - What if it isn't!? + printf("Assuming channel MODE request received, marking as pending.\n"); + clients[arrindex(clients, sourcefd)].pendingchannelmode = 1; + } + + // Either way, send it on the server + sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings); + free(strcopy); + return 1; + } + + // WHO requested, mark the client as waiting for the reply (so not all clients get it) and send it on the server + if (strncmp(tokens[0], "WHO", strlen(tokens[0])) == 0) { + printf("Client WHO found and it is: %s with length %zd! Marking as pending.\n", tokens[0], strlen(tokens[0])); + clients[arrindex(clients, sourcefd)].pendingwho = 1; + + // Either way, send it on the server + sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings); + return 1; + } + + // LIST requested, mark the client as waiting for the reply (so not all clients get it) and send it on the server + if (strncmp(tokens[0], "LIST", strlen(tokens[0])) == 0) { + printf("Client LIST found and it is: %s with length %zd! Marking as pending.\n", tokens[0], strlen(tokens[0])); + clients[arrindex(clients, sourcefd)].pendingwho = 1; + + // Either way, send it on the server sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings); return 1; } @@ -1249,11 +1360,15 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { // Set up clients structure struct client clients[MAXCLIENTS]; - // Set all the clients to be "not connected", "not authenticated", and "not registered" + // Set all the clients to be "not connected", "not authenticated", "not registered", "not pending replies" for (int i = 0; i < MAXCLIENTS; 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; } // Initialise OpenSSL (used for both client and server) |