From 87b890b501a9ed7bfbfbe0fabde6ca1ca4c15086 Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Sun, 16 Jun 2019 22:19:51 +0100 Subject: Handle very long lines and very short lines. Print to terminal if we fail to connect to server at startup. Don't print to terminal if sending to a client or to the server fails. --- TODO | 2 -- blabouncer.c | 22 +++++++++++++++++++--- functions.c | 29 ++++++++++++++++++++++------- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/TODO b/TODO index d0d4bf8..c5a5517 100644 --- a/TODO +++ b/TODO @@ -6,5 +6,3 @@ Add various auto replay options: - All logs since the current client last disconnected (track clients with some special token the client auto sends on connect) Might need to #include in blabouncer.c to make some operating systems and/or compilers happy. - -What happens if an extremely long line is received? diff --git a/blabouncer.c b/blabouncer.c index c9a91aa..3b0a538 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -274,6 +274,11 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie if (*token == '\0') continue; // Skip consecutive matches if (messagecount >= MAXTOKENS) break; // Too many tokens debugprint(DEBUG_FULL, "String Token: \"%s\", length %zd.\n", token, strlen(token)); + // Make sure it's not too long + if (strlen(token) > MAXDATASIZE - 1) { + debugprint(DEBUG_CRIT, "Token too long, discarding.\n"); + continue; + } // Copy into the token array (strlen + 1 to get the NULL terminator) strncpy(messages[messagecount], token, strlen(token) + 1); messagecount++; @@ -297,7 +302,7 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie // If the final characters of the raw string weren't \r\n then assume the final token is a truncated message // Copy to a holding area for continuation next time // (Only if source was the server since we always strip \r\n from client messages when recving - TODO - Should we be doing that? - if ((str[strlen(str)-2] != 13 || str[strlen(str)-1] != 10) && source == SOURCE_SERVER) { + if (strlen(str) > 2 && (str[strlen(str)-2] != 13 || str[strlen(str)-1] != 10) && source == SOURCE_SERVER) { debugprint(DEBUG_FULL, "processrawstring(): Truncated message detected, storing final token '%s' for later.\n", messages[messagecount - 1]); strncpy(ircdstate->currentmsg, messages[messagecount - 1], strlen(messages[messagecount - 1])); ircdstate->currentmsg[strlen(messages[messagecount - 1])] = '\0'; @@ -762,7 +767,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { } else { debugprint(DEBUG_FULL, "...previous connection!\n"); // handle data from a client - if ((clientnumbytes = sockread(clients[arrindex(clients, i)].ssl, clientbuf, sizeof clientbuf, settings->clienttls)) <= 0) { + if ((clientnumbytes = sockread(clients[arrindex(clients, i)].ssl, clientbuf, MAXRCVSIZE - 1, settings->clienttls)) <= 0) { // got error or connection closed by client if (clientnumbytes == 0) { // connection closed @@ -777,6 +782,16 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { debugprint(DEBUG_FULL, "bouncer-client: total client connections: %d\n", numclients(clients)); } else { // we got some data from a client + + // Make sure it's not too long + if (clientnumbytes > MAXRCVSIZE - 1) { + debugprint(DEBUG_CRIT, "bouncer-client: too many bytes received (%d out of a max of %d).\n", clientnumbytes, MAXRCVSIZE - 1); + // Clear clientbuf since it's overflowed + clientbuf[0] = '\0'; + // And go back to the top of the loop + continue; + } + // null terminate that baby clientbuf[clientnumbytes] = '\0'; // TODO make sure this can't overrun if some super long line (max bytes?) was received // clear up any newlines - TODO - Should we be doing this? If not, we can stop only doing truncation checks for the server in processrawstring(). @@ -1141,8 +1156,9 @@ int main(int argc, char *argv[]) { // Create server socket int serversockfd; if ((serversockfd = createserversocket(settings.ircserver, settings.ircserverport)) == -1) { + fprintf(stderr, "main(): Couldn't connect to server, exiting.\n"); debugprint(DEBUG_CRIT, "main(): Couldn't connect to server, exiting.\n"); - exit(1); + exit(EXIT_FAILURE); } // Create client socket (after server so we can use its fd number later as fdmax) diff --git a/functions.c b/functions.c index 82a98eb..3aa474f 100644 --- a/functions.c +++ b/functions.c @@ -387,6 +387,12 @@ int arrindex(struct client *clients, int clientfd) { // Send whatever string to a specific client by providing the FD // If "bypass" == 1 then permit sending to client even if unauthenticated (for instance for a CAP LS response) int sendtoclient(int fd, char *strsrc, struct client *clients, struct settings *settings, int bypass) { + if (strlen(strsrc) > MAXDATASIZE) { + // String is too long! + debugprint(DEBUG_CRIT, "sendtoclient(): strsrc '%s' was too long (%d out of a max of %d characters).\n", strsrc, strlen(strsrc), MAXDATASIZE); + return 0; + } + // Copy to new string for passing to appendcrlf() to avoid overrun in appendcrlf() char str[MAXDATASIZE]; strcpy(str, strsrc); @@ -409,7 +415,6 @@ int sendtoclient(int fd, char *strsrc, struct client *clients, struct settings * debugprint(DEBUG_SOME, "sendtoclient(): sending \"%s\" (length %zd) to client with fd %d.\n", str, strlen(str), fd); if (socksend(clients[i].ssl, str, strlen(str), settings->clienttls) == -1) { - perror("error: sendtoclient() socksend()\n"); debugprint(DEBUG_CRIT, "error: sendtoclient() socksend() error sending to client with fd '%d', errno '%d'.\n", fd, errno); return 0; } @@ -421,9 +426,14 @@ int sendtoclient(int fd, char *strsrc, struct client *clients, struct settings * // "except" is used to send to all clients _except_ the fd provided (except = 0 (EXCEPT_NONE) avoids this, i.e. sends to all) // "except" is really the "sourcefd" and is also used as part of the authentication check - this is messy and they should perhaps be two separate arguments. int sendtoallclients(struct client *clients, char *strsrc, int except, struct settings *settings) { - char *sendertype; + if (strlen(strsrc) > MAXDATASIZE) { + // String is too long! + debugprint(DEBUG_CRIT, "sendtoallclients(): strsrc '%s' was too long (%d out of a max of %d characters).\n", strsrc, strlen(strsrc), MAXDATASIZE); + return 0; + } + // Copy to new string for passing to appendcrlf() to avoid overrun in appendcrlf() char str[MAXDATASIZE]; strcpy(str, strsrc); @@ -470,7 +480,6 @@ int sendtoallclients(struct client *clients, char *strsrc, int except, struct se } debugprint(DEBUG_SOME, "sendtoallclients(): %s: sending '%s' to client with fd %d.\n", sendertype, str, clients[i].fd); if (socksend(clients[i].ssl, str, strlen(str), settings->clienttls) == -1) { - perror("error: sendtoallclients() socksend()\n"); debugprint(DEBUG_CRIT, "error: sendtoallclients() socksend() error sending to client with fd '%d', errno '%d'.\n", clients[i].fd, errno); } } @@ -483,7 +492,14 @@ int sendtoallclients(struct client *clients, char *strsrc, int except, struct se // Client FD and arrays needed to make sure anything relayed from a client is from an authenticated client. // clientfd of "0" means trusted, used when we are sending things ourselves that weren't relayed // from a real client. +// Returns 1 on success or 0 on failure. - TODO - Make callers care about this. int sendtoserver(SSL *server_ssl, char *strsrc, int str_len, int clientfd, struct client *clients, struct settings *settings) { + if (strlen(strsrc) > MAXDATASIZE) { + // String is too long! + debugprint(DEBUG_CRIT, "sendtoserver(): strsrc '%s' was too long (%d out of a max of %d characters).\n", strsrc, strlen(strsrc), MAXDATASIZE); + return 0; + } + // Copy to new string for passing to appendcrlf() to avoid overrun in appendcrlf() char str[MAXDATASIZE]; strcpy(str, strsrc); @@ -502,19 +518,18 @@ int sendtoserver(SSL *server_ssl, char *strsrc, int str_len, int clientfd, struc // Found client in array, check authentication status if (!clients[i].authed) { debugprint(DEBUG_SOME, "sendtoserver(): skipping unauthenticated client with fd %d.\n", clients[i].fd); - return 0; + return 1; } } } debugprint(DEBUG_SOME, "sendtoserver(): sending '%s' to IRC server (length %d).\n", str, str_len); if (socksend(server_ssl, str, str_len, settings->servertls) == -1) { - printf("error: sendtoserver() socksend()\n"); debugprint(DEBUG_CRIT, "error: sendtoserver() socksend() error sending to server, errno '%d'.\n", clientfd, errno); - return 0; + return 1; } - return 1; + return 0; } // Disconnect the client fd "fd" by close()ing it and remove -- cgit v1.2.3