summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-05-27 16:12:28 +0100
committerLuke Bratch <luke@bratch.co.uk>2019-05-27 16:12:28 +0100
commit8aaafbc8dce9a7556737d2d7d9ea3acefbc734ae (patch)
tree55a4fb4fb6c51a682618dbfe4bd6baa7e6902ee7
parent90fcfc730331e66c2927ecc61bc36be0e51c8eff (diff)
Automatically try new nicks if there's no more configured nicks to try (e.g. if foo is in use, try foo1, foo2, ..., foo9).
-rw-r--r--TODO2
-rw-r--r--blabouncer.c105
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);