summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)