updates.
authorPekka Riikonen <priikone@silcnet.org>
Thu, 14 Feb 2002 20:43:59 +0000 (20:43 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 14 Feb 2002 20:43:59 +0000 (20:43 +0000)
CHANGES
Makefile.am.pre
TODO
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_internal.h
apps/silcd/serverconfig.c
apps/silcd/serverconfig.h
doc/Makefile.am.pre
doc/example_silcd.conf.in
doc/silcalgs.conf [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 3a5df3570e9d9cc54bb49ac5f301b2aeac538f8c..9fadd907048bbed7094f7cf9226d8d810f2f4634 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,27 @@
+Thu Feb 14 22:03:58 EET 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added new configuration options and blocks:
+         keepalive_secs, reconnect_count, reconnect_interval,
+         reconnect_interval_max, reconnect_keep_trying and
+         require_reverser_lookup.  Added ConnectionParam block, and
+         implemented the connection parameters when connecting as
+         initiator and when accepting connections as responder. 
+
+         Added CONFIG_IS_DOUBLE macro in config file parsing, to check
+         whether given configuration value has been given already.
+
+         Affected files silcd/serverconfig.[c], server.[c].
+
+       * Splitted the doc/example_silcd.conf.in.  Separated the crypto
+         algorithm parts and created new file silcalgs.conf, that
+         is now included from the example_silcd.conf.in.
+
+       * Optimized the silc_server_connect_to_router_second to take
+         the connection configuration object from the SilcServerConnection
+         object instead of finding it during the connecting phase.
+         Added the configuration object to SilcServerConnection struct.
+         Affected files silcd/server_internal.h, server.c.
+
 Thu Feb 14 16:02:26 CET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Add the client on channel after it was resolved at the
index 6bf3d2e35a05ca81fabcbf66a7aceb0bd7bd0c29..3d5f545608480c2b503384c77b282a8625044b6e 100644 (file)
@@ -83,7 +83,9 @@ examples-install:
 etc-install:
        -@if test '!' -f $(etcdir)/silcd.conf ; then \
          $(INSTALL_DATA) $(srcdir)/doc/example_silcd.conf \
-         $(etcdir)/silcd.conf; \
+               $(etcdir)/silcd.conf; \
+         $(INSTALL_DATA) $(srcdir)/doc/silcalgs.conf \
+               $(etcdir)/silcalgs.conf; \
           chmod go= $(etcdir)/silcd.conf; \
        fi
        -@if test '!' -f $(etcdir)/silc.conf ; then \
diff --git a/TODO b/TODO
index 7e307c9d1c5c346aaebba5894159a1fedff33894..69330deccef3d7ae9977bdc36d816ce220fdcb31 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,9 @@
 TODO/bugs in Irssi SILC client
 ==============================
 
+ o When autoconnect="yes" is set in silc.conf the irssi complains about
+   unknown chat protocol.
+
  o Rewrite the notify handling in the new Irssi SILC client.
 
  o /cumode for unknown nick does not give any error message.
index 32287521198710908c38c3b58161477601255e58..3f8cd46fdc730f560e2a4fe4984caae027edba88 100644 (file)
@@ -93,8 +93,6 @@ void silc_server_free(SilcServer server)
     silc_dlist_uninit(server->sim);
 #endif
 
-    silc_free(server->params);
-
     if (server->pending_commands)
       silc_dlist_uninit(server->pending_commands);
 
@@ -130,15 +128,8 @@ int silc_server_init(SilcServer server)
   server->public_key = server->config->server_info->public_key;
   server->private_key = server->config->server_info->private_key;
 
-  /* XXX After server is made as Silc Server Library this can be given
-     as argument, for now this is hard coded */
-  server->params = silc_calloc(1, sizeof(*server->params));
-  server->params->retry_count = SILC_SERVER_RETRY_COUNT;
-  server->params->retry_interval_min = SILC_SERVER_RETRY_INTERVAL_MIN;
-  server->params->retry_interval_max = SILC_SERVER_RETRY_INTERVAL_MAX;
-  server->params->retry_keep_trying = FALSE;
-  server->params->protocol_timeout = 60;
-  server->params->require_reverse_mapping = FALSE;
+  /* Set default to configuration parameters */
+  silc_server_config_set_defaults(server);
 
   /* Register all configured ciphers, PKCS and hash functions. */
   if (!silc_server_config_register_ciphers(server))
@@ -223,7 +214,7 @@ int silc_server_init(SilcServer server)
        and port. */
     if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname, 
                                      &newsocket->ip)) {
-      if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
+      if ((server->config->require_reverse_lookup && !newsocket->hostname) ||
          !newsocket->ip) {
        SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
                        newsocket->hostname ? newsocket->hostname :
@@ -555,11 +546,10 @@ void silc_server_start_key_exchange(SilcServer server,
      is not executed within set limit. */
   proto_ctx->timeout_task = 
     silc_schedule_task_add(server->schedule, sock, 
-                      silc_server_timeout_remote,
-                      server, server->params->protocol_timeout,
-                      server->params->protocol_timeout_usec,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_LOW);
+                          silc_server_timeout_remote,
+                          server, 60, 0, /* XXX hardcoded */
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
 
   /* Register the connection for network input and output. This sets
      that scheduler will listen for incoming packets for this connection 
@@ -583,24 +573,27 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 {
   SilcServerConnection sconn = (SilcServerConnection)context;
   SilcServer server = sconn->server;
+  SilcServerConfigSectionConnectionParam *param;
+
+  param = (sconn->param ? sconn->param : &server->config->param);
 
   SILC_LOG_INFO(("Retrying connecting to a router"));
 
   /* Calculate next timeout */
   if (sconn->retry_count >= 1) {
     sconn->retry_timeout = sconn->retry_timeout * SILC_SERVER_RETRY_MULTIPLIER;
-    if (sconn->retry_timeout > SILC_SERVER_RETRY_INTERVAL_MAX)
-      sconn->retry_timeout = SILC_SERVER_RETRY_INTERVAL_MAX;
+    if (sconn->retry_timeout > param->reconnect_interval_max)
+      sconn->retry_timeout = param->reconnect_interval_max;
   } else {
-    sconn->retry_timeout = server->params->retry_interval_min;
+    sconn->retry_timeout = param->reconnect_interval;
   }
   sconn->retry_count++;
   sconn->retry_timeout = sconn->retry_timeout +
     silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER;
 
   /* If we've reached max retry count, give up. */
-  if (sconn->retry_count > server->params->retry_count && 
-      server->params->retry_keep_trying == FALSE) {
+  if (sconn->retry_count > param->reconnect_count && 
+      param->reconnect_keep_trying == FALSE) {
     SILC_LOG_ERROR(("Could not connect to router, giving up"));
     silc_free(sconn->remote_host);
     silc_free(sconn);
@@ -609,8 +602,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 
   /* Wait one before retrying */
   silc_schedule_task_add(server->schedule, fd, silc_server_connect_router,
-                        context, sconn->retry_timeout, 
-                        server->params->retry_interval_min_usec,
+                        context, sconn->retry_timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
 
@@ -626,7 +618,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
                 (sconn->backup ? "backup router" : "router"), 
                 sconn->remote_host, sconn->remote_port));
 
-  server->router_connect = time(0);
+  server->router_connect = time(NULL);
 
   /* Connect to remote host */
   sock = silc_net_create_connection(server->config->server_info->server_ip,
@@ -692,6 +684,9 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       if (!server->router_conn && !sconn->backup)
        server->router_conn = sconn;
 
+      sconn->conn = ptr;
+      sconn->param = ptr->param;
+
       silc_schedule_task_add(server->schedule, fd, 
                             silc_server_connect_router,
                             (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
@@ -786,8 +781,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
 
   /* Resolve the authentication method used in this connection. Check if 
      we find a match from user configured connections */
-  conn = silc_server_config_find_router_conn(server, sock->hostname,
-                                            sock->port);
+  if (!sconn->conn)
+    conn = silc_server_config_find_router_conn(server, sock->hostname,
+                                              sock->port);
+  else
+    conn = sconn->conn;
+
   if (conn) {
     /* Match found. Use the configured authentication method */
     if (conn->passphrase) {
@@ -841,14 +840,13 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
                      silc_server_connect_to_router_final);
 
   /* Register timeout task. If the protocol is not executed inside
-     this timelimit the connection will be terminated. Currently
-     this is 15 seconds and is hard coded limit (XXX). */
+     this timelimit the connection will be terminated. */
   proto_ctx->timeout_task = 
     silc_schedule_task_add(server->schedule, sock->sock, 
-                      silc_server_timeout_remote,
-                      (void *)server, 15, 0,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_LOW);
+                          silc_server_timeout_remote,
+                          (void *)server, 15, 0, /* XXX hardcoded */
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
 
   /* Run the protocol */
   silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
@@ -871,6 +869,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   unsigned char *id_string;
   uint32 id_len;
   SilcIDListData idata;
+  SilcServerConfigSectionConnectionParam *param;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -949,12 +948,14 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   idata = (SilcIDListData)sock->user_data;
   idata->status |= SILC_IDLIST_STATUS_REGISTERED;
 
+  param = (sconn->param ? sconn->param : &server->config->param);
+
   /* Perform keepalive. The `hb_context' will be freed automatically
      when finally calling the silc_socket_free function. XXX hardcoded 
      timeout!! */
   hb_context = silc_calloc(1, sizeof(*hb_context));
   hb_context->server = server;
-  silc_socket_set_heartbeat(sock, 300, hb_context,
+  silc_socket_set_heartbeat(sock, param->keepalive_secs, hb_context,
                            silc_server_perform_heartbeat,
                            server->schedule);
 
@@ -1037,7 +1038,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
 
   /* Check whether we could resolve both IP and FQDN. */
   if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
-                   server->params->require_reverse_mapping)) {
+                   server->config->require_reverse_lookup)) {
     SILC_LOG_ERROR(("IP/DNS lookup failed %s",
                    sock->hostname ? sock->hostname :
                    sock->ip ? sock->ip : ""));
@@ -1120,12 +1121,12 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
 
   /* Register a timeout task that will be executed if the connector
      will not start the key exchange protocol within 60 seconds. For
-     now, this is a hard coded limit. After 60 secs the connection will
+     now, this is a hard coded limit. After the timeout the connection will
      be closed if the key exchange protocol has not been started. */
   proto_ctx->timeout_task = 
     silc_schedule_task_add(server->schedule, sock->sock, 
                           silc_server_timeout_remote,
-                          context, 60, 0,
+                          context, 60, 0, /* XXX hardcoded */
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 }
@@ -1269,12 +1270,11 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
                      silc_server_accept_new_connection_final);
 
   /* Register timeout task. If the protocol is not executed inside
-     this timelimit the connection will be terminated. Currently
-     this is 60 seconds and is hard coded limit (XXX). */
+     this timelimit the connection will be terminated. */
   proto_ctx->timeout_task = 
     silc_schedule_task_add(server->schedule, sock->sock, 
                           silc_server_timeout_remote,
-                          (void *)server, 60, 0,
+                          (void *)server, 60, 0, /* XXX hardcoded */
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 }
@@ -1293,6 +1293,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   SilcServerHBContext hb_context;
   SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
   void *id_entry;
+  uint32 hearbeat_timeout = SILC_SERVER_KEEPALIVE;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1321,6 +1322,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry client;
+      SilcServerConfigSectionClient *conn = ctx->cconfig;
 
       SILC_LOG_DEBUG(("Remote host is client"));
       SILC_LOG_INFO(("Connection from %s (%s) is client", sock->hostname,
@@ -1347,6 +1349,12 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       if (server->server_type == SILC_ROUTER)
        server->stat.cell_clients++;
 
+      /* Get connection parameters */
+      if (conn->param) {
+       if (conn->param->keepalive_secs)
+         hearbeat_timeout = conn->param->keepalive_secs;
+      }
+
       id_entry = (void *)client;
       break;
     }
@@ -1354,18 +1362,43 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   case SILC_SOCKET_TYPE_ROUTER:
     {
       SilcServerEntry new_server;
-      /* XXX FIXME: Now server and router has different table, so this is probably broken. */
-      SilcServerConfigSectionRouter *conn =
-       ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
-       ctx->sconfig : ctx->rconfig;
+      bool initiator = FALSE;
+      bool backup_local = FALSE;
+      bool backup_router = FALSE;
+      char *backup_replace_ip = NULL;
+      uint16 backup_replace_port = 0;
+      SilcServerConfigSectionServer *sconn = ctx->sconfig;
+      SilcServerConfigSectionRouter *rconn = ctx->rconfig;
+
+      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && rconn) {
+       initiator = rconn->initiator;
+       backup_local = rconn->backup_local;
+       backup_router = rconn->backup_router;
+       backup_replace_ip = rconn->backup_replace_ip;
+       backup_replace_port = rconn->backup_replace_port;
+
+       if (rconn->param) {
+         if (rconn->param->keepalive_secs)
+           hearbeat_timeout = rconn->param->keepalive_secs;
+       }
+      }
+
+      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER && sconn) {
+       backup_router = sconn->backup_router;
+
+       if (sconn->param) {
+         if (sconn->param->keepalive_secs)
+           hearbeat_timeout = sconn->param->keepalive_secs;
+       }
+      }
 
       SILC_LOG_DEBUG(("Remote host is %s", 
                      ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
-                     "server" : (conn->backup_router ? 
+                     "server" : (backup_router ? 
                                  "backup router" : "router")));
       SILC_LOG_INFO(("Connection from %s (%s) is %s", sock->hostname,
                     sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
-                    "server" : (conn->backup_router ? 
+                    "server" : (backup_router ? 
                                 "backup router" : "router")));
 
       /* Add the server into server cache. The server name and Server ID
@@ -1374,7 +1407,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
         are router. */
       new_server = 
        silc_idlist_add_server((ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                               server->local_list : (conn->backup_router ?
+                               server->local_list : (backup_router ?
                                                      server->local_list :
                                                      server->global_list)),
                               NULL,
@@ -1382,7 +1415,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
                                SILC_SERVER : SILC_ROUTER), 
                               NULL, 
                               (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                               server->id_entry : (conn->backup_router ? 
+                               server->id_entry : (backup_router ? 
                                                    server->id_entry : NULL)),
                               sock);
       if (!new_server) {
@@ -1406,12 +1439,12 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
       /* If the incoming connection is router and marked as backup router
         then add it to be one of our backups */
-      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && conn->backup_router) {
-       silc_server_backup_add(server, new_server, conn->backup_replace_ip,
-                              conn->backup_replace_port, conn->backup_local);
+      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && backup_router) {
+       silc_server_backup_add(server, new_server, backup_replace_ip,
+                              backup_replace_port, backup_local);
 
        /* Change it back to SERVER type since that's what it really is. */
-       if (conn->backup_local)
+       if (backup_local)
          ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
 
        new_server->server_type = SILC_BACKUP_ROUTER;
@@ -1420,8 +1453,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       /* Check whether this connection is to be our primary router connection
         if we do not already have the primary route. */
       if (server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
-       if (silc_server_config_is_primary_route(server) &&
-           !conn->initiator)
+       if (silc_server_config_is_primary_route(server) && !initiator)
          break;
 
        SILC_LOG_DEBUG(("We are not standalone server anymore"));
@@ -1452,11 +1484,10 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   SILC_LOG_DEBUG(("New connection authenticated"));
 
   /* Perform keepalive. The `hb_context' will be freed automatically
-     when finally calling the silc_socket_free function. XXX hardcoded 
-     timeout!! */
+     when finally calling the silc_socket_free function. */
   hb_context = silc_calloc(1, sizeof(*hb_context));
   hb_context->server = server;
-  silc_socket_set_heartbeat(sock, 400, hb_context,
+  silc_socket_set_heartbeat(sock, hearbeat_timeout, hb_context,
                            silc_server_perform_heartbeat,
                            server->schedule);
 
@@ -2219,6 +2250,7 @@ void silc_server_create_connection(SilcServer server,
   sconn->remote_host = strdup(remote_host);
   sconn->remote_port = port;
   sconn->no_reconnect = TRUE;
+  sconn->param = &server->config->param;
 
   silc_schedule_task_add(server->schedule, 0, 
                         silc_server_connect_router,
index 65ab966e51115a25809f265c020d6ecedb4d428c..afff2b97a9e51399ac794001ba68637ec4c0d0fb 100644 (file)
@@ -29,47 +29,6 @@ typedef struct SilcServerStruct *SilcServer;
 /* Forward declaration of backup server context */
 typedef struct SilcServerBackupStruct *SilcServerBackup;
 
-#define SILC_SERVER_MAX_CONNECTIONS 1000
-
-/* General definitions */
-
-/* SILC port */
-#define SILC_PORT 768;
-
-/* Server and router. Used internally by the code. */
-#define SILC_SERVER 0
-#define SILC_ROUTER 1
-#define SILC_BACKUP_ROUTER 2
-
-/* Connection retry timeout. We implement exponential backoff algorithm
-   in connection retry. The interval of timeout grows when retry count
-   grows. */
-#define SILC_SERVER_RETRY_COUNT        7        /* Max retry count */
-#define SILC_SERVER_RETRY_MULTIPLIER   2        /* Interval growth */
-#define SILC_SERVER_RETRY_RANDOMIZER   2        /* timeout += rnd % 2 */
-#define SILC_SERVER_RETRY_INTERVAL_MIN 10       /* Min retry timeout */
-#define SILC_SERVER_RETRY_INTERVAL_MAX 600      /* Max generated timeout */
-
-/* 
-   Silc Server Params.
-
-   Structure to hold various default parameters for server that can be
-   given before running the server. 
-
-*/
-typedef struct {
-  uint32 retry_count;
-  uint32 retry_interval_min;
-  uint32 retry_interval_min_usec;
-  uint32 retry_interval_max;
-  char retry_keep_trying;
-
-  uint32 protocol_timeout;
-  uint32 protocol_timeout_usec;
-
-  char require_reverse_mapping;
-} *SilcServerParams;
-
 /* Callback function that is called after the key exchange and connection
    authentication protocols has been completed with a remote router. The
    `server_entry' is the remote router entry. */
@@ -77,6 +36,7 @@ typedef void (*SilcServerConnectRouterCallback)(SilcServer server,
                                                SilcServerEntry server_entry,
                                                void *context);
 
+/* Connection structure used when connection to remote */
 typedef struct {
   SilcSocketConnection sock;
 
@@ -87,7 +47,11 @@ typedef struct {
   char *backup_replace_ip;
   int backup_replace_port;
   bool no_reconnect;
-  
+
+  /* Connection configuration (maybe NULL), and connection params */
+  void *conn;
+  void *param;
+
   /* Current connection retry info */
   uint32 retry_count;
   uint32 retry_timeout;
@@ -99,6 +63,31 @@ typedef struct {
   void *callback_context;
 } *SilcServerConnection;
 
+#define SILC_SERVER_MAX_CONNECTIONS 1000
+
+/* General definitions */
+
+/* SILC port */
+#define SILC_PORT 768;
+
+/* Server and router. Used internally by the code. */
+#define SILC_SERVER 0
+#define SILC_ROUTER 1
+#define SILC_BACKUP_ROUTER 2
+
+/* Default parameter values */
+
+/* Connection retry timeout. We implement exponential backoff algorithm
+   in connection retry. The interval of timeout grows when retry count
+   grows. */
+#define SILC_SERVER_RETRY_COUNT        7        /* Max retry count */
+#define SILC_SERVER_RETRY_MULTIPLIER   2        /* Interval growth */
+#define SILC_SERVER_RETRY_RANDOMIZER   2        /* timeout += rnd % 2 */
+#define SILC_SERVER_RETRY_INTERVAL_MIN 10       /* Min retry timeout */
+#define SILC_SERVER_RETRY_INTERVAL_MAX 600      /* Max generated timeout */
+
+#define SILC_SERVER_KEEPALIVE          300       /* Heartbeat interval */
+
 /* Macros */
 
 /* This macro is used to send notify messages with formatted string. The
index 41df9ab805195c78fd85d781c76f7235afd29b42..423e37e6d9f34b499fb177ca9017326ebec0e0e8 100644 (file)
@@ -121,9 +121,6 @@ struct SilcServerStruct {
   /* Pending command queue */
   SilcDList pending_commands;
 
-  /* Default parameteres for server */
-  SilcServerParams params;
-
 #ifdef SILC_SIM
   /* SIM (SILC Module) list */
   SilcDList sim;
index f34616bfa100a4a688e3039bc847a002aa484c95..16866fd2f941d17204bfc485667cef8cfb7e0aaa 100644 (file)
     __type__ *di = (__type__ *) tmp;                                   \
     tmp = (void *) di->next;
 
+/* Set EDOUBLE error value and bail out if necessary */
+#define CONFIG_IS_DOUBLE(x)                    \
+ if ((x)) {                                    \
+   got_errno = SILC_CONFIG_EDOUBLE;            \
+   goto got_err;                               \
+ }
+
+/* Find connection parameters by the parameter block name. */
+static SilcServerConfigSectionConnectionParam *
+my_find_param(SilcServerConfig config, const char *name)
+{
+  SilcServerConfigSectionConnectionParam *param;
+
+  if (!name)
+    return NULL;
+
+  for (param = config->conn_params; param; param = param->next) {
+    if (!strcasecmp(param->name, name))
+      return param;
+  }
+
+  return NULL;
+}
+
 /* free an authdata according to its auth method */
 static void my_free_authdata(char *passphrase, void *public_key)
 {
@@ -95,21 +119,40 @@ static bool my_parse_authdata(SilcAuthMethod auth_meth, char *p, uint32 line,
 SILC_CONFIG_CALLBACK(fetch_generic)
 {
   SilcServerConfig config = (SilcServerConfig) context;
+  int got_errno = 0;
 
   if (!strcmp(name, "module_path")) {
-    if (config->module_path) 
-      return SILC_CONFIG_EDOUBLE;
-
-    /* dup it only if non-empty, otherwise point it to NULL */
+    CONFIG_IS_DOUBLE(config->module_path);
     config->module_path = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "prefer_passphrase_auth")) {
     config->prefer_passphrase_auth = *(bool *)val;
   }
+  else if (!strcmp(name, "require_reverse_lookup")) {
+    config->require_reverse_lookup = *(bool *)val;
+  }
+  else if (!strcmp(name, "keepalive_secs")) {
+    config->param.keepalive_secs = *(uint32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_count")) {
+    config->param.reconnect_count = *(uint32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_interval")) {
+    config->param.reconnect_interval = *(uint32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_interval_max")) {
+    config->param.reconnect_interval_max = *(uint32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_keep_trying")) {
+    config->param.reconnect_keep_trying = *(bool *)val;
+  }
   else
     return SILC_CONFIG_EINTERNAL;
 
   return SILC_CONFIG_OK;
+
+ got_err:
+  return got_errno;
 }
 
 SILC_CONFIG_CALLBACK(fetch_cipher)
@@ -139,18 +182,19 @@ SILC_CONFIG_CALLBACK(fetch_cipher)
 
   /* Identify and save this value */
   if (!strcmp(name, "name")) {
-    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
-  else if (!strcmp(name, "module")) { /* can be empty */
-    if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
-    /* dup it only if non-empty, otherwise point it to NULL */
+  else if (!strcmp(name, "module")) {
+    CONFIG_IS_DOUBLE(tmp->module);
     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
   }
-  else if (!strcmp(name, "keylength"))
+  else if (!strcmp(name, "keylength")) {
     tmp->key_length = *(uint32 *)val;
-  else if (!strcmp(name, "blocklength"))
+  }
+  else if (!strcmp(name, "blocklength")) {
     tmp->block_length = *(uint32 *)val;
+  }
   else
     return SILC_CONFIG_EINTERNAL;
   return SILC_CONFIG_OK;
@@ -182,6 +226,7 @@ SILC_CONFIG_CALLBACK(fetch_hash)
     config->tmp = NULL;
     return SILC_CONFIG_OK;
   }
+
   /* if there isn't a temporary struct alloc one */
   if (!tmp) {
     config->tmp = silc_calloc(1, sizeof(*findtmp));
@@ -190,18 +235,19 @@ SILC_CONFIG_CALLBACK(fetch_hash)
 
   /* Identify and save this value */
   if (!strcmp(name, "name")) {
-    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
-  else if (!strcmp(name, "module")) { /* can be empty */
-    if (tmp->module) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
-    /* dup it only if non-empty, otherwise point it to NULL */
+  else if (!strcmp(name, "module")) {
+    CONFIG_IS_DOUBLE(tmp->module);
     tmp->module = (*(char *)val ? strdup((char *) val) : NULL);
   }
-  else if (!strcmp(name, "blocklength"))
+  else if (!strcmp(name, "blocklength")) {
     tmp->block_length = *(int *)val;
-  else if (!strcmp(name, "digestlength"))
+  }
+  else if (!strcmp(name, "digestlength")) {
     tmp->digest_length = *(int *)val;
+  }
   else
     return SILC_CONFIG_EINTERNAL;
   return SILC_CONFIG_OK;
@@ -241,15 +287,16 @@ SILC_CONFIG_CALLBACK(fetch_hmac)
 
   /* Identify and save this value */
   if (!strcmp(name, "name")) {
-    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
   else if (!strcmp(name, "hash")) {
-    if (tmp->hash) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->hash);
     tmp->hash = strdup((char *) val);
   }
-  else if (!strcmp(name, "maclength"))
+  else if (!strcmp(name, "maclength")) {
     tmp->mac_length = *(int *)val;
+  }
   else
     return SILC_CONFIG_EINTERNAL;
   return SILC_CONFIG_OK;
@@ -289,7 +336,7 @@ SILC_CONFIG_CALLBACK(fetch_pkcs)
 
   /* Identify and save this value */
   if (!strcmp(name, "name")) {
-    if (tmp->name) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->name);
     tmp->name = strdup((char *) val);
   }
   else
@@ -307,23 +354,23 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
 {
   SilcServerConfig config = (SilcServerConfig) context;
   SilcServerConfigSectionServerInfo *server_info = config->server_info;
+  int got_errno = 0;
 
   /* if there isn't the struct alloc it */
-  if (!server_info) {
+  if (!server_info)
     config->server_info = server_info = (SilcServerConfigSectionServerInfo *)
                silc_calloc(1, sizeof(*server_info));
-  }
 
   if (type == SILC_CONFIG_ARG_BLOCK) {
     /* check for mandatory inputs */
     return SILC_CONFIG_OK;
   }
   if (!strcmp(name, "hostname")) {
-    if (server_info->server_name) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->server_name);
     server_info->server_name = strdup((char *) val);
   }
   else if (!strcmp(name, "ip")) {
-    if (server_info->server_ip) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->server_ip);
     server_info->server_ip = strdup((char *) val);
   }
   else if (!strcmp(name, "port")) {
@@ -335,35 +382,35 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
     server_info->port = (uint16) port;
   }
   else if (!strcmp(name, "servertype")) {
-    if (server_info->server_type) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->server_type);
     server_info->server_type = strdup((char *) val);
   }
   else if (!strcmp(name, "admin")) {
-    if (server_info->admin) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->admin);
     server_info->admin = strdup((char *) val);
   }
   else if (!strcmp(name, "adminemail")) {
-    if (server_info->email) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->email);
     server_info->email = strdup((char *) val);
   }
   else if (!strcmp(name, "location")) {
-    if (server_info->location) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->location);
     server_info->location = strdup((char *) val);
   }
   else if (!strcmp(name, "user")) {
-    if (server_info->user) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->user);
     server_info->user = strdup((char *) val);
   }
   else if (!strcmp(name, "group")) {
-    if (server_info->group) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->group);
     server_info->group = strdup((char *) val);
   }
   else if (!strcmp(name, "motdfile")) {
-    if (server_info->motd_file) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->motd_file);
     server_info->motd_file = strdup((char *) val);
   }
   else if (!strcmp(name, "pidfile")) {
-    if (server_info->pid_file) return SILC_CONFIG_EDOUBLE;
+    CONFIG_IS_DOUBLE(server_info->pid_file);
     server_info->pid_file = strdup((char *) val);
   }
   else if (!strcmp(name, "publickey")) {
@@ -395,6 +442,9 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
   else
     return SILC_CONFIG_EINTERNAL;
   return SILC_CONFIG_OK;
+
+ got_err:
+  return got_errno;
 }
 
 SILC_CONFIG_CALLBACK(fetch_logging)
@@ -458,6 +508,59 @@ SILC_CONFIG_CALLBACK(fetch_logging)
   return got_errno;
 }
 
+SILC_CONFIG_CALLBACK(fetch_connparam)
+{
+  SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionConnectionParam);
+
+  SERVER_CONFIG_DEBUG(("Received CONNPARAM type=%d name=\"%s\" (val=%x)", 
+                      type, name, context));
+
+  if (type == SILC_CONFIG_ARG_BLOCK) {
+    if (!tmp)
+      return SILC_CONFIG_OK;
+
+    SILC_SERVER_CONFIG_LIST_APPENDTMP(config->conn_params);
+    config->tmp = NULL;
+    return SILC_CONFIG_OK;
+  }
+
+  /* if there isn't a temporary struct alloc one */
+  if (!tmp) {
+    config->tmp = silc_calloc(1, sizeof(*findtmp));
+    tmp = (SilcServerConfigSectionConnectionParam *) config->tmp;
+  }
+
+  if (!strcmp(name, "name")) {
+    CONFIG_IS_DOUBLE(tmp->name);
+    tmp->name = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "keepalive_secs")) {
+    tmp->keepalive_secs = *(uint32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_count")) {
+    tmp->reconnect_count = *(uint32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_interval")) {
+    tmp->reconnect_interval = *(uint32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_interval_max")) {
+    tmp->reconnect_interval_max = *(uint32 *)val;
+  }
+  else if (!strcmp(name, "reconnect_keep_trying")) {
+    tmp->reconnect_keep_trying = *(bool *)val;
+  }
+  else
+    return SILC_CONFIG_EINTERNAL;
+
+  return SILC_CONFIG_OK;
+
+ got_err:
+  silc_free(tmp->name);
+  silc_free(tmp);
+  config->tmp = NULL;
+  return got_errno;
+}
+
 SILC_CONFIG_CALLBACK(fetch_client)
 {
   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigSectionClient);
@@ -469,6 +572,18 @@ SILC_CONFIG_CALLBACK(fetch_client)
     if (!tmp) /* empty sub-block? */
       return SILC_CONFIG_OK;
 
+    /* Find connection parameter block */
+    if (tmp->param_name) {
+      tmp->param = my_find_param(config, tmp->param_name);
+      if (!tmp->param) {
+       fprintf(stderr, "Unknown ConnectionParam: %s\n", tmp->param_name);
+       silc_free(tmp->param_name);
+       got_errno = SILC_CONFIG_ESILENT;
+       goto got_err;
+      }
+      silc_free(tmp->param_name);
+    }
+
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->clients);
     config->tmp = NULL;
     return SILC_CONFIG_OK;
@@ -481,8 +596,8 @@ SILC_CONFIG_CALLBACK(fetch_client)
   }
 
   /* Identify and save this value */
-  if (!strcmp(name, "host")) { /* any host (*) accepted */
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+  if (!strcmp(name, "host")) {
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "passphrase")) {
@@ -504,13 +619,14 @@ SILC_CONFIG_CALLBACK(fetch_client)
     int port = *(int *)val;
     if ((port <= 0) || (port > 65535)) {
       fprintf(stderr, "Invalid port number!\n");
-      got_errno = SILC_CONFIG_ESILENT; goto got_err;
+      got_errno = SILC_CONFIG_ESILENT; 
+      goto got_err;
     }
     tmp->port = (uint16) port;
   }
-  /* FIXME: Improvement: use a direct class struct pointer instead of num */
-  else if (!strcmp(name, "class")) {
-    /* XXX do nothing */
+  else if (!strcmp(name, "param")) {
+    CONFIG_IS_DOUBLE(tmp->param_name);
+    tmp->param_name = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else
     return SILC_CONFIG_EINTERNAL;
@@ -548,16 +664,16 @@ SILC_CONFIG_CALLBACK(fetch_admin)
   }
 
   /* Identify and save this value */
-  if (!strcmp(name, "host")) { /* any host (*) accepted */
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+  if (!strcmp(name, "host")) {
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "user")) {
-    if (tmp->user) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->user);
     tmp->user = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "nick")) {
-    if (tmp->nick) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->nick);
     tmp->nick = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "passphrase")) {
@@ -614,8 +730,8 @@ SILC_CONFIG_CALLBACK(fetch_deny)
   }
 
   /* Identify and save this value */
-  if (!strcmp(name, "host")) { /* any host (*) accepted */
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+  if (!strcmp(name, "host")) {
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
   }
   else if (!strcmp(name, "port")) {
@@ -627,7 +743,7 @@ SILC_CONFIG_CALLBACK(fetch_deny)
     tmp->port = (uint16) port;
   }
   else if (!strcmp(name, "reason")) {
-    if (tmp->reason) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->reason);
     tmp->reason = strdup((char *) val);
   }
   else
@@ -654,6 +770,18 @@ SILC_CONFIG_CALLBACK(fetch_server)
     if (!tmp) /* empty sub-block? */
       return SILC_CONFIG_OK;
 
+    /* Find connection parameter block */
+    if (tmp->param_name) {
+      tmp->param = my_find_param(config, tmp->param_name);
+      if (!tmp->param) {
+       fprintf(stderr, "Unknown ConnectionParam: %s\n", tmp->param_name);
+       silc_free(tmp->param_name);
+       got_errno = SILC_CONFIG_ESILENT;
+       goto got_err;
+      }
+      silc_free(tmp->param_name);
+    }
+
     /* the temporary struct is ok, append it to the list */
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
     config->tmp = NULL;
@@ -667,8 +795,8 @@ SILC_CONFIG_CALLBACK(fetch_server)
   }
 
   /* Identify and save this value */
-  if (!strcmp(name, "host")) { /* any host (*) accepted */
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+  if (!strcmp(name, "host")) {
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = (*(char *)val ? strdup((char *) val) : strdup("*"));
   }
   else if (!strcmp(name, "passphrase")) {
@@ -687,12 +815,12 @@ SILC_CONFIG_CALLBACK(fetch_server)
     }
   }
   else if (!strcmp(name, "versionid")) {
-    if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->version);
     tmp->version = strdup((char *) val);
   }
-  /* FIXME: Improvement: use a direct class struct pointer instead of num */
-  else if (!strcmp(name, "class")) {
-    /* XXX do nothing */
+  else if (!strcmp(name, "param")) {
+    CONFIG_IS_DOUBLE(tmp->param_name);
+    tmp->param_name = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "backup")) {
     tmp->backup_router = *(bool *)val;
@@ -722,6 +850,18 @@ SILC_CONFIG_CALLBACK(fetch_router)
     if (!tmp) /* empty sub-block? */
       return SILC_CONFIG_OK;
 
+    /* Find connection parameter block */
+    if (tmp->param_name) {
+      tmp->param = my_find_param(config, tmp->param_name);
+      if (!tmp->param) {
+       fprintf(stderr, "Unknown ConnectionParam: %s\n", tmp->param_name);
+       silc_free(tmp->param_name);
+       got_errno = SILC_CONFIG_ESILENT;
+       goto got_err;
+      }
+      silc_free(tmp->param_name);
+    }
+
     /* the temporary struct is ok, append it to the list */
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
     config->tmp = NULL;
@@ -736,7 +876,7 @@ SILC_CONFIG_CALLBACK(fetch_router)
 
   /* Identify and save this value */
   if (!strcmp(name, "host")) {
-    if (tmp->host) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->host);
     tmp->host = strdup((char *) val);
   }
   else if (!strcmp(name, "port")) {
@@ -763,18 +903,20 @@ SILC_CONFIG_CALLBACK(fetch_router)
     }
   }
   else if (!strcmp(name, "versionid")) {
-    if (tmp->version) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
+    CONFIG_IS_DOUBLE(tmp->version);
     tmp->version = strdup((char *) val);
   }
-  /* FIXME: Improvement: use a direct class struct pointer instead of num */
-  else if (!strcmp(name, "class")) {
-    /* XXX do nothing */
+  else if (!strcmp(name, "param")) {
+    CONFIG_IS_DOUBLE(tmp->param_name);
+    tmp->param_name = (*(char *)val ? strdup((char *) val) : NULL);
   }
-  else if (!strcmp(name, "initiator"))
+  else if (!strcmp(name, "initiator")) {
     tmp->initiator = *(bool *)val;
+  }
   else if (!strcmp(name, "backuphost")) {
-    if (tmp->backup_replace_ip) { got_errno = SILC_CONFIG_EDOUBLE; goto got_err; }
-    tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) : strdup("*"));
+    CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
+    tmp->backup_replace_ip = (*(char *)val ? strdup((char *) val) : 
+                             strdup("*"));
   }
   else
     return SILC_CONFIG_EINTERNAL;
@@ -793,8 +935,14 @@ SILC_CONFIG_CALLBACK(fetch_router)
 
 /* known config options tables */
 static const SilcConfigTable table_general[] = {
-  { "module_path",     SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
-  { "prefer_passphrase_auth",  SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
+  { "module_path",             SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
+  { "prefer_passphrase_auth",  SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
+  { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
+  { "keepalive_secs",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "reconnect_count",         SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "reconnect_interval",              SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "reconnect_interval_max",   SILC_CONFIG_ARG_INT,   fetch_generic,  NULL },
+  { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
   { 0, 0, 0, 0 }
 };
 
@@ -860,21 +1008,23 @@ static const SilcConfigTable table_logging[] = {
   { 0, 0, 0, 0 }
 };
 
-/* still unsupported
-static const SilcConfigTable table_class[] = {
-  { "name",            SILC_CONFIG_ARG_STR,    fetch_class,    NULL },
-  { "ping",            SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
-  { "connect",         SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
-  { "links",           SILC_CONFIG_ARG_INT,    fetch_class,    NULL },
+static const SilcConfigTable table_connparam[] = {
+  { "name",                   SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
+  { "require_reverse_lookup",  SILC_CONFIG_ARG_TOGGLE, fetch_connparam,        NULL },
+  { "keepalive_secs",         SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
+  { "reconnect_count",        SILC_CONFIG_ARG_INT,    fetch_connparam, NULL },
+  { "reconnect_interval",      SILC_CONFIG_ARG_INT,    fetch_connparam,        NULL },
+  { "reconnect_interval_max",  SILC_CONFIG_ARG_INT,    fetch_connparam,        NULL },
+  { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam,        NULL },
   { 0, 0, 0, 0 }
-}; */
+};
 
 static const SilcConfigTable table_client[] = {
   { "host",            SILC_CONFIG_ARG_STRE,   fetch_client,   NULL },
   { "passphrase",      SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
   { "publickey",       SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
   { "port",            SILC_CONFIG_ARG_INT,    fetch_client,   NULL },
-  { "class",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
+  { "param",           SILC_CONFIG_ARG_STR,    fetch_client,   NULL },
   { 0, 0, 0, 0 }
 };
 
@@ -885,7 +1035,7 @@ static const SilcConfigTable table_admin[] = {
   { "passphrase",      SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
   { "publickey",       SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
   { "port",            SILC_CONFIG_ARG_INT,    fetch_admin,    NULL },
-  { "class",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
+  { "param",           SILC_CONFIG_ARG_STR,    fetch_admin,    NULL },
   { 0, 0, 0, 0 }
 };
 
@@ -901,7 +1051,7 @@ static const SilcConfigTable table_serverconn[] = {
   { "passphrase",      SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
   { "publickey",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
   { "versionid",       SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
-  { "class",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
+  { "param",           SILC_CONFIG_ARG_STR,    fetch_server,   NULL },
   { "backup",          SILC_CONFIG_ARG_TOGGLE, fetch_server,   NULL },
   { 0, 0, 0, 0 }
 };
@@ -912,7 +1062,7 @@ static const SilcConfigTable table_routerconn[] = {
   { "passphrase",      SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
   { "publickey",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
   { "versionid",       SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
-  { "class",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
+  { "param",           SILC_CONFIG_ARG_STR,    fetch_router,   NULL },
   { "initiator",       SILC_CONFIG_ARG_TOGGLE, fetch_router,   NULL },
   { "backuphost",      SILC_CONFIG_ARG_STRE,   fetch_router,   NULL },
   { "backupport",      SILC_CONFIG_ARG_INT,    fetch_router,   NULL },
@@ -921,19 +1071,19 @@ static const SilcConfigTable table_routerconn[] = {
 };
 
 static const SilcConfigTable table_main[] = {
-  { "general",         SILC_CONFIG_ARG_BLOCK,  NULL,           table_general },
-  { "cipher",          SILC_CONFIG_ARG_BLOCK,  fetch_cipher,   table_cipher },
-  { "hash",            SILC_CONFIG_ARG_BLOCK,  fetch_hash,     table_hash },
-  { "hmac",            SILC_CONFIG_ARG_BLOCK,  fetch_hmac,     table_hmac },
-  { "pkcs",            SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,     table_pkcs },
+  { "general",         SILC_CONFIG_ARG_BLOCK,  NULL,          table_general },
+  { "cipher",          SILC_CONFIG_ARG_BLOCK,  fetch_cipher,  table_cipher },
+  { "hash",            SILC_CONFIG_ARG_BLOCK,  fetch_hash,    table_hash },
+  { "hmac",            SILC_CONFIG_ARG_BLOCK,  fetch_hmac,    table_hmac },
+  { "pkcs",            SILC_CONFIG_ARG_BLOCK,  fetch_pkcs,    table_pkcs },
   { "serverinfo",      SILC_CONFIG_ARG_BLOCK,  fetch_serverinfo, table_serverinfo },
-  { "logging",         SILC_CONFIG_ARG_BLOCK,  NULL,           table_logging },
-/*{ "class",           SILC_CONFIG_ARG_BLOCK,  fetch_class,    table_class }, */
-  { "client",          SILC_CONFIG_ARG_BLOCK,  fetch_client,   table_client },
-  { "admin",           SILC_CONFIG_ARG_BLOCK,  fetch_admin,    table_admin },
-  { "deny",            SILC_CONFIG_ARG_BLOCK,  fetch_deny,     table_deny },
-  { "serverconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_server,   table_serverconn },
-  { "routerconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_router,   table_routerconn },
+  { "logging",         SILC_CONFIG_ARG_BLOCK,  NULL,          table_logging },
+  { "connectionparam", SILC_CONFIG_ARG_BLOCK,  fetch_connparam, table_connparam },
+  { "client",          SILC_CONFIG_ARG_BLOCK,  fetch_client,  table_client },
+  { "admin",           SILC_CONFIG_ARG_BLOCK,  fetch_admin,   table_admin },
+  { "deny",            SILC_CONFIG_ARG_BLOCK,  fetch_deny,    table_deny },
+  { "serverconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_server,  table_serverconn },
+  { "routerconnection",        SILC_CONFIG_ARG_BLOCK,  fetch_router,  table_routerconn },
   { 0, 0, 0, 0 }
 };
 
@@ -1532,3 +1682,26 @@ silc_server_config_get_primary_router(SilcServer server)
 
   return NULL;
 }
+
+/* Set default values to stuff that was not configured. */
+
+bool silc_server_config_set_defaults(SilcServer server)
+{
+  SilcServerConfig config = server->config;
+
+  config->param.keepalive_secs = (config->param.keepalive_secs ? 
+                                 config->param.keepalive_secs :
+                                 SILC_SERVER_KEEPALIVE);
+  config->param.reconnect_count = (config->param.reconnect_count ? 
+                                  config->param.reconnect_count :
+                                  SILC_SERVER_RETRY_COUNT);
+  config->param.reconnect_interval = (config->param.reconnect_interval ? 
+                                     config->param.reconnect_interval :
+                                     SILC_SERVER_RETRY_INTERVAL_MIN);
+  config->param.reconnect_interval_max = 
+    (config->param.reconnect_interval_max ? 
+     config->param.reconnect_interval_max :
+     SILC_SERVER_RETRY_INTERVAL_MAX);
+
+  return TRUE;
+}
index 858abcf6c39610851c09f7e9fb4674c0004ce2f7..2a37bb941aa056a4e6b234c24d8d8a963c97245c 100644 (file)
@@ -70,14 +70,20 @@ typedef struct SilcServerConfigSectionLoggingStruct {
   uint32 maxsize;
 } SilcServerConfigSectionLogging;
 
-/* Holds all configured connection classes */
-/* typedef struct SilcServerConfigSectionClassStruct {
-  uint32 class;
-  uint32 ping_freq;
+/* Connection parameters */
+typedef struct SilcServerConfigSectionConnectionParam {
+  char *name;
+  uint32 keepalive_secs;
+  uint32 reconnect_count;
+  uint32 reconnect_interval;
+  uint32 reconnect_interval_max;
+  bool reconnect_keep_trying;
+  /* 
   uint32 connect_freq;
   uint32 max_links;
-  struct SilcServerConfigSectionClassStruct *next;
-} SilcServerConfigSectionClass; */
+  */
+  struct SilcServerConfigSectionConnectionParam *next;
+} SilcServerConfigSectionConnectionParam;
 
 /* Holds all client authentication data from config file */
 typedef struct SilcServerConfigSectionClientStruct {
@@ -86,7 +92,8 @@ typedef struct SilcServerConfigSectionClientStruct {
   uint32 passphrase_len;
   void *publickey;
   uint16 port;
-  uint32 class;
+  char *param_name;
+  SilcServerConfigSectionConnectionParam *param;
   struct SilcServerConfigSectionClientStruct *next;
 } SilcServerConfigSectionClient;
 
@@ -116,7 +123,8 @@ typedef struct SilcServerConfigSectionServerStruct {
   uint32 passphrase_len;
   void *publickey;
   char *version;
-  uint32 class;
+  char *param_name;
+  SilcServerConfigSectionConnectionParam *param;
   bool backup_router;
   struct SilcServerConfigSectionServerStruct *next;
 } SilcServerConfigSectionServer;
@@ -129,7 +137,8 @@ typedef struct SilcServerConfigSectionRouterStruct {
   void *publickey;
   uint16 port;
   char *version;
-  uint32 class;
+  char *param_name;
+  SilcServerConfigSectionConnectionParam *param;
   bool initiator;
   bool backup_router;
   char *backup_replace_ip;
@@ -141,9 +150,15 @@ typedef struct SilcServerConfigSectionRouterStruct {
 /* define the SilcServerConfig object */
 typedef struct {
   void *tmp;
+
+  /* The General section */
   char *module_path;
   bool prefer_passphrase_auth;
+  bool require_reverse_lookup;
+  /* XXX Still think whether to actually have params in general... -Pekka */
+  SilcServerConfigSectionConnectionParam param;
 
+  /* Other configuration sections */
   SilcServerConfigSectionCipher *cipher;
   SilcServerConfigSectionHash *hash;
   SilcServerConfigSectionHmac *hmac;
@@ -153,7 +168,7 @@ typedef struct {
   SilcServerConfigSectionLogging *logging_errors;
   SilcServerConfigSectionLogging *logging_fatals;
   SilcServerConfigSectionServerInfo *server_info;
-/*SilcServerConfigSectionClass *conn_class; */
+  SilcServerConfigSectionConnectionParam *conn_params;
   SilcServerConfigSectionClient *clients;
   SilcServerConfigSectionAdmin *admins;
   SilcServerConfigSectionDeny *denied;
@@ -189,5 +204,6 @@ silc_server_config_find_router_conn(SilcServer server, char *host, int port);
 bool silc_server_config_is_primary_route(SilcServer server);
 SilcServerConfigSectionRouter *
 silc_server_config_get_primary_router(SilcServer server);
+bool silc_server_config_set_defaults(SilcServer server);
 
 #endif /* !SERVERCONFIG_H */
index d61ac41b677656684752ce532bce78fd68e0199d..9f210b676966b9018004b0e81508ace8eda873ab 100644 (file)
@@ -91,4 +91,5 @@ EXTRA_DIST = \
        CodingStyle \
        FAQ \
        example_silcd.conf \
+       silcalgs.conf \
        draft-riikonen*.txt $(SILC_EXTRA_DIST)
index 8650140935f108aa0c983c504b979c246dc2a185..ce9c2e9816c6fa08b964ab7f337b833e11572e38 100644 (file)
 #
+# silcd.conf
+#
 # Example configuration file.  Note that this attempts to present various
 # configuration possibilities and may not actually give any sensible
 # configuration.  For real life example see the examples/ directory.
 #
 
+#
+# Include global algorithms from the "silcalgs.conf" file. This file
+# defines ciphers, hash functions, HMACs and PKCS algorithms that can
+# be used.
+#
+Include "@ETCDIR@/silcalgs.conf";
+
 #
 # General configuration options
 #
+# These defines the default behaviour of the server.  Most of these values
+# can be overridden with ConnectionParam, which can be defined independently
+# for different connections.
+#
 General {
-       # This is the default path where to search modules
-       # You can comment it out to use builtin modules globally.
+       # This is the default path where to search modules.  If omitted
+       # built-in modules will be used.  Built-in modules will also be
+       # used if a module file cannot be located.
        module_path = "@MODULESDIR@";
 
        # If both passphrase and public key authentication is set for a
        # connection the public key authentication is the preferred one
        # to use.  Set this to `true' to prefer passphrase authentication
        # over public key authentication in these cases.
-       #
-       # prefer_passphrase_auth = true;
-};
+       #prefer_passphrase_auth = true;
 
-#
-# Configured ciphers
-#
-# The "Module" option can be either absolute or relative to the "ModulePath"
-# option.
-# If commented out forces using of built-in modules.
-#
-cipher {
-       name = "aes-256-cbc";
-       module = "aes.sim.so";
-       keylength = 32;
-       blocklength = 16;
-};
-cipher {
-       name = "aes-192-cbc";
-       module = "aes.sim.so";
-       keylength = 24;
-       blocklength = 16;
-};
-cipher {
-       name = "aes-128-cbc";
-       module = "aes.sim.so";
-       keylength = 16;
-       blocklength = 16;
-};
-cipher {
-       name = "twofish-256-cbc";
-       module = "twofish.sim.so";
-       keylength = 32;
-       blocklength = 16;
-};
-cipher {
-       name = "twofish-192-cbc";
-       module = "twofish.sim.so";
-       keylength = 24;
-       blocklength = 16;
-};
-cipher {
-       name = "twofish-128-cbc";
-       module = "twofish.sim.so";
-       keylength = 16;
-       blocklength = 16;
-};
-cipher {
-       name = "mars-256-cbc";
-       module = "mars.sim.so";
-       keylength = 32;
-       blocklength = 16;
-};
-cipher {
-       name = "mars-192-cbc";
-       module = "mars.sim.so";
-       keylength = 24;
-       blocklength = 16;
-};
-cipher {
-       name = "mars-128-cbc";
-       module = "mars.sim.so";
-       keylength = 16;
-       blocklength = 16;
-};
-cipher {
-       name = "none";
-       module = "none.sim.so";
-};
+       # Set this to true if you the server to require fully qualified
+       # domain names (FQDN) for incoming connections.
+       #require_reverse_lookup = false;        
 
-#
-# Configured hash functions
-#
-hash {
-       name = "sha1";
-       blocklength = 64;
-       digestlength = 20;
-};
-hash {
-       name = "md5";
-       blocklength = 64;
-       digestlength = 16;
-};
+       # Default keepalive frequency (seconds). This can be overridden
+       # with ConnectionParam.
+       keepalive_secs = 300;
 
-#
-# Configured HMAC functions. The hash function used in the HMAC must
-# be configured in the hash section.
-#
-hmac {
-       name = "hmac-sha1-96";
-       hash = "sha1";
-       maclength = 12;
-};
-hmac {
-       name = "hmac-md5-96";
-       hash = "md5";
-       maclength = 12;
-};
-hmac {
-       name = "hmac-sha1";
-       hash = "sha1";
-       maclength = 20;
-};
-hmac {
-       name = "hmac-md5";
-       hash = "md5";
-       maclength = 16;
+       # Default reconnection parameters defines how the server reconnect
+       # to the remote if the connection was lost.  The reconnection phase
+       # use so called exponential backoff algorithm;  The reconnect
+       # interval grows when reconnect count grows.  Next example will
+       # attempt to reconnect after 10 seconds of disconnect, and the
+       # interval grows up to 600 seconds or until 7 times was attempted
+       # to reconnect.
+       #
+       # reconnect_count        - how many times reconnect is attempted
+       # reconnect_interval     - how often reconnect it performed (seconds)
+       # reconnect_interval_max - maximum interval for reconnect, the
+       #                          server never waits longer than this to
+       #                          reconnect (seconds).
+       # reconnect_keep_trying  - whether to keep trying even after 
+       #                          reconnect_count is reached (the interval
+       #                          will be reconnect_interval_max).
+       #
+       # These can be overridden with ConnectionParam.
+       reconnect_count = 7;
+       reconnect_interval = 10;
+       reconnect_interval_max = 600;
+       reconnect_keep_trying = true;
 };
 
-#
-# Configured PKCS
-#
-PKCS { name = "rsa"; };
-
 #
 # Server information
 #
@@ -234,33 +168,76 @@ Logging {
 };
 
 #
-# Connection classes (UNSUPPORTED)
+# Connection Parameters
 #
-# This section is used to define connection classes. These can be
-# used to optimize the server and the connections.
+# This section defined connection parameters.  It is possible to use
+# specific parameters in different connections, and to define different
+# parameters to different connections.  The parameters can define how the
+# connection is handled and how the session is managed.  If connection
+# parameters are not used in connections the default values will apply
+# (or values defined in General section).  You can have multiple
+# ConnectionParams blocks defined.
 #
-#Class {
-#      Name = "norm";
-#      Ping = 100;
-#      Connect = 100;
-#      Links = 100;
-#};
+ConnectionParam {
+       # unique name. The name is used to reference to this parameter 
+       # block from the connections.
+       name = "normal";
+
+       # Keepalive frequency (seconds).
+       keepalive_secs = 300;
+
+       # Reconnection parameters defines how the server reconnects to
+       # the remote if the connection was lost.  The reconnection phase
+       # use so called exponential backoff algorithm;  The reconnect
+       # interval grows when reconnect count grows.  Next example will
+       # attempt to reconnect after 10 seconds of disconnect, and the
+       # interval grows up to 600 seconds or until 7 times was attempted
+       # to reconnect.
+       #
+       # reconnect_count        - how many times reconnect is attempted
+       # reconnect_interval     - how often reconnect it performed (seconds)
+       # reconnect_interval_max - maximum interval for reconnect, the
+       #                          server never waits longer than this to
+       #                          reconnect (seconds).
+       # reconnect_keep_trying  - whether to keep trying even after 
+       #                          reconnect_count is reached (the interval
+       #                          will be reconnect_interval_max).
+       reconnect_count = 7;
+       reconnect_interval = 10;
+       reconnect_interval_max = 600;
+       reconnect_keep_trying = true;
+
+       #TODO:
+       #key_exchange_rekey - rekey timeout
+       #key_exchange_pfs - rekey PFS
+       #key_exchange_mutual_auth - SKE mutual auth
+
+       #connections_max - max incoming connection
+       #connections_interval - incoming connection interval limit ?
+};
 
 #
 # Configured client connections.
 #
-# All fields except Class are optional.  Omitted fields are assumed
-# to be generic (e.g. if the "Host" field is omitted all hosts will match
-# this client class).
+# The "host" defines the incoming IP address or hostname of the client.
+# If it is omitted all hosts will match this client connection.  The
+# "param" is optional and can be used to set specific connection parameters
+# for this connection.
 #
-#Client {
-#      Host = "127.0.0.1";
-#      Port = 706;
-#      Class = "local";
-#};
-Client {
-       Port = 706;
-       Class = "norm";
+# The authentication data is specified by Passphrase and/or Publickey.
+# If both are provided then both password and public key based authentication
+# is allowed.  If the Publickey is used it includes the file path to the
+# public key file.  If none of them is provided then authentication is not
+# required.
+#
+# Next example connection will match to all incoming client connections,
+# and no authentication is required
+#
+Client { 
+       #host = "";
+       #passphrase = "secret";
+       #publickey = "/path/to/the/public.key";
+       param = "normal";
 };
 
 #
@@ -283,24 +260,6 @@ Admin {
        # Publickey = "/path/to/the/public.key";
 };
 
-#
-# Denied connections
-#
-# These connections are denied to connect to our server.
-#
-# The "Reason" field is mandatory, while the "Host" and "Port" fields can be
-# omitted to match everything.
-#
-#Deny {
-#      Host = "10.2.1.99";
-#      Port = 706;
-#      Reason = "Go away spammer";
-#};
-#Deny {
-#      Host = "10.3.*";
-#      Reason = "You are not welcome.";
-#};
-
 #
 # Configured server connections.
 #
@@ -324,7 +283,7 @@ ServerConnection {
        Passphrase = "verysecret";
        # Publickey = "/path/to/the/public.key";
        VersionID = 1;
-       Class = "norm";
+       Param = "normal";
        Backup = false;
 };
 
@@ -359,9 +318,27 @@ RouterConnection {
        Passphrase = "verysecret";
        # Publickey = "/path/to/the/public.key";
        VersionID = 1;
-       Class = "norm";
+       Param = "normal";
        Initiator = true;
        #BackupHost = "10.2.1.6";
        #BackupPort = 706;
        #LocalBackup = true;
 };
+
+#
+# Denied connections
+#
+# These connections are denied to connect to our server.
+#
+# The "Reason" field is mandatory, while the "Host" and "Port" fields can be
+# omitted to match everything.
+#
+#Deny {
+#      Host = "10.2.1.99";
+#      Port = 706;
+#      Reason = "Go away spammer";
+#};
+#Deny {
+#      Host = "10.3.*";
+#      Reason = "You are not welcome.";
+#};
diff --git a/doc/silcalgs.conf b/doc/silcalgs.conf
new file mode 100644 (file)
index 0000000..a0fb89b
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# Algorithms
+#
+# This file defines ciphers, hash functions, HMACs and PKCS algorithms that
+# can be used.  This file can be included into different configuration files.
+#
+# You should not change the contents of this file unless you know what you
+# are doing.
+#
+
+#
+# Configured ciphers
+#
+# The "name" is unique name to the cipher. The "module" option can be either
+# absolute or relative to the "module_path", and it defines where the cipher
+# module is found.  If omitted the built-in cipher is used.  The "keylength"
+# defines the length of the key (bytes), and the "blocklength" defines the
+# block size of the cipher (bytes).
+#
+cipher {
+       name = "aes-256-cbc";
+       module = "aes.sim.so";
+       keylength = 32;
+       blocklength = 16;
+};
+cipher {
+       name = "aes-192-cbc";
+       module = "aes.sim.so";
+       keylength = 24;
+       blocklength = 16;
+};
+cipher {
+       name = "aes-128-cbc";
+       module = "aes.sim.so";
+       keylength = 16;
+       blocklength = 16;
+};
+cipher {
+       name = "twofish-256-cbc";
+       module = "twofish.sim.so";
+       keylength = 32;
+       blocklength = 16;
+};
+cipher {
+       name = "twofish-192-cbc";
+       module = "twofish.sim.so";
+       keylength = 24;
+       blocklength = 16;
+};
+cipher {
+       name = "twofish-128-cbc";
+       module = "twofish.sim.so";
+       keylength = 16;
+       blocklength = 16;
+};
+cipher {
+       name = "mars-256-cbc";
+       module = "mars.sim.so";
+       keylength = 32;
+       blocklength = 16;
+};
+cipher {
+       name = "mars-192-cbc";
+       module = "mars.sim.so";
+       keylength = 24;
+       blocklength = 16;
+};
+cipher {
+       name = "mars-128-cbc";
+       module = "mars.sim.so";
+       keylength = 16;
+       blocklength = 16;
+};
+cipher {
+       name = "none";
+       module = "none.sim.so";
+};
+
+#
+# Configured hash functions
+#
+hash {
+       name = "sha1";
+       blocklength = 64;
+       digestlength = 20;
+};
+hash {
+       name = "md5";
+       blocklength = 64;
+       digestlength = 16;
+};
+
+#
+# Configured HMAC functions. The hash function used in the HMAC must
+# be configured in the hash section.
+#
+hmac {
+       name = "hmac-sha1-96";
+       hash = "sha1";
+       maclength = 12;
+};
+hmac {
+       name = "hmac-md5-96";
+       hash = "md5";
+       maclength = 12;
+};
+hmac {
+       name = "hmac-sha1";
+       hash = "sha1";
+       maclength = 20;
+};
+hmac {
+       name = "hmac-md5";
+       hash = "md5";
+       maclength = 16;
+};
+
+#
+# Configured PKCS
+#
+PKCS { 
+       name = "rsa"; 
+};