From 8aaafbc8dce9a7556737d2d7d9ea3acefbc734ae Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Mon, 27 May 2019 16:12:28 +0100 Subject: Automatically try new nicks if there's no more configured nicks to try (e.g. if foo is in use, try foo1, foo2, ..., foo9). --- TODO | 2 -- blabouncer.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/TODO b/TODO index badc398..0eee5d6 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,5 @@ Move debug output into some debug function that can be enabled/disabled. -Automatically try new nicks if there's no more configured nicks to try (e.g. if foo is in use, try foo1, foo2, etc.) - Add various auto replay options: - All logs since the final client disconnected - All logs since the most recent client connect/disconnect diff --git a/blabouncer.c b/blabouncer.c index 07bee1a..e837977 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -47,6 +47,7 @@ #define MAXCHANLENGTH 50 // 50 according to RFC 2811 and RFC 2822 #define MAXCHANUSERS 8192 // Randomly picked (TODO - is there an actual maximum number of users per channel?) #define MAXNICKLENGTH 64 // Randomly picked (TODO - is there an actual maximum number (ignoring the RFC preference of 9)?) +#define MAXRFCNICKLEN 9 // From RFC 1459 #define MAXUSERNAMELEN 64 // Randomly picked (TODO - is there an actual maximum username length?) #define MAXREALNAMELEN 128 // Randomly picked (TODO - is there an actual maximum real name length?) #define MAXPORTLEN 6 // Up to 65535, so 5 characters + 1 for null @@ -77,6 +78,7 @@ struct ircdstrings { char currentmsg[MAXDATASIZE]; // Holding area for the current server-received IRC message being processed in case it needs building across multiple reads (i.e. a truncated/split message) char mode[MAXDATASIZE]; int capmultiprefix; // Whether the server approved our CAP multi-prefix request + int autonicknum; // Number of attempts made at automatically setting a nick if all configured nicks were in use }; // Structure of settings either to be read from the configuration file or set/changed at runtime @@ -627,6 +629,46 @@ int joinautochannels(SSL *server_ssl, struct client *clients, struct settings *s return 1; } +// Try to make a new nick if no configured are available or liked by the server +// Do this by sticking a number on the end of the current nick and trying numbers +// 1 through to 9. +void tryautonick(struct ircdstrings *ircdstrings) { + // Increment the attempts counter + ircdstrings->autonicknum++; + + if (ircdstrings->autonicknum == 10) { + // We've already tried 9 nicks and failed, give up + printf("tryautonick(): Tried 9 automatic nicks and the server didn't like any, giving up.\n"); + exit(1); + } + + int oldlen = strlen(ircdstrings->ircnick); + + // If we've already started trying autonick, just replace the last character a the new number + if (ircdstrings->autonicknum > 1) { + printf("tryautonick(): already started autonick, starting with '%s' length '%ld'.\n", ircdstrings->ircnick, strlen(ircdstrings->ircnick)); + ircdstrings->ircnick[oldlen - 1] = ircdstrings->autonicknum + '0'; + // And null terminate + ircdstrings->ircnick[oldlen] = '\0'; + // If the nick is longer than or equal to the RFC 1459 max nick + // length then try sticking the number at the end + } else if (oldlen >= MAXRFCNICKLEN) { + printf("tryautonick(): long old nick, starting with '%s' length '%ld'.\n", ircdstrings->ircnick, strlen(ircdstrings->ircnick)); + // (+ '0' to make char from int) + ircdstrings->ircnick[MAXRFCNICKLEN] = ircdstrings->autonicknum + '0'; + // And null terminate + ircdstrings->ircnick[MAXRFCNICKLEN + 1] = '\0'; + // Otherwise, just stick it on the end (+ '0' to make char from int) + } else { + printf("tryautonick(): short old nick, starting with '%s' length '%ld'.\n", ircdstrings->ircnick, strlen(ircdstrings->ircnick)); + ircdstrings->ircnick[oldlen] = ircdstrings->autonicknum + '0'; + // And null terminate + ircdstrings->ircnick[oldlen + 1] = '\0'; + } + + printf("tryautonick(): set irdstrings->ircnick to '%s'.\n", ircdstrings->ircnick); +} + // Figure out what to do with each CRLF-split IRC message (if anything) // by splitting out the different components by space character (ASCII 0x20). // @@ -1226,32 +1268,52 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli if ((strncmp(tokens[1], "432", strlen(tokens[1])) == 0 || strncmp(tokens[1], "433", strlen(tokens[1])) == 0) && !strlen(ircdstrings->greeting004)) { printf("Server 432 (ERR_ERRONEUSNICKNAME) or 433 (ERR_NICKNAMEINUSE) found and it is: %s with length %zd! Trying another nick...\n", tokens[1], strlen(tokens[1])); - // Make sure nick3 hasn't already been tried - if (getconfstr("nick3", settings->conffile, settings->ircnick)) { - // If it's the current nick already then... - if (strncmp(ircdstrings->ircnick, settings->ircnick, strlen(settings->ircnick)) == 0) { - // ...give up - printf("error: server doesn't like any configured nicks, giving up.\n"); - exit(1); - } + // Try to get nick2 and nick3 from the configuration file + char nick2[MAXNICKLENGTH]; + char nick3[MAXNICKLENGTH]; + if (!getconfstr("nick2", settings->conffile, nick2)) { + nick2[0] = '\0'; } - - // Try nick2 - if (!getconfstr("nick2", settings->conffile, settings->ircnick)) { - printf("error: server doesn't like nick and can't get 'nick2' from configuration file.\n"); - exit(1); + if (!getconfstr("nick3", settings->conffile, nick3)) { + nick3[0] = '\0'; } - // Have we already tried this one? (i.e. is it the current nick) - if (strncmp(ircdstrings->ircnick, settings->ircnick, strlen(settings->ircnick)) == 0) { - // Then try nick3 - if (!getconfstr("nick3", settings->conffile, settings->ircnick)) { - printf("error: server doesn't like nick or nick2 and can't get 'nick3' from configuration file.\n"); - exit(1); + + // Do we have both a nick2 and a nick3? (And not tried autonick yet.) + if (nick2[0] && nick3[0] && !ircdstrings->autonicknum) { + // Has nick3 already been tried? + if (strncmp(ircdstrings->ircnick, nick3, strlen(settings->ircnick)) == 0) { + // Then try autonick + tryautonick(ircdstrings); + // Has nick2 already been tried? + } else if (strncmp(ircdstrings->ircnick, nick2, strlen(settings->ircnick)) == 0) { + // Then try nick3 + printf("Trying nick3, nick2 was already tried.\n"); + strcpy(ircdstrings->ircnick, nick3); + // Have neither been tried? + } else { + // Then try nick2 + printf("Trying nick2, nick3 is also configured.\n"); + strcpy(ircdstrings->ircnick, nick2); + } + // Do we only have a nick2? (And not tried autonick yet.) + } else if (nick2[0] && !ircdstrings->autonicknum) { + // Has it already been tried? + if (strncmp(ircdstrings->ircnick, nick2, strlen(settings->ircnick)) == 0) { + // Then try autonick + tryautonick(ircdstrings); + } else { + // Then try it + printf("Trying nick2, nick3 is not configured.\n"); + strcpy(ircdstrings->ircnick, nick2); } + // Do we have neither? (Or have already started autonick.) + } else { + // Then try autonick + tryautonick(ircdstrings); } - // Set whichever one we settled on as the current nick - strcpy(ircdstrings->ircnick, settings->ircnick); + // Set whichever one we settled on in the settings in case we reference settings later + strcpy(settings->ircnick, ircdstrings->ircnick); // Try it with the server char outgoingmsg[MAXDATASIZE]; @@ -1922,6 +1984,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { ircdstrings.mode[0] = '\0'; // And set non-string things to zero (TODO - Rename this from ircdstrings since it's not all strings any more) ircdstrings.capmultiprefix = 0; + ircdstrings.autonicknum = 0; // Populate nick and username from our configuration file for now, real IRCd may change them later (TODO - Is this true of username?) strcpy(ircdstrings.ircnick, settings->ircnick); -- cgit v1.2.3