X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=d62be359c5435000418d75956e9b5fa2b41e086e;hb=44acf41cc172e8131c3a987d430b9f948afd26ad;hp=b29ad7e353dbb5042d94db35f97798b0ef26bb07;hpb=4c113d8850dfc423e3dae2d2f90e7e9a9d42f0b0;p=ngircd-alex.git diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index b29ad7e3..d62be359 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -75,13 +75,16 @@ #define SERVER_WAIT (NONE - 1) +#define MAX_COMMANDS 3 +#define MAX_COMMANDS_SERVER 10 + static bool Handle_Write PARAMS(( CONN_ID Idx )); static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len )); static int New_Connection PARAMS(( int Sock )); static CONN_ID Socket2Index PARAMS(( int Sock )); static void Read_Request PARAMS(( CONN_ID Idx )); -static void Handle_Buffer PARAMS(( CONN_ID Idx )); +static unsigned int Handle_Buffer PARAMS(( CONN_ID Idx )); static void Check_Connections PARAMS(( void )); static void Check_Servers PARAMS(( void )); static void Init_Conn_Struct PARAMS(( CONN_ID Idx )); @@ -234,12 +237,12 @@ cb_connserver_login_ssl(int sock, short unused) case 0: LogDebug("ConnSSL_Connect: not ready"); return; case -1: - Log(LOG_INFO, "SSL connection on socket %d failed", sock); + Log(LOG_ERR, "SSL connection on socket %d failed!", sock); Conn_Close(idx, "Can't connect!", NULL, false); return; } - Log( LOG_INFO, "SSL Connection %d with \"%s:%d\" established.", idx, + Log( LOG_INFO, "SSL connection %d with \"%s:%d\" established.", idx, My_Connections[idx].host, Conf_Server[Conf_GetServer( idx )].port ); server_login(idx); @@ -304,8 +307,6 @@ cb_clientserver_ssl(int sock, short what) GLOBAL void Conn_Init( void ) { - /* Modul initialisieren: statische Strukturen "ausnullen". */ - CONN_ID i; /* Speicher fuer Verbindungs-Pool anfordern */ @@ -341,16 +342,11 @@ Conn_Init( void ) GLOBAL void Conn_Exit( void ) { - /* Modul abmelden: alle noch offenen Connections - * schliessen und freigeben. */ - CONN_ID idx; - LogDebug("Shutting down all connections ..." ); - Conn_ExitListeners(); - /* Sockets schliessen */ + LogDebug("Shutting down all connections ..." ); for( idx = 0; idx < Pool_Size; idx++ ) { if( My_Connections[idx].sock > NONE ) { Conn_Close( idx, NULL, NGIRCd_SignalRestart ? @@ -451,7 +447,8 @@ Conn_ExitListeners( void ) #endif arraylen = array_length(&My_Listeners, sizeof (int)); - Log( LOG_INFO, "Shutting down all listening sockets (%d total)...", arraylen ); + Log(LOG_INFO, + "Shutting down all listening sockets (%d total) ...", arraylen); fd = array_start(&My_Listeners); while(arraylen--) { assert(fd != NULL); @@ -628,7 +625,7 @@ GLOBAL void Conn_Handler(void) { int i; - unsigned int wdatalen; + unsigned int wdatalen, bytes_processed; struct timeval tv; time_t t; @@ -651,9 +648,19 @@ Conn_Handler(void) for (i = 0; i < Pool_Size; i++) { if ((My_Connections[i].sock > NONE) && (array_bytes(&My_Connections[i].rbuf) > 0) - && (My_Connections[i].delaytime < t)) { + && (My_Connections[i].delaytime <= t)) { /* ... and try to handle the received data */ - Handle_Buffer(i); + bytes_processed = Handle_Buffer(i); + /* if we processed data, and there might be + * more commands in the input buffer, do not + * try to read any more data now */ + if (bytes_processed && + array_bytes(&My_Connections[i].rbuf) > 2) { + LogDebug + ("Throttling connection %d: command limit reached!", + i); + Conn_SetPenalty(i, 1); + } } } @@ -887,13 +894,13 @@ Conn_Write( CONN_ID Idx, char *Data, size_t Len ) GLOBAL void -Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) +Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClient ) { /* Close connection. Open pipes of asyncronous resolver * sub-processes are closed down. */ CLIENT *c; - char *txt; + const char *txt; double in_k, out_k; UINT16 port; #ifdef ZLIB @@ -943,7 +950,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) (double)My_Connections[Idx].bytes_out / 1024); } #endif - /* Send ERROR to client (see RFC!) */ + /* Send ERROR to client (see RFC 2812, section 3.1.7) */ if (FwdMsg) Conn_WriteStr(Idx, "ERROR :%s", FwdMsg); else @@ -960,7 +967,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) c = Conn_GetClient( Idx ); #ifdef SSL_SUPPORT if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_SSL )) { - Log( LOG_INFO, "SSL Connection %d shutting down", Idx ); + Log(LOG_INFO, "SSL connection %d shutting down ...", Idx); ConnSSL_Free(&My_Connections[Idx]); } #endif @@ -1262,14 +1269,21 @@ New_Connection( int Sock ) My_Connections[new_sock].addr = new_addr; My_Connections[new_sock].client = c; - Log( LOG_INFO, "Accepted connection %d from %s:%d on socket %d.", new_sock, - ip_str, ng_ipaddr_getport(&new_addr), Sock); - - /* Hostnamen ermitteln */ - strlcpy(My_Connections[new_sock].host, ip_str, sizeof(My_Connections[new_sock].host)); + /* Set initial hostname to IP address. This becomes overwritten when + * the DNS lookup is enabled and succeeds, but is used otherwise. */ + if (ng_ipaddr_af(&new_addr) != AF_INET) + snprintf(My_Connections[new_sock].host, + sizeof(My_Connections[new_sock].host), "[%s]", ip_str); + else + strlcpy(My_Connections[new_sock].host, ip_str, + sizeof(My_Connections[new_sock].host)); Client_SetHostname(c, My_Connections[new_sock].host); + Log(LOG_INFO, "Accepted connection %d from %s:%d on socket %d.", + new_sock, My_Connections[new_sock].host, + ng_ipaddr_getport(&new_addr), Sock); + identsock = new_sock; #ifdef IDENTAUTH if (Conf_NoIdent) @@ -1286,13 +1300,11 @@ New_Connection( int Sock ) static CONN_ID Socket2Index( int Sock ) { - /* zum Socket passende Connection suchen */ - assert( Sock >= 0 ); if( Sock >= Pool_Size || My_Connections[Sock].sock != Sock ) { - /* die Connection wurde vermutlich (wegen eines - * Fehlers) bereits wieder abgebaut ... */ + /* the Connection was already closed again, likely due to + * an error. */ LogDebug("Socket2Index: can't get connection for socket %d!", Sock); return NONE; } @@ -1308,7 +1320,9 @@ static void Read_Request( CONN_ID Idx ) { ssize_t len; + static const unsigned int maxbps = COMMAND_LEN / 2; char readbuf[READBUFFER_LEN]; + time_t t; CLIENT *c; assert( Idx > NONE ); assert( My_Connections[Idx].sock > NONE ); @@ -1385,21 +1399,34 @@ Read_Request( CONN_ID Idx ) if (c && (Client_Type(c) == CLIENT_USER || Client_Type(c) == CLIENT_SERVER || Client_Type(c) == CLIENT_SERVICE)) { - My_Connections[Idx].lastdata = time(NULL); + t = time(NULL); + if (My_Connections[Idx].lastdata != t) + My_Connections[Idx].bps = 0; + + My_Connections[Idx].lastdata = t; My_Connections[Idx].lastping = My_Connections[Idx].lastdata; } /* Look at the data in the (read-) buffer of this connection */ - Handle_Buffer(Idx); + My_Connections[Idx].bps += Handle_Buffer(Idx); + if (Client_Type(c) != CLIENT_SERVER + && My_Connections[Idx].bps >= maxbps) { + LogDebug("Throttling connection %d: BPS exceeded! (%u >= %u)", + Idx, My_Connections[Idx].bps, maxbps); + Conn_SetPenalty(Idx, 1); + } } /* Read_Request */ /** * Handle all data in the connection read-buffer. - * All data is precessed until no complete command is left. When a fatal - * error occurs, the connection is shut down. + * Data is processed until no complete command is left in the read buffer, + * or MAX_COMMANDS[_SERVER] commands were processed. + * When a fatal error occurs, the connection is shut down. + * @param Idx Index of the connection. + * @return number of bytes processed. */ -static void +static unsigned int Handle_Buffer(CONN_ID Idx) { #ifndef STRICT_RFC @@ -1411,31 +1438,41 @@ Handle_Buffer(CONN_ID Idx) #ifdef ZLIB bool old_z; #endif + unsigned int i, maxcmd = MAX_COMMANDS, len_processed = 0; + CLIENT *c; + + c = Conn_GetClient(Idx); + assert( c != NULL); + + /* Servers do get special command limits, so they can process + * all the messages that are required while peering. */ + if (Client_Type(c) == CLIENT_SERVER) + maxcmd = MAX_COMMANDS_SERVER; starttime = time(NULL); - for (;;) { + for (i=0; i < maxcmd; i++) { /* Check penalty */ if (My_Connections[Idx].delaytime > starttime) - return; + return 0; #ifdef ZLIB /* Unpack compressed data, if compression is in use */ if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) { /* When unzipping fails, Unzip_Buffer() shuts * down the connection itself */ if (!Unzip_Buffer(Idx)) - return; + return 0; } #endif if (0 == array_bytes(&My_Connections[Idx].rbuf)) - return; + break; /* Make sure that the buffer is NULL terminated */ if (!array_cat0_temporary(&My_Connections[Idx].rbuf)) { Conn_Close(Idx, NULL, "Can't allocate memory [Handle_Buffer]", true); - return; + return 0; } /* RFC 2812, section "2.3 Messages", 5th paragraph: @@ -1471,7 +1508,7 @@ Handle_Buffer(CONN_ID Idx) #endif if (!ptr) - return; + break; /* Complete (=line terminated) request found, handle it! */ *ptr = '\0'; @@ -1486,16 +1523,16 @@ Handle_Buffer(CONN_ID Idx) Idx, array_bytes(&My_Connections[Idx].rbuf), COMMAND_LEN - 1); Conn_Close(Idx, NULL, "Request too long", true); - return; + return 0; } + len_processed += len; if (len <= delta) { /* Request is empty (only '\r\n', '\r' or '\n'); * delta is 2 ('\r\n') or 1 ('\r' or '\n'), see above */ array_moveleft(&My_Connections[Idx].rbuf, 1, len); - return; + continue; } - #ifdef ZLIB /* remember if stream is already compressed */ old_z = My_Connections[Idx].options & CONN_ZIP; @@ -1504,7 +1541,7 @@ Handle_Buffer(CONN_ID Idx) My_Connections[Idx].msg_in++; if (!Parse_Request (Idx, (char *)array_start(&My_Connections[Idx].rbuf))) - return; + return 0; /* error -> connection has been closed */ array_moveleft(&My_Connections[Idx].rbuf, 1, len); LogDebug("Connection %d: %d bytes left in read buffer.", @@ -1521,7 +1558,7 @@ Handle_Buffer(CONN_ID Idx) Conn_Close(Idx, NULL, "Can't allocate memory [Handle_Buffer]", true); - return; + return 0; } array_trunc(&My_Connections[Idx].rbuf); @@ -1531,6 +1568,7 @@ Handle_Buffer(CONN_ID Idx) } #endif } + return len_processed; } /* Handle_Buffer */ @@ -1541,6 +1579,7 @@ Check_Connections(void) * if this doesn't help either, disconnect client. */ CLIENT *c; CONN_ID i; + char msg[64]; for (i = 0; i < Pool_Size; i++) { if (My_Connections[i].sock < 0) @@ -1560,8 +1599,8 @@ Check_Connections(void) LogDebug ("Connection %d: Ping timeout: %d seconds.", i, Conf_PongTimeout); - Conn_Close(i, NULL, "Ping timeout", - true); + snprintf(msg, sizeof(msg), "Ping timeout: %d seconds", Conf_PongTimeout); + Conn_Close(i, NULL, msg, true); } } else if (My_Connections[i].lastdata < time(NULL) - Conf_PingTimeout) { @@ -1696,6 +1735,8 @@ New_Server( int Server , ng_ipaddr_t *dest) return; } + /* Conn_Close() decrements this counter again */ + NumConnections++; Client_SetIntroducer( c, c ); Client_SetToken( c, TOKEN_OUTBOUND ); @@ -1722,9 +1763,9 @@ New_Server( int Server , ng_ipaddr_t *dest) Conn_Close( new_sock, "Could not initialize SSL for outgoing connection", NULL, false ); Init_Conn_Struct( new_sock ); Conf_Server[Server].conn_id = NONE; + return; } #endif - NumConnections++; LogDebug("Registered new connection %d on socket %d (%ld in total).", new_sock, My_Connections[new_sock].sock, NumConnections); Conn_OPTION_ADD( &My_Connections[new_sock], CONN_ISCONNECTING ); @@ -1825,8 +1866,8 @@ cb_Connect_to_Server(int fd, UNUSED short events) len -= sizeof(ng_ipaddr_t); if (len > sizeof(&Conf_Server[i].dst_addr)) { len = sizeof(&Conf_Server[i].dst_addr); - Log(LOG_NOTICE, "Notice: Resolver returned more IP Addresses for host than we can handle," - " additional addresses dropped"); + Log(LOG_NOTICE, + "Notice: Resolver returned more IP Addresses for host than we can handle, additional addresses dropped."); } memcpy(&Conf_Server[i].dst_addr, &dest_addrs[1], len); } @@ -1951,6 +1992,9 @@ Conn_GetClient( CONN_ID Idx ) GLOBAL bool Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len) { + if (Idx < 0) + return false; + assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION))); return ConnSSL_GetCipherInfo(&My_Connections[Idx], buf, len); } @@ -1958,6 +2002,9 @@ Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len) GLOBAL bool Conn_UsesSSL(CONN_ID Idx) { + if (Idx < 0) + return false; + assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION))); return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL); } #endif