updates.
authorPekka Riikonen <priikone@silcnet.org>
Wed, 14 Mar 2001 19:38:18 +0000 (19:38 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 14 Mar 2001 19:38:18 +0000 (19:38 +0000)
CHANGES
apps/silcd/command.c
apps/silcd/idlist.h
doc/draft-riikonen-silc-spec-01.nroff
lib/silccore/silccommand.h

diff --git a/CHANGES b/CHANGES
index 03d80a67fe93851365915e16e81d83d240d4f4da..9333281e78b8d82416c95baa84af07e810d001cb 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,14 @@
+Wed Mar 14 20:37:35 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added new SILC_CF_LAG_STRICT command flag that strictly forces
+         that the command may be executed only once in (about) 2 seconds.
+         The old SILC_CF_LAG flag is same but allows command bursts up
+         to five before limiting.
+
+         Added the support for CF_LAG and CF_LAG_STRICT flags to the
+         server code.  Various commands now includes the CF_LAG_STRICT
+         flag to disallow any kind of miss-use of the command.
+
 Wed Mar 14 16:10:30 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Changed the format of AdminConnection configuration section
 Wed Mar 14 16:10:30 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Changed the format of AdminConnection configuration section
index 9f0866a5dbb00e6d6b01826f2dfe69843ff6d1b6..6792f3c0f72ad40082c4ea82814b007ceabcbec7 100644 (file)
@@ -45,23 +45,23 @@ SilcServerCommand silc_command_list[] =
   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
-  SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
-  SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
+  SILC_SERVER_CMD(list, LIST, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
-  SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+  SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(connect, CONNECT, 
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(connect, CONNECT, 
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
-  SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
-  SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(restart, RESTART, 
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(close, CLOSE,
   SILC_SERVER_CMD(restart, RESTART, 
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(close, CLOSE,
@@ -70,7 +70,7 @@ SilcServerCommand silc_command_list[] =
                  SILC_CF_OPER),
   SILC_SERVER_CMD(silcoper, SILCOPER,
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
                  SILC_CF_OPER),
   SILC_SERVER_CMD(silcoper, SILCOPER,
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
-  SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
 
   { NULL, 0 },
   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
 
   { NULL, 0 },
@@ -116,9 +116,8 @@ static int silc_server_is_registered(SilcServer server,
 
 /* Internal context to hold data when executed command with timeout. */
 typedef struct {
 
 /* Internal context to hold data when executed command with timeout. */
 typedef struct {
-  SilcServer server;
-  SilcSocketConnection sock;
-  SilcPacketContext *packet;
+  SilcServerCommandContext ctx;
+  SilcServerCommand *cmd;
 } *SilcServerCommandTimeout;
 
 /* Timeout callback to process commands with timeout for client. Client's
 } *SilcServerCommandTimeout;
 
 /* Timeout callback to process commands with timeout for client. Client's
@@ -127,67 +126,61 @@ typedef struct {
 SILC_TASK_CALLBACK(silc_server_command_process_timeout)
 {
   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
 SILC_TASK_CALLBACK(silc_server_command_process_timeout)
 {
   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
-  SilcServerCommandContext ctx;
-  SilcServerCommand *cmd;
-  SilcClientEntry client = (SilcClientEntry)timeout->sock->user_data;
+  SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
 
   /* Update access time */
   client->last_command = time(NULL);
 
 
   /* Update access time */
   client->last_command = time(NULL);
 
+  if (!(timeout->cmd->flags & SILC_CF_REG))
+    timeout->cmd->cb(timeout->ctx);
+  else if (silc_server_is_registered(timeout->ctx->server, 
+                                    timeout->ctx->sock, 
+                                    timeout->ctx, 
+                                    timeout->cmd->cmd))
+    timeout->cmd->cb(timeout->ctx);
+
+  silc_free(timeout);
+}
+
+/* Processes received command packet. */
+
+void silc_server_command_process(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet)
+{
+  SilcServerCommandContext ctx;
+  SilcServerCommand *cmd;
+
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
   ctx = silc_server_command_alloc();
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
   ctx = silc_server_command_alloc();
-  ctx->server = timeout->server;
-  ctx->sock = timeout->sock;
-  ctx->packet = timeout->packet;
-
+  ctx->server = server;
+  ctx->sock = silc_socket_dup(sock);
+  ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
+  
   /* Parse the command payload in the packet */
   /* Parse the command payload in the packet */
-  ctx->payload = silc_command_payload_parse(ctx->packet->buffer);
+  ctx->payload = silc_command_payload_parse(packet->buffer);
   if (!ctx->payload) {
     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
   if (!ctx->payload) {
     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
-    silc_buffer_free(ctx->packet->buffer);
+    silc_buffer_free(packet->buffer);
+    silc_packet_context_free(packet);
     silc_socket_free(ctx->sock);
     silc_socket_free(ctx->sock);
-    silc_packet_context_free(ctx->packet);
     silc_free(ctx);
     silc_free(ctx);
-    silc_free(timeout);
     return;
   }
   ctx->args = silc_command_get_args(ctx->payload);
   
     return;
   }
   ctx->args = silc_command_get_args(ctx->payload);
   
-  /* Execute command. If this fails the packet is dropped. */
+  /* Get the command */
   for (cmd = silc_command_list; cmd->cb; cmd++)
   for (cmd = silc_command_list; cmd->cb; cmd++)
-    if (cmd->cmd == silc_command_get(ctx->payload)) {
-
-      if (!(cmd->flags & SILC_CF_REG)) {
-       cmd->cb(ctx);
-       break;
-      }
-      
-      if (silc_server_is_registered(ctx->server, ctx->sock, ctx, cmd->cmd)) {
-       cmd->cb(ctx);
-       break;
-      }
-    }
+    if (cmd->cmd == silc_command_get(ctx->payload))
+      break;
 
   if (cmd == NULL) {
     SILC_LOG_ERROR(("Unknown command, packet dropped"));
     silc_server_command_free(ctx);
 
   if (cmd == NULL) {
     SILC_LOG_ERROR(("Unknown command, packet dropped"));
     silc_server_command_free(ctx);
-    silc_free(timeout);
     return;
   }
 
     return;
   }
 
-  silc_free(timeout);
-}
-
-/* Processes received command packet. */
-
-void silc_server_command_process(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet)
-{
-  SilcServerCommandContext ctx;
-  SilcServerCommand *cmd;
-
   /* Execute client's commands always with timeout.  Normally they are
      executed with zero (0) timeout but if client is sending command more
      frequently than once in 2 seconds, then the timeout may be 0 to 2
   /* Execute client's commands always with timeout.  Normally they are
      executed with zero (0) timeout but if client is sending command more
      frequently than once in 2 seconds, then the timeout may be 0 to 2
@@ -195,12 +188,22 @@ void silc_server_command_process(SilcServer server,
   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
     SilcClientEntry client = (SilcClientEntry)sock->user_data;
     SilcServerCommandTimeout timeout = silc_calloc(1, sizeof(*timeout));
   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
     SilcClientEntry client = (SilcClientEntry)sock->user_data;
     SilcServerCommandTimeout timeout = silc_calloc(1, sizeof(*timeout));
+    int fast;
 
 
-    timeout->server = server;
-    timeout->sock = silc_socket_dup(sock);
-    timeout->packet = silc_packet_context_dup(packet);
+    timeout->ctx = ctx;
+    timeout->cmd = cmd;
 
 
-    if (client->last_command && (time(NULL) - client->last_command) < 2)
+    if (client->last_command && (time(NULL) - client->last_command) < 2) {
+      client->fast_command++;
+      fast = FALSE;
+    } else {
+      client->fast_command = ((client->fast_command - 1) <= 0 ? 0 : 
+                             client->fast_command--);
+      fast = TRUE;
+    }
+
+    if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
+                 (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
       silc_task_register(server->timeout_queue, sock->sock, 
                         silc_server_command_process_timeout,
                         (void *)timeout, 
       silc_task_register(server->timeout_queue, sock->sock, 
                         silc_server_command_process_timeout,
                         (void *)timeout, 
@@ -217,45 +220,12 @@ void silc_server_command_process(SilcServer server,
     return;
   }
 
     return;
   }
 
-  /* Allocate command context. This must be free'd by the
-     command routine receiving it. */
-  ctx = silc_server_command_alloc();
-  ctx->server = server;
-  ctx->sock = silc_socket_dup(sock);
-  ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
-  
-  /* Parse the command payload in the packet */
-  ctx->payload = silc_command_payload_parse(packet->buffer);
-  if (!ctx->payload) {
-    SILC_LOG_ERROR(("Bad command payload, packet dropped"));
-    silc_buffer_free(packet->buffer);
-    silc_packet_context_free(packet);
-    silc_socket_free(ctx->sock);
-    silc_free(ctx);
-    return;
-  }
-  ctx->args = silc_command_get_args(ctx->payload);
-  
-  /* Execute command. If this fails the packet is dropped. */
-  for (cmd = silc_command_list; cmd->cb; cmd++)
-    if (cmd->cmd == silc_command_get(ctx->payload)) {
-
-      if (!(cmd->flags & SILC_CF_REG)) {
-       cmd->cb(ctx);
-       break;
-      }
-      
-      if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
-       cmd->cb(ctx);
-       break;
-      }
-    }
+  /* Execute for server */
 
 
-  if (cmd == NULL) {
-    SILC_LOG_ERROR(("Unknown command, packet dropped"));
-    silc_server_command_free(ctx);
-    return;
-  }
+  if (!(cmd->flags & SILC_CF_REG))
+    cmd->cb(ctx);
+  else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
+    cmd->cb(ctx);
 }
 
 /* Allocate Command Context */
 }
 
 /* Allocate Command Context */
index e05bcbdab834b225b1148c9c6be526d6c5708856..9d29d74fdfc02a0c0f054673981b31099ffd4ddb 100644 (file)
@@ -241,6 +241,12 @@ typedef struct SilcChannelClientEntryStruct {
        not allow any command to be exeucted more than once in about
        2 seconds. This is result of normal time().
 
        not allow any command to be exeucted more than once in about
        2 seconds. This is result of normal time().
 
+   char fast_command
+
+       Counter to check command bursts.  By default, up to 5 commands
+       are allowed before limiting the execution.  See command flags
+       for more detail.
+
    SilcServerEntry router
 
        This is a pointer to the server list. This is the router server whose 
    SilcServerEntry router
 
        This is a pointer to the server list. This is the router server whose 
@@ -270,6 +276,7 @@ struct SilcClientEntryStruct {
   int mode;
 
   long last_command;
   int mode;
 
   long last_command;
+  char fast_command;
 
   /* Pointer to the router */
   SilcServerEntry router;
 
   /* Pointer to the router */
   SilcServerEntry router;
index f36990e456381ba5584dd9db658349f9de811b19..fa5909171dd745fbaaa800b123ff8b468a5bdf4b 100644 (file)
@@ -847,8 +847,12 @@ however, choose ignore the command reply, but should not.
 It is expected that some of the commands may be miss-used by clients
 resulting various problems on the server side.  Every implementation
 should assure that commands may not be executed more than once, say,
 It is expected that some of the commands may be miss-used by clients
 resulting various problems on the server side.  Every implementation
 should assure that commands may not be executed more than once, say,
-in two (2) seconds.  This should be sufficient to prevent the miss-use
-of commands.
+in two (2) seconds.  However, to keep response rate up, allowing for
+example five (5) commands before limiting is allowed.  It is recommended
+that commands such as SILC_COMMAND_NICK, SILC_COMMAND_JOIN and 
+SILC_COMMAND_LEAVE should be limited in all cases as they require
+heavy operations.  This should be sufficient to prevent the miss-use of
+commands.
 
 SILC commands are described in section 5 SILC Commands.
 
 
 SILC commands are described in section 5 SILC Commands.
 
index ec34d8344b2cfa3c95abae57e70b27bfc50f8a40..dd20052dc81cf22d6e4470ca41260045616831a0 100644 (file)
@@ -36,19 +36,24 @@ typedef struct SilcCommandPayloadStruct *SilcCommandPayload;
 typedef enum {
   SILC_CF_NONE           = 0,
 
 typedef enum {
   SILC_CF_NONE           = 0,
 
-  /* Command may only be used once per (about) 2 seconds */
+  /* Command may only be used once per (about) 2 seconds. Bursts up
+     to 5 commands are allowed though. */
   SILC_CF_LAG            = (1L << 1),
 
   SILC_CF_LAG            = (1L << 1),
 
+  /* Command may only be used once per (about) 2 seconds. No bursts
+     are allowed at all. */
+  SILC_CF_LAG_STRICT     = (1L << 2),
+
   /* Command is available for registered connections (connections
      whose ID has been created. */
   /* Command is available for registered connections (connections
      whose ID has been created. */
-  SILC_CF_REG            = (1L << 2),
+  SILC_CF_REG            = (1L << 3),
 
   /* Command is available only for server operators */
 
   /* Command is available only for server operators */
-  SILC_CF_OPER           = (1L << 3),
+  SILC_CF_OPER           = (1L << 4),
 
   /* Command is available only for SILC (router) operators. If this 
      is set SILC_CF_OPER is not necessary to be set. */
 
   /* Command is available only for SILC (router) operators. If this 
      is set SILC_CF_OPER is not necessary to be set. */
-  SILC_CF_SILC_OPER      = (1L << 4),
+  SILC_CF_SILC_OPER      = (1L << 5),
 
 } SilcCommandFlag;
 
 
 } SilcCommandFlag;