+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
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.
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
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",
SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
void *id_entry;
SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
- SilcUInt32 num_sockets;
SILC_LOG_DEBUG(("Start"));
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;
}
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")));
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;
+}
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 */
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. */
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 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;
{ "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 }
};
{ "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 }
};
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;
# 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;
# 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;
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);
+}
***/
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 */
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);
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);
+}
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