]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conn.c
Specify session context for OpenSSL clients
[ngircd-alex.git] / src / ngircd / conn.c
index 4ed586206f42107b0e32132530631545fede4ea4..62561544866413f5abb1534da27caac1e2aa2218 100644 (file)
@@ -9,8 +9,6 @@
  * Please read the file COPYING, README and AUTHORS for more information.
  */
 
-#undef DEBUG_BUFFER
-
 #define CONN_MODULE
 
 #include "portab.h"
@@ -20,6 +18,9 @@
  * Connection management
  */
 
+/* Additionan debug messages related to buffer handling: 0=off / 1=on */
+#define DEBUG_BUFFER 0
+
 #include <assert.h>
 #ifdef PROTOTYPES
 # include <stdarg.h>
@@ -73,6 +74,9 @@
 
 #define SD_LISTEN_FDS_START 3          /** systemd(8) socket activation offset */
 
+#define THROTTLE_CMDS 1                        /** Throttling: max commands reached */
+#define THROTTLE_BPS 2                 /** Throttling: max bps reached */
+
 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, bool IsSSL ));
@@ -87,6 +91,8 @@ static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest ));
 static void Simple_Message PARAMS(( int Sock, const char *Msg ));
 static int NewListener PARAMS(( const char *listen_addr, UINT16 Port ));
 static void Account_Connection PARAMS((void));
+static void Throttle_Connection PARAMS((const CONN_ID Idx, CLIENT *Client,
+                                       const int Reason, unsigned int Value));
 
 static array My_Listeners;
 static array My_ConnArray;
@@ -664,7 +670,7 @@ GLOBAL void
 Conn_Handler(void)
 {
        int i;
-       size_t wdatalen, bytes_processed;
+       size_t wdatalen;
        struct timeval tv;
        time_t t;
 
@@ -683,17 +689,7 @@ Conn_Handler(void)
                        if ((My_Connections[i].sock > NONE)
                            && (array_bytes(&My_Connections[i].rbuf) > 0)) {
                                /* ... and try to handle the received data */
-                               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);
-                               }
+                               Handle_Buffer(i);
                        }
                }
 
@@ -1265,7 +1261,7 @@ Handle_Write( CONN_ID Idx )
                return true;
        }
 
-#ifdef DEBUG_BUFFER
+#if DEBUG_BUFFER
        LogDebug
            ("Handle_Write() called for connection %d, %ld bytes pending ...",
             Idx, wdatalen);
@@ -1572,8 +1568,8 @@ Read_Request( CONN_ID Idx )
        {
                /* Read buffer is full */
                Log(LOG_ERR,
-                   "Receive buffer space exhausted (connection %d): %d bytes",
-                   Idx, array_bytes(&My_Connections[Idx].rbuf));
+                   "Receive buffer space exhausted (connection %d): %d/%d bytes",
+                   Idx, array_bytes(&My_Connections[Idx].rbuf), READBUFFER_LEN);
                Conn_Close(Idx, "Receive buffer space exhausted", NULL, false);
                return;
        }
@@ -1625,6 +1621,8 @@ Read_Request( CONN_ID Idx )
 
        /* Update connection statistics */
        My_Connections[Idx].bytes_in += len;
+
+       /* Handle read buffer */
        My_Connections[Idx].bps += Handle_Buffer(Idx);
 
        /* Make sure that there is still a valid client registered */
@@ -1650,14 +1648,8 @@ Read_Request( CONN_ID Idx )
        }
 
        /* Look at the data in the (read-) buffer of this connection */
-       if (Client_Type(c) != CLIENT_SERVER
-           && Client_Type(c) != CLIENT_UNKNOWNSERVER
-           && Client_Type(c) != CLIENT_SERVICE
-           && My_Connections[Idx].bps >= maxbps) {
-               LogDebug("Throttling connection %d: BPS exceeded! (%u >= %u)",
-                        Idx, My_Connections[Idx].bps, maxbps);
-               Conn_SetPenalty(Idx, 1);
-       }
+       if (My_Connections[Idx].bps >= maxbps)
+               Throttle_Connection(Idx, c, THROTTLE_BPS, maxbps);
 } /* Read_Request */
 
 /**
@@ -1701,7 +1693,12 @@ Handle_Buffer(CONN_ID Idx)
                        maxcmd *= 5;
                break;
            case CLIENT_SERVICE:
-               maxcmd = MAX_COMMANDS_SERVICE; break;
+               maxcmd = MAX_COMMANDS_SERVICE;
+               break;
+           case CLIENT_USER:
+               if (Client_HasMode(c, 'F'))
+                       maxcmd = MAX_COMMANDS_SERVICE;
+               break;
        }
 
        for (i=0; i < maxcmd; i++) {
@@ -1798,10 +1795,6 @@ Handle_Buffer(CONN_ID Idx)
                        return 0; /* error -> connection has been closed */
 
                array_moveleft(&My_Connections[Idx].rbuf, 1, len);
-#ifdef DEBUG_BUFFER
-               LogDebug("Connection %d: %d bytes left in read buffer.",
-                        Idx, array_bytes(&My_Connections[Idx].rbuf));
-#endif
 #ifdef ZLIB
                if ((!old_z) && (My_Connections[Idx].options & CONN_ZIP) &&
                    (array_bytes(&My_Connections[Idx].rbuf) > 0)) {
@@ -1824,6 +1817,17 @@ Handle_Buffer(CONN_ID Idx)
                }
 #endif
        }
+#if DEBUG_BUFFER
+       LogDebug("Connection %d: Processed %ld commands (max=%ld), %ld bytes. %ld bytes left in read buffer.",
+                Idx, i, maxcmd, len_processed,
+                array_bytes(&My_Connections[Idx].rbuf));
+#endif
+
+       /* If data has been processed but there is still data in the read
+        * buffer, the command limit triggered. Enforce the penalty time: */
+       if (len_processed && array_bytes(&My_Connections[Idx].rbuf) > 2)
+               Throttle_Connection(Idx, c, THROTTLE_CMDS, maxcmd);
+
        return len_processed;
 } /* Handle_Buffer */
 
@@ -1900,7 +1904,7 @@ Check_Servers(void)
        for (i = 0; i < MAX_SERVERS; i++) {
                if (Conf_Server[i].conn_id != NONE)
                        continue;       /* Already establishing or connected */
-               if (!Conf_Server[i].host[0] || !Conf_Server[i].port > 0)
+               if (!Conf_Server[i].host[0] || Conf_Server[i].port <= 0)
                        continue;       /* No host and/or port configured */
                if (Conf_Server[i].flags & CONF_SFLAG_DISABLED)
                        continue;       /* Disabled configuration entry */
@@ -2407,6 +2411,35 @@ Conn_GetFromProc(int fd)
        return NONE;
 } /* Conn_GetFromProc */
 
+/**
+ * Throttle a connection because of excessive usage.
+ *
+ * @param Reason The reason, see THROTTLE_xxx constants.
+ * @param Idx The connection index.
+ * @param Client The client of this connection.
+ * @param Seconds The time to delay this connection.
+ */
+static void
+Throttle_Connection(const CONN_ID Idx, CLIENT *Client, const int Reason,
+                   unsigned int Value)
+{
+       assert(Idx > NONE);
+       assert(Client != NULL);
+
+       /* Never throttle servers or services, only interrupt processing */
+       if (Client_Type(Client) == CLIENT_SERVER
+           || Client_Type(Client) == CLIENT_UNKNOWNSERVER
+           || Client_Type(Client) == CLIENT_SERVICE)
+               return;
+
+       /* Don't throttle clients with user mode 'F' set */
+       if (Client_HasMode(Client, 'F'))
+               return;
+
+       LogDebug("Throttling connection %d: code %d, value %d!", Idx,
+                Reason, Value);
+       Conn_SetPenalty(Idx, 1);
+}
 
 #ifndef STRICT_RFC