Added remote version control support to server.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 17 Mar 2002 14:00:30 +0000 (14:00 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 17 Mar 2002 14:00:30 +0000 (14:00 +0000)
14 files changed:
CHANGES
TODO
apps/silcd/protocol.c
apps/silcd/server.c
apps/silcd/server_util.c
apps/silcd/server_util.h
apps/silcd/serverconfig.c
apps/silcd/serverconfig.h
doc/example_silcd.conf.in
lib/silcske/silcske.c
lib/silcske/silcske.h
lib/silcutil/silclog.c
lib/silcutil/silcutil.c
lib/silcutil/silcutil.h

diff --git a/CHANGES b/CHANGES
index d5e56ae7a9dbcf090243b8077338935c3dd2e633..aaa98c62a0361b6a9e9fccab60bd84b166a8112d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,19 @@
+Sun Mar 17 15:44:56 EET 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added functions silc_parse_version_string, silc_version_to_num,
+         and silc_ske_parse_version to parse SILC protocol style version
+         strings.  Affected files lib/silcutil/silcutil.[ch] and
+         lib/silcske/silcske.[ch].
+
+       * Added new configuration params: version_protocol, version_software
+         and version_software_vendor to specify what version the remote
+         host must at least be to be able to connect to server.  The vendor
+         string can be regex matched too.  Added new function 
+         silc_server_connection_allowed to check maximum number of allowed
+         connections, and allowed versions for incoming connections.
+         Affected files are silcd/server.c, server_util.[ch] and
+         serverconfig.[ch].
+
 Sun Mar 17 10:24:50 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Added preliminary support for signals in scheduler.  The
 Sun Mar 17 10:24:50 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Added preliminary support for signals in scheduler.  The
diff --git a/TODO b/TODO
index 57226a956fe2ca34f894e581e2ebc70896626272..7ec1bc17ba0786b203e6c3820848c03c7b5a384a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -37,9 +37,6 @@ TODO/bugs In SILC Server
 
  o Configuration file additions:
 
 
  o Configuration file additions:
 
-       o Add version handling, to allow, disallow certain versions to
-         connect.
-
        o Add incoming connection frequency, incoming connection frequency
          for single IP address, key exchange frequency, key exchange
          frequency for single IP. Add also frequency base.
        o Add incoming connection frequency, incoming connection frequency
          for single IP address, key exchange frequency, key exchange
          frequency for single IP. Add also frequency base.
@@ -94,8 +91,19 @@ TODO in Toolkit Documentation
 Stuff that needs to be done in order to complete the Tooolkit Reference
 Manual.
 
 Stuff that needs to be done in order to complete the Tooolkit Reference
 Manual.
 
- o Lots of ROBOdoc header formatting is undone in lib/silcutil, and 
-   lib/silccrypt.
+ o ROBOdoc documenting missing from lib/silcutil/silcbuffer.h.
+
+ o ROBOdoc documenting missing from lib/silcutil/silcdlist.h.
+
+ o ROBOdoc documenting missing from lib/silcutil/silcfileutil.h.
+
+ o ROBOdoc documenting missing from lib/silcutil/silcutil.h.
+
+ o ROBOdoc documenting missing from lib/silccrypt/silchash.h.
+
+ o ROBOdoc documenting missing from lib/silccrypt/silccipher.h.
+
+ o ROBOdoc documenting missing from lib/silccrypt/silcpkcs.h.
 
  o Write "Programming with Toolkit" document, describing how to build
    Toolkit, how the build system works, where is everything, how
 
  o Write "Programming with Toolkit" document, describing how to build
    Toolkit, how the build system works, where is everything, how
index 2200bfb8ccdad5cca50d4f4473bf0adf8be9c7c8..7cb72adaa51914cf1b156e34e10e421386bd3142 100644 (file)
@@ -371,14 +371,6 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
 
   if (maj != maj2)
     status = SILC_SKE_STATUS_BAD_VERSION;
 
   if (maj != maj2)
     status = SILC_SKE_STATUS_BAD_VERSION;
-#if 0
-  if (min > min2)
-    status = SILC_SKE_STATUS_BAD_VERSION;
-#endif
-
-  /* XXX < 0.6 is not allowed */
-  if (maj == 0 && min < 5)
-    status = SILC_SKE_STATUS_BAD_VERSION;
 
   if (status == SILC_SKE_STATUS_BAD_VERSION)
     SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version", 
 
   if (status == SILC_SKE_STATUS_BAD_VERSION)
     SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version", 
index dec04e2663c8f485fa0bc59fa1edf18f923175ff..4dc47c92ae196841f3ce80228cb22d57bc8e4688 100644 (file)
@@ -1284,7 +1284,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
   void *id_entry;
   SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
   SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
   void *id_entry;
   SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
-  SilcUInt32 num_sockets;
 
   SILC_LOG_DEBUG(("Start"));
 
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1309,38 +1308,16 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
   entry->data.last_receive = time(NULL);
 
 
   entry->data.last_receive = time(NULL);
 
-  num_sockets = silc_server_num_sockets_by_ip(server, sock->ip, 
-                                             ctx->conn_type);
-
   switch (ctx->conn_type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry client;
       SilcServerConfigClient *conn = ctx->cconfig;
   switch (ctx->conn_type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry client;
       SilcServerConfigClient *conn = ctx->cconfig;
-      SilcUInt32 max_per_host = server->config->param.connections_max_per_host;
 
 
-      /* Check for maximum connections limit */
-      if (conn->param) {
-       if (conn->param->connections_max &&
-           server->stat.my_clients >= conn->param->connections_max) {
-         SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
-                        sock->hostname, sock->ip));
-         silc_server_disconnect_remote(server, sock, 
-                                       "Server closed connection: "
-                                       "Server is full, try again later");
-         server->stat.auth_failures++;
-         goto out;
-       }
-
-       max_per_host = conn->param->connections_max_per_host;
-      }
-
-      if (num_sockets >= max_per_host) {
-       SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
-                      sock->hostname, sock->ip));
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Too many connections from your host");
+      /* Verify whether this connection is after all allowed to connect */
+      if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
+                                         &server->config->param,
+                                         conn->param, ctx->ske)) {
        server->stat.auth_failures++;
        goto out;
       }
        server->stat.auth_failures++;
        goto out;
       }
@@ -1390,69 +1367,55 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       SilcUInt16 backup_replace_port = 0;
       SilcServerConfigServer *sconn = ctx->sconfig;
       SilcServerConfigRouter *rconn = ctx->rconfig;
       SilcUInt16 backup_replace_port = 0;
       SilcServerConfigServer *sconn = ctx->sconfig;
       SilcServerConfigRouter *rconn = ctx->rconfig;
-      SilcUInt32 max_per_host = server->config->param.connections_max_per_host;
-
-      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && rconn) {
-       if (rconn->param) {
-         /* Check for maximum connections limit */
-         if (rconn->param->connections_max &&
-             server->stat.my_routers >= rconn->param->connections_max) {
-           silc_server_disconnect_remote(server, sock, 
-                                         "Server closed connection: "
-                                         "Server is full, try again later");
-           server->stat.auth_failures++;
-           goto out;
-         }
-         max_per_host = rconn->param->connections_max_per_host;
 
 
-         if (rconn->param->keepalive_secs)
-           hearbeat_timeout = rconn->param->keepalive_secs;
+      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
+       /* Verify whether this connection is after all allowed to connect */
+       if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
+                                           &server->config->param,
+                                           rconn ? rconn->param : NULL, 
+                                           ctx->ske)) {
+         server->stat.auth_failures++;
+         goto out;
        }
 
        }
 
-       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 (ctx->conn_type == SILC_SOCKET_TYPE_SERVER && sconn) {
-       if (sconn->param) {
-         /* Check for maximum connections limit */
-         if (sconn->param->connections_max &&
-             server->stat.my_servers >= sconn->param->connections_max) {
-           SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
-                          sock->hostname, sock->ip));
-           silc_server_disconnect_remote(server, sock, 
-                                         "Server closed connection: "
-                                         "Server is full, try again later");
-           server->stat.auth_failures++;
-           goto out;
+       if (rconn) {
+         if (rconn->param) {
+           if (rconn->param->keepalive_secs)
+             hearbeat_timeout = rconn->param->keepalive_secs;
          }
          }
-         max_per_host = sconn->param->connections_max_per_host;
 
 
-         if (sconn->param->keepalive_secs)
-           hearbeat_timeout = sconn->param->keepalive_secs;
+         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;
        }
        }
-
-       backup_router = sconn->backup_router;
       }
 
       }
 
-      if (num_sockets >= max_per_host) {
-       SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
-                      sock->hostname, sock->ip));
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Too many connections from your host");
-       server->stat.auth_failures++;
-       goto out;
+      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
+       /* Verify whether this connection is after all allowed to connect */
+       if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
+                                           &server->config->param,
+                                           sconn ? sconn->param : NULL, 
+                                           ctx->ske)) {
+         server->stat.auth_failures++;
+         goto out;
+       }
+       if (sconn) {
+         if (sconn->param) {
+           if (sconn->param->keepalive_secs)
+             hearbeat_timeout = sconn->param->keepalive_secs;
+         }
+
+         backup_router = sconn->backup_router;
+       }
       }
 
       SILC_LOG_DEBUG(("Remote host is %s", 
                      ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
                      "server" : (backup_router ? 
                                  "backup router" : "router")));
       }
 
       SILC_LOG_DEBUG(("Remote host is %s", 
                      ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
                      "server" : (backup_router ? 
                                  "backup router" : "router")));
-      SILC_LOG_INFO(("Connection s (%s) is %s", sock->hostname,
+      SILC_LOG_INFO(("Connection %s (%s) is %s", sock->hostname,
                     sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
                     "server" : (backup_router ? 
                                 "backup router" : "router")));
                     sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
                     "server" : (backup_router ? 
                                 "backup router" : "router")));
index dc76c48161f642ac13932a06fc0148f71bbe463e..529b75de5fdcca6999210533542f7fa7350b9944 100644 (file)
@@ -856,3 +856,104 @@ SilcPublicKey silc_server_get_public_key(SilcServer server,
 
   return cached_key;
 }
 
   return cached_key;
 }
+
+/* Check whether the connection `sock' is allowed to connect to us.  This
+   checks for example whether there is too much connections for this host,
+   and required version for the host etc. */
+
+bool silc_server_connection_allowed(SilcServer server, 
+                                   SilcSocketConnection sock,
+                                   SilcSocketType type,
+                                   SilcServerConfigConnParams *global,
+                                   SilcServerConfigConnParams *params,
+                                   SilcSKE ske)
+{
+  SilcUInt32 conn_number = (type == SILC_SOCKET_TYPE_CLIENT ?
+                           server->stat.my_clients :
+                           type == SILC_SOCKET_TYPE_SERVER ?
+                           server->stat.my_servers :
+                           server->stat.my_routers);
+  SilcUInt32 num_sockets, max_hosts, max_per_host;
+  SilcUInt32 r_protocol_version, l_protocol_version;
+  SilcUInt32 r_software_version, l_software_version;
+  char *r_vendor_version = NULL, *l_vendor_version;
+
+  /* Check version */
+
+  l_protocol_version = 
+    silc_version_to_num(params && params->version_protocol ? 
+                       params->version_protocol : 
+                       global->version_protocol);
+  l_software_version = 
+    silc_version_to_num(params && params->version_software ? 
+                       params->version_software : 
+                       global->version_software);
+  l_vendor_version = (params && params->version_software_vendor ? 
+                     params->version_software_vendor : 
+                     global->version_software_vendor);
+  
+  if (ske && silc_ske_parse_version(ske, &r_protocol_version, NULL,
+                                   &r_software_version, NULL,
+                                   &r_vendor_version)) {
+    /* Match protocol version */
+    if (l_protocol_version && r_protocol_version &&
+       r_protocol_version < l_protocol_version) {
+      SILC_LOG_INFO(("Connection %s (%s) is too old version",
+                    sock->hostname, sock->ip));
+      silc_server_disconnect_remote(server, sock, 
+                                   "Server closed connection: "
+                                   "You support too old protocol version");
+      return FALSE;
+    }
+
+    /* Math software version */
+    if (l_software_version && r_software_version &&
+       r_software_version < l_software_version) {
+      SILC_LOG_INFO(("Connection %s (%s) is too old version",
+                    sock->hostname, sock->ip));
+      silc_server_disconnect_remote(server, sock, 
+                                   "Server closed connection: "
+                                   "You support too old software version");
+      return FALSE;
+    }
+
+    /* Regex match vendor version */
+    if (l_vendor_version && r_vendor_version && 
+       !silc_string_match(l_vendor_version, r_vendor_version)) {
+      SILC_LOG_INFO(("Connection %s (%s) is unsupported version",
+                    sock->hostname, sock->ip));
+      silc_server_disconnect_remote(server, sock, 
+                                   "Server closed connection: "
+                                   "Your software is not supported");
+      return FALSE;
+    }
+  }
+  silc_free(r_vendor_version);
+
+  /* Check for maximum connections limit */
+
+  num_sockets = silc_server_num_sockets_by_ip(server, sock->ip, type);
+  max_hosts = (params ? params->connections_max : global->connections_max);
+  max_per_host = (params ? params->connections_max_per_host :
+                 global->connections_max_per_host);
+
+  if (max_hosts && conn_number >= max_hosts) {
+    SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
+                  sock->hostname, sock->ip));
+    silc_server_disconnect_remote(server, sock, 
+                                 "Server closed connection: "
+                                 "Server is full, try again later");
+    return FALSE;
+  }
+
+  if (num_sockets >= max_per_host) {
+    SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
+                  sock->hostname, sock->ip));
+    silc_server_disconnect_remote(server, sock, 
+                                 "Server closed connection: "
+                                 "Too many connections from your host");
+    return FALSE;
+  }
+
+  return TRUE;
+}
index ca54b1b8614851b5316d44445838c8a52de0f1c8..4feb4ee545bd8f6d977b9cb2ce50a9519f20a1b3 100644 (file)
@@ -101,4 +101,14 @@ SilcPublicKey silc_server_find_public_key(SilcServer server,
 SilcPublicKey silc_server_get_public_key(SilcServer server,
                                         SilcHashTable local_public_keys);
 
 SilcPublicKey silc_server_get_public_key(SilcServer server,
                                         SilcHashTable local_public_keys);
 
+/* Check whether the connection `sock' is allowed to connect to us.  This
+   checks for example whether there is too much connections for this host,
+   and required version for the host etc. */
+bool silc_server_connection_allowed(SilcServer server, 
+                                   SilcSocketConnection sock,
+                                   SilcSocketType type,
+                                   SilcServerConfigConnParams *global,
+                                   SilcServerConfigConnParams *params,
+                                   SilcSKE ske);
+
 #endif /* SERVER_UTIL_H */
 #endif /* SERVER_UTIL_H */
index 2e4773c77ffdb465725a5140570cfa873b5816f6..2153870e0dc904ef599b9a510e7a78de12b49440 100644 (file)
@@ -74,24 +74,17 @@ static void
 my_set_param_defaults(SilcServerConfigConnParams *params,
                      SilcServerConfigConnParams *defaults)
 {
 my_set_param_defaults(SilcServerConfigConnParams *params,
                      SilcServerConfigConnParams *defaults)
 {
-#define SET_PARAM_DEFAULT(p, d)                                                \
+#define SET_PARAM_DEFAULT(p, d)        params->p =                             \
   (params->p ? params->p : (defaults && defaults->p ? defaults->p : d))
 
   (params->p ? params->p : (defaults && defaults->p ? defaults->p : d))
 
-  params->connections_max = 
-    SET_PARAM_DEFAULT(connections_max, SILC_SERVER_MAX_CONNECTIONS);
-  params->connections_max_per_host = 
-    SET_PARAM_DEFAULT(connections_max_per_host, 
-                     SILC_SERVER_MAX_CONNECTIONS_SINGLE);
-  params->keepalive_secs = 
-    SET_PARAM_DEFAULT(keepalive_secs, SILC_SERVER_KEEPALIVE);
-  params->reconnect_count = 
-    SET_PARAM_DEFAULT(reconnect_count, SILC_SERVER_RETRY_COUNT);
-  params->reconnect_interval = 
-    SET_PARAM_DEFAULT(reconnect_interval, SILC_SERVER_RETRY_INTERVAL_MIN);
-  params->reconnect_interval_max = 
-    SET_PARAM_DEFAULT(reconnect_interval_max, SILC_SERVER_RETRY_INTERVAL_MAX);
-  params->key_exchange_rekey = 
-    SET_PARAM_DEFAULT(key_exchange_rekey, SILC_SERVER_REKEY);
+  SET_PARAM_DEFAULT(connections_max, SILC_SERVER_MAX_CONNECTIONS);
+  SET_PARAM_DEFAULT(connections_max_per_host, 
+                   SILC_SERVER_MAX_CONNECTIONS_SINGLE);
+  SET_PARAM_DEFAULT(keepalive_secs, SILC_SERVER_KEEPALIVE);
+  SET_PARAM_DEFAULT(reconnect_count, SILC_SERVER_RETRY_COUNT);
+  SET_PARAM_DEFAULT(reconnect_interval, SILC_SERVER_RETRY_INTERVAL_MIN);
+  SET_PARAM_DEFAULT(reconnect_interval_max, SILC_SERVER_RETRY_INTERVAL_MAX);
+  SET_PARAM_DEFAULT(key_exchange_rekey, SILC_SERVER_REKEY);
 }
 
 /* Find connection parameters by the parameter block name. */
 }
 
 /* Find connection parameters by the parameter block name. */
@@ -203,6 +196,21 @@ SILC_CONFIG_CALLBACK(fetch_generic)
   else if (!strcmp(name, "conn_auth_timeout")) {
     config->conn_auth_timeout = (SilcUInt32) *(int *)val;
   }
   else if (!strcmp(name, "conn_auth_timeout")) {
     config->conn_auth_timeout = (SilcUInt32) *(int *)val;
   }
+  else if (!strcmp(name, "version_protocol")) {
+    CONFIG_IS_DOUBLE(config->param.version_protocol);
+    config->param.version_protocol = 
+      (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "version_software")) {
+    CONFIG_IS_DOUBLE(config->param.version_software);
+    config->param.version_software = 
+      (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "version_software_vendor")) {
+    CONFIG_IS_DOUBLE(config->param.version_software_vendor);;
+    config->param.version_software_vendor = 
+      (*(char *)val ? strdup((char *) val) : NULL);
+  }
   else
     return SILC_CONFIG_EINTERNAL;
 
   else
     return SILC_CONFIG_EINTERNAL;
 
@@ -626,6 +634,19 @@ SILC_CONFIG_CALLBACK(fetch_connparam)
   else if (!strcmp(name, "key_exchange_pfs")) {
     tmp->key_exchange_pfs = *(bool *)val;
   }
   else if (!strcmp(name, "key_exchange_pfs")) {
     tmp->key_exchange_pfs = *(bool *)val;
   }
+  else if (!strcmp(name, "version_protocol")) {
+    CONFIG_IS_DOUBLE(tmp->version_protocol);
+    tmp->version_protocol = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "version_software")) {
+    CONFIG_IS_DOUBLE(tmp->version_software);
+    tmp->version_software = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "version_software_vendor")) {
+    CONFIG_IS_DOUBLE(tmp->version_software_vendor);;
+    tmp->version_software_vendor = 
+      (*(char *)val ? strdup((char *) val) : NULL);
+  }
   else
     return SILC_CONFIG_EINTERNAL;
 
   else
     return SILC_CONFIG_EINTERNAL;
 
@@ -1002,6 +1023,9 @@ static const SilcConfigTable table_general[] = {
   { "channel_rekey_secs",      SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { "key_exchange_timeout",    SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { "conn_auth_timeout",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { "channel_rekey_secs",      SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { "key_exchange_timeout",    SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { "conn_auth_timeout",       SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "version_protocol",                SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
+  { "version_software",                SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
+  { "version_software_vendor",  SILC_CONFIG_ARG_STR,    fetch_generic, NULL },
   { 0, 0, 0, 0 }
 };
 
   { 0, 0, 0, 0 }
 };
 
@@ -1079,6 +1103,9 @@ static const SilcConfigTable table_connparam[] = {
   { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam,        NULL },
   { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam,        NULL },
   { "key_exchange_pfs",               SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
   { "reconnect_keep_trying",   SILC_CONFIG_ARG_TOGGLE, fetch_connparam,        NULL },
   { "key_exchange_rekey",      SILC_CONFIG_ARG_INT,    fetch_connparam,        NULL },
   { "key_exchange_pfs",               SILC_CONFIG_ARG_TOGGLE, fetch_connparam, NULL },
+  { "version_protocol",               SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
+  { "version_software",               SILC_CONFIG_ARG_STR,    fetch_connparam, NULL },
+  { "version_software_vendor", SILC_CONFIG_ARG_STR,    fetch_connparam,        NULL },
   { 0, 0, 0, 0 }
 };
 
   { 0, 0, 0, 0 }
 };
 
index 2af85bbd8618fffb7ed540cfd335dd213d5a7f96..b27c7b6564bf2ba89c1cffff4e6c535004d1c891 100644 (file)
@@ -82,6 +82,9 @@ typedef struct SilcServerConfigConnParams {
   bool reconnect_keep_trying;
   SilcUInt32 key_exchange_rekey;
   bool key_exchange_pfs;
   bool reconnect_keep_trying;
   SilcUInt32 key_exchange_rekey;
   bool key_exchange_pfs;
+  char *version_protocol;
+  char *version_software;
+  char *version_software_vendor;
   struct SilcServerConfigConnParams *next;
 } SilcServerConfigConnParams;
 
   struct SilcServerConfigConnParams *next;
 } SilcServerConfigConnParams;
 
index d32f0612d8258025bb1ef04560b33a9023f5f353..bf0a81b4ff509e78bea59d088adf5609593c0c7a 100644 (file)
@@ -59,6 +59,22 @@ General {
        # refused. This can be overridden with ConnectionParams.
        #connections_max_per_host = 10;
 
        # refused. This can be overridden with ConnectionParams.
        #connections_max_per_host = 10;
 
+       # Required version of the remote.  If these are specified then the
+       # remote must be of at least this version, or newer.  If older then
+       # the connection will not be allowed.
+       #
+       # version_protocol         - SILC protocol version ("majog.minor")
+       # version_software         - software version ("major.minor")
+       # version_software_vendor  - vendor specific version extension
+       #
+       # The version_software_vendor may be for example a string or a build
+       # number of the software.  The string can be a regex string to match
+       # more widely.  Usually the vendor version checking is not necessary
+       # and can be omitted.  These can be overridden with ConnectionParams.
+       #version_protocol = "1.0";
+       #version_software = "1.3";
+       #version_software_vendor = "SomeVendor";
+
        # Default keepalive frequency (seconds). This can be overridden
        # with ConnectionParams.
        keepalive_secs = 300;
        # Default keepalive frequency (seconds). This can be overridden
        # with ConnectionParams.
        keepalive_secs = 300;
@@ -256,6 +272,22 @@ ConnectionParams {
        # connections it is recommended that this value is set to one (1).
        connections_max_per_host = 10;
 
        # connections it is recommended that this value is set to one (1).
        connections_max_per_host = 10;
 
+       # Required version of the remote.  If these are specified then the
+       # remote must be of at least this version, or newer.  If older then
+       # the connection will not be allowed.
+       #
+       # version_protocol         - SILC protocol version
+       # version_software         - software version
+       # version_software_vendor  - vendor specific version extension
+       #
+       # The version_software_vendor may be for example a string or a build
+       # number of the software.  The string can be a regex string to match
+       # more widely.  Usually the vendor version checking is not necessary
+       # and can be omitted.
+       #version_protocol = "1.0";
+       #version_software = "1.3";
+       #version_software_vendor = "SomeVendor";
+
        # Keepalive frequency (seconds).
        keepalive_secs = 300;
 
        # Keepalive frequency (seconds).
        keepalive_secs = 300;
 
index 836a4fb8a27032df82fab62ef574a2a9433ac720..56b38eb44ca9db766e974a0bcec903131e6db83e 100644 (file)
@@ -1993,3 +1993,20 @@ const char *silc_ske_map_status(SilcSKEStatus status)
 
   return "";
 }
 
   return "";
 }
+
+/* Parses remote host's version string. */
+
+bool silc_ske_parse_version(SilcSKE ske, 
+                           SilcUInt32 *protocol_version,
+                           char **protocol_version_string,
+                           SilcUInt32 *software_version, 
+                           char **software_version_string,
+                           char **vendor_version)
+{
+  return silc_parse_version_string(ske->start_payload->version,
+                                  protocol_version, 
+                                  protocol_version_string, 
+                                  software_version,
+                                  software_version_string,
+                                  vendor_version);
+}
index ffb25b0aa62b4c1f59276c9b9b7ad634482fcee2..7d0aab9e82543def58db09c3ab366d3774654ca0 100644 (file)
@@ -892,4 +892,32 @@ silc_ske_process_key_material_data(unsigned char *data,
  ***/
 void silc_ske_free_key_material(SilcSKEKeyMaterial *key);
 
  ***/
 void silc_ske_free_key_material(SilcSKEKeyMaterial *key);
 
+/****f* silcske/SilcSKEAPI/silc_ske_parse_version
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_ske_parse_version(SilcSKE ske, 
+ *                                SilcUInt32 *protocol_version,
+ *                                char **protocol_version_string,
+ *                                SilcUInt32 *software_version, 
+ *                                char **software_version_string,
+ *                                char **vendor_version);
+ *
+ * DESCRIPTION
+ *
+ *    This utility function can be used to parse the remote host's version
+ *    string.  This returns the protocol version, and software version into
+ *    the `protocol_version', `software_version' and `vendor_version' pointers
+ *    if they are provided.  The string versions of the versions are saved
+ *    in *_string pointers if they are provided.  Returns TRUE if the version
+ *    string was successfully parsed.
+ *
+ ***/
+bool silc_ske_parse_version(SilcSKE ske, 
+                           SilcUInt32 *protocol_version,
+                           char **protocol_version_string,
+                           SilcUInt32 *software_version, 
+                           char **software_version_string,
+                           char **vendor_version);
+
 #endif /* !SILCSKE_H */
 #endif /* !SILCSKE_H */
index 06e5771f31f220d2eb8598314e6cd566322455d6..3d371749627f5f05e9e379b7e72af99610b9b634 100644 (file)
@@ -484,9 +484,8 @@ void silc_log_reset_debug_callbacks()
 void silc_log_set_debug_string(const char *debug_string)
 {
   silc_free(silc_log_debug_string);
 void silc_log_set_debug_string(const char *debug_string)
 {
   silc_free(silc_log_debug_string);
-  if ((strchr(debug_string, '(') &&
-       strchr(debug_string, ')')) ||
-       strchr(debug_string, '$'))
+  if ((strchr(debug_string, '(') && strchr(debug_string, ')')) ||
+      strchr(debug_string, '$'))
     silc_log_debug_string = strdup(debug_string);
   else
     silc_log_debug_string = silc_string_regexify(debug_string);
     silc_log_debug_string = strdup(debug_string);
   else
     silc_log_debug_string = silc_string_regexify(debug_string);
index 6ef7c57651805a6d0b6c5e0088e3fc915e1a931d..82068283708b5a3b64da0bf4ce23d8ebec0f1310 100644 (file)
@@ -859,3 +859,95 @@ bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
 
   return TRUE;
 }
 
   return TRUE;
 }
+
+/* Parses SILC protocol style version string. */
+
+bool silc_parse_version_string(const char *version,
+                              SilcUInt32 *protocol_version,
+                              char **protocol_version_string,
+                              SilcUInt32 *software_version, 
+                              char **software_version_string,
+                              char **vendor_version)
+{
+  char *cp, buf[32];
+  int maj = 0, min = 0;
+
+  if (!strstr(version, "SILC-"))
+    return FALSE;
+
+  cp = (char *)version + 5;
+  if (!cp)
+    return FALSE;
+
+  /* Take protocol version */
+
+  maj = atoi(cp);
+  cp = strchr(cp, '.');
+  if (cp) {
+    min = atoi(cp + 1);
+    cp++;
+  }
+
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
+  if (protocol_version)
+    *protocol_version = atoi(buf);
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
+  if (protocol_version_string)
+    *protocol_version_string = strdup(buf);
+
+  /* Take software version */
+
+  maj = 0; 
+  min = 0;
+  cp = strchr(cp, '-');
+  if (!cp)
+    return FALSE;
+
+  maj = atoi(cp + 1);
+  cp = strchr(cp, '.');
+  if (cp)
+    min = atoi(cp + 1);
+
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
+  if (software_version)
+    *software_version = atoi(buf);
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
+  if (software_version_string)
+    *software_version_string = strdup(buf);
+
+  /* Take vendor string */
+
+  cp++;
+  if (cp) {
+    cp = strchr(cp, '.');
+    if (cp && cp + 1 && vendor_version)
+      *vendor_version = strdup(cp + 1);
+  }
+
+  return TRUE;
+}
+
+/* Converts version string x.x into number representation. */
+
+SilcUInt32 silc_version_to_num(const char *version)
+{
+  int maj = 0, min = 0;
+  char *cp, buf[32];
+
+  if (!version)
+    return 0;
+
+  cp = (char *)version;
+  maj = atoi(cp);
+  cp = strchr(cp, '.');
+  if (cp)
+    min = atoi(cp + 1);
+
+  memset(buf, 0, sizeof(buf));
+  snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
+  return (SilcUInt32)atoi(buf);
+}
index 2d6fa7f31a3b0f3c78a37eb76a4374a767699703..aa4112bcface6035e36fd68d9497f4d2beeeaec7 100644 (file)
@@ -62,5 +62,12 @@ char *silc_client_chumode_char(SilcUInt32 mode);
 int silc_gettimeofday(struct timeval *p);
 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len);
 bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len);
 int silc_gettimeofday(struct timeval *p);
 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len);
 bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len);
+bool silc_parse_version_string(const char *version,
+                              SilcUInt32 *protocol_version,
+                              char **protocol_version_string,
+                              SilcUInt32 *software_version, 
+                              char **software_version_string,
+                              char **vendor_version);
+SilcUInt32 silc_version_to_num(const char *version);
 
 #endif
 
 #endif