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
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 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.
@@ -94,8 +91,19 @@ TODO in Toolkit Documentation
 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
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 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", 
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;
-  SilcUInt32 num_sockets;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1309,38 +1308,16 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
   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;
-      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;
       }
@@ -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;
-      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_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")));
index dc76c48161f642ac13932a06fc0148f71bbe463e..529b75de5fdcca6999210533542f7fa7350b9944 100644 (file)
@@ -856,3 +856,104 @@ SilcPublicKey silc_server_get_public_key(SilcServer server,
 
   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);
 
+/* 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 */
index 2e4773c77ffdb465725a5140570cfa873b5816f6..2153870e0dc904ef599b9a510e7a78de12b49440 100644 (file)
@@ -74,24 +74,17 @@ static void
 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->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. */
@@ -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, "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;
 
@@ -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, "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;
 
@@ -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 },
+  { "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 }
 };
 
@@ -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 },
+  { "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 }
 };
 
index 2af85bbd8618fffb7ed540cfd335dd213d5a7f96..b27c7b6564bf2ba89c1cffff4e6c535004d1c891 100644 (file)
@@ -82,6 +82,9 @@ typedef struct SilcServerConfigConnParams {
   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;
 
index d32f0612d8258025bb1ef04560b33a9023f5f353..bf0a81b4ff509e78bea59d088adf5609593c0c7a 100644 (file)
@@ -59,6 +59,22 @@ General {
        # 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;
@@ -256,6 +272,22 @@ ConnectionParams {
        # 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;
 
index 836a4fb8a27032df82fab62ef574a2a9433ac720..56b38eb44ca9db766e974a0bcec903131e6db83e 100644 (file)
@@ -1993,3 +1993,20 @@ const char *silc_ske_map_status(SilcSKEStatus status)
 
   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);
 
+/****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 */
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);
-  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);
index 6ef7c57651805a6d0b6c5e0088e3fc915e1a931d..82068283708b5a3b64da0bf4ce23d8ebec0f1310 100644 (file)
@@ -859,3 +859,95 @@ bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
 
   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);
+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