summaryrefslogtreecommitdiff
path: root/blabouncer.c
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-05-18 17:24:00 +0100
committerLuke Bratch <luke@bratch.co.uk>2019-05-18 17:24:00 +0100
commit400b252abe3f585ea2feb98fc110f013f3bef1f1 (patch)
tree27d7f9b64bc42d637f7da00e28bc0f3f098ba049 /blabouncer.c
parentfe27073f78cd198d7029a8e81494858d602d8bde (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.
Diffstat (limited to 'blabouncer.c')
-rw-r--r--blabouncer.c123
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)