Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2005 Pekka Riikonen
+ Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
GNU General Public License for more details.
*/
-/*
- * This is the actual SILC server than handles everything relating to
- * servicing the SILC connections. This is also a SILC router as a router
- * is also normal server.
- */
-/* $Id$ */
#include "serverincludes.h"
#include "server_internal.h"
-/* Static prototypes */
-SILC_TASK_CALLBACK(silc_server_rehash_close_connection);
-SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
-SILC_TASK_CALLBACK(silc_server_connect_router);
-SILC_TASK_CALLBACK(silc_server_connect_to_router_second);
-SILC_TASK_CALLBACK(silc_server_connect_to_router_final);
-SILC_TASK_CALLBACK(silc_server_accept_new_connection);
-SILC_TASK_CALLBACK(silc_server_accept_new_connection_second);
-SILC_TASK_CALLBACK(silc_server_accept_new_connection_final);
-SILC_TASK_CALLBACK(silc_server_packet_process);
-SILC_TASK_CALLBACK(silc_server_packet_parse_real);
-SILC_TASK_CALLBACK(silc_server_close_connection_final);
-SILC_TASK_CALLBACK(silc_server_free_client_data_timeout);
-SILC_TASK_CALLBACK(silc_server_timeout_remote);
-SILC_TASK_CALLBACK(silc_server_channel_key_rekey);
+/************************* Types and definitions ***************************/
+
SILC_TASK_CALLBACK(silc_server_get_stats);
SILC_TASK_CALLBACK(silc_server_connect_router);
+SILC_TASK_CALLBACK(silc_server_do_rekey);
+static void silc_server_accept_new_connection(SilcNetStatus status,
+ SilcStream stream,
+ void *context);
+static void silc_server_packet_parse_type(SilcServer server,
+ SilcPacketStream sock,
+ SilcPacket packet);
-/* Allocates a new SILC server object. This has to be done before the server
- can be used. After allocation one must call silc_server_init to initialize
- the server. The new allocated server object is returned to the new_server
- argument. */
-
-int silc_server_alloc(SilcServer *new_server)
-{
- SilcServer server;
-
- SILC_LOG_DEBUG(("Allocating new server object"));
-
- server = silc_calloc(1, sizeof(*server));
- server->server_type = SILC_SERVER;
- server->standalone = TRUE;
- server->local_list = silc_calloc(1, sizeof(*server->local_list));
- server->global_list = silc_calloc(1, sizeof(*server->global_list));
- server->pending_commands = silc_dlist_init();
-#ifdef SILC_SIM
- server->sim = silc_dlist_init();
-#endif
-
- *new_server = server;
- return TRUE;
-}
+/************************ Static utility functions **************************/
-/* Free's the SILC server object. This is called at the very end before
- the program ends. */
+/* SKE public key verification callback */
-void silc_server_free(SilcServer server)
+static void
+silc_server_verify_key(SilcSKE ske,
+ SilcPublicKey public_key,
+ void *context,
+ SilcSKEVerifyCbCompletion completion,
+ void *completion_context)
{
- SilcIDCacheList list;
- SilcIDCacheEntry cache;
+ SilcPacketStream sock = context;
+ SilcUnknownEntry entry = silc_packet_get_context(sock);
- if (!server)
- return;
+ SILC_LOG_DEBUG(("Verifying public key"));
-#ifdef SILC_SIM
- {
- SilcSim sim;
- silc_dlist_start(server->sim);
- while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
- silc_dlist_del(server->sim, sim);
- silc_sim_close(sim);
- silc_sim_free(sim);
- }
- silc_dlist_uninit(server->sim);
+ if (silc_pkcs_get_type(public_key) != SILC_SKE_PK_TYPE_SILC) {
+ SILC_LOG_WARNING(("We don't support %s (%s) port %d public key type %d",
+ entry->hostname, entry->ip, entry->port,
+ silc_pkcs_get_type(public_key)));
+ completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
+ completion_context);
+ return;
}
-#endif
- silc_server_backup_free(server);
- silc_server_config_unref(&server->config_ref);
- if (server->rng)
- silc_rng_free(server->rng);
- if (server->pkcs)
- silc_pkcs_free(server->pkcs);
- if (server->public_key)
- silc_pkcs_public_key_free(server->public_key);
- if (server->private_key)
- silc_pkcs_private_key_free(server->private_key);
- if (server->pending_commands)
- silc_dlist_uninit(server->pending_commands);
- if (server->id_entry)
- silc_idlist_del_server(server->local_list, server->id_entry);
+ /* We accept all keys without explicit verification */
+ completion(ske, SILC_SKE_STATUS_OK, completion_context);
+}
- /* Delete all channels */
- list = NULL;
- if (silc_idcache_get_all(server->local_list->channels, &list) &&
- silc_idcache_list_first(list, &cache)) {
- silc_idlist_del_channel(server->local_list, cache->context);
- while (silc_idcache_list_next(list, &cache))
- silc_idlist_del_channel(server->local_list, cache->context);
- }
- if (list)
- silc_idcache_list_free(list);
- list = NULL;
- if (silc_idcache_get_all(server->global_list->channels, &list) &&
- silc_idcache_list_first(list, &cache)) {
- silc_idlist_del_channel(server->global_list, cache->context);
- while (silc_idcache_list_next(list, &cache))
- silc_idlist_del_channel(server->global_list, cache->context);
- }
- if (list)
- silc_idcache_list_free(list);
- if (server->pk_hash)
- silc_hash_table_free(server->pk_hash);
+/************************ Packet engine callbacks ***************************/
- /* Delete all clients */
- list = NULL;
- if (silc_idcache_get_all(server->local_list->clients, &list) &&
- silc_idcache_list_first(list, &cache)) {
- silc_idlist_del_client(server->local_list, cache->context);
- while (silc_idcache_list_next(list, &cache))
- silc_idlist_del_client(server->local_list, cache->context);
- }
- if (list)
- silc_idcache_list_free(list);
- list = NULL;
- if (silc_idcache_get_all(server->global_list->clients, &list) &&
- silc_idcache_list_first(list, &cache)) {
- silc_idlist_del_client(server->global_list, cache->context);
- while (silc_idcache_list_next(list, &cache))
- silc_idlist_del_client(server->global_list, cache->context);
- }
- if (list)
- silc_idcache_list_free(list);
+/* Packet engine callback to receive a packet */
+static SilcBool silc_server_packet_receive(SilcPacketEngine engine,
+ SilcPacketStream stream,
+ SilcPacket packet,
+ void *callback_context,
+ void *stream_context)
+{
+ SilcServer server = callback_context;
+ SilcIDListData idata = stream_context;
- /* Delete all servers */
- list = NULL;
- if (silc_idcache_get_all(server->local_list->servers, &list) &&
- silc_idcache_list_first(list, &cache)) {
- silc_idlist_del_server(server->local_list, cache->context);
- while (silc_idcache_list_next(list, &cache))
- silc_idlist_del_server(server->local_list, cache->context);
- }
- if (list)
- silc_idcache_list_free(list);
- list = NULL;
- if (silc_idcache_get_all(server->global_list->servers, &list) &&
- silc_idcache_list_first(list, &cache)) {
- silc_idlist_del_server(server->global_list, cache->context);
- while (silc_idcache_list_next(list, &cache))
- silc_idlist_del_server(server->global_list, cache->context);
+ /* Packets we do not handle */
+ switch (packet->type) {
+ case SILC_PACKET_HEARTBEAT:
+ case SILC_PACKET_SUCCESS:
+ case SILC_PACKET_FAILURE:
+ case SILC_PACKET_REJECT:
+ case SILC_PACKET_KEY_EXCHANGE:
+ case SILC_PACKET_KEY_EXCHANGE_1:
+ case SILC_PACKET_KEY_EXCHANGE_2:
+ case SILC_PACKET_REKEY_DONE:
+ case SILC_PACKET_CONNECTION_AUTH:
+ return FALSE;
+ break;
}
- if (list)
- silc_idcache_list_free(list);
- silc_idcache_free(server->local_list->clients);
- silc_idcache_free(server->local_list->servers);
- silc_idcache_free(server->local_list->channels);
- silc_idcache_free(server->global_list->clients);
- silc_idcache_free(server->global_list->servers);
- silc_idcache_free(server->global_list->channels);
- silc_hash_table_free(server->watcher_list);
- silc_hash_table_free(server->watcher_list_pk);
+ /* Only specific packets can come without source ID present. */
+ if ((!packet->src_id ||
+ !(idata->status & SILC_IDLIST_STATUS_REGISTERED)) &&
+ packet->type != SILC_PACKET_NEW_CLIENT &&
+ packet->type != SILC_PACKET_NEW_SERVER &&
+ packet->type != SILC_PACKET_DISCONNECT)
+ return FALSE;
- silc_hash_free(server->md5hash);
- silc_hash_free(server->sha1hash);
- silc_hmac_unregister_all();
- silc_hash_unregister_all();
- silc_cipher_unregister_all();
- silc_pkcs_unregister_all();
+ /* NEW_CLIENT and NEW_SERVER are accepted only without source ID
+ and for unregistered connection. */
+ if (packet->src_id && (packet->type == SILC_PACKET_NEW_CLIENT ||
+ packet->type == SILC_PACKET_NEW_SERVER) &&
+ (idata->status & SILC_IDLIST_STATUS_REGISTERED))
+ return FALSE;
- silc_free(server->local_list);
- silc_free(server->global_list);
- silc_free(server->server_name);
- silc_free(server->id_string);
- silc_free(server->purge_i);
- silc_free(server->purge_g);
- silc_free(server);
+ /* Process packet */
+ silc_server_packet_parse_type(server, stream, packet);
+
+ return TRUE;
}
-/* Creates a new server listener. */
+/* Packet engine callback to indicate end of stream */
-static bool silc_server_listen(SilcServer server, const char *server_ip,
- SilcUInt16 port, int *sock)
+static void silc_server_packet_eos(SilcPacketEngine engine,
+ SilcPacketStream stream,
+ void *callback_context,
+ void *stream_context)
{
- *sock = silc_net_create_server(port, server_ip);
- if (*sock < 0) {
- SILC_SERVER_LOG_ERROR(("Could not create server listener: %s on %hu",
- server_ip, port));
- return FALSE;
- }
- return TRUE;
+ SILC_LOG_DEBUG(("End of stream received"));
}
-/* Adds a secondary listener. */
+/* Packet engine callback to indicate error */
-bool silc_server_init_secondary(SilcServer server)
+static void silc_server_packet_error(SilcPacketEngine engine,
+ SilcPacketStream stream,
+ SilcPacketError error,
+ void *callback_context,
+ void *stream_context)
{
- int sock = 0, sock_list[server->config->param.connections_max];
- SilcSocketConnection newsocket = NULL;
- SilcServerConfigServerInfoInterface *interface;
- for (interface = server->config->server_info->secondary; interface;
- interface = interface->next, sock++) {
+}
- if (!silc_server_listen(server,
- interface->server_ip, interface->port, &sock_list[sock]))
- goto err;
+/* Packet stream callbacks */
+static SilcPacketCallbacks silc_server_stream_cbs =
+{
+ silc_server_packet_receive,
+ silc_server_packet_eos,
+ silc_server_packet_error
+};
- /* Set socket to non-blocking mode */
- silc_net_set_socket_nonblock(sock_list[sock]);
+/* Parses the packet type and calls what ever routines the packet type
+ requires. This is done for all incoming packets. */
- /* Add ourselves also to the socket table. The entry allocated above
- is sent as argument for fast referencing in the future. */
- silc_socket_alloc(sock_list[sock],
- SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
- server->sockets[sock_list[sock]] = newsocket;
- SILC_SET_LISTENER(newsocket);
+static void silc_server_packet_parse_type(SilcServer server,
+ SilcPacketStream sock,
+ SilcPacket packet)
+{
+ SilcPacketType type = packet->type;
+ SilcIDListData idata = silc_packet_get_context(sock);
- /* Perform name and address lookups to resolve the listenning address
- and port. */
- if (!silc_net_check_local_by_sock(sock_list[sock], &newsocket->hostname,
- &newsocket->ip)) {
- 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 :
- newsocket->ip ? newsocket->ip : ""));
- server->stat.conn_failures++;
- goto err;
- }
- if (!newsocket->hostname)
- newsocket->hostname = strdup(newsocket->ip);
- }
- newsocket->port = silc_net_get_local_port(sock);
+ SILC_LOG_DEBUG(("Received %s packet [flags %d]",
+ silc_get_packet_name(type), packet->flags));
- newsocket->user_data = (void *)server->id_entry;
- silc_schedule_task_add(server->schedule, sock_list[sock],
- silc_server_accept_new_connection,
- (void *)server, 0, 0,
- SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL);
- }
+ /* Parse the packet type */
+ switch (type) {
+ case SILC_PACKET_NOTIFY:
+ /*
+ * Received notify packet. Server can receive notify packets from
+ * router. Server then relays the notify messages to clients if needed.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ silc_server_notify_list(server, sock, packet);
+ else
+ silc_server_notify(server, sock, packet);
+ break;
- return TRUE;
+ /*
+ * Private Message packets
+ */
+ case SILC_PACKET_PRIVATE_MESSAGE:
+ /*
+ * Received private message packet. The packet is coming from either
+ * client or server.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ idata->last_receive = time(NULL);
+ silc_server_private_message(server, sock, packet);
+ break;
- err:
- do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
- return FALSE;
-}
+ /*
+ * Channel packets
+ */
+ case SILC_PACKET_CHANNEL_MESSAGE:
+ /*
+ * Received channel message. Channel messages are special packets
+ * (although probably most common ones) thus they are handled
+ * specially.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ idata->last_receive = time(NULL);
+ silc_server_channel_message(server, sock, packet);
+ break;
-/* Initializes the entire SILC server. This is called always before running
- the server. This is called only once at the initialization of the program.
- This binds the server to its listenning port. After this function returns
- one should call silc_server_run to start the server. This returns TRUE
- when everything is ok to run the server. Configuration file must be
- read and parsed before calling this. */
+ /*
+ * Command packets
+ */
+ case SILC_PACKET_COMMAND:
+ /*
+ * Recived command. Processes the command request and allocates the
+ * command context and calls the command.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ server->stat.commands_received++;
+ silc_server_command_process(server, sock, packet);
+ break;
-bool silc_server_init(SilcServer server)
-{
- int sock = -1;
- SilcServerID *id;
- SilcServerEntry id_entry;
- SilcIDListPurge purge;
- SilcSocketConnection newsocket = NULL;
+ case SILC_PACKET_COMMAND_REPLY:
+ /*
+ * Received command reply packet. Received command reply to command. It
+ * may be reply to command sent by us or reply to command sent by client
+ * that we've routed further.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ server->stat.commands_received++;
+ silc_server_command_reply(server, sock, packet);
+ break;
- SILC_LOG_DEBUG(("Initializing server"));
+ case SILC_PACKET_DISCONNECT:
+ {
+ SilcStatus status;
+ char *message = NULL;
- server->starttime = time(NULL);
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ if (silc_buffer_len(&packet->buffer) < 1)
+ break;
- /* Take config object for us */
- silc_server_config_ref(&server->config_ref, server->config,
- server->config);
+ status = (SilcStatus)packet->buffer.data[0];
+ if (silc_buffer_len(&packet->buffer) > 1 &&
+ silc_utf8_valid(packet->buffer.data + 1, silc_buffer_len(&packet->buffer) - 1))
+ message = silc_memdup(packet->buffer.data + 1,
+ silc_buffer_len(&packet->buffer) - 1);
-#ifdef SILC_DEBUG
- /* Set debugging on if configured */
- if (server->config->debug_string) {
- silc_log_debug(TRUE);
- silc_log_set_debug_string(server->config->debug_string);
- }
-#endif /* SILC_DEBUG */
+#if 0
+ SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s",
+ sock->ip, sock->hostname,
+ silc_get_status_message(status), status,
+ message ? message : ""));
+#endif
+ silc_free(message);
- /* Steal public and private key from the config object */
- server->public_key = server->config->server_info->public_key;
- server->private_key = server->config->server_info->private_key;
- server->config->server_info->public_key = NULL;
- server->config->server_info->private_key = NULL;
-
- /* Register all configured ciphers, PKCS and hash functions. */
- if (!silc_server_config_register_ciphers(server))
- silc_cipher_register_default();
- if (!silc_server_config_register_pkcs(server))
- silc_pkcs_register_default();
- if (!silc_server_config_register_hashfuncs(server))
- silc_hash_register_default();
- if (!silc_server_config_register_hmacs(server))
- silc_hmac_register_default();
-
- /* Initialize random number generator for the server. */
- server->rng = silc_rng_alloc();
- silc_rng_init(server->rng);
- silc_rng_global_init(server->rng);
-
- /* Initialize hash functions for server to use */
- silc_hash_alloc("md5", &server->md5hash);
- silc_hash_alloc("sha1", &server->sha1hash);
-
- /* Allocate PKCS context for local public and private keys */
- if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
- goto err;
- silc_pkcs_public_key_set(server->pkcs, server->public_key);
- silc_pkcs_private_key_set(server->pkcs, server->private_key);
-
- /* Initialize the scheduler */
- server->schedule = silc_schedule_init(server->config->param.connections_max,
- server);
- if (!server->schedule)
- goto err;
-
- /* First, register log files configuration for error output */
- silc_server_config_setlogfiles(server);
-
- /* Initialize ID caches */
- server->local_list->clients =
- silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
- server, FALSE, TRUE);
- server->local_list->servers =
- silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL, FALSE, TRUE);
- server->local_list->channels =
- silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL, FALSE, TRUE);
-
- /* These are allocated for normal server as well as these hold some
- global information that the server has fetched from its router. For
- router these are used as they are supposed to be used on router. */
- server->global_list->clients =
- silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
- server, FALSE, TRUE);
- server->global_list->servers =
- silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL, FALSE, TRUE);
- server->global_list->channels =
- silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL, FALSE, TRUE);
-
- /* Init watcher lists */
- server->watcher_list =
- silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL,
- silc_hash_data_compare, (void *)CLIENTID_HASH_LEN,
- NULL, NULL, TRUE);
- if (!server->watcher_list)
- goto err;
- server->watcher_list_pk =
- silc_hash_table_alloc(1, silc_hash_public_key, NULL,
- silc_hash_public_key_compare, NULL,
- NULL, NULL, TRUE);
- if (!server->watcher_list_pk)
- goto err;
-
- /* Init public key list */
- server->pk_hash =
- silc_hash_table_alloc(0, silc_hash_public_key, NULL,
- silc_hash_public_key_compare, NULL,
- NULL, NULL, TRUE);
-
- if (!server->pk_hash)
- goto err;
+ /* Do not switch to backup in case of error */
+ server->backup_noswitch = (status == SILC_STATUS_OK ? FALSE : TRUE);
- /* Create a listening server */
- if (!silc_server_listen(server,
- server->config->server_info->primary == NULL ? NULL :
- server->config->server_info->primary->server_ip,
- server->config->server_info->primary == NULL ? 0 :
- server->config->server_info->primary->port,
- &sock))
- goto err;
+ /* If backup disconnected then mark that resuming will not be allowed */
+#if 0
+ if (server->server_type == SILC_ROUTER && !server->backup_router &&
+ sock->type == SILC_CONN_SERVER && sock->user_data) {
+ SilcServerEntry server_entry = sock->user_data;
+ if (server_entry->server_type == SILC_BACKUP_ROUTER)
+ server->backup_closed = TRUE;
+ }
- /* Set socket to non-blocking mode */
- silc_net_set_socket_nonblock(sock);
- server->sock = sock;
+ /* Handle the disconnection from our end too */
+ if (sock->user_data && SILC_IS_LOCAL(sock->user_data))
+ silc_server_free_sock_user_data(server, sock, NULL);
+ SILC_SET_DISCONNECTING(sock);
+ silc_server_close_connection(server, sock);
+ server->backup_noswitch = FALSE;
+#endif
+ }
+ break;
- /* Allocate the entire socket list that is used in server. Eventually
- all connections will have entry in this table (it is a table of
- pointers to the actual object that is allocated individually
- later). */
- server->sockets = silc_calloc(server->config->param.connections_max,
- sizeof(*server->sockets));
- if (!server->sockets)
- goto err;
+ case SILC_PACKET_CHANNEL_KEY:
+ /*
+ * Received key for channel. As channels are created by the router
+ * the keys are as well. We will distribute the key to all of our
+ * locally connected clients on the particular channel. Router
+ * never receives this channel and thus is ignored.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_channel_key(server, sock, packet);
+ break;
- /* Add ourselves also to the socket table. The entry allocated above
- is sent as argument for fast referencing in the future. */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
- server->sockets[sock] = newsocket;
- SILC_SET_LISTENER(newsocket);
+ case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+ /*
+ * Private message key packet.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_private_message_key(server, sock, packet);
+ break;
- /* Perform name and address lookups to resolve the listenning address
- and port. */
- if (!silc_net_check_local_by_sock(sock, &newsocket->hostname,
- &newsocket->ip)) {
- 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 :
- newsocket->ip ? newsocket->ip : ""));
- server->stat.conn_failures++;
- goto err;
- }
- if (!newsocket->hostname)
- newsocket->hostname = strdup(newsocket->ip);
- }
- newsocket->port = silc_net_get_local_port(sock);
+ case SILC_PACKET_CONNECTION_AUTH_REQUEST:
+ /*
+ * Connection authentication request packet. When we receive this packet
+ * we will send to the other end information about our mandatory
+ * authentication method for the connection. This packet maybe received
+ * at any time.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_connection_auth_request(server, sock, packet);
+ break;
- /* Create a Server ID for the server. */
- silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
- if (!id)
- goto err;
+ case SILC_PACKET_NEW_ID:
+ /*
+ * Received New ID packet. This includes some new ID that has been
+ * created. It may be for client, server or channel. This is the way
+ * to distribute information about new registered entities in the
+ * SILC network.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ silc_server_new_id_list(server, sock, packet);
+ else
+ silc_server_new_id(server, sock, packet);
+ break;
- server->id = id;
- server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
- server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
- server->server_name = server->config->server_info->server_name;
- server->config->server_info->server_name = NULL;
+ case SILC_PACKET_NEW_CLIENT:
+ /*
+ * Received new client packet. This includes client information that
+ * we will use to create initial client ID. After creating new
+ * ID we will send it to the client.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_new_client(server, sock, packet);
+ break;
- /* Add ourselves to the server list. We don't have a router yet
- beacuse we haven't established a route yet. It will be done later.
- For now, NULL is sent as router. This allocates new entry to
- the ID list. */
- id_entry =
- silc_idlist_add_server(server->local_list, strdup(server->server_name),
- server->server_type, server->id, NULL, NULL);
- if (!id_entry) {
- SILC_LOG_ERROR(("Could not add ourselves to cache"));
- goto err;
- }
- id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+ case SILC_PACKET_NEW_SERVER:
+ /*
+ * Received new server packet. This includes Server ID and some other
+ * information that we may save. This is received after server has
+ * connected to us.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_new_server(server, sock, packet);
+ break;
- /* Put the allocated socket pointer also to the entry allocated above
- for fast back-referencing to the socket list. */
- newsocket->user_data = (void *)id_entry;
- id_entry->connection = (void *)newsocket;
- server->id_entry = id_entry;
+ case SILC_PACKET_NEW_CHANNEL:
+ /*
+ * Received new channel packet. Information about new channel in the
+ * network are distributed using this packet.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ silc_server_new_channel_list(server, sock, packet);
+ else
+ silc_server_new_channel(server, sock, packet);
+ break;
- /* Register protocols */
- silc_server_protocols_register();
+ case SILC_PACKET_HEARTBEAT:
+ /*
+ * Received heartbeat.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ break;
- /* Create connections to configured routers. */
- silc_server_create_connections(server);
+ case SILC_PACKET_KEY_AGREEMENT:
+ /*
+ * Received heartbeat.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_key_agreement(server, sock, packet);
+ break;
- /* Add listener task to the scheduler. This task receives new connections
- to the server. This task remains on the queue until the end of the
- program. */
- silc_schedule_task_add(server->schedule, sock,
- silc_server_accept_new_connection,
- (void *)server, 0, 0,
- SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL);
+ case SILC_PACKET_REKEY:
+ /*
+ * Received re-key packet. The sender wants to regenerate the session
+ * keys.
+ */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ /* XXX handle rekey */
+ break;
- if (silc_server_init_secondary(server) == FALSE)
- goto err;
+ case SILC_PACKET_FTP:
+ /* FTP packet */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_ftp(server, sock, packet);
+ break;
- server->listenning = TRUE;
+ case SILC_PACKET_RESUME_CLIENT:
+ /* Resume client */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_resume_client(server, sock, packet);
+ break;
- /* If server connections has been configured then we must be router as
- normal server cannot have server connections, only router connections. */
- if (server->config->servers) {
- SilcServerConfigServer *ptr = server->config->servers;
+ case SILC_PACKET_RESUME_ROUTER:
+ /* Resume router packet received. This packet is received for backup
+ router resuming protocol. */
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+#if 0
+ silc_server_backup_resume_router(server, sock, packet);
+#endif
+ break;
- server->server_type = SILC_ROUTER;
- while (ptr) {
- if (ptr->backup_router) {
- server->server_type = SILC_BACKUP_ROUTER;
- server->backup_router = TRUE;
- server->id_entry->server_type = SILC_BACKUP_ROUTER;
- break;
- }
- ptr = ptr->next;
- }
+ default:
+ SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
+ break;
}
+}
- /* Register the ID Cache purge task. This periodically purges the ID cache
- and removes the expired cache entries. */
+/****************************** Server API **********************************/
- /* Clients local list */
- server->purge_i = purge = silc_calloc(1, sizeof(*purge));
- purge->cache = server->local_list->clients;
- purge->timeout = 600;
- silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
- (void *)purge, purge->timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+/* Allocates a new SILC server object. This has to be done before the server
+ can be used. After allocation one must call silc_server_init to initialize
+ the server. The new allocated server object is returned to the new_server
+ argument. */
- /* Clients global list */
- server->purge_g = purge = silc_calloc(1, sizeof(*purge));
- purge->cache = server->global_list->clients;
- purge->timeout = 300;
- silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
- (void *)purge, purge->timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+SilcBool silc_server_alloc(SilcServer *new_server)
+{
+ SilcServer server;
- /* If we are normal server we'll retrieve network statisticial information
- once in a while from the router. */
- if (server->server_type != SILC_ROUTER)
- silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
- server, 10, 0, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
+ SILC_LOG_DEBUG(("Allocating new server object"));
- if (server->server_type == SILC_ROUTER)
- server->stat.routers++;
+ server = silc_calloc(1, sizeof(*server));
+ if (!server)
+ return FALSE;
+ server->server_type = SILC_SERVER;
+ server->standalone = TRUE;
+ server->local_list = silc_calloc(1, sizeof(*server->local_list));
+ if (!server->local_list)
+ return FALSE;
+ server->global_list = silc_calloc(1, sizeof(*server->global_list));
+ if (!server->global_list)
+ return FALSE;
+ server->pending_commands = silc_dlist_init();
+ if (!server->pending_commands)
+ return FALSE;
+ server->listeners = silc_dlist_init();
+ if (!server->listeners)
+ return FALSE;
+ server->repository = silc_skr_alloc();
+ if (!server->repository)
+ return FALSE;
- SILC_LOG_DEBUG(("Server initialized"));
+ *new_server = server;
- /* We are done here, return succesfully */
return TRUE;
-
- err:
- silc_server_config_unref(&server->config_ref);
- silc_net_close_server(sock);
- return FALSE;
}
-/* Task callback to close a socket connection after rehash */
+/* Free's the SILC server object. This is called at the very end before
+ the program ends. */
-SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
+void silc_server_free(SilcServer server)
{
- SilcServer server = context;
- SilcSocketConnection sock = server->sockets[fd];
+ SilcList list;
+ SilcIDCacheEntry cache;
- if (!sock)
+ if (!server)
return;
- SILC_LOG_INFO(("Connection %s:%d [%s] is unconfigured",
- sock->hostname, sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
- silc_schedule_task_del_by_context(server->schedule, sock);
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_BANNED_FROM_SERVER,
- "This connection is removed from "
- "configuration");
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
-}
-
-/* This function basically reads the config file again and switches the config
- object pointed by the server object. After that, we have to fix various
- things such as the server_name and the listening ports.
- Keep in mind that we no longer have the root privileges at this point. */
-
-bool silc_server_rehash(SilcServer server)
-{
- SilcServerConfig newconfig;
-
- SILC_LOG_INFO(("Rehashing server"));
-
- /* Reset the logging system */
- silc_log_quick(TRUE);
- silc_log_flush_all();
+ silc_server_backup_free(server);
+ silc_server_config_unref(&server->config_ref);
+ if (server->pk_hash)
+ silc_hash_table_free(server->pk_hash);
+ if (server->rng)
+ silc_rng_free(server->rng);
+ if (server->public_key)
+ silc_pkcs_public_key_free(server->public_key);
+ if (server->private_key)
+ silc_pkcs_private_key_free(server->private_key);
+ if (server->pending_commands)
+ silc_dlist_uninit(server->pending_commands);
+ if (server->id_entry)
+ silc_idlist_del_server(server->local_list, server->id_entry);
- /* Start the main rehash phase (read again the config file) */
- newconfig = silc_server_config_alloc(server->config_file);
- if (!newconfig) {
- SILC_LOG_ERROR(("Rehash FAILED."));
- return FALSE;
+ /* Delete all channels */
+ if (silc_idcache_get_all(server->local_list->channels, &list)) {
+ silc_list_start(list);
+ while ((cache = silc_list_get(list)))
+ silc_idlist_del_channel(server->local_list, cache->context);
}
-
- /* Reinit scheduler if necessary */
- if (newconfig->param.connections_max > server->config->param.connections_max)
- if (!silc_schedule_reinit(server->schedule,
- newconfig->param.connections_max))
- return FALSE;
-
- /* Fix the server_name field */
- if (strcmp(server->server_name, newconfig->server_info->server_name)) {
- silc_free(server->server_name);
-
- /* Check server name */
- server->server_name =
- silc_identifier_check(newconfig->server_info->server_name,
- strlen(newconfig->server_info->server_name),
- SILC_STRING_LOCALE, 256, NULL);
- if (!server->server_name) {
- SILC_LOG_ERROR(("Malformed server name string '%s'",
- server->config->server_info->server_name));
- return FALSE;
- }
-
- /* Update the idcache list with a fresh pointer */
- silc_free(server->id_entry->server_name);
- server->id_entry->server_name = strdup(server->server_name);
- if (!silc_idcache_del_by_context(server->local_list->servers,
- server->id_entry))
- return FALSE;
- if (!silc_idcache_add(server->local_list->servers,
- strdup(server->id_entry->server_name),
- server->id_entry->id, server->id_entry, 0, NULL))
- return FALSE;
+ if (silc_idcache_get_all(server->global_list->channels, &list)) {
+ silc_list_start(list);
+ while ((cache = silc_list_get(list)))
+ silc_idlist_del_channel(server->global_list, cache->context);
}
- /* Set logging */
- silc_server_config_setlogfiles(server);
-
- /* Change new key pair if necessary */
- if (newconfig->server_info->public_key &&
- !silc_pkcs_public_key_compare(server->public_key,
- newconfig->server_info->public_key)) {
- silc_pkcs_public_key_free(server->public_key);
- silc_pkcs_private_key_free(server->private_key);
- server->public_key = newconfig->server_info->public_key;
- server->private_key = newconfig->server_info->private_key;
- newconfig->server_info->public_key = NULL;
- newconfig->server_info->private_key = NULL;
-
- /* Allocate PKCS context for local public and private keys */
- silc_pkcs_free(server->pkcs);
- if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
- return FALSE;
- silc_pkcs_public_key_set(server->pkcs, server->public_key);
- silc_pkcs_private_key_set(server->pkcs, server->private_key);
+ /* Delete all clients */
+ if (silc_idcache_get_all(server->local_list->clients, &list)) {
+ silc_list_start(list);
+ while ((cache = silc_list_get(list)))
+ silc_idlist_del_client(server->local_list, cache->context);
+ }
+ if (silc_idcache_get_all(server->global_list->clients, &list)) {
+ silc_list_start(list);
+ while ((cache = silc_list_get(list)))
+ silc_idlist_del_client(server->global_list, cache->context);
}
- /* Check for unconfigured server and router connections and close
- connections that were unconfigured. */
+ /* Delete all servers */
+ if (silc_idcache_get_all(server->local_list->servers, &list)) {
+ silc_list_start(list);
+ while ((cache = silc_list_get(list)))
+ silc_idlist_del_server(server->local_list, cache->context);
+ }
+ if (silc_idcache_get_all(server->global_list->servers, &list)) {
+ while ((cache = silc_list_get(list)))
+ silc_idlist_del_server(server->global_list, cache->context);
+ }
- if (server->config->routers) {
- SilcServerConfigRouter *ptr;
- SilcServerConfigRouter *newptr;
- bool found;
+ silc_idcache_free(server->local_list->clients);
+ silc_idcache_free(server->local_list->servers);
+ silc_idcache_free(server->local_list->channels);
+ silc_idcache_free(server->global_list->clients);
+ silc_idcache_free(server->global_list->servers);
+ silc_idcache_free(server->global_list->channels);
+ silc_hash_table_free(server->watcher_list);
+ silc_hash_table_free(server->watcher_list_pk);
- for (ptr = server->config->routers; ptr; ptr = ptr->next) {
- found = FALSE;
+ silc_hash_free(server->md5hash);
+ silc_hash_free(server->sha1hash);
+ silc_hmac_unregister_all();
+ silc_hash_unregister_all();
+ silc_cipher_unregister_all();
+ silc_pkcs_unregister_all();
- /* Check whether new config has this one too */
- for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
- if (silc_string_compare(newptr->host, ptr->host) &&
- newptr->port == ptr->port &&
- newptr->initiator == ptr->initiator) {
- found = TRUE;
- break;
- }
- }
+ silc_free(server->local_list);
+ silc_free(server->global_list);
+ silc_free(server->server_name);
+ silc_free(server->id_string);
+ silc_free(server->purge_i);
+ silc_free(server->purge_g);
+ silc_free(server);
+}
- if (!found && ptr->host) {
- /* Remove this connection */
- SilcSocketConnection sock;
- sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
- ptr->host, ptr->port);
- if (sock && !SILC_IS_LISTENER(sock))
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rehash_close_connection,
- server, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- }
- }
+/* Creates a new server listener. */
+
+static SilcNetListener
+silc_server_listen(SilcServer server, const char *server_ip, SilcUInt16 port)
+{
+ SilcNetListener listener;
+
+ listener =
+ silc_net_tcp_create_listener(&server_ip, 1, port, TRUE,
+ server->config->require_reverse_lookup,
+ server->schedule,
+ silc_server_accept_new_connection, server);
+ if (!listener) {
+ SILC_SERVER_LOG_ERROR(("Could not create server listener: %s on %hu",
+ server_ip, port));
+ return NULL;
}
- if (server->config->servers) {
- SilcServerConfigServer *ptr;
- SilcServerConfigServer *newptr;
- bool found;
+ return listener;
+}
- for (ptr = server->config->servers; ptr; ptr = ptr->next) {
- found = FALSE;
+/* Adds a secondary listener. */
- /* Check whether new config has this one too */
- for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
- if (silc_string_compare(newptr->host, ptr->host)) {
- found = TRUE;
- break;
- }
- }
+SilcBool silc_server_init_secondary(SilcServer server)
+{
+#if 0
+ int sock = 0;
+ SilcPacketStream newsocket = NULL;
+ SilcServerConfigServerInfoInterface *interface;
- if (!found && ptr->host) {
- /* Remove this connection */
- SilcSocketConnection sock;
- sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
- ptr->host, 0);
- if (sock && !SILC_IS_LISTENER(sock))
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rehash_close_connection,
- server, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- }
- }
- }
+ for (interface = server->config->server_info->secondary; interface;
+ interface = interface->next, sock++) {
- if (server->config->clients) {
- SilcServerConfigClient *ptr;
- SilcServerConfigClient *newptr;
- bool found;
+ if (!silc_server_listen(server,
+ interface->server_ip, interface->port, &sock_list[sock]))
+ goto err;
- for (ptr = server->config->clients; ptr; ptr = ptr->next) {
- found = FALSE;
+ /* Set socket to non-blocking mode */
+ silc_net_set_socket_nonblock(sock_list[sock]);
- /* Check whether new config has this one too */
- for (newptr = newconfig->clients; newptr; newptr = newptr->next) {
- if (silc_string_compare(newptr->host, ptr->host)) {
- found = TRUE;
- break;
- }
- }
+ /* Add ourselves also to the socket table. The entry allocated above
+ is sent as argument for fast referencing in the future. */
+ silc_socket_alloc(sock_list[sock],
+ SILC_CONN_SERVER, NULL, &newsocket);
+ server->sockets[sock_list[sock]] = newsocket;
+ SILC_SET_LISTENER(newsocket);
- if (!found && ptr->host) {
- /* Remove this connection */
- SilcSocketConnection sock;
- sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_CLIENT,
- ptr->host, 0);
- if (sock)
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rehash_close_connection,
- server, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ /* Perform name and address lookups to resolve the listenning address
+ and port. */
+ if (!silc_net_check_local_by_sock(sock_list[sock], &newsocket->hostname,
+ &newsocket->ip)) {
+ 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 :
+ newsocket->ip ? newsocket->ip : ""));
+ server->stat.conn_failures++;
+ goto err;
}
+ if (!newsocket->hostname)
+ newsocket->hostname = strdup(newsocket->ip);
}
+ newsocket->port = silc_net_get_local_port(sock);
+
+ newsocket->user_data = (void *)server->id_entry;
+ silc_schedule_task_add(server->schedule, sock_list[sock],
+ silc_server_accept_new_connection,
+ (void *)server, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
}
- /* Create connections after rehash */
- silc_server_create_connections(server);
+ return TRUE;
- /* Check whether our router status has changed */
- if (newconfig->servers) {
- SilcServerConfigServer *ptr = newconfig->servers;
+ err:
+ do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
+#endif /* 0 */
+ return FALSE;
+}
- server->server_type = SILC_ROUTER;
- while (ptr) {
- if (ptr->backup_router) {
- server->server_type = SILC_BACKUP_ROUTER;
- server->backup_router = TRUE;
- server->id_entry->server_type = SILC_BACKUP_ROUTER;
- break;
- }
- ptr = ptr->next;
- }
- }
+/* Initializes the entire SILC server. This is called always before running
+ the server. This is called only once at the initialization of the program.
+ This binds the server to its listenning port. After this function returns
+ one should call silc_server_run to start the server. This returns TRUE
+ when everything is ok to run the server. Configuration file must be
+ read and parsed before calling this. */
- /* Our old config is gone now. We'll unreference our reference made in
- silc_server_init and then destroy it since we are destroying it
- underneath the application (layer which called silc_server_init). */
- silc_server_config_unref(&server->config_ref);
- silc_server_config_destroy(server->config);
+SilcBool silc_server_init(SilcServer server)
+{
+ SilcServerID *id;
+ SilcServerEntry id_entry;
+ SilcIDListPurge purge;
+ SilcNetListener listener;
+ SilcUInt16 *port;
+ char **ip;
- /* Take new config context */
- server->config = newconfig;
- silc_server_config_ref(&server->config_ref, server->config, server->config);
+ SILC_LOG_DEBUG(("Initializing server"));
+
+ server->starttime = time(NULL);
+
+ /* Take config object for us */
+ silc_server_config_ref(&server->config_ref, server->config,
+ server->config);
#ifdef SILC_DEBUG
/* Set debugging on if configured */
}
#endif /* SILC_DEBUG */
- SILC_LOG_DEBUG(("Server rehashed"));
+ /* Steal public and private key from the config object */
+ server->public_key = server->config->server_info->public_key;
+ server->private_key = server->config->server_info->private_key;
+ server->config->server_info->public_key = NULL;
+ server->config->server_info->private_key = NULL;
- return TRUE;
-}
+ /* Register all configured ciphers, PKCS and hash functions. */
+ if (!silc_server_config_register_ciphers(server))
+ silc_cipher_register_default();
+ if (!silc_server_config_register_pkcs(server))
+ silc_pkcs_register_default();
+ if (!silc_server_config_register_hashfuncs(server))
+ silc_hash_register_default();
+ if (!silc_server_config_register_hmacs(server))
+ silc_hmac_register_default();
-/* The heart of the server. This runs the scheduler thus runs the server.
- When this returns the server has been stopped and the program will
- be terminated. */
+ /* Initialize random number generator for the server. */
+ server->rng = silc_rng_alloc();
+ silc_rng_init(server->rng);
+ silc_rng_global_init(server->rng);
-void silc_server_run(SilcServer server)
-{
- SILC_LOG_INFO(("SILC Server started"));
+ /* Initialize hash functions for server to use */
+ silc_hash_alloc("md5", &server->md5hash);
+ silc_hash_alloc("sha1", &server->sha1hash);
- /* Start the scheduler, the heart of the SILC server. When this returns
- the program will be terminated. */
- silc_schedule(server->schedule);
-}
+ /* Initialize the scheduler */
+ server->schedule = silc_schedule_init(server->config->param.connections_max,
+ server);
+ if (!server->schedule)
+ goto err;
-/* Stops the SILC server. This function is used to shutdown the server.
- This is usually called after the scheduler has returned. After stopping
- the server one should call silc_server_free. */
+ /* First, register log files configuration for error output */
+ silc_server_config_setlogfiles(server);
-void silc_server_stop(SilcServer server)
-{
- SILC_LOG_INFO(("SILC Server shutting down"));
+ /* Initialize ID caches */
+ server->local_list->clients =
+ silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
+ server);
+ server->local_list->servers =
+ silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL);
+ server->local_list->channels =
+ silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL);
+
+ /* These are allocated for normal server as well as these hold some
+ global information that the server has fetched from its router. For
+ router these are used as they are supposed to be used on router. */
+ server->global_list->clients =
+ silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
+ server);
+ server->global_list->servers =
+ silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL);
+ server->global_list->channels =
+ silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL);
+
+ /* Init watcher lists */
+ server->watcher_list =
+ silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL,
+ silc_hash_data_compare, (void *)CLIENTID_HASH_LEN,
+ NULL, NULL, TRUE);
+ if (!server->watcher_list)
+ goto err;
+ server->watcher_list_pk =
+ silc_hash_table_alloc(1, silc_hash_public_key, NULL,
+ silc_hash_public_key_compare, NULL,
+ NULL, NULL, TRUE);
+ if (!server->watcher_list_pk)
+ goto err;
+
+ /* Init public key list */
+ server->pk_hash =
+ silc_hash_table_alloc(0, silc_hash_public_key, NULL,
+ silc_hash_public_key_compare, NULL,
+ NULL, NULL, TRUE);
- if (server->schedule) {
- int i;
+ if (!server->pk_hash)
+ goto err;
- server->server_shutdown = TRUE;
+ /* Create TCP listener */
+ listener = silc_server_listen(
+ server,
+ server->config->server_info->primary == NULL ? NULL :
+ server->config->server_info->primary->server_ip,
+ server->config->server_info->primary == NULL ? 0 :
+ server->config->server_info->primary->port);
+ if (!listener)
+ goto err;
- /* Close all connections */
- for (i = 0; i < server->config->param.connections_max; i++) {
- if (!server->sockets[i])
- continue;
- if (!SILC_IS_LISTENER(server->sockets[i])) {
- SilcSocketConnection sock = server->sockets[i];
- SilcIDListData idata = sock->user_data;
-
- if (idata)
- idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
-
- silc_schedule_task_del_by_context(server->schedule,
- server->sockets[i]);
- silc_schedule_task_del_by_fd(server->schedule,
- server->sockets[i]->sock);
- silc_server_disconnect_remote(server, server->sockets[i],
- SILC_STATUS_OK,
- "Server is shutting down");
- if (server->sockets[i]) {
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock,
- "Server is shutting down");
- silc_socket_free(sock);
- }
- } else {
- silc_socket_free(server->sockets[i]);
- server->sockets[i] = NULL;
- server->stat.conn_num--;
- }
+ silc_dlist_add(server->listeners, listener);
+
+#if 0
+ /* Perform name and address lookups to resolve the listenning address
+ and port. */
+ if (!silc_net_check_local_by_sock(sock, &newsocket->hostname,
+ &newsocket->ip)) {
+ 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 :
+ newsocket->ip ? newsocket->ip : ""));
+ server->stat.conn_failures++;
+ goto err;
}
+ if (!newsocket->hostname)
+ newsocket->hostname = strdup(newsocket->ip);
+ }
+ newsocket->port = silc_net_get_local_port(sock);
+#endif
- /* We are not connected to network anymore */
- server->standalone = TRUE;
+ /* Create a Server ID for the server. */
+ port = silc_net_listener_get_port(listener, NULL);
+ ip = silc_net_listener_get_ip(listener, NULL);
+ silc_id_create_server_id(ip[0], port[0], server->rng, &id);
+ if (!id)
+ goto err;
- silc_schedule_stop(server->schedule);
- silc_schedule_uninit(server->schedule);
- server->schedule = NULL;
+ silc_free(port);
+ silc_free(ip[0]);
+ silc_free(ip);
- silc_free(server->sockets);
- server->sockets = NULL;
+ server->id = id;
+ server->server_name = server->config->server_info->server_name;
+ server->config->server_info->server_name = NULL;
+
+ /* Add ourselves to the server list. We don't have a router yet
+ beacuse we haven't established a route yet. It will be done later.
+ For now, NULL is sent as router. This allocates new entry to
+ the ID list. */
+ id_entry =
+ silc_idlist_add_server(server->local_list, strdup(server->server_name),
+ server->server_type, server->id, NULL, NULL);
+ if (!id_entry) {
+ SILC_LOG_ERROR(("Could not add ourselves to cache"));
+ goto err;
}
+ id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+ server->id_entry = id_entry;
- silc_server_protocols_unregister();
+ /* Create secondary TCP listeners */
+ if (silc_server_init_secondary(server) == FALSE)
+ goto err;
- SILC_LOG_DEBUG(("Server stopped"));
-}
+ /* Create connections to configured routers. */
+ silc_server_create_connections(server);
-/* Function that is called when the network connection to a router has
- been established. This will continue with the key exchange protocol
- with the remote router. */
+ server->listenning = TRUE;
-void silc_server_start_key_exchange(SilcServer server,
- SilcServerConnection sconn,
- int sock)
-{
- SilcSocketConnection newsocket;
- SilcProtocol protocol;
- SilcServerKEInternalContext *proto_ctx;
- SilcServerConfigRouter *conn =
- (SilcServerConfigRouter *) sconn->conn.ref_ptr;
- void *context;
+ /* Allocate the entire socket list that is used in server. Eventually
+ all connections will have entry in this table (it is a table of
+ pointers to the actual object that is allocated individually
+ later). */
+ server->sockets = silc_calloc(server->config->param.connections_max,
+ sizeof(*server->sockets));
+ if (!server->sockets)
+ goto err;
- /* Cancel any possible retry timeouts */
- silc_schedule_task_del_by_callback(server->schedule,
- silc_server_connect_to_router_retry);
-
- /* Set socket options */
- silc_net_set_socket_nonblock(sock);
- silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
- /* Create socket connection for the connection. Even though we
- know that we are connecting to a router we will mark the socket
- to be unknown connection until we have executed authentication
- protocol. */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
- server->sockets[sock] = newsocket;
- newsocket->hostname = strdup(sconn->remote_host);
- newsocket->ip = strdup(sconn->remote_host);
- newsocket->port = sconn->remote_port;
- sconn->sock = newsocket;
-
- /* Allocate internal protocol context. This is sent as context
- to the protocol. */
- proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
- proto_ctx->server = (void *)server;
- proto_ctx->context = (void *)sconn;
- proto_ctx->sock = newsocket;
- proto_ctx->rng = server->rng;
- proto_ctx->responder = FALSE;
+ /* If server connections has been configured then we must be router as
+ normal server cannot have server connections, only router connections. */
+ if (server->config->servers) {
+ SilcServerConfigServer *ptr = server->config->servers;
- /* Set Key Exchange flags from configuration, but fall back to global
- settings too. */
- SILC_GET_SKE_FLAGS(conn, proto_ctx);
- if (server->config->param.key_exchange_pfs)
- proto_ctx->flags |= SILC_SKE_SP_FLAG_PFS;
-
- /* Perform key exchange protocol. silc_server_connect_to_router_second
- will be called after the protocol is finished. */
- silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
- &protocol, proto_ctx,
- silc_server_connect_to_router_second);
- newsocket->protocol = protocol;
-
- /* Register a timeout task that will be executed if the protocol
- is not executed within set limit. */
- proto_ctx->timeout_task =
- silc_schedule_task_add(server->schedule, sock,
- silc_server_timeout_remote,
- server, server->config->key_exchange_timeout, 0,
- 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
- and sets that outgoing packets may be sent to this connection as
- well. However, this doesn't set the scheduler for outgoing traffic,
- it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
- later when outgoing data is available. */
- context = (void *)server;
- SILC_REGISTER_CONNECTION_FOR_IO(sock);
-
- /* Run the protocol */
- silc_protocol_execute(protocol, server->schedule, 0, 0);
-}
+ server->server_type = SILC_ROUTER;
+ while (ptr) {
+ if (ptr->backup_router) {
+ server->server_type = SILC_BACKUP_ROUTER;
+ server->backup_router = TRUE;
+ server->id_entry->server_type = SILC_BACKUP_ROUTER;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ }
-/* Timeout callback that will be called to retry connecting to remote
- router. This is used by both normal and router server. This will wait
- before retrying the connecting. The timeout is generated by exponential
- backoff algorithm. */
+ /* Register the ID Cache purge task. This periodically purges the ID cache
+ and removes the expired cache entries. */
-SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
-{
- SilcServer server = app_context;
- SilcServerConnection sconn = (SilcServerConnection)context;
- SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
- SilcServerConfigConnParams *param =
- (conn->param ? conn->param : &server->config->param);
+ /* Clients local list */
+ server->purge_i = purge = silc_calloc(1, sizeof(*purge));
+ purge->cache = server->local_list->clients;
+ purge->timeout = 600;
+ silc_schedule_task_add_timeout(server->schedule, silc_idlist_purge,
+ (void *)purge, purge->timeout, 0);
- /* Don't retry if we are shutting down. */
- if (server->server_shutdown) {
- silc_server_config_unref(&sconn->conn);
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- return;
- }
+ /* Clients global list */
+ server->purge_g = purge = silc_calloc(1, sizeof(*purge));
+ purge->cache = server->global_list->clients;
+ purge->timeout = 300;
+ silc_schedule_task_add_timeout(server->schedule, silc_idlist_purge,
+ (void *)purge, purge->timeout, 0);
- SILC_LOG_INFO(("Retrying connecting to a router"));
+ /* If we are normal server we'll retrieve network statisticial information
+ once in a while from the router. */
+ if (server->server_type != SILC_ROUTER)
+ silc_schedule_task_add_timeout(server->schedule, silc_server_get_stats,
+ server, 10, 0);
- /* Calculate next timeout */
- if (sconn->retry_count >= 1) {
- sconn->retry_timeout = sconn->retry_timeout * SILC_SERVER_RETRY_MULTIPLIER;
- if (sconn->retry_timeout > param->reconnect_interval_max)
- sconn->retry_timeout = param->reconnect_interval_max;
- } else {
- 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 (server->server_type == SILC_ROUTER)
+ server->stat.routers++;
- /* If we've reached max retry count, give up. */
- if ((sconn->retry_count > param->reconnect_count) &&
- !param->reconnect_keep_trying) {
- SILC_LOG_ERROR(("Could not connect to router, giving up"));
- silc_server_config_unref(&sconn->conn);
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- return;
- }
+ /* Start packet engine */
+ server->packet_engine =
+ silc_packet_engine_start(server->rng, server->server_type == SILC_ROUTER,
+ &silc_server_stream_cbs, server);
+ if (!server->packet_engine)
+ goto err;
- SILC_LOG_DEBUG(("Retrying connecting to a router in %d seconds",
- sconn->retry_timeout));
+ SILC_LOG_DEBUG(("Server initialized"));
- /* We will lookup a fresh pointer later */
- silc_server_config_unref(&sconn->conn);
+ /* We are done here, return succesfully */
+ return TRUE;
- /* Wait one before retrying */
- silc_schedule_task_add(server->schedule, 0, silc_server_connect_router,
- context, sconn->retry_timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ err:
+ silc_server_config_unref(&server->config_ref);
+ return FALSE;
}
-/* Callback for async connection to remote router */
+#if 0
+/* Task callback to close a socket connection after rehash */
-SILC_TASK_CALLBACK(silc_server_connection_established)
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
{
- SilcServer server = app_context;
- SilcServerConnection sconn = (SilcServerConnection)context;
- int sock = fd;
- int opt = EINVAL, optlen = sizeof(opt), ret;
-
- ret = silc_net_get_socket_opt(sock, SOL_SOCKET, SO_ERROR, &opt, &optlen);
-
- silc_schedule_task_del_by_fd(server->schedule, sock);
- silc_schedule_unset_listen_fd(server->schedule, sock);
+ SilcServer server = context;
+ SilcPacketStream sock = server->sockets[fd];
- if (ret != 0 || opt != 0) {
- SILC_LOG_ERROR(("Could not connect to router %s:%d: %s",
- sconn->remote_host, sconn->remote_port, strerror(opt)));
- silc_net_close_connection(sock);
- if (!sconn->no_reconnect) {
- silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_to_router_retry,
- context, 1, 0, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- } else {
- silc_server_config_unref(&sconn->conn);
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- }
+ if (!sock)
return;
- }
-
- SILC_LOG_DEBUG(("Connection to router %s:%d established", sconn->remote_host,
- sconn->remote_port));
- /* Continue with key exchange protocol */
- silc_server_start_key_exchange(server, sconn, sock);
+ SILC_LOG_INFO(("Connection %s:%d [%s] is unconfigured",
+ sock->hostname, sock->port,
+ (sock->type == SILC_CONN_UNKNOWN ? "Unknown" :
+ sock->type == SILC_CONN_CLIENT ? "Client" :
+ sock->type == SILC_CONN_SERVER ? "Server" :
+ "Router")));
+ silc_schedule_task_del_by_context(server->schedule, sock);
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_BANNED_FROM_SERVER,
+ "This connection is removed from "
+ "configuration");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
}
+#endif /* 0 */
-/* Generic routine to use connect to a router. */
+/* This function basically reads the config file again and switches the config
+ object pointed by the server object. After that, we have to fix various
+ things such as the server_name and the listening ports.
+ Keep in mind that we no longer have the root privileges at this point. */
-SILC_TASK_CALLBACK(silc_server_connect_router)
+SilcBool silc_server_rehash(SilcServer server)
{
- SilcServer server = app_context;
- SilcServerConnection sconn = (SilcServerConnection)context;
- SilcServerConfigRouter *rconn;
- int sock;
+#if 0
+ SilcServerConfig newconfig;
- /* Don't connect if we are shutting down. */
- if (server->server_shutdown) {
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- return;
- }
+ SILC_LOG_INFO(("Rehashing server"));
- SILC_LOG_INFO(("Connecting to the %s %s on port %d",
- (sconn->backup ? "backup router" : "router"),
- sconn->remote_host, sconn->remote_port));
+ /* Reset the logging system */
+ silc_log_quick(TRUE);
+ silc_log_flush_all();
- server->router_connect = time(NULL);
- rconn = silc_server_config_find_router_conn(server, sconn->remote_host,
- sconn->remote_port);
- if (!rconn) {
- SILC_LOG_INFO(("Unconfigured %s connection %s:%d, cannot connect",
- (sconn->backup ? "backup router" : "router"),
- sconn->remote_host, sconn->remote_port));
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- return;
+ /* Start the main rehash phase (read again the config file) */
+ newconfig = silc_server_config_alloc(server->config_file, server);
+ if (!newconfig) {
+ SILC_LOG_ERROR(("Rehash FAILED."));
+ return FALSE;
}
- silc_server_config_ref(&sconn->conn, server->config, (void *)rconn);
- /* Connect to remote host */
- sock = silc_net_create_connection_async(
- (!server->config->server_info->primary ? NULL :
- server->config->server_info->primary->server_ip),
- sconn->remote_port, sconn->remote_host);
- if (sock < 0) {
- SILC_LOG_ERROR(("Could not connect to router %s:%d",
- sconn->remote_host, sconn->remote_port));
- if (!sconn->no_reconnect) {
- silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_to_router_retry,
- context, 1, 0, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- } else {
- silc_server_config_unref(&sconn->conn);
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- }
- return;
- }
+ /* Reinit scheduler if necessary */
+ if (newconfig->param.connections_max > server->config->param.connections_max)
+ if (!silc_schedule_reinit(server->schedule,
+ newconfig->param.connections_max))
+ return FALSE;
- /* wait for the connection to be established */
- silc_schedule_task_add(server->schedule, sock,
- silc_server_connection_established,
- context, 0, 0, SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL);
- silc_schedule_set_listen_fd(server->schedule, sock,
- SILC_TASK_WRITE, FALSE);
-}
+ /* Fix the server_name field */
+ if (strcmp(server->server_name, newconfig->server_info->server_name)) {
+ silc_free(server->server_name);
-/* This function connects to our primary router or if we are a router this
- establishes all our primary routes. This is called at the start of the
- server to do authentication and key exchange with our router - called
- from schedule. */
+ /* Check server name */
+ server->server_name =
+ silc_identifier_check(newconfig->server_info->server_name,
+ strlen(newconfig->server_info->server_name),
+ SILC_STRING_LOCALE, 256, NULL);
+ if (!server->server_name) {
+ SILC_LOG_ERROR(("Malformed server name string '%s'",
+ server->config->server_info->server_name));
+ return FALSE;
+ }
-SILC_TASK_CALLBACK_GLOBAL(silc_server_connect_to_router)
-{
- SilcServer server = (SilcServer)context;
- SilcServerConnection sconn;
- SilcServerConfigRouter *ptr;
+ /* Update the idcache list with a fresh pointer */
+ silc_free(server->id_entry->server_name);
+ server->id_entry->server_name = strdup(server->server_name);
+ if (!silc_idcache_del_by_context(server->local_list->servers,
+ server->id_entry))
+ return FALSE;
+ if (!silc_idcache_add(server->local_list->servers,
+ strdup(server->id_entry->server_name),
+ server->id_entry->id, server->id_entry, 0, NULL))
+ return FALSE;
+ }
- /* Don't connect if we are shutting down. */
- if (server->server_shutdown)
- return;
+ /* Set logging */
+ silc_server_config_setlogfiles(server);
- SILC_LOG_DEBUG(("We are %s",
- (server->server_type == SILC_SERVER ?
- "normal server" : server->server_type == SILC_ROUTER ?
- "router" : "backup router/normal server")));
+ /* Change new key pair if necessary */
+ if (newconfig->server_info->public_key &&
+ !silc_pkcs_public_key_compare(server->public_key,
+ newconfig->server_info->public_key)) {
+ silc_pkcs_public_key_free(server->public_key);
+ silc_pkcs_private_key_free(server->private_key);
+ server->public_key = newconfig->server_info->public_key;
+ server->private_key = newconfig->server_info->private_key;
+ newconfig->server_info->public_key = NULL;
+ newconfig->server_info->private_key = NULL;
- if (!server->config->routers) {
- /* There wasn't a configured router, we will continue but we don't
- have a connection to outside world. We will be standalone server. */
- SILC_LOG_DEBUG(("No router(s), we are standalone"));
- server->standalone = TRUE;
- return;
+ /* Allocate PKCS context for local public and private keys */
+ silc_pkcs_free(server->pkcs);
+ if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
+ return FALSE;
+ silc_pkcs_public_key_set(server->pkcs, server->public_key);
+ silc_pkcs_private_key_set(server->pkcs, server->private_key);
}
- /* Cancel any possible retry timeouts */
- silc_schedule_task_del_by_callback(server->schedule,
- silc_server_connect_router);
- silc_schedule_task_del_by_callback(server->schedule,
- silc_server_connect_to_router_retry);
-
- /* Create the connections to all our routes */
- for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+ /* Check for unconfigured server and router connections and close
+ connections that were unconfigured. */
- SILC_LOG_DEBUG(("%s connection [%s] %s:%d",
- ptr->backup_router ? "Backup router" : "Router",
- ptr->initiator ? "Initiator" : "Responder",
- ptr->host, ptr->port));
+ if (server->config->routers) {
+ SilcServerConfigRouter *ptr;
+ SilcServerConfigRouter *newptr;
+ SilcBool found;
- if (server->server_type == SILC_ROUTER && ptr->backup_router &&
- ptr->initiator == FALSE && !server->backup_router &&
- !silc_server_config_get_backup_router(server))
- server->wait_backup = TRUE;
+ for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+ found = FALSE;
- if (ptr->initiator) {
- /* Check whether we are connecting or connected to this host already */
- if (silc_server_num_sockets_by_remote(server,
- silc_net_is_ip(ptr->host) ?
- ptr->host : NULL,
- silc_net_is_ip(ptr->host) ?
- NULL : ptr->host, ptr->port,
- SILC_SOCKET_TYPE_ROUTER)) {
- SILC_LOG_DEBUG(("We are already connected to this router"));
-
- /* If we don't have primary router and this connection is our
- primary router we are in desync. Reconnect to the primary. */
- if (server->standalone && !server->router) {
- SilcServerConfigRouter *primary =
- silc_server_config_get_primary_router(server);
- if (primary == ptr) {
- SilcSocketConnection sock =
- silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
- ptr->host, ptr->port);
- if (sock) {
- server->backup_noswitch = TRUE;
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
- silc_server_disconnect_remote(server, sock, 0, NULL);
- server->backup_noswitch = FALSE;
- SILC_LOG_DEBUG(("Reconnecting to primary router"));
- } else {
- continue;
- }
- } else {
- continue;
- }
- } else {
- continue;
+ /* Check whether new config has this one too */
+ for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
+ if (silc_string_compare(newptr->host, ptr->host) &&
+ newptr->port == ptr->port &&
+ newptr->initiator == ptr->initiator) {
+ found = TRUE;
+ break;
}
}
- if (silc_server_num_sockets_by_remote(server,
- silc_net_is_ip(ptr->host) ?
- ptr->host : NULL,
- silc_net_is_ip(ptr->host) ?
- NULL : ptr->host, ptr->port,
- SILC_SOCKET_TYPE_UNKNOWN)) {
- SILC_LOG_DEBUG(("We are already connecting to this router"));
- continue;
- }
- /* Allocate connection object for hold connection specific stuff. */
- sconn = silc_calloc(1, sizeof(*sconn));
- sconn->remote_host = strdup(ptr->host);
- sconn->remote_port = ptr->port;
- sconn->backup = ptr->backup_router;
- if (sconn->backup) {
- sconn->backup_replace_ip = strdup(ptr->backup_replace_ip);
- sconn->backup_replace_port = ptr->backup_replace_port;
+ if (!found && ptr->host) {
+ /* Remove this connection */
+ SilcPacketStream sock;
+ sock = silc_server_find_socket_by_host(server, SILC_CONN_ROUTER,
+ ptr->host, ptr->port);
+ if (sock && !SILC_IS_LISTENER(sock))
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rehash_close_connection,
+ server, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
-
- if (!server->router_conn && !sconn->backup)
- server->router_conn = sconn;
-
- silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_router,
- (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
}
}
-}
-/* Second part of connecting to router(s). Key exchange protocol has been
- executed and now we will execute authentication protocol. */
-
-SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
-{
- SilcProtocol protocol = (SilcProtocol)context;
- SilcServerKEInternalContext *ctx =
- (SilcServerKEInternalContext *)protocol->context;
- SilcServer server = (SilcServer)ctx->server;
- SilcServerConnection sconn = (SilcServerConnection)ctx->context;
- SilcSocketConnection sock = ctx->sock;
- SilcServerConnAuthInternalContext *proto_ctx;
- SilcServerConfigRouter *conn = NULL;
+ if (server->config->servers) {
+ SilcServerConfigServer *ptr;
+ SilcServerConfigServer *newptr;
+ SilcBool found;
- SILC_LOG_DEBUG(("Start"));
+ for (ptr = server->config->servers; ptr; ptr = ptr->next) {
+ found = FALSE;
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
- protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
- /* Error occured during protocol */
- silc_protocol_free(protocol);
- sock->protocol = NULL;
- silc_ske_free_key_material(ctx->keymat);
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_free(ctx->dest_id);
- silc_free(ctx);
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ /* Check whether new config has this one too */
+ for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
+ if (silc_string_compare(newptr->host, ptr->host)) {
+ found = TRUE;
+ break;
+ }
+ }
- /* Try reconnecting if configuration wants it */
- if (!sconn->no_reconnect) {
- silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_to_router_retry,
- sconn, 1, 0, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- return;
+ if (!found && ptr->host) {
+ /* Remove this connection */
+ SilcPacketStream sock;
+ sock = silc_server_find_socket_by_host(server, SILC_CONN_SERVER,
+ ptr->host, 0);
+ if (sock && !SILC_IS_LISTENER(sock))
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rehash_close_connection,
+ server, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ }
}
-
- /* Call completion to indicate error */
- if (sconn->callback)
- (*sconn->callback)(server, NULL, sconn->callback_context);
-
- silc_server_config_unref(&sconn->conn);
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- return;
}
- /* We now have the key material as the result of the key exchange
- protocol. Take the key material into use. Free the raw key material
- as soon as we've set them into use. */
- if (!silc_server_protocol_ke_set_keys(server, ctx->ske,
- ctx->sock, ctx->keymat,
- ctx->ske->prop->cipher,
- ctx->ske->prop->pkcs,
- ctx->ske->prop->hash,
- ctx->ske->prop->hmac,
- ctx->ske->prop->group,
- ctx->responder)) {
- silc_protocol_free(protocol);
- sock->protocol = NULL;
- silc_ske_free_key_material(ctx->keymat);
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_free(ctx->dest_id);
- silc_free(ctx);
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
-
- /* Try reconnecting if configuration wants it */
- if (!sconn->no_reconnect) {
- silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_to_router_retry,
- sconn, 1, 0, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- return;
- }
+ if (server->config->clients) {
+ SilcServerConfigClient *ptr;
+ SilcServerConfigClient *newptr;
+ SilcBool found;
- /* Call completion to indicate error */
- if (sconn->callback)
- (*sconn->callback)(server, NULL, sconn->callback_context);
+ for (ptr = server->config->clients; ptr; ptr = ptr->next) {
+ found = FALSE;
- silc_server_config_unref(&sconn->conn);
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- return;
- }
- silc_ske_free_key_material(ctx->keymat);
-
- /* Allocate internal context for the authentication protocol. This
- is sent as context for the protocol. */
- proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
- proto_ctx->server = (void *)server;
- proto_ctx->context = (void *)sconn;
- proto_ctx->sock = sock;
- proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
- proto_ctx->dest_id_type = ctx->dest_id_type;
- proto_ctx->dest_id = ctx->dest_id;
-
- /* Resolve the authentication method used in this connection. Check if
- we find a match from user configured connections */
- if (!sconn->conn.ref_ptr)
- conn = silc_server_config_find_router_conn(server, sock->hostname,
- sock->port);
- else
- conn = sconn->conn.ref_ptr;
+ /* Check whether new config has this one too */
+ for (newptr = newconfig->clients; newptr; newptr = newptr->next) {
+ if (silc_string_compare(newptr->host, ptr->host)) {
+ found = TRUE;
+ break;
+ }
+ }
- if (conn) {
- /* Match found. Use the configured authentication method. Take only
- the passphrase, since for public key auth we automatically use
- our local key pair. */
- if (conn->passphrase) {
- if (conn->publickeys && !server->config->prefer_passphrase_auth) {
- proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
- } else {
- proto_ctx->auth_data = strdup(conn->passphrase);
- proto_ctx->auth_data_len = strlen(conn->passphrase);
- proto_ctx->auth_meth = SILC_AUTH_PASSWORD;
+ if (!found && ptr->host) {
+ /* Remove this connection */
+ SilcPacketStream sock;
+ sock = silc_server_find_socket_by_host(server, SILC_CONN_CLIENT,
+ ptr->host, 0);
+ if (sock)
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rehash_close_connection,
+ server, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
- } else if (conn->publickeys) {
- proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
- } else {
- proto_ctx->auth_meth = SILC_AUTH_NONE;
}
- } else {
- SILC_LOG_ERROR(("Could not find connection data for %s (%s) on port",
- sock->hostname, sock->ip, sock->port));
- silc_protocol_free(protocol);
- sock->protocol = NULL;
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_free(ctx->dest_id);
- silc_free(ctx);
- silc_server_config_unref(&sconn->conn);
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
- return;
}
- /* Free old protocol as it is finished now */
- silc_protocol_free(protocol);
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- silc_free(ctx);
- sock->protocol = NULL;
-
- /* Allocate the authentication protocol. This is allocated here
- but we won't start it yet. We will be receiving party of this
- protocol thus we will wait that connecting party will make
- their first move. */
- silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
- &sock->protocol, proto_ctx,
- silc_server_connect_to_router_final);
-
- /* Register timeout task. If the protocol is not executed inside
- 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,
- server->config->conn_auth_timeout, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
-
- /* Run the protocol */
- silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-}
-
-/* Finalizes the connection to router. Registers a server task to the
- queue so that we can accept new connections. */
-
-SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
-{
- SilcProtocol protocol = (SilcProtocol)context;
- SilcServerConnAuthInternalContext *ctx =
- (SilcServerConnAuthInternalContext *)protocol->context;
- SilcServer server = (SilcServer)ctx->server;
- SilcServerConnection sconn = (SilcServerConnection)ctx->context;
- SilcSocketConnection sock = ctx->sock;
- SilcServerEntry id_entry = NULL;
- SilcBuffer packet;
- unsigned char *id_string;
- SilcUInt32 id_len;
- SilcIDListData idata;
- SilcServerConfigRouter *conn = NULL;
- SilcServerConfigConnParams *param = NULL;
-
- SILC_LOG_DEBUG(("Start"));
+ /* Create connections after rehash */
+ silc_server_create_connections(server);
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
- protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
- /* Error occured during protocol */
- silc_free(ctx->dest_id);
- sock->protocol = NULL;
- silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
- NULL);
- sock->protocol = protocol;
+ /* Check whether our router status has changed */
+ if (newconfig->servers) {
+ SilcServerConfigServer *ptr = newconfig->servers;
- /* Try reconnecting if configuration wants it */
- if (!sconn->no_reconnect) {
- silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_to_router_retry,
- sconn, 1, 0, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- goto out2;
+ server->server_type = SILC_ROUTER;
+ while (ptr) {
+ if (ptr->backup_router) {
+ server->server_type = SILC_BACKUP_ROUTER;
+ server->backup_router = TRUE;
+ server->id_entry->server_type = SILC_BACKUP_ROUTER;
+ break;
+ }
+ ptr = ptr->next;
}
-
- goto out;
}
- /* Add a task to the queue. This task receives new connections to the
- server. This task remains on the queue until the end of the program. */
- if (!server->listenning && !sconn->backup) {
- silc_schedule_task_add(server->schedule, server->sock,
- silc_server_accept_new_connection,
- (void *)server, 0, 0,
- SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL);
- server->listenning = TRUE;
- }
-
- /* Send NEW_SERVER packet to the router. We will become registered
- to the SILC network after sending this packet. */
- id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
- id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
- packet = silc_buffer_alloc(2 + 2 + id_len + strlen(server->server_name));
- silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
- silc_buffer_format(packet,
- SILC_STR_UI_SHORT(id_len),
- SILC_STR_UI_XNSTRING(id_string, id_len),
- SILC_STR_UI_SHORT(strlen(server->server_name)),
- SILC_STR_UI_XNSTRING(server->server_name,
- strlen(server->server_name)),
- SILC_STR_END);
-
- /* Send the packet */
- silc_server_packet_send(server, ctx->sock, SILC_PACKET_NEW_SERVER, 0,
- packet->data, packet->len, TRUE);
- silc_buffer_free(packet);
- silc_free(id_string);
-
- SILC_LOG_INFO(("Connected to router %s", sock->hostname));
-
- /* Check that we do not have this ID already */
- id_entry = silc_idlist_find_server_by_id(server->local_list,
- ctx->dest_id, TRUE, NULL);
- if (id_entry) {
- silc_idcache_del_by_context(server->local_list->servers, id_entry);
- } else {
- id_entry = silc_idlist_find_server_by_id(server->global_list,
- ctx->dest_id, TRUE, NULL);
- if (id_entry)
- silc_idcache_del_by_context(server->global_list->servers, id_entry);
- }
+ /* Our old config is gone now. We'll unreference our reference made in
+ silc_server_init and then destroy it since we are destroying it
+ underneath the application (layer which called silc_server_init). */
+ silc_server_config_unref(&server->config_ref);
+ silc_server_config_destroy(server->config);
- SILC_LOG_DEBUG(("New server id(%s)",
- silc_id_render(ctx->dest_id, SILC_ID_SERVER)));
+ /* Take new config context */
+ server->config = newconfig;
+ silc_server_config_ref(&server->config_ref, server->config, server->config);
- /* Add the connected router to global server list. Router is sent
- as NULL since it's local to us. */
- id_entry = silc_idlist_add_server(server->global_list,
- strdup(sock->hostname),
- SILC_ROUTER, ctx->dest_id, NULL, sock);
- if (!id_entry) {
- silc_free(ctx->dest_id);
- SILC_LOG_ERROR(("Cannot add new server entry to cache"));
- sock->protocol = NULL;
- silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
- NULL);
- sock->protocol = protocol;
- goto out;
+#ifdef SILC_DEBUG
+ /* Set debugging on if configured */
+ if (server->config->debug_string) {
+ silc_log_debug(TRUE);
+ silc_log_set_debug_string(server->config->debug_string);
}
+#endif /* SILC_DEBUG */
- silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
- silc_free(sock->user_data);
- sock->user_data = (void *)id_entry;
- sock->type = SILC_SOCKET_TYPE_ROUTER;
- idata = (SilcIDListData)sock->user_data;
- idata->status |= (SILC_IDLIST_STATUS_REGISTERED |
- SILC_IDLIST_STATUS_LOCAL);
-
- conn = sconn->conn.ref_ptr;
- param = &server->config->param;
- if (conn && conn->param)
- param = conn->param;
-
- /* Perform keepalive. */
- silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
- silc_server_perform_heartbeat,
- server->schedule);
-
- /* Register re-key timeout */
- idata->rekey->timeout = param->key_exchange_rekey;
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rekey_callback,
- (void *)sock, idata->rekey->timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-
- if (!sconn->backup) {
- /* Mark this router our primary router if we're still standalone */
- if (server->standalone) {
- SILC_LOG_DEBUG(("This connection is our primary router"));
- server->id_entry->router = id_entry;
- server->router = id_entry;
- server->router->server_type = SILC_ROUTER;
- server->standalone = FALSE;
- server->backup_primary = FALSE;
-
- /* Announce data if we are not backup router (unless not as primary
- currently). Backup router announces later at the end of
- resuming protocol. */
- if (server->backup_router && server->server_type == SILC_ROUTER) {
- SILC_LOG_DEBUG(("Announce data after resume protocol"));
- } else {
- /* If we are router then announce our possible servers. Backup
- router announces also global servers. */
- if (server->server_type == SILC_ROUTER)
- silc_server_announce_servers(server,
- server->backup_router ? TRUE : FALSE,
- 0, SILC_PRIMARY_ROUTE(server));
-
- /* Announce our clients and channels to the router */
- silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server));
- silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
- }
-
- /* If we are backup router then this primary router is whom we are
- backing up. */
- if (server->server_type == SILC_BACKUP_ROUTER)
- silc_server_backup_add(server, server->id_entry, sock->ip,
- sconn->remote_port, TRUE);
- }
- } else {
- /* Add this server to be our backup router */
- id_entry->server_type = SILC_BACKUP_ROUTER;
- silc_server_backup_add(server, id_entry, sconn->backup_replace_ip,
- sconn->backup_replace_port, FALSE);
- }
+ SILC_LOG_DEBUG(("Server rehashed"));
+#endif /* 0 */
- sock->protocol = NULL;
+ return TRUE;
+}
- out:
- /* Call the completion callback to indicate that we've connected to
- the router */
- if (sconn && sconn->callback)
- (*sconn->callback)(server, id_entry, sconn->callback_context);
+/* The heart of the server. This runs the scheduler thus runs the server.
+ When this returns the server has been stopped and the program will
+ be terminated. */
- /* Free the temporary connection data context */
- if (sconn) {
- silc_server_config_unref(&sconn->conn);
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- }
- if (sconn == server->router_conn)
- server->router_conn = NULL;
+void silc_server_run(SilcServer server)
+{
+ SILC_LOG_INFO(("SILC Server started"));
- out2:
- /* Free the protocol object */
- if (sock->protocol == protocol)
- sock->protocol = NULL;
- silc_protocol_free(protocol);
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- if (ctx->auth_meth == SILC_AUTH_PASSWORD)
- silc_free(ctx->auth_data);
- silc_free(ctx);
+ /* Start the scheduler, the heart of the SILC server. When this returns
+ the program will be terminated. */
+ silc_schedule(server->schedule);
}
-/* Host lookup callback that is called after the incoming connection's
- IP and FQDN lookup is performed. This will actually check the acceptance
- of the incoming connection and will register the key exchange protocol
- for this connection. */
-
-static void
-silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
- void *context)
+/* Stops the SILC server. This function is used to shutdown the server.
+ This is usually called after the scheduler has returned. After stopping
+ the server one should call silc_server_free. */
+
+void silc_server_stop(SilcServer server)
{
- SilcServerKEInternalContext *proto_ctx =
- (SilcServerKEInternalContext *)context;
- SilcServer server = (SilcServer)proto_ctx->server;
- SilcServerConfigClient *cconfig = NULL;
- SilcServerConfigServer *sconfig = NULL;
- SilcServerConfigRouter *rconfig = NULL;
- SilcServerConfigDeny *deny;
- int port;
-
- /* Check whether we could resolve both IP and FQDN. */
- if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
- server->config->require_reverse_lookup)) {
- SILC_LOG_ERROR(("IP/DNS lookup failed %s",
- sock->hostname ? sock->hostname :
- sock->ip ? sock->ip : ""));
- server->stat.conn_failures++;
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
- "Unknown host or IP");
- silc_free(proto_ctx);
- return;
- }
+ SilcDList list;
+ SilcPacketStream ps;
- /* Register the connection for network input and output. This sets
- that scheduler will listen for incoming packets for this connection
- and sets that outgoing packets may be sent to this connection as well.
- However, this doesn't set the scheduler for outgoing traffic, it
- will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
- later when outgoing data is available. */
- context = (void *)server;
- SILC_REGISTER_CONNECTION_FOR_IO(sock->sock);
+ SILC_LOG_INFO(("SILC Server shutting down"));
- SILC_LOG_INFO(("Incoming connection %s (%s)", sock->hostname,
- sock->ip));
+ server->server_shutdown = TRUE;
- /* Listenning port */
- if (!server->sockets[SILC_PTR_TO_32(proto_ctx->context)]) {
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_RESOURCE_LIMIT,
- "Connection refused");
- server->stat.conn_failures++;
- silc_free(proto_ctx);
- return;
- }
- port = server->sockets[SILC_PTR_TO_32(proto_ctx->context)]->port;
+ /* Close all connections */
+ if (server->packet_engine) {
+ list = silc_packet_engine_get_streams(server->packet_engine);
- /* Check whether this connection is denied to connect to us. */
- deny = silc_server_config_find_denied(server, sock->ip);
- if (!deny)
- deny = silc_server_config_find_denied(server, sock->hostname);
- if (deny) {
- /* The connection is denied */
- SILC_LOG_INFO(("Connection %s (%s) is denied",
- sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_BANNED_FROM_SERVER,
- deny->reason);
- server->stat.conn_failures++;
- silc_free(proto_ctx);
- return;
- }
+ silc_dlist_start(list);
+ while ((ps = silc_dlist_get(list))) {
+ SilcIDListData idata = silc_packet_get_context(ps);
- /* Check whether we have configured this sort of connection at all. We
- have to check all configurations since we don't know what type of
- connection this is. */
- if (!(cconfig = silc_server_config_find_client(server, sock->ip)))
- cconfig = silc_server_config_find_client(server, sock->hostname);
- if (!(sconfig = silc_server_config_find_server_conn(server, sock->ip)))
- sconfig = silc_server_config_find_server_conn(server, sock->hostname);
- if (server->server_type == SILC_ROUTER) {
- if (!(rconfig = silc_server_config_find_router_conn(server,
- sock->ip, sock->port)))
- rconfig = silc_server_config_find_router_conn(server, sock->hostname,
- sock->port);
- }
- if (!cconfig && !sconfig && !rconfig) {
- SILC_LOG_INFO(("Connection %s (%s) is not allowed", sock->hostname,
- sock->ip));
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_BANNED_FROM_SERVER, NULL);
- server->stat.conn_failures++;
- silc_free(proto_ctx);
- return;
- }
+ if (idata)
+ idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
- /* The connection is allowed */
+ silc_server_disconnect_remote(server, ps, SILC_STATUS_OK,
+ "Server is shutting down");
+ silc_server_free_sock_user_data(server, ps,
+ "Server is shutting down");
+ }
+ }
- /* Set internal context for key exchange protocol. This is
- sent as context for the protocol. */
- proto_ctx->sock = sock;
- proto_ctx->rng = server->rng;
- proto_ctx->responder = TRUE;
- silc_server_config_ref(&proto_ctx->cconfig, server->config, cconfig);
- silc_server_config_ref(&proto_ctx->sconfig, server->config, sconfig);
- silc_server_config_ref(&proto_ctx->rconfig, server->config, rconfig);
+ /* We are not connected to network anymore */
+ server->standalone = TRUE;
- /* Take flags for key exchange. Since we do not know what type of connection
- this is, we go through all found configurations and use the global ones
- as well. This will result always into strictest key exchange flags. */
- SILC_GET_SKE_FLAGS(cconfig, proto_ctx);
- SILC_GET_SKE_FLAGS(sconfig, proto_ctx);
- SILC_GET_SKE_FLAGS(rconfig, proto_ctx);
- if (server->config->param.key_exchange_pfs)
- proto_ctx->flags |= SILC_SKE_SP_FLAG_PFS;
+ silc_schedule_stop(server->schedule);
+ silc_schedule_uninit(server->schedule);
+ server->schedule = NULL;
- /* Prepare the connection for key exchange protocol. We allocate the
- protocol but will not start it yet. The connector will be the
- initiator of the protocol thus we will wait for initiation from
- there before we start the protocol. */
- server->stat.auth_attempts++;
- SILC_LOG_DEBUG(("Starting key exchange protocol"));
- silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
- &sock->protocol, proto_ctx,
- silc_server_accept_new_connection_second);
-
- /* Register a timeout task that will be executed if the connector
- will not start the key exchange protocol within specified timeout
- and the connection will be closed. */
- proto_ctx->timeout_task =
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_timeout_remote,
- (void *)server,
- server->config->key_exchange_timeout, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
+ SILC_LOG_DEBUG(("Server stopped"));
}
-/* Accepts new connections to the server. Accepting new connections are
- done in three parts to make it async. */
+#if 0
+/* Parses whole packet, received earlier. */
-SILC_TASK_CALLBACK(silc_server_accept_new_connection)
+SILC_TASK_CALLBACK(silc_server_packet_parse_real)
{
- SilcServer server = (SilcServer)context;
- SilcSocketConnection newsocket;
- SilcServerKEInternalContext *proto_ctx;
- int sock;
+ SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
+ SilcServer server = (SilcServer)parse_ctx->context;
+ SilcPacketStream sock = parse_ctx->sock;
+ SilcPacket *packet = parse_ctx->packet;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+ int ret;
- SILC_LOG_DEBUG(("Accepting new connection"));
+ if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
+ SILC_LOG_DEBUG(("Connection is disconnected"));
+ goto out;
+ }
- server->stat.conn_attempts++;
+ server->stat.packets_received++;
- sock = silc_net_accept_connection(fd);
- if (sock < 0) {
- SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
- server->stat.conn_failures++;
- return;
+ /* Parse the packet */
+ if (parse_ctx->normal)
+ ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL);
+ else
+ ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
+
+ /* If entry is disabled ignore what we got. */
+ if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
+ ret != SILC_PACKET_HEARTBEAT && ret != SILC_PACKET_RESUME_ROUTER &&
+ ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE &&
+ ret != SILC_PACKET_KEY_EXCHANGE_1 && ret != SILC_PACKET_KEY_EXCHANGE_2) {
+ SILC_LOG_DEBUG(("Connection is disabled (packet %s dropped)",
+ silc_get_packet_name(ret)));
+ goto out;
}
- /* Check for maximum allowed connections */
- if (sock > server->config->param.connections_max) {
- SILC_LOG_ERROR(("Refusing connection, server is full"));
- server->stat.conn_failures++;
- silc_net_close_connection(sock);
- return;
+ if (ret == SILC_PACKET_NONE) {
+ SILC_LOG_DEBUG(("Error parsing packet"));
+ goto out;
}
- server->stat.conn_num++;
- /* Set socket options */
- silc_net_set_socket_nonblock(sock);
- silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
- /* We don't create a ID yet, since we don't know what type of connection
- this is yet. But, we do add the connection to the socket table. */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
- server->sockets[sock] = newsocket;
-
- /* Perform asynchronous host lookup. This will lookup the IP and the
- FQDN of the remote connection. After the lookup is done the connection
- is accepted further. */
- proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
- proto_ctx->server = server;
- proto_ctx->context = SILC_32_TO_PTR(fd);
- silc_socket_host_lookup(newsocket, TRUE,
- silc_server_accept_new_connection_lookup,
- (void *)proto_ctx, server->schedule);
-}
+ /* Check that the the current client ID is same as in the client's packet. */
+ if (sock->type == SILC_CONN_CLIENT) {
+ SilcClientEntry client = (SilcClientEntry)sock->user_data;
+ if (client && client->id && packet->src_id) {
+ void *id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) {
+ silc_free(id);
+ SILC_LOG_DEBUG(("Packet source is not same as sender"));
+ goto out;
+ }
+ silc_free(id);
+ }
+ }
-/* Second part of accepting new connection. Key exchange protocol has been
- performed and now it is time to do little connection authentication
- protocol to figure out whether this connection is client or server
- and whether it has right to access this server (especially server
- connections needs to be authenticated). */
+ if (server->server_type == SILC_ROUTER) {
+ /* Route the packet if it is not destined to us. Other ID types but
+ server are handled separately after processing them. */
+ if (packet->dst_id && !(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
+ packet->dst_id_type == SILC_ID_SERVER &&
+ sock->type != SILC_CONN_CLIENT &&
+ memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
+ SilcPacketStream conn;
-SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
-{
- SilcProtocol protocol = (SilcProtocol)context;
- SilcServerKEInternalContext *ctx =
- (SilcServerKEInternalContext *)protocol->context;
- SilcServer server = (SilcServer)ctx->server;
- SilcSocketConnection sock = ctx->sock;
- SilcServerConnAuthInternalContext *proto_ctx;
+ /* Route the packet to fastest route for the destination ID */
+ void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ packet->dst_id_type);
+ if (!id)
+ goto out;
- SILC_LOG_DEBUG(("Start"));
+ conn = silc_server_route_get(server, id, packet->dst_id_type);
+ if (!conn) {
+ SILC_LOG_WARNING(("Packet to unknown server ID %s, dropped (no route)",
+ silc_id_render(id, SILC_ID_SERVER)));
+ goto out;
+ }
- if ((protocol->state == SILC_PROTOCOL_STATE_ERROR) ||
- (protocol->state == SILC_PROTOCOL_STATE_FAILURE)) {
- /* Error occured during protocol */
- SILC_LOG_DEBUG(("Error in key exchange protocol"));
- silc_protocol_free(protocol);
- sock->protocol = NULL;
- silc_ske_free_key_material(ctx->keymat);
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_free(ctx->dest_id);
- silc_server_config_unref(&ctx->cconfig);
- silc_server_config_unref(&ctx->sconfig);
- silc_server_config_unref(&ctx->rconfig);
- silc_free(ctx);
-
- if (!SILC_IS_DISCONNECTING(sock)) {
- SILC_LOG_INFO(("Key exchange failed for %s:%d [%s]", sock->hostname,
- sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
- NULL);
+ silc_server_packet_route(server, conn, packet);
+ silc_free(id);
+ goto out;
}
-
- server->stat.auth_failures++;
- return;
}
- /* We now have the key material as the result of the key exchange
- protocol. Take the key material into use. Free the raw key material
- as soon as we've set them into use. */
- if (!silc_server_protocol_ke_set_keys(server, ctx->ske,
- ctx->sock, ctx->keymat,
- ctx->ske->prop->cipher,
- ctx->ske->prop->pkcs,
- ctx->ske->prop->hash,
- ctx->ske->prop->hmac,
- ctx->ske->prop->group,
- ctx->responder)) {
- SILC_LOG_ERROR(("Error setting key material in use"));
- silc_protocol_free(protocol);
- sock->protocol = NULL;
- silc_ske_free_key_material(ctx->keymat);
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_free(ctx->dest_id);
- silc_server_config_unref(&ctx->cconfig);
- silc_server_config_unref(&ctx->sconfig);
- silc_server_config_unref(&ctx->rconfig);
- silc_free(ctx);
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
- server->stat.auth_failures++;
- return;
+ /* Parse the incoming packet type */
+ silc_server_packet_parse_type(server, sock, packet);
+
+ /* Broadcast packet if it is marked as broadcast packet and it is
+ originated from router and we are router. */
+ if (server->server_type == SILC_ROUTER &&
+ sock->type == SILC_CONN_ROUTER &&
+ packet->flags & SILC_PACKET_FLAG_BROADCAST) {
+ /* Broadcast to our primary route */
+ silc_server_packet_broadcast(server, SILC_PRIMARY_ROUTE(server), packet);
+
+ /* If we have backup routers then we need to feed all broadcast
+ data to those servers. */
+ silc_server_backup_broadcast(server, sock, packet);
}
- silc_ske_free_key_material(ctx->keymat);
-
- /* Allocate internal context for the authentication protocol. This
- is sent as context for the protocol. */
- proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
- proto_ctx->server = (void *)server;
- proto_ctx->sock = sock;
- proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
- proto_ctx->responder = TRUE;
- proto_ctx->dest_id_type = ctx->dest_id_type;
- proto_ctx->dest_id = ctx->dest_id;
- proto_ctx->cconfig = ctx->cconfig;
- proto_ctx->sconfig = ctx->sconfig;
- proto_ctx->rconfig = ctx->rconfig;
-
- /* Free old protocol as it is finished now */
- silc_protocol_free(protocol);
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- silc_free(ctx);
- sock->protocol = NULL;
-
- /* Allocate the authentication protocol. This is allocated here
- but we won't start it yet. We will be receiving party of this
- protocol thus we will wait that connecting party will make
- their first move. */
- SILC_LOG_DEBUG(("Starting connection authentication protocol"));
- silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
- &sock->protocol, proto_ctx,
- silc_server_accept_new_connection_final);
-
- /* Register timeout task. If the protocol is not executed inside
- 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,
- server->config->conn_auth_timeout, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
+
+ out:
+ silc_packet_context_free(packet);
+ silc_free(parse_ctx);
}
+#endif /* 0 */
-/* After this is called, server don't wait for backup router anymore.
- This gets called automatically even after we have backup router
- connection established. */
-SILC_TASK_CALLBACK(silc_server_backup_router_wait)
+/******************************* Connecting *********************************/
+
+/* Free connection context */
+
+static void silc_server_connection_free(SilcServerConnection sconn)
{
- SilcServer server = context;
- server->wait_backup = FALSE;
+ silc_dlist_del(sconn->server->conns, sconn);
+ silc_server_config_unref(&sconn->conn);
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
}
-/* Final part of accepting new connection. The connection has now
- been authenticated and keys has been exchanged. We also know whether
- this is client or server connection. */
+/* Creates connection to a remote router. */
-SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
+void silc_server_create_connection(SilcServer server,
+ SilcBool reconnect,
+ const char *remote_host, SilcUInt32 port,
+ SilcServerConnectCallback callback,
+ void *context)
{
- SilcProtocol protocol = (SilcProtocol)context;
- SilcServerConnAuthInternalContext *ctx =
- (SilcServerConnAuthInternalContext *)protocol->context;
- SilcServer server = (SilcServer)ctx->server;
- SilcSocketConnection sock = ctx->sock;
- SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
- void *id_entry;
- SilcServerConfigConnParams *param = &server->config->param;
+ SilcServerConnection sconn;
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
- protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
- /* Error occured during protocol */
- SILC_LOG_DEBUG(("Error during authentication protocol"));
- silc_protocol_free(protocol);
- sock->protocol = NULL;
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_free(ctx->dest_id);
- silc_server_config_unref(&ctx->cconfig);
- silc_server_config_unref(&ctx->sconfig);
- silc_server_config_unref(&ctx->rconfig);
- silc_free(ctx);
-
- if (!SILC_IS_DISCONNECTING(sock)) {
- SILC_LOG_INFO(("Authentication failed for %s:%d [%s]", sock->hostname,
- sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
- silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
- NULL);
- }
- server->stat.auth_failures++;
+ /* Allocate connection object for hold connection specific stuff. */
+ sconn = silc_calloc(1, sizeof(*sconn));
+ if (!sconn)
return;
- }
-
- entry->data.last_receive = time(NULL);
+ sconn->remote_host = strdup(remote_host);
+ sconn->remote_port = port;
+ sconn->no_reconnect = reconnect == FALSE;
+ sconn->callback = callback;
+ sconn->callback_context = context;
- switch (ctx->conn_type) {
- case SILC_SOCKET_TYPE_CLIENT:
- {
- SilcClientEntry client;
- SilcServerConfigClient *conn = ctx->cconfig.ref_ptr;
+ silc_schedule_task_add_timeout(server->schedule, silc_server_connect_router,
+ sconn, 0, 0);
+}
- /* 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;
- }
+/* Connection authentication completion callback */
- /* If we are primary router and we have backup router configured
- but it has not connected to use yet, do not accept any other
- connection. */
- if (server->wait_backup && server->server_type == SILC_ROUTER &&
- !server->backup_router) {
- SilcServerConfigRouter *router;
- router = silc_server_config_get_backup_router(server);
- if (router && strcmp(server->config->server_info->primary->server_ip,
- sock->ip) &&
- silc_server_find_socket_by_host(server,
- SILC_SOCKET_TYPE_SERVER,
- router->backup_replace_ip, 0)) {
- SILC_LOG_INFO(("Will not accept connections because we do "
- "not have backup router connection established"));
- sock->protocol = NULL;
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_PERM_DENIED,
- "We do not have connection to backup "
- "router established, try later");
- silc_free(sock->user_data);
- server->stat.auth_failures++;
+static void
+silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
+ void *context)
+{
+ SilcServerConnection sconn = context;
+ SilcUnknownEntry entry = silc_packet_get_context(sconn->sock);
+ SilcServer server = entry->server;
+ SilcServerConfigServer *conn;
+ SilcServerConfigConnParams *param;
+ SilcIDListData idata;
+ SilcServerEntry id_entry;
+ unsigned char id[32];
+ SilcUInt32 id_len;
+ SilcID remote_id;
- /* From here on, wait 20 seconds for the backup router to appear. */
- silc_schedule_task_add(server->schedule, 0,
- silc_server_backup_router_wait,
- (void *)server, 20, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- goto out;
- }
- }
+ SILC_LOG_DEBUG(("Connection authentication completed"));
- SILC_LOG_DEBUG(("Remote host is client"));
- SILC_LOG_INFO(("Connection %s (%s) is client", sock->hostname,
- sock->ip));
+ if (success == FALSE) {
+ /* Authentication failed */
+ /* XXX retry connecting */
- /* Add the client to the client ID cache. The nickname and Client ID
- and other information is created after we have received NEW_CLIENT
- packet from client. */
- client = silc_idlist_add_client(server->local_list,
- NULL, NULL, NULL, NULL, NULL, sock, 0);
- if (!client) {
- SILC_LOG_ERROR(("Could not add new client to cache"));
- silc_free(sock->user_data);
- sock->protocol = NULL;
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_AUTH_FAILED, NULL);
- server->stat.auth_failures++;
- goto out;
- }
- entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_AUTH_FAILED, NULL);
+ return;
+ }
- /* Statistics */
- server->stat.my_clients++;
- server->stat.clients++;
- server->stat.cell_clients++;
+ SILC_LOG_INFO(("Connected to %s %s",
+ SILC_CONNTYPE_STRING(entry->data.conn_type),
+ sconn->remote_host));
+
+ /* Create the actual entry for remote entity */
+ switch (entry->data.conn_type) {
+ case SILC_CONN_SERVER:
+ SILC_LOG_DEBUG(("Remote is SILC server"));
+
+ /* Add new server. The server must register itself to us before it
+ becomes registered to SILC network. */
+ id_entry = silc_idlist_add_server(server->local_list,
+ strdup(sconn->remote_host),
+ SILC_SERVER, NULL, NULL, sconn->sock);
+ if (!id_entry) {
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ silc_server_connection_free(sconn);
+ silc_free(entry);
+ return;
+ }
- /* Get connection parameters */
- if (conn->param) {
- param = conn->param;
+ silc_idlist_add_data(id_entry, (SilcIDListData)entry);
+ break;
- if (!param->keepalive_secs)
- param->keepalive_secs = server->config->param.keepalive_secs;
+ case SILC_CONN_ROUTER:
+ SILC_LOG_DEBUG(("Remote is SILC router"));
- if (!param->qos && server->config->param.qos) {
- param->qos = server->config->param.qos;
- param->qos_rate_limit = server->config->param.qos_rate_limit;
- param->qos_bytes_limit = server->config->param.qos_bytes_limit;
- param->qos_limit_sec = server->config->param.qos_limit_sec;
- param->qos_limit_usec = server->config->param.qos_limit_usec;
- }
+ /* Register to network */
+ silc_id_id2str(server->id, SILC_ID_SERVER, id, sizeof(id), &id_len);
+ if (!silc_packet_send_va(sconn->sock, SILC_PACKET_NEW_SERVER, 0,
+ SILC_STR_UI_SHORT(id_len),
+ SILC_STR_DATA(id, id_len),
+ SILC_STR_UI_SHORT(strlen(server->server_name)),
+ SILC_STR_DATA(server->server_name,
+ strlen(server->server_name)),
+ SILC_STR_END)) {
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ silc_server_connection_free(sconn);
+ silc_free(entry);
+ return;
+ }
- /* Check if to be anonymous connection */
- if (param->anonymous)
- client->mode |= SILC_UMODE_ANONYMOUS;
- }
+ /* Get remote ID */
+ silc_packet_get_ids(sconn->sock, NULL, NULL, NULL, &remote_id);
- /* Add public key to hash list (for whois using attributes) */
- if (!silc_hash_table_find_by_context(server->pk_hash,
- entry->data.public_key,
- client, NULL))
- silc_hash_table_add(server->pk_hash,
- entry->data.public_key, client);
+ /* Check that we do not have this ID already */
+ id_entry = silc_idlist_find_server_by_id(server->local_list,
+ &remote_id.u.server_id,
+ TRUE, NULL);
+ if (id_entry) {
+ silc_idcache_del_by_context(server->local_list->servers, id_entry, NULL);
+ } else {
+ id_entry = silc_idlist_find_server_by_id(server->global_list,
+ &remote_id.u.server_id,
+ TRUE, NULL);
+ if (id_entry)
+ silc_idcache_del_by_context(server->global_list->servers, id_entry,
+ NULL);
+ }
- id_entry = (void *)client;
- break;
+ SILC_LOG_DEBUG(("New server id(%s)",
+ silc_id_render(&remote_id.u.server_id, SILC_ID_SERVER)));
+
+ /* Add the connected router to global server list. Router is sent
+ as NULL since it's local to us. */
+ id_entry = silc_idlist_add_server(server->global_list,
+ strdup(sconn->remote_host),
+ SILC_ROUTER, &remote_id.u.server_id,
+ NULL, sconn->sock);
+ if (!id_entry) {
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ silc_server_connection_free(sconn);
+ silc_free(entry);
+ return;
}
- case SILC_SOCKET_TYPE_SERVER:
- case SILC_SOCKET_TYPE_ROUTER:
- {
- SilcServerEntry new_server;
- bool initiator = FALSE;
- bool backup_local = FALSE;
- bool backup_router = FALSE;
- char *backup_replace_ip = NULL;
- SilcUInt16 backup_replace_port = 0;
- SilcServerConfigServer *sconn = ctx->sconfig.ref_ptr;
- SilcServerConfigRouter *rconn = ctx->rconfig.ref_ptr;
- /* If we are backup router and this is incoming server connection
- and we do not have connection to primary router, do not allow
- the connection. */
- if (server->server_type == SILC_BACKUP_ROUTER &&
- ctx->conn_type == SILC_SOCKET_TYPE_SERVER &&
- !SILC_PRIMARY_ROUTE(server)) {
- SILC_LOG_INFO(("Will not accept server connection because we do "
- "not have primary router connection established"));
- sock->protocol = NULL;
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_PERM_DENIED,
- "We do not have connection to primary "
- "router established, try later");
- silc_free(sock->user_data);
- server->stat.auth_failures++;
- goto out;
- }
+ /* Registered */
+ silc_idlist_add_data(id_entry, (SilcIDListData)entry);
+ idata = (SilcIDListData)entry;
+ idata->status |= (SILC_IDLIST_STATUS_REGISTERED |
+ SILC_IDLIST_STATUS_LOCAL);
+
+ if (!sconn->backup) {
+ /* Mark this router our primary router if we're still standalone */
+ if (server->standalone) {
+ SILC_LOG_DEBUG(("This connection is our primary router"));
+ server->id_entry->router = id_entry;
+ server->router = id_entry;
+ server->router->server_type = SILC_ROUTER;
+ server->standalone = FALSE;
+ server->backup_primary = FALSE;
- 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)) {
- silc_free(sock->user_data);
- server->stat.auth_failures++;
- goto out;
+ /* Announce data if we are not backup router (unless not as primary
+ currently). Backup router announces later at the end of
+ resuming protocol. */
+ if (server->backup_router && server->server_type == SILC_ROUTER) {
+ SILC_LOG_DEBUG(("Announce data after resume protocol"));
+ } else {
+ /* If we are router then announce our possible servers. Backup
+ router announces also global servers. */
+ if (server->server_type == SILC_ROUTER)
+ silc_server_announce_servers(server,
+ server->backup_router ? TRUE : FALSE,
+ 0, SILC_PRIMARY_ROUTE(server));
+
+ /* Announce our clients and channels to the router */
+ silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server));
+ silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
}
- if (rconn) {
- if (rconn->param) {
- param = rconn->param;
+#if 0
+ /* If we are backup router then this primary router is whom we are
+ backing up. */
+ if (server->server_type == SILC_BACKUP_ROUTER)
+ silc_server_backup_add(server, server->id_entry, sock->ip,
+ sconn->remote_port, TRUE);
+#endif /* 0 */
+ }
+ } else {
+ /* Add this server to be our backup router */
+ id_entry->server_type = SILC_BACKUP_ROUTER;
+ silc_server_backup_add(server, id_entry, sconn->backup_replace_ip,
+ sconn->backup_replace_port, FALSE);
+ }
- if (!param->keepalive_secs)
- param->keepalive_secs = server->config->param.keepalive_secs;
+ break;
- if (!param->qos && server->config->param.qos) {
- param->qos = server->config->param.qos;
- param->qos_rate_limit = server->config->param.qos_rate_limit;
- param->qos_bytes_limit = server->config->param.qos_bytes_limit;
- param->qos_limit_sec = server->config->param.qos_limit_sec;
- param->qos_limit_usec = server->config->param.qos_limit_usec;
- }
- }
+ default:
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_AUTH_FAILED, NULL);
+ silc_server_connection_free(sconn);
+ silc_free(entry);
+ return;
+ }
- 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;
- }
- }
+ conn = sconn->conn.ref_ptr;
+ param = &server->config->param;
+ if (conn && conn->param)
+ param = conn->param;
- 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)) {
- silc_free(sock->user_data);
- server->stat.auth_failures++;
- goto out;
- }
- if (sconn) {
- if (sconn->param) {
- param = sconn->param;
+ /* Register rekey timeout */
+ sconn->rekey_timeout = param->key_exchange_rekey;
+ silc_schedule_task_add_timeout(server->schedule, silc_server_do_rekey,
+ sconn->sock, sconn->rekey_timeout, 0);
- if (!param->keepalive_secs)
- param->keepalive_secs = server->config->param.keepalive_secs;
+#if 0
+ /* Perform keepalive. */
+ silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
+ silc_server_perform_heartbeat,
+ server->schedule);
- if (!param->qos && server->config->param.qos) {
- param->qos = server->config->param.qos;
- param->qos_rate_limit = server->config->param.qos_rate_limit;
- param->qos_bytes_limit = server->config->param.qos_bytes_limit;
- param->qos_limit_sec = server->config->param.qos_limit_sec;
- param->qos_limit_usec = server->config->param.qos_limit_usec;
- }
- }
+ out:
+ /* Call the completion callback to indicate that we've connected to
+ the router */
+ if (sconn && sconn->callback)
+ (*sconn->callback)(server, id_entry, sconn->callback_context);
- backup_router = sconn->backup_router;
- }
- }
+ /* Free the temporary connection data context */
+ if (sconn) {
+ silc_server_config_unref(&sconn->conn);
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
+ }
+ if (sconn == server->router_conn)
+ server->router_conn = NULL;
+#endif /* 0 */
- /* If we are primary router and we have backup router configured
- but it has not connected to use yet, do not accept any other
- connection. */
- if (server->wait_backup && server->server_type == SILC_ROUTER &&
- !server->backup_router && !backup_router) {
- SilcServerConfigRouter *router;
- router = silc_server_config_get_backup_router(server);
- if (router && strcmp(server->config->server_info->primary->server_ip,
- sock->ip) &&
- silc_server_find_socket_by_host(server,
- SILC_SOCKET_TYPE_SERVER,
- router->backup_replace_ip, 0)) {
- SILC_LOG_INFO(("Will not accept connections because we do "
- "not have backup router connection established"));
- sock->protocol = NULL;
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_PERM_DENIED,
- "We do not have connection to backup "
- "router established, try later");
- silc_free(sock->user_data);
- server->stat.auth_failures++;
+ silc_free(entry);
+}
- /* From here on, wait 20 seconds for the backup router to appear. */
- silc_schedule_task_add(server->schedule, 0,
- silc_server_backup_router_wait,
- (void *)server, 20, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- goto out;
- }
- }
+/* SKE completion callback */
- 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,
- sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
- "server" : (backup_router ?
- "backup router" : "router")));
+static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status,
+ SilcSKESecurityProperties prop,
+ SilcSKEKeyMaterial keymat,
+ SilcSKERekeyMaterial rekey,
+ void *context)
+{
+ SilcServerConnection sconn = context;
+ SilcUnknownEntry entry = silc_packet_get_context(sconn->sock);
+ SilcServer server = entry->server;
+ SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
+ SilcAuthMethod auth_meth = SILC_AUTH_NONE;
+ void *auth_data = NULL;
+ SilcUInt32 auth_data_len = 0;
+ SilcConnAuth connauth;
+ SilcCipher send_key, receive_key;
+ SilcHmac hmac_send, hmac_receive;
+ SilcHash hash;
+
+ if (status != SILC_SKE_STATUS_OK) {
+ /* SKE failed */
+ SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
+ silc_ske_map_status(status), entry->hostname, entry->ip));
+
+ /* XXX retry connecting */
+ silc_ske_free(ske);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ silc_server_connection_free(sconn);
+ return;
+ }
- /* Add the server into server cache. The server name and Server ID
- is updated after we have received NEW_SERVER packet from the
- server. We mark ourselves as router for this server if we really
- are router. */
- new_server =
- silc_idlist_add_server((ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
- server->local_list : (backup_router ?
- server->local_list :
- server->global_list)),
- NULL,
- (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
- SILC_SERVER : SILC_ROUTER),
- NULL,
- (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
- server->id_entry : (backup_router ?
- server->id_entry : NULL)),
- sock);
- if (!new_server) {
- SILC_LOG_ERROR(("Could not add new server to cache"));
- silc_free(sock->user_data);
- sock->protocol = NULL;
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_AUTH_FAILED, NULL);
- server->stat.auth_failures++;
- goto out;
- }
- entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
+ SILC_LOG_DEBUG(("Setting keys into use"));
- id_entry = (void *)new_server;
+ /* Set the keys into use. The data will be encrypted after this. */
+ if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
+ &hmac_send, &hmac_receive, &hash)) {
- /* 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 && backup_router) {
- /* Change it back to SERVER type since that's what it really is. */
- if (backup_local)
- ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
- new_server->server_type = SILC_BACKUP_ROUTER;
+ /* XXX retry connecting */
- SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE,
- ("Backup router %s is now online",
- sock->hostname));
+ /* Error setting keys */
+ silc_ske_free(ske);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ silc_server_connection_free(sconn);
+ return;
+ }
+ silc_packet_set_keys(sconn->sock, send_key, receive_key, hmac_send,
+ hmac_receive, FALSE);
- /* Remove the backup waiting with timeout */
- silc_schedule_task_add(server->schedule, 0,
- silc_server_backup_router_wait,
- (void *)server, 10, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- }
+ SILC_LOG_DEBUG(("Starting connection authentication"));
- /* Statistics */
- if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
- server->stat.my_servers++;
- server->stat.servers++;
+ connauth = silc_connauth_alloc(server->schedule, ske,
+ server->config->conn_auth_timeout);
+ if (!connauth) {
+ /* XXX retry connecting */
+
+ /** Error allocating auth protocol */
+ silc_ske_free(ske);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ silc_server_connection_free(sconn);
+ return;
+ }
+
+ /* Get authentication method */
+ if (conn) {
+ if (conn->passphrase) {
+ if (conn->publickeys && !server->config->prefer_passphrase_auth) {
+ auth_meth = SILC_AUTH_PUBLIC_KEY;
+ auth_data = server->private_key;
} else {
- server->stat.my_routers++;
- server->stat.routers++;
+ auth_meth = SILC_AUTH_PASSWORD;
+ auth_data = conn->passphrase;
+ auth_data_len = conn->passphrase_len;
}
+ } else {
+ auth_meth = SILC_AUTH_PUBLIC_KEY;
+ auth_data = server->private_key;
+ }
+ }
- /* Check whether this connection is to be our primary router connection
- if we do not already have the primary route. */
- if (!backup_router &&
- server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
- if (silc_server_config_is_primary_route(server) && !initiator)
- break;
+ /* Start connection authentication */
+ silc_connauth_initiator(connauth, server->server_type == SILC_ROUTER ?
+ SILC_CONN_ROUTER : SILC_CONN_SERVER, auth_meth,
+ auth_data, auth_data_len,
+ silc_server_ke_auth_compl, sconn);
+}
- SILC_LOG_DEBUG(("We are not standalone server anymore"));
- server->standalone = FALSE;
- if (!server->id_entry->router) {
- server->id_entry->router = id_entry;
- server->router = id_entry;
- }
- }
+/* Function that is called when the network connection to a router has
+ been established. This will continue with the key exchange protocol
+ with the remote router. */
- break;
- }
- default:
- goto out;
- break;
+void silc_server_start_key_exchange(SilcServerConnection sconn)
+{
+ SilcServer server = sconn->server;
+ SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
+ SilcUnknownEntry entry;
+ SilcSKEParamsStruct params;
+ SilcSKE ske;
+
+ /* Cancel any possible retry timeouts */
+ silc_schedule_task_del_by_context(server->schedule, sconn);
+
+ /* Create packet stream */
+ sconn->sock = silc_packet_stream_create(server->packet_engine,
+ server->schedule, sconn->stream);
+ if (!sconn->sock) {
+ SILC_LOG_ERROR(("Cannot connect: cannot create packet stream"));
+ silc_stream_destroy(sconn->stream);
+ silc_server_connection_free(sconn);
+ return;
}
+ server->stat.conn_num++;
- sock->type = ctx->conn_type;
+ /* Set source ID to packet stream */
+ if (!silc_packet_set_ids(sconn->sock, SILC_ID_SERVER, &server->id,
+ 0, NULL)) {
+ silc_packet_stream_destroy(sconn->sock);
+ silc_server_connection_free(sconn);
+ return;
+ }
- /* Add the common data structure to the ID entry. */
- silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
+ /* Create entry for remote entity */
+ entry = silc_calloc(1, sizeof(*entry));
+ if (!entry) {
+ silc_packet_stream_destroy(sconn->sock);
+ silc_server_connection_free(sconn);
+ return;
+ }
+ entry->server = server;
+ silc_packet_set_context(sconn->sock, entry);
- /* Add to sockets internal pointer for fast referencing */
- silc_free(sock->user_data);
- sock->user_data = id_entry;
+ /* Set Key Exchange flags from configuration, but fall back to global
+ settings too. */
+ memset(¶ms, 0, sizeof(params));
+ SILC_GET_SKE_FLAGS(conn, params.flags);
+ if (server->config->param.key_exchange_pfs)
+ params.flags |= SILC_SKE_SP_FLAG_PFS;
- /* Connection has been fully established now. Everything is ok. */
- SILC_LOG_DEBUG(("New connection authenticated"));
+ /* Start SILC Key Exchange protocol */
+ SILC_LOG_DEBUG(("Starting key exchange protocol"));
+ ske = silc_ske_alloc(server->rng, server->schedule, server->repository,
+ server->public_key, server->private_key, sconn->sock);
+ if (!ske) {
+ silc_free(entry);
+ silc_packet_stream_destroy(sconn->sock);
+ silc_server_connection_free(sconn);
+ return;
+ }
+ silc_ske_set_callbacks(ske, silc_server_verify_key,
+ silc_server_ke_completed, sconn->sock);
+
+ /* Start key exchange protocol */
+ params.version = silc_version_string;
+ params.timeout_secs = server->config->key_exchange_timeout;
+ silc_ske_initiator(ske, sconn->sock, ¶ms, NULL);
+}
+
+/* Timeout callback that will be called to retry connecting to remote
+ router. This is used by both normal and router server. This will wait
+ before retrying the connecting. The timeout is generated by exponential
+ backoff algorithm. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
+{
+ SilcServerConnection sconn = context;
+ SilcServer server = sconn->server;
+ SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
+ SilcServerConfigConnParams *param =
+ (conn->param ? conn->param : &server->config->param);
+
+ SILC_LOG_INFO(("Retrying connecting to %s:%d", sconn->remote_host,
+ sconn->remote_port));
+
+ /* Calculate next timeout */
+ if (sconn->retry_count >= 1) {
+ sconn->retry_timeout = sconn->retry_timeout * SILC_SERVER_RETRY_MULTIPLIER;
+ if (sconn->retry_timeout > param->reconnect_interval_max)
+ sconn->retry_timeout = param->reconnect_interval_max;
+ } else {
+ 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 > param->reconnect_count) &&
+ !param->reconnect_keep_trying) {
+ SILC_LOG_ERROR(("Could not connect, giving up"));
+ silc_server_connection_free(sconn);
+ return;
+ }
- /* Perform keepalive. */
- if (param->keepalive_secs)
- silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
- silc_server_perform_heartbeat,
- server->schedule);
+ SILC_LOG_DEBUG(("Retrying connecting %d seconds", sconn->retry_timeout));
- /* Perform Quality of Service */
- if (param->qos)
- silc_socket_set_qos(sock, param->qos_rate_limit, param->qos_bytes_limit,
- param->qos_limit_sec, param->qos_limit_usec,
- server->schedule);
+ /* We will lookup a fresh pointer later */
+ silc_server_config_unref(&sconn->conn);
- out:
- if (sock->protocol == protocol)
- silc_protocol_free(protocol);
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_free(ctx->dest_id);
- silc_server_config_unref(&ctx->cconfig);
- silc_server_config_unref(&ctx->sconfig);
- silc_server_config_unref(&ctx->rconfig);
- silc_free(ctx);
- sock->protocol = NULL;
+ /* Wait before retrying */
+ silc_schedule_task_del_by_context(server->schedule, sconn);
+ silc_schedule_task_add_timeout(server->schedule, silc_server_connect_router,
+ sconn, sconn->retry_timeout, 0);
}
-/* This function is used to read packets from network and send packets to
- network. This is usually a generic task. */
+/* Callback for async connection to remote router */
-SILC_TASK_CALLBACK(silc_server_packet_process)
+static void silc_server_connection_established(SilcNetStatus status,
+ SilcStream stream,
+ void *context)
{
- SilcServer server = (SilcServer)context;
- SilcSocketConnection sock = server->sockets[fd];
- SilcIDListData idata;
- SilcCipher cipher = NULL;
- SilcHmac hmac = NULL;
- SilcUInt32 sequence = 0;
- bool local_is_router;
- int ret;
-
- if (!sock) {
- SILC_LOG_DEBUG(("Unknown socket connection"));
- return;
- }
-
- /* Packet sending */
+ SilcServerConnection sconn = context;
+ SilcServer server = sconn->server;
- if (type == SILC_TASK_WRITE) {
- /* Do not send data to disconnected connection */
- if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
- SILC_LOG_DEBUG(("Disconnected socket connection, cannot send"));
- SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
- SILC_UNSET_OUTBUF_PENDING(sock);
- silc_buffer_clear(sock->outbuf);
- return;
- }
+ silc_schedule_task_del_by_context(server->schedule, sconn);
+ sconn->op = NULL;
- server->stat.packets_sent++;
-
- /* Send the packet */
- ret = silc_packet_send(sock, TRUE);
+ switch (status) {
+ case SILC_NET_OK:
+ SILC_LOG_DEBUG(("Connection to %s:%d established",
+ sconn->remote_host, sconn->remote_port));
- /* If returned -2 could not write to connection now, will do
- it later. */
- if (ret == -2)
- return;
+ /* Continue with key exchange protocol */
+ sconn->stream = stream;
+ silc_server_start_key_exchange(sconn);
+ break;
- /* The packet has been sent and now it is time to set the connection
- back to only for input. When there is again some outgoing data
- available for this connection it will be set for output as well.
- This call clears the output setting and sets it only for input. */
- SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
- SILC_UNSET_OUTBUF_PENDING(sock);
- silc_buffer_clear(sock->outbuf);
-
- if (ret == -1) {
- SILC_LOG_ERROR(("Error sending packet to connection "
- "%s:%d [%s]", sock->hostname, sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
-
- if (sock->user_data) {
- /* If backup then mark that resuming will not be allowed */
- if (server->server_type == SILC_ROUTER && !server->backup_router &&
- sock->type == SILC_SOCKET_TYPE_SERVER) {
- SilcServerEntry server_entry = sock->user_data;
- if (server_entry->server_type == SILC_BACKUP_ROUTER)
- server->backup_closed = TRUE;
- }
+ case SILC_NET_UNKNOWN_IP:
+ case SILC_NET_UNKNOWN_HOST:
+ SILC_LOG_ERROR(("Could not connect to %s:%d: %s",
+ sconn->remote_host, sconn->remote_port,
+ silc_net_get_error_string(status)));
+ silc_server_connection_free(sconn);
+ break;
- silc_server_free_sock_user_data(server, sock, NULL);
- }
- SILC_SET_DISCONNECTING(sock);
- silc_server_close_connection(server, sock);
+ default:
+ SILC_LOG_ERROR(("Could not connect to %s:%d: %s",
+ sconn->remote_host, sconn->remote_port,
+ silc_net_get_error_string(status)));
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(sconn->server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ } else {
+ silc_server_connection_free(sconn);
}
- return;
+ break;
}
+}
- /* Packet receiving */
-
- /* Read some data from connection */
- ret = silc_packet_receive(sock);
- if (ret < 0) {
+/* Generic routine to use connect to a router. */
- if (ret == -1) {
- SILC_LOG_ERROR(("Error receiving packet from connection "
- "%s:%d [%s] %s", sock->hostname, sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router"), strerror(errno)));
+SILC_TASK_CALLBACK(silc_server_connect_router)
+{
+ SilcServerConnection sconn = context;
+ SilcServer server = sconn->server;
+ SilcServerConfigRouter *rconn;
- if (sock->user_data) {
- /* If backup then mark that resuming will not be allowed */
- if (server->server_type == SILC_ROUTER && !server->backup_router &&
- sock->type == SILC_SOCKET_TYPE_SERVER) {
- SilcServerEntry server_entry = sock->user_data;
- if (server_entry->server_type == SILC_BACKUP_ROUTER)
- server->backup_closed = TRUE;
- }
+ silc_schedule_task_del_by_context(server->schedule, sconn);
- silc_server_free_sock_user_data(server, sock, NULL);
- }
- SILC_SET_DISCONNECTING(sock);
- silc_server_close_connection(server, sock);
- }
+ /* Don't connect if we are shutting down. */
+ if (server->server_shutdown) {
+ silc_server_connection_free(sconn);
return;
}
- /* EOF */
- if (ret == 0) {
- SILC_LOG_DEBUG(("Read EOF"));
+ SILC_LOG_INFO(("Connecting to the %s %s on port %d",
+ (sconn->backup ? "backup router" : "router"),
+ sconn->remote_host, sconn->remote_port));
- /* If connection is disconnecting already we will finally
- close the connection */
- if (SILC_IS_DISCONNECTING(sock)) {
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
- silc_server_close_connection(server, sock);
+ if (!server->no_conf) {
+ /* Find connection configuration */
+ rconn = silc_server_config_find_router_conn(server, sconn->remote_host,
+ sconn->remote_port);
+ if (!rconn) {
+ SILC_LOG_INFO(("Unconfigured %s connection %s:%d, cannot connect",
+ (sconn->backup ? "backup router" : "router"),
+ sconn->remote_host, sconn->remote_port));
+ silc_server_connection_free(sconn);
return;
}
-
- SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
-
- if (sock->user_data) {
- char tmp[128];
-
- /* If backup disconnected then mark that resuming will not be allowed */
- if (server->server_type == SILC_ROUTER && !server->backup_router &&
- sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
- SilcServerEntry server_entry = sock->user_data;
- if (server_entry->server_type == SILC_BACKUP_ROUTER)
- server->backup_closed = TRUE;
- }
-
- if (silc_socket_get_error(sock, tmp, sizeof(tmp) - 1))
- silc_server_free_sock_user_data(server, sock, tmp);
- else
- silc_server_free_sock_user_data(server, sock, NULL);
- } else if (server->router_conn && server->router_conn->sock == sock &&
- !server->router && server->standalone) {
- silc_server_create_connections(server);
- }
-
- SILC_SET_DISCONNECTING(sock);
- silc_server_close_connection(server, sock);
- return;
+ silc_server_config_ref(&sconn->conn, server->config, (void *)rconn);
}
- /* If connection is disconnecting or disconnected we will ignore
- what we read. */
- if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
- SILC_LOG_DEBUG(("Ignoring read data from disconnected connection"));
+ /* Connect to remote host */
+ sconn->op =
+ silc_net_tcp_connect((!server->config->server_info->primary ? NULL :
+ server->config->server_info->primary->server_ip),
+ sconn->remote_host, sconn->remote_port,
+ server->schedule, silc_server_connection_established,
+ sconn);
+ if (!sconn->op) {
+ SILC_LOG_ERROR(("Could not connect to router %s:%d",
+ sconn->remote_host, sconn->remote_port));
+ silc_server_connection_free(sconn);
return;
}
- /* Get keys and stuff from ID entry */
- idata = (SilcIDListData)sock->user_data;
- if (idata) {
- cipher = idata->receive_key;
- hmac = idata->hmac_receive;
- sequence = idata->psn_receive;
- }
-
- /* Then, process the packet. This will call the parser that will then
- decrypt and parse the packet. */
-
- local_is_router = (server->server_type == SILC_ROUTER);
-
- /* If socket connection is our primary, we are backup and we are doing
- backup resuming, we won't process the packet as being a router
- (affects channel message decryption). */
- if (server->backup_router && SILC_SERVER_IS_BACKUP(sock) &&
- SILC_PRIMARY_ROUTE(server) == sock)
- local_is_router = FALSE;
-
- ret = silc_packet_receive_process(sock, local_is_router,
- cipher, hmac, sequence,
- silc_server_packet_parse, server);
-
- /* If processing failed the connection is closed. */
- if (!ret) {
- /* On packet processing errors we may close our primary router
- connection but won't become primary router if we are the backup
- since this is local error condition. */
- if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
- server->backup_noswitch = TRUE;
-
- if (sock->user_data) {
- /* If we are router and backup errorred then mark that resuming
- will not be allowed */
- if (server->server_type == SILC_ROUTER && !server->backup_router &&
- sock->type == SILC_SOCKET_TYPE_SERVER) {
- SilcServerEntry server_entry = sock->user_data;
- if (server_entry->server_type == SILC_BACKUP_ROUTER)
- server->backup_closed = TRUE;
- }
-
- silc_server_free_sock_user_data(server, sock, NULL);
- }
- SILC_SET_DISCONNECTING(sock);
- silc_server_close_connection(server, sock);
- }
+ /* Add to connection list */
+ silc_dlist_add(server->conns, sconn);
}
-/* Parses whole packet, received earlier. */
+/* This function connects to our primary router or if we are a router this
+ establishes all our primary routes. This is called at the start of the
+ server to do authentication and key exchange with our router - called
+ from schedule. */
-SILC_TASK_CALLBACK(silc_server_packet_parse_real)
+SILC_TASK_CALLBACK(silc_server_connect_to_router)
{
- SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
- SilcServer server = (SilcServer)parse_ctx->context;
- SilcSocketConnection sock = parse_ctx->sock;
- SilcPacketContext *packet = parse_ctx->packet;
- SilcIDListData idata = (SilcIDListData)sock->user_data;
- int ret;
-
- if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
- SILC_LOG_DEBUG(("Connection is disconnected"));
- goto out;
- }
+ SilcServer server = context;
+ SilcServerConnection sconn;
+ SilcServerConfigRouter *ptr;
- server->stat.packets_received++;
+ /* Don't connect if we are shutting down. */
+ if (server->server_shutdown)
+ return;
- /* Parse the packet */
- if (parse_ctx->normal)
- ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL);
- else
- ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
+ SILC_LOG_DEBUG(("We are %s",
+ (server->server_type == SILC_SERVER ?
+ "normal server" : server->server_type == SILC_ROUTER ?
+ "router" : "backup router/normal server")));
- /* If entry is disabled ignore what we got. */
- if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
- ret != SILC_PACKET_HEARTBEAT && ret != SILC_PACKET_RESUME_ROUTER &&
- ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE &&
- ret != SILC_PACKET_KEY_EXCHANGE_1 && ret != SILC_PACKET_KEY_EXCHANGE_2) {
- SILC_LOG_DEBUG(("Connection is disabled (packet %s dropped)",
- silc_get_packet_name(ret)));
- goto out;
+ /* XXX */
+ if (!server->config->routers) {
+ /* There wasn't a configured router, we will continue but we don't
+ have a connection to outside world. We will be standalone server. */
+ SILC_LOG_DEBUG(("No router(s), we are standalone"));
+ server->standalone = TRUE;
+ return;
}
- if (ret == SILC_PACKET_NONE) {
- SILC_LOG_DEBUG(("Error parsing packet"));
- goto out;
- }
+ /* Create the connections to all our routes */
+ for (ptr = server->config->routers; ptr; ptr = ptr->next) {
- /* Check that the the current client ID is same as in the client's packet. */
- if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
- SilcClientEntry client = (SilcClientEntry)sock->user_data;
- if (client && client->id && packet->src_id) {
- void *id = silc_id_str2id(packet->src_id, packet->src_id_len,
- packet->src_id_type);
- if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) {
- silc_free(id);
- SILC_LOG_DEBUG(("Packet source is not same as sender"));
- goto out;
- }
- silc_free(id);
- }
- }
+ SILC_LOG_DEBUG(("%s connection [%s] %s:%d",
+ ptr->backup_router ? "Backup router" : "Router",
+ ptr->initiator ? "Initiator" : "Responder",
+ ptr->host, ptr->port));
- if (server->server_type == SILC_ROUTER) {
- /* Route the packet if it is not destined to us. Other ID types but
- server are handled separately after processing them. */
- if (packet->dst_id && !(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
- packet->dst_id_type == SILC_ID_SERVER &&
- sock->type != SILC_SOCKET_TYPE_CLIENT &&
- memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
- SilcSocketConnection conn;
+ if (server->server_type == SILC_ROUTER && ptr->backup_router &&
+ ptr->initiator == FALSE && !server->backup_router &&
+ !silc_server_config_get_backup_router(server))
+ server->wait_backup = TRUE;
- /* Route the packet to fastest route for the destination ID */
- void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
- packet->dst_id_type);
- if (!id)
- goto out;
+ if (!ptr->initiator)
+ continue;
- conn = silc_server_route_get(server, id, packet->dst_id_type);
- if (!conn) {
- SILC_LOG_WARNING(("Packet to unknown server ID %s, dropped (no route)",
- silc_id_render(id, SILC_ID_SERVER)));
- goto out;
+ /* Check whether we are connecting or connected to this host already */
+ if (silc_server_num_sockets_by_remote(server,
+ silc_net_is_ip(ptr->host) ?
+ ptr->host : NULL,
+ silc_net_is_ip(ptr->host) ?
+ NULL : ptr->host, ptr->port)) {
+ SILC_LOG_DEBUG(("We are already connected to %s:%d",
+ ptr->host, ptr->port));
+
+ /* If we don't have primary router and this connection is our
+ primary router we are in desync. Reconnect to the primary. */
+ if (server->standalone && !server->router) {
+ /* XXX */
+ SilcPacketStream sock;
+ SilcServerConfigRouter *primary =
+ silc_server_config_get_primary_router(server);
+ if (primary != ptr)
+ continue;
+ sock = silc_server_find_socket_by_host(server, SILC_CONN_ROUTER,
+ ptr->host, ptr->port);
+ if (!sock)
+ continue;
+ server->backup_noswitch = TRUE;
+#if 0
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_server_disconnect_remote(server, sock, 0, NULL);
+#endif /* 0 */
+ server->backup_noswitch = FALSE;
+ SILC_LOG_DEBUG(("Reconnecting to primary router"));
+ } else {
+ continue;
}
+ }
- silc_server_packet_route(server, conn, packet);
- silc_free(id);
- goto out;
+ /* Allocate connection object for hold connection specific stuff. */
+ sconn = silc_calloc(1, sizeof(*sconn));
+ if (!sconn)
+ continue;
+ sconn->remote_host = strdup(ptr->host);
+ sconn->remote_port = ptr->port;
+ sconn->backup = ptr->backup_router;
+ if (sconn->backup) {
+ sconn->backup_replace_ip = strdup(ptr->backup_replace_ip);
+ sconn->backup_replace_port = ptr->backup_replace_port;
}
+
+ /* XXX */
+ if (!server->router_conn && !sconn->backup)
+ server->router_conn = sconn;
+
+ /* Connect */
+ silc_server_connect_router(server->schedule, server, SILC_TASK_EXPIRE,
+ 0, sconn);
}
+}
- /* Parse the incoming packet type */
- silc_server_packet_parse_type(server, sock, packet);
- /* Broadcast packet if it is marked as broadcast packet and it is
- originated from router and we are router. */
- if (server->server_type == SILC_ROUTER &&
- sock->type == SILC_SOCKET_TYPE_ROUTER &&
- packet->flags & SILC_PACKET_FLAG_BROADCAST) {
- /* Broadcast to our primary route */
- silc_server_packet_broadcast(server, SILC_PRIMARY_ROUTE(server), packet);
+/************************ Accepting new connection **************************/
- /* If we have backup routers then we need to feed all broadcast
- data to those servers. */
- silc_server_backup_broadcast(server, sock, packet);
- }
+/* After this is called, server don't wait for backup router anymore.
+ This gets called automatically even after we have backup router
+ connection established. */
- out:
- silc_packet_context_free(packet);
- silc_free(parse_ctx);
+SILC_TASK_CALLBACK(silc_server_backup_router_wait)
+{
+ SilcServer server = context;
+ server->wait_backup = FALSE;
}
-/* Parser callback called by silc_packet_receive_process. This merely
- registers timeout that will handle the actual parsing when appropriate. */
+/* Authentication data callback */
-bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
- void *context)
+static SilcBool
+silc_server_accept_get_auth(SilcConnAuth connauth,
+ SilcConnectionType conn_type,
+ unsigned char **passphrase,
+ SilcUInt32 *passphrase_len,
+ SilcSKR *repository,
+ void *context)
{
- SilcServer server = (SilcServer)context;
- SilcSocketConnection sock = parser_context->sock;
- SilcIDListData idata = (SilcIDListData)sock->user_data;
- bool ret;
+ SilcPacketStream sock = context;
+ SilcUnknownEntry entry = silc_packet_get_context(sock);
+ SilcServer server = entry->server;
- if (idata)
- idata->psn_receive = parser_context->packet->sequence + 1;
+ SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
- /* If protocol for this connection is key exchange or rekey then we'll
- process all packets synchronously, since there might be packets in
- queue that we are not able to decrypt without first processing the
- packets before them. */
- if (sock->protocol && sock->protocol->protocol &&
- (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
- silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
- parser_context);
-
- if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
- SILC_LOG_DEBUG(("Connection is disconnected"));
+ /* Remote end is client */
+ if (conn_type == SILC_CONN_CLIENT) {
+ SilcServerConfigClient *cconfig = entry->cconfig.ref_ptr;
+ if (!cconfig)
return FALSE;
- }
- /* Reprocess data since we'll return FALSE here. This is because
- the idata->receive_key might have become valid in the last packet
- and we want to call this processor with valid cipher. */
- if (idata)
- ret = silc_packet_receive_process(
- sock, server->server_type == SILC_ROUTER,
- idata->receive_key,
- idata->hmac_receive, idata->psn_receive,
- silc_server_packet_parse, server);
- else
- ret = silc_packet_receive_process(
- sock, server->server_type == SILC_ROUTER,
- NULL, NULL, 0,
- silc_server_packet_parse, server);
-
- if (!ret) {
- /* On packet processing errors we may close our primary router
- connection but won't become primary router if we are the backup
- since this is local error condition. */
- if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
- server->backup_noswitch = TRUE;
+ *passphrase = cconfig->passphrase;
+ *passphrase_len = cconfig->passphrase_len;
+ if (cconfig->publickeys)
+ *repository = server->repository;
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
- SILC_SET_DISCONNECTING(sock);
- silc_server_close_connection(server, sock);
- }
+ entry->data.conn_type = conn_type;
+ return TRUE;
+ }
- return FALSE;
+ /* Remote end is server */
+ if (conn_type == SILC_CONN_SERVER) {
+ SilcServerConfigServer *sconfig = entry->sconfig.ref_ptr;
+ if (!sconfig)
+ return FALSE;
+
+ *passphrase = sconfig->passphrase;
+ *passphrase_len = sconfig->passphrase_len;
+ if (sconfig->publickeys)
+ *repository = server->repository;
+
+ entry->data.conn_type = conn_type;
+ return TRUE;
}
- switch (sock->type) {
- case SILC_SOCKET_TYPE_UNKNOWN:
- case SILC_SOCKET_TYPE_CLIENT:
- /* Parse the packet with timeout */
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_packet_parse_real,
- (void *)parser_context, 0, 100000,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- break;
- case SILC_SOCKET_TYPE_SERVER:
- case SILC_SOCKET_TYPE_ROUTER:
- /* Packets from servers are parsed immediately */
- silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
- parser_context);
- break;
+ /* Remote end is router */
+ if (conn_type == SILC_CONN_ROUTER) {
+ SilcServerConfigRouter *rconfig = entry->rconfig.ref_ptr;
+ if (!rconfig)
+ return FALSE;
+
+ *passphrase = rconfig->passphrase;
+ *passphrase_len = rconfig->passphrase_len;
+ if (rconfig->publickeys)
+ *repository = server->repository;
+
+ entry->data.conn_type = conn_type;
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
-/* Parses the packet type and calls what ever routines the packet type
- requires. This is done for all incoming packets. */
+/* Authentication completion callback. */
-void silc_server_packet_parse_type(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
+static void
+silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
+ void *context)
{
- SilcPacketType type = packet->type;
- SilcIDListData idata = (SilcIDListData)sock->user_data;
+ SilcPacketStream sock = context;
+ SilcUnknownEntry entry = silc_packet_get_context(sock);
+ SilcServer server = entry->server;
+ SilcServerConfigConnParams *param;
+ void *id_entry;
- SILC_LOG_DEBUG(("Received %s packet [flags %d]",
- silc_get_packet_name(type), packet->flags));
+ if (success == FALSE) {
+ /* Authentication failed */
+ SILC_LOG_INFO(("Authentication failed for %s (%s) [%s]", entry->hostname,
+ entry->ip, SILC_CONNTYPE_STRING(entry->data.conn_type)));
+ server->stat.auth_failures++;
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ goto out;
+ }
- /* Parse the packet type */
- switch (type) {
- case SILC_PACKET_DISCONNECT:
+ SILC_LOG_DEBUG(("Checking whether connection is allowed"));
+
+ switch (entry->data.conn_type) {
+ case SILC_CONN_CLIENT:
{
- SilcStatus status;
- char *message = NULL;
+ SilcClientEntry client;
+ SilcServerConfigClient *conn = entry->cconfig.ref_ptr;
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- if (packet->buffer->len < 1)
- break;
+ /* Verify whether this connection is after all allowed to connect */
+ if (!silc_server_connection_allowed(server, sock, entry->data.conn_type,
+ &server->config->param,
+ conn->param,
+ silc_connauth_get_ske(connauth))) {
+ server->stat.auth_failures++;
+ goto out;
+ }
- status = (SilcStatus)packet->buffer->data[0];
- if (packet->buffer->len > 1 &&
- silc_utf8_valid(packet->buffer->data + 1, packet->buffer->len - 1))
- message = silc_memdup(packet->buffer->data + 1,
- packet->buffer->len - 1);
+ /* If we are primary router and we have backup router configured
+ but it has not connected to use yet, do not accept any other
+ connection. */
+ if (server->wait_backup && server->server_type == SILC_ROUTER &&
+ !server->backup_router) {
+ SilcServerConfigRouter *router;
+ router = silc_server_config_get_backup_router(server);
+ if (router && strcmp(server->config->server_info->primary->server_ip,
+ entry->ip) &&
+ silc_server_find_socket_by_host(server,
+ SILC_CONN_SERVER,
+ router->backup_replace_ip, 0)) {
+ SILC_LOG_INFO(("Will not accept connections because we do "
+ "not have backup router connection established"));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_PERM_DENIED,
+ "We do not have connection to backup "
+ "router established, try later");
+ server->stat.auth_failures++;
- SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s",
- sock->ip, sock->hostname,
- silc_get_status_message(status), status,
- message ? message : ""));
- silc_free(message);
+ /* From here on, wait 20 seconds for the backup router to appear. */
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_backup_router_wait,
+ (void *)server, 20, 0);
+ goto out;
+ }
+ }
- /* Do not switch to backup in case of error */
- server->backup_noswitch = (status == SILC_STATUS_OK ? FALSE : TRUE);
+ SILC_LOG_DEBUG(("Remote host is client"));
+ SILC_LOG_INFO(("Connection %s (%s) is client", entry->hostname,
+ entry->ip));
- /* If backup disconnected then mark that resuming will not be allowed */
- if (server->server_type == SILC_ROUTER && !server->backup_router &&
- sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
- SilcServerEntry server_entry = sock->user_data;
- if (server_entry->server_type == SILC_BACKUP_ROUTER)
- server->backup_closed = TRUE;
+ /* Add the client to the client ID cache. The nickname and Client ID
+ and other information is created after we have received NEW_CLIENT
+ packet from client. */
+ client = silc_idlist_add_client(server->local_list,
+ NULL, NULL, NULL, NULL, NULL, sock);
+ if (!client) {
+ SILC_LOG_ERROR(("Could not add new client to cache"));
+ server->stat.auth_failures++;
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_AUTH_FAILED, NULL);
+ goto out;
}
+ entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
- /* Handle the disconnection from our end too */
- if (sock->user_data && SILC_IS_LOCAL(sock->user_data))
- silc_server_free_sock_user_data(server, sock, NULL);
- SILC_SET_DISCONNECTING(sock);
- silc_server_close_connection(server, sock);
- server->backup_noswitch = FALSE;
- }
- break;
-
- case SILC_PACKET_SUCCESS:
- /*
- * Success received for something. For now we can have only
- * one protocol for connection executing at once hence this
- * success message is for whatever protocol is executing currently.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- if (sock->protocol)
- silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
- break;
+ /* Statistics */
+ server->stat.my_clients++;
+ server->stat.clients++;
+ server->stat.cell_clients++;
- case SILC_PACKET_FAILURE:
- /*
- * Failure received for something. For now we can have only
- * one protocol for connection executing at once hence this
- * failure message is for whatever protocol is executing currently.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
+ /* Get connection parameters */
+ if (conn->param) {
+ param = conn->param;
- /* Check for failure START_USE from backup router */
- if (server->server_type == SILC_SERVER &&
- server->backup_primary && packet->buffer->len == 4) {
- SilcUInt32 type;
- SILC_GET32_MSB(type, packet->buffer->data);
- if (type == SILC_SERVER_BACKUP_START_USE) {
- /* Attempt to reconnect to primary */
- SILC_LOG_DEBUG(("Received failed START_USE from backup %s", sock->ip));
-
- /* Default action is to disconnect from backup and reconnect to
- primary. Since this failure can happen during switching to
- backup (backup might have not noticed the primary going down yet),
- we will wait a while and keep sending START_USE to backup.
- Only after that we'll give up. */
- if (server->router == sock->user_data &&
- (time(0) - server->router_connect) < 30) {
- SILC_LOG_DEBUG(("Resending START_USE to backup router"));
- silc_server_backup_send_start_use(server, sock, FALSE);
- break;
- }
+ if (!param->keepalive_secs)
+ param->keepalive_secs = server->config->param.keepalive_secs;
- /* If backup is our primary, disconnect now. */
- if (server->router == sock->user_data) {
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
- SILC_SET_DISCONNECTING(sock);
- silc_server_close_connection(server, sock);
+ if (!param->qos && server->config->param.qos) {
+ param->qos = server->config->param.qos;
+ param->qos_rate_limit = server->config->param.qos_rate_limit;
+ param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+ param->qos_limit_sec = server->config->param.qos_limit_sec;
+ param->qos_limit_usec = server->config->param.qos_limit_usec;
}
- /* Reconnect */
- silc_server_create_connections(server);
+ /* Check if to be anonymous connection */
+ if (param->anonymous)
+ client->mode |= SILC_UMODE_ANONYMOUS;
}
- }
- /* Execute protocol */
- if (sock->protocol) {
- sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
- silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+ /* Add public key to hash list (for whois using attributes) */
+ if (!silc_hash_table_find_by_context(server->pk_hash,
+ entry->data.public_key,
+ client, NULL))
+ silc_hash_table_add(server->pk_hash,
+ entry->data.public_key, client);
+
+ id_entry = (void *)client;
break;
}
- break;
- case SILC_PACKET_REJECT:
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- return;
- break;
+ case SILC_CONN_SERVER:
+ case SILC_CONN_ROUTER:
+ {
+ SilcServerEntry new_server;
+ SilcBool initiator = FALSE;
+ SilcBool backup_local = FALSE;
+ SilcBool backup_router = FALSE;
+ char *backup_replace_ip = NULL;
+ SilcUInt16 backup_replace_port = 0;
+ SilcServerConfigServer *sconn = entry->sconfig.ref_ptr;
+ SilcServerConfigRouter *rconn = entry->rconfig.ref_ptr;
- case SILC_PACKET_NOTIFY:
- /*
- * Received notify packet. Server can receive notify packets from
- * router. Server then relays the notify messages to clients if needed.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- silc_server_notify_list(server, sock, packet);
- else
- silc_server_notify(server, sock, packet);
- break;
+ /* If we are backup router and this is incoming server connection
+ and we do not have connection to primary router, do not allow
+ the connection. */
+ if (server->server_type == SILC_BACKUP_ROUTER &&
+ entry->data.conn_type == SILC_CONN_SERVER &&
+ !SILC_PRIMARY_ROUTE(server)) {
+ SILC_LOG_INFO(("Will not accept server connection because we do "
+ "not have primary router connection established"));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_PERM_DENIED,
+ "We do not have connection to primary "
+ "router established, try later");
+ server->stat.auth_failures++;
+ goto out;
+ }
- /*
- * Channel packets
- */
- case SILC_PACKET_CHANNEL_MESSAGE:
- /*
- * Received channel message. Channel messages are special packets
- * (although probably most common ones) thus they are handled
- * specially.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- idata->last_receive = time(NULL);
- silc_server_channel_message(server, sock, packet);
- break;
+ if (entry->data.conn_type == SILC_CONN_ROUTER) {
+ /* Verify whether this connection is after all allowed to connect */
+ if (!silc_server_connection_allowed(server, sock,
+ entry->data.conn_type,
+ &server->config->param,
+ rconn ? rconn->param : NULL,
+ silc_connauth_get_ske(connauth))) {
+ server->stat.auth_failures++;
+ goto out;
+ }
- case SILC_PACKET_CHANNEL_KEY:
- /*
- * Received key for channel. As channels are created by the router
- * the keys are as well. We will distribute the key to all of our
- * locally connected clients on the particular channel. Router
- * never receives this channel and thus is ignored.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_channel_key(server, sock, packet);
- break;
+ if (rconn) {
+ if (rconn->param) {
+ param = rconn->param;
- /*
- * Command packets
- */
- case SILC_PACKET_COMMAND:
- /*
- * Recived command. Processes the command request and allocates the
- * command context and calls the command.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- server->stat.commands_received++;
- silc_server_command_process(server, sock, packet);
- break;
+ if (!param->keepalive_secs)
+ param->keepalive_secs = server->config->param.keepalive_secs;
- case SILC_PACKET_COMMAND_REPLY:
- /*
- * Received command reply packet. Received command reply to command. It
- * may be reply to command sent by us or reply to command sent by client
- * that we've routed further.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- server->stat.commands_received++;
- silc_server_command_reply(server, sock, packet);
- break;
+ if (!param->qos && server->config->param.qos) {
+ param->qos = server->config->param.qos;
+ param->qos_rate_limit = server->config->param.qos_rate_limit;
+ param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+ param->qos_limit_sec = server->config->param.qos_limit_sec;
+ param->qos_limit_usec = server->config->param.qos_limit_usec;
+ }
+ }
- /*
- * Private Message packets
- */
- case SILC_PACKET_PRIVATE_MESSAGE:
- /*
- * Received private message packet. The packet is coming from either
- * client or server.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- idata->last_receive = time(NULL);
- silc_server_private_message(server, sock, packet);
- break;
+ 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;
+ }
+ }
- case SILC_PACKET_PRIVATE_MESSAGE_KEY:
- /*
- * Private message key packet.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_private_message_key(server, sock, packet);
- break;
+ if (entry->data.conn_type == SILC_CONN_SERVER) {
+ /* Verify whether this connection is after all allowed to connect */
+ if (!silc_server_connection_allowed(server, sock,
+ entry->data.conn_type,
+ &server->config->param,
+ sconn ? sconn->param : NULL,
+ silc_connauth_get_ske(connauth))) {
+ server->stat.auth_failures++;
+ goto out;
+ }
+ if (sconn) {
+ if (sconn->param) {
+ param = sconn->param;
- /*
- * Key Exchange protocol packets
- */
- case SILC_PACKET_KEY_EXCHANGE:
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
+ if (!param->keepalive_secs)
+ param->keepalive_secs = server->config->param.keepalive_secs;
- if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
- SilcServerKEInternalContext *proto_ctx =
- (SilcServerKEInternalContext *)sock->protocol->context;
+ if (!param->qos && server->config->param.qos) {
+ param->qos = server->config->param.qos;
+ param->qos_rate_limit = server->config->param.qos_rate_limit;
+ param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+ param->qos_limit_sec = server->config->param.qos_limit_sec;
+ param->qos_limit_usec = server->config->param.qos_limit_usec;
+ }
+ }
- proto_ctx->packet = silc_packet_context_dup(packet);
+ backup_router = sconn->backup_router;
+ }
+ }
- /* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->schedule, 0, 100000);
- } else {
- SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
- "protocol active (%s:%d [%s]).", sock->hostname,
- sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
- }
- break;
+ /* If we are primary router and we have backup router configured
+ but it has not connected to use yet, do not accept any other
+ connection. */
+#if 0
+ if (server->wait_backup && server->server_type == SILC_ROUTER &&
+ !server->backup_router && !backup_router) {
+ SilcServerConfigRouter *router;
+ router = silc_server_config_get_backup_router(server);
+ if (router && strcmp(server->config->server_info->primary->server_ip,
+ ip) &&
+ silc_server_find_socket_by_host(server,
+ SILC_CONN_SERVER,
+ router->backup_replace_ip, 0)) {
+ SILC_LOG_INFO(("Will not accept connections because we do "
+ "not have backup router connection established"));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_PERM_DENIED,
+ "We do not have connection to backup "
+ "router established, try later");
+ server->stat.auth_failures++;
- case SILC_PACKET_KEY_EXCHANGE_1:
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
+ /* From here on, wait 20 seconds for the backup router to appear. */
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_backup_router_wait,
+ (void *)server, 20, 0);
+ goto out;
+ }
+ }
+#endif /* 0 */
+
+ SILC_LOG_DEBUG(("Remote host is %s",
+ entry->data.conn_type == SILC_CONN_SERVER ?
+ "server" : (backup_router ?
+ "backup router" : "router")));
+ SILC_LOG_INFO(("Connection %s (%s) is %s", entry->hostname,
+ entry->ip, entry->data.conn_type == SILC_CONN_SERVER ?
+ "server" : (backup_router ?
+ "backup router" : "router")));
+
+ /* Add the server into server cache. The server name and Server ID
+ is updated after we have received NEW_SERVER packet from the
+ server. We mark ourselves as router for this server if we really
+ are router. */
+ new_server =
+ silc_idlist_add_server((entry->data.conn_type == SILC_CONN_SERVER ?
+ server->local_list : (backup_router ?
+ server->local_list :
+ server->global_list)),
+ NULL,
+ (entry->data.conn_type == SILC_CONN_SERVER ?
+ SILC_SERVER : SILC_ROUTER),
+ NULL,
+ (entry->data.conn_type == SILC_CONN_SERVER ?
+ server->id_entry : (backup_router ?
+ server->id_entry : NULL)),
+ sock);
+ if (!new_server) {
+ SILC_LOG_ERROR(("Could not add new server to cache"));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_AUTH_FAILED, NULL);
+ server->stat.auth_failures++;
+ goto out;
+ }
+ entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
- if (sock->protocol && sock->protocol->protocol &&
- (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
+ id_entry = (void *)new_server;
- if (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
- SilcServerRekeyInternalContext *proto_ctx =
- (SilcServerRekeyInternalContext *)sock->protocol->context;
+ /* If the incoming connection is router and marked as backup router
+ then add it to be one of our backups */
+ if (entry->data.conn_type == SILC_CONN_ROUTER && backup_router) {
+ /* Change it back to SERVER type since that's what it really is. */
+ if (backup_local)
+ entry->data.conn_type = SILC_CONN_SERVER;
+ new_server->server_type = SILC_BACKUP_ROUTER;
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
+ SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE,
+ ("Backup router %s is now online",
+ entry->hostname));
- proto_ctx->packet = silc_packet_context_dup(packet);
+ /* Remove the backup waiting with timeout */
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_backup_router_wait,
+ (void *)server, 10, 0);
+ }
- /* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+ /* Statistics */
+ if (entry->data.conn_type == SILC_CONN_SERVER) {
+ server->stat.my_servers++;
+ server->stat.servers++;
} else {
- SilcServerKEInternalContext *proto_ctx =
- (SilcServerKEInternalContext *)sock->protocol->context;
-
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
+ server->stat.my_routers++;
+ server->stat.routers++;
+ }
- proto_ctx->packet = silc_packet_context_dup(packet);
- proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
- packet->src_id_type);
- if (!proto_ctx->dest_id)
+ /* Check whether this connection is to be our primary router connection
+ if we do not already have the primary route. */
+ if (!backup_router &&
+ server->standalone && entry->data.conn_type == SILC_CONN_ROUTER) {
+ if (silc_server_config_is_primary_route(server) && !initiator)
break;
- /* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->schedule,
- 0, 100000);
+ SILC_LOG_DEBUG(("We are not standalone server anymore"));
+ server->standalone = FALSE;
+ if (!server->id_entry->router) {
+ server->id_entry->router = id_entry;
+ server->router = id_entry;
+ }
}
- } else {
- SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
- "protocol active (%s:%d [%s]).", sock->hostname,
- sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
- }
- break;
- case SILC_PACKET_KEY_EXCHANGE_2:
- if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
+ }
- if (sock->protocol && sock->protocol->protocol &&
- (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
-
- if (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
- SilcServerRekeyInternalContext *proto_ctx =
- (SilcServerRekeyInternalContext *)sock->protocol->context;
-
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
-
- proto_ctx->packet = silc_packet_context_dup(packet);
+ default:
+ goto out;
+ break;
+ }
- /* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
- } else {
- SilcServerKEInternalContext *proto_ctx =
- (SilcServerKEInternalContext *)sock->protocol->context;
+ /* Add the common data structure to the ID entry. */
+ silc_idlist_add_data(id_entry, (SilcIDListData)entry);
+ silc_packet_set_context(sock, id_entry);
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
+ /* Connection has been fully established now. Everything is ok. */
+ SILC_LOG_DEBUG(("New connection authenticated"));
- proto_ctx->packet = silc_packet_context_dup(packet);
- proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
- packet->src_id_type);
- if (!proto_ctx->dest_id)
- break;
+ /* XXX Add connection to server->conns so that we know we have connection
+ to this peer. */
+ /* XXX */
- /* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->schedule,
- 0, 100000);
- }
- } else {
- SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
- "protocol active (%s:%d [%s]).", sock->hostname,
- sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
- }
- break;
+#if 0
+ /* Perform keepalive. */
+ if (param->keepalive_secs)
+ silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
+ silc_server_perform_heartbeat,
+ server->schedule);
- case SILC_PACKET_CONNECTION_AUTH_REQUEST:
- /*
- * Connection authentication request packet. When we receive this packet
- * we will send to the other end information about our mandatory
- * authentication method for the connection. This packet maybe received
- * at any time.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_connection_auth_request(server, sock, packet);
- break;
+ /* Perform Quality of Service */
+ if (param->qos)
+ silc_socket_set_qos(sock, param->qos_rate_limit, param->qos_bytes_limit,
+ param->qos_limit_sec, param->qos_limit_usec,
+ server->schedule);
+#endif
- /*
- * Connection Authentication protocol packets
- */
- case SILC_PACKET_CONNECTION_AUTH:
- /* Start of the authentication protocol. We receive here the
- authentication data and will verify it. */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_free(entry);
- if (sock->protocol && sock->protocol->protocol->type
- == SILC_PROTOCOL_SERVER_CONNECTION_AUTH) {
+ out:
+ silc_ske_free(silc_connauth_get_ske(connauth));
+ silc_connauth_free(connauth);
+}
- SilcServerConnAuthInternalContext *proto_ctx =
- (SilcServerConnAuthInternalContext *)sock->protocol->context;
+/* SKE completion callback. We set the new keys into use here. */
- proto_ctx->packet = silc_packet_context_dup(packet);
+static void
+silc_server_accept_completed(SilcSKE ske, SilcSKEStatus status,
+ SilcSKESecurityProperties prop,
+ SilcSKEKeyMaterial keymat,
+ SilcSKERekeyMaterial rekey,
+ void *context)
+{
+ SilcPacketStream sock = context;
+ SilcUnknownEntry entry = silc_packet_get_context(sock);
+ SilcServer server = entry->server;
+ SilcConnAuth connauth;
+ SilcCipher send_key, receive_key;
+ SilcHmac hmac_send, hmac_receive;
+ SilcHash hash;
+
+ if (status != SILC_SKE_STATUS_OK) {
+ /* SKE failed */
+ SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
+ silc_ske_map_status(status), entry->hostname, entry->ip));
+ silc_ske_free(ske);
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ return;
+ }
- /* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
- } else {
- SILC_LOG_ERROR(("Received Connection Auth packet but no authentication "
- "protocol active (%s:%d [%s]).", sock->hostname,
- sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
- }
- break;
+ SILC_LOG_DEBUG(("Setting keys into use"));
- case SILC_PACKET_NEW_ID:
- /*
- * Received New ID packet. This includes some new ID that has been
- * created. It may be for client, server or channel. This is the way
- * to distribute information about new registered entities in the
- * SILC network.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- silc_server_new_id_list(server, sock, packet);
- else
- silc_server_new_id(server, sock, packet);
- break;
+ /* Set the keys into use. The data will be encrypted after this. */
+ if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
+ &hmac_send, &hmac_receive, &hash)) {
+ /* Error setting keys */
+ silc_ske_free(ske);
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ return;
+ }
+ silc_packet_set_keys(sock, send_key, receive_key, hmac_send,
+ hmac_receive, FALSE);
- case SILC_PACKET_NEW_CLIENT:
- /*
- * Received new client packet. This includes client information that
- * we will use to create initial client ID. After creating new
- * ID we will send it to the client.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_new_client(server, sock, packet);
- break;
+ SILC_LOG_DEBUG(("Starting connection authentication"));
+ server->stat.auth_attempts++;
- case SILC_PACKET_NEW_SERVER:
- /*
- * Received new server packet. This includes Server ID and some other
- * information that we may save. This is received after server has
- * connected to us.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_new_server(server, sock, packet);
- break;
+ connauth = silc_connauth_alloc(server->schedule, ske,
+ server->config->conn_auth_timeout);
+ if (!connauth) {
+ /** Error allocating auth protocol */
+ silc_ske_free(ske);
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ return;
+ }
- case SILC_PACKET_NEW_CHANNEL:
- /*
- * Received new channel packet. Information about new channel in the
- * network are distributed using this packet.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- silc_server_new_channel_list(server, sock, packet);
- else
- silc_server_new_channel(server, sock, packet);
- break;
+ /* Start connection authentication */
+ silc_connauth_responder(connauth, silc_server_accept_get_auth,
+ silc_server_accept_auth_compl, sock);
+}
- case SILC_PACKET_HEARTBEAT:
- /*
- * Received heartbeat.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- break;
+/* Accept new TCP connection */
- case SILC_PACKET_KEY_AGREEMENT:
- /*
- * Received heartbeat.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_key_agreement(server, sock, packet);
- break;
+static void silc_server_accept_new_connection(SilcNetStatus status,
+ SilcStream stream,
+ void *context)
+{
+ SilcServer server = context;
+ SilcPacketStream packet_stream;
+ SilcServerConfigClient *cconfig = NULL;
+ SilcServerConfigServer *sconfig = NULL;
+ SilcServerConfigRouter *rconfig = NULL;
+ SilcServerConfigDeny *deny;
+ SilcUnknownEntry entry;
+ SilcSKE ske;
+ SilcSKEParamsStruct params;
+ char *hostname, *ip;
+ SilcUInt16 port;
- case SILC_PACKET_REKEY:
- /*
- * Received re-key packet. The sender wants to regenerate the session
- * keys.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_rekey(server, sock, packet);
- break;
+ SILC_LOG_DEBUG(("Accepting new connection"));
- case SILC_PACKET_REKEY_DONE:
- /*
- * The re-key is done.
- */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
+ /* Check for maximum allowed connections */
+ server->stat.conn_attempts++;
+#if 0
+ if (silc_server_num_connections(server) >
+ server->config->param.connections_max) {
+ SILC_LOG_ERROR(("Refusing connection, server is full"));
+ server->stat.conn_failures++;
+ silc_stream_destroy(stream);
+ return;
+ }
+#endif
- if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
+ /* Get hostname, IP and port */
+ if (!silc_socket_stream_get_info(stream, NULL, (const char **)&hostname,
+ (const char **)&ip, &port)) {
+ /* Bad socket stream */
+ server->stat.conn_failures++;
+ silc_stream_destroy(stream);
+ return;
+ }
- SilcServerRekeyInternalContext *proto_ctx =
- (SilcServerRekeyInternalContext *)sock->protocol->context;
+ /* Create packet stream */
+ packet_stream = silc_packet_stream_create(server->packet_engine,
+ server->schedule, stream);
+ if (!packet_stream) {
+ SILC_LOG_ERROR(("Refusing connection, cannot create packet stream"));
+ server->stat.conn_failures++;
+ silc_stream_destroy(stream);
+ return;
+ }
+ server->stat.conn_num++;
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
+ /* Set source ID to packet stream */
+ if (!silc_packet_set_ids(packet_stream, SILC_ID_SERVER, &server->id,
+ 0, NULL)) {
+ /* Out of memory */
+ server->stat.conn_failures++;
+ silc_packet_stream_destroy(packet_stream);
+ return;
+ }
- proto_ctx->packet = silc_packet_context_dup(packet);
+ /* Check whether this connection is denied to connect to us. */
+ deny = silc_server_config_find_denied(server, ip);
+ if (!deny)
+ deny = silc_server_config_find_denied(server, hostname);
+ if (deny) {
+ /* The connection is denied */
+ SILC_LOG_INFO(("Connection %s (%s) is denied", hostname, ip));
+ silc_server_disconnect_remote(server, packet_stream,
+ SILC_STATUS_ERR_BANNED_FROM_SERVER,
+ deny->reason);
+ return;
+ }
- /* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
- } else {
- SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
- "protocol active (%s:%d [%s]).", sock->hostname,
- sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
- }
- break;
+ /* Check whether we have configured this sort of connection at all. We
+ have to check all configurations since we don't know what type of
+ connection this is. */
+ if (!(cconfig = silc_server_config_find_client(server, ip)))
+ cconfig = silc_server_config_find_client(server, hostname);
+ if (!(sconfig = silc_server_config_find_server_conn(server, ip)))
+ sconfig = silc_server_config_find_server_conn(server, hostname);
+ if (server->server_type == SILC_ROUTER)
+ if (!(rconfig = silc_server_config_find_router_conn(server, ip, port)))
+ rconfig = silc_server_config_find_router_conn(server, hostname, port);
+ if (!cconfig && !sconfig && !rconfig) {
+ SILC_LOG_INFO(("Connection %s (%s) is not allowed", hostname, ip));
+ server->stat.conn_failures++;
+ silc_server_disconnect_remote(server, packet_stream,
+ SILC_STATUS_ERR_BANNED_FROM_SERVER, NULL);
+ return;
+ }
- case SILC_PACKET_FTP:
- /* FTP packet */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_ftp(server, sock, packet);
- break;
+ /* The connection is allowed */
+ entry = silc_calloc(1, sizeof(*entry));
+ if (!entry) {
+ server->stat.conn_failures++;
+ silc_server_disconnect_remote(server, packet_stream,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ return;
+ }
+ entry->hostname = hostname;
+ entry->ip = ip;
+ entry->port = port;
+ entry->server = server;
+ silc_packet_set_context(packet_stream, entry);
- case SILC_PACKET_RESUME_CLIENT:
- /* Resume client */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_resume_client(server, sock, packet);
- break;
+ silc_server_config_ref(&entry->cconfig, server->config, cconfig);
+ silc_server_config_ref(&entry->sconfig, server->config, sconfig);
+ silc_server_config_ref(&entry->rconfig, server->config, rconfig);
- case SILC_PACKET_RESUME_ROUTER:
- /* Resume router packet received. This packet is received for backup
- router resuming protocol. */
- if (packet->flags & SILC_PACKET_FLAG_LIST)
- break;
- silc_server_backup_resume_router(server, sock, packet);
- break;
+ /* Take flags for key exchange. Since we do not know what type of connection
+ this is, we go through all found configurations and use the global ones
+ as well. This will result always into strictest key exchange flags. */
+ memset(¶ms, 0, sizeof(params));
+ SILC_GET_SKE_FLAGS(cconfig, params.flags);
+ SILC_GET_SKE_FLAGS(sconfig, params.flags);
+ SILC_GET_SKE_FLAGS(rconfig, params.flags);
+ if (server->config->param.key_exchange_pfs)
+ params.flags |= SILC_SKE_SP_FLAG_PFS;
- default:
- SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
- break;
+ SILC_LOG_INFO(("Incoming connection %s (%s)", hostname, ip));
+ server->stat.conn_attempts++;
+
+ /* Start SILC Key Exchange protocol */
+ SILC_LOG_DEBUG(("Starting key exchange protocol"));
+ ske = silc_ske_alloc(server->rng, server->schedule, server->repository,
+ server->public_key, server->private_key,
+ packet_stream);
+ if (!ske) {
+ server->stat.conn_failures++;
+ silc_server_disconnect_remote(server, packet_stream,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ return;
}
+ silc_ske_set_callbacks(ske, silc_server_verify_key,
+ silc_server_accept_completed, packet_stream);
+
+ /* Start key exchange protocol */
+ params.version = silc_version_string;
+ params.timeout_secs = server->config->key_exchange_timeout;
+ silc_ske_responder(ske, packet_stream, ¶ms);
}
-/* Creates connection to a remote router. */
-void silc_server_create_connection(SilcServer server,
- const char *remote_host, SilcUInt32 port)
+/********************************** Rekey ***********************************/
+
+/* Initiator rekey completion callback */
+
+static void silc_server_rekey_completion(SilcSKE ske,
+ SilcSKEStatus status,
+ const SilcSKESecurityProperties prop,
+ const SilcSKEKeyMaterial keymat,
+ SilcSKERekeyMaterial rekey,
+ void *context)
{
- SilcServerConnection sconn;
+ SilcPacketStream sock = context;
+ SilcIDListData idata = silc_packet_get_context(sock);
+ SilcServer server = idata->sconn->server;
+
+ idata->sconn->op = NULL;
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_ERROR(("Error during rekey protocol with %s",
+ idata->sconn->remote_host));
+ return;
+ }
- /* Allocate connection object for hold connection specific stuff. */
- sconn = silc_calloc(1, sizeof(*sconn));
- sconn->remote_host = strdup(remote_host);
- sconn->remote_port = port;
- sconn->no_reconnect = TRUE;
+ SILC_LOG_DEBUG(("Rekey protocol completed with %s:%d [%s]",
+ idata->sconn->remote_host, idata->sconn->remote_port,
+ SILC_CONNTYPE_STRING(idata->conn_type)));
- silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_router,
- (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ /* Save rekey data for next rekey */
+ idata->rekey = rekey;
+
+ /* Register new rekey timeout */
+ silc_schedule_task_add_timeout(server->schedule, silc_server_do_rekey,
+ sock, idata->sconn->rekey_timeout, 0);
}
-SILC_TASK_CALLBACK(silc_server_close_connection_final)
+/* Rekey callback. Start rekey as initiator */
+
+SILC_TASK_CALLBACK(silc_server_do_rekey)
{
SilcServer server = app_context;
- SilcSocketConnection sock = context;
+ SilcPacketStream sock = context;
+ SilcIDListData idata = silc_packet_get_context(sock);
+ SilcSKE ske;
- SILC_LOG_DEBUG(("Deleting socket %p", sock));
+ /* Do not execute rekey with disabled connections */
+ if (idata->status & SILC_IDLIST_STATUS_DISABLED)
+ return;
- /* Close the actual connection */
- silc_net_close_connection(sock->sock);
- server->sockets[sock->sock] = NULL;
- server->stat.conn_num--;
+ /* If another protocol is active do not start rekey */
+ if (idata->sconn->op) {
+ SILC_LOG_DEBUG(("Waiting for other protocol to finish before rekeying"));
+ silc_schedule_task_add_timeout(server->schedule, silc_server_do_rekey,
+ sock, 60, 0);
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s]",
+ idata->sconn->remote_host, idata->sconn->remote_port,
+ SILC_CONNTYPE_STRING(idata->conn_type)));
+
+ /* Allocate SKE */
+ ske = silc_ske_alloc(server->rng, server->schedule, server->repository,
+ server->public_key, server->private_key, sock);
+ if (!ske)
+ return;
+
+ /* Set SKE callbacks */
+ silc_ske_set_callbacks(ske, NULL, silc_server_rekey_completion, sock);
- /* We won't listen for this connection anymore */
- silc_schedule_task_del_by_fd(server->schedule, sock->sock);
- silc_schedule_unset_listen_fd(server->schedule, sock->sock);
+ /* Perform rekey */
+ idata->sconn->op = silc_ske_rekey_initiator(ske, sock, idata->rekey);
+}
+
+
+/****************************** Disconnection *******************************/
+
+/* Destroys packet stream. */
- silc_socket_free(sock);
+SILC_TASK_CALLBACK(silc_server_close_connection_final)
+{
+ silc_packet_stream_destroy(context);
}
/* Closes connection to socket connection */
void silc_server_close_connection(SilcServer server,
- SilcSocketConnection sock)
+ SilcPacketStream sock)
{
+ SilcIDListData idata = silc_packet_get_context(sock);
char tmp[128];
+ const char *hostname;
+ SilcUInt16 port;
- if (SILC_IS_DISCONNECTED(sock)) {
- silc_schedule_task_del_by_fd(server->schedule, sock->sock);
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_close_connection_final,
- (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- server->sockets[sock->sock] = NULL;
- return;
- }
-
+#if 0
/* If any protocol is active cancel its execution. It will call
the final callback which will finalize the disconnection. */
if (sock->protocol && sock->protocol->protocol &&
sock->protocol = NULL;
return;
}
+#endif
memset(tmp, 0, sizeof(tmp));
- silc_socket_get_error(sock, tmp, sizeof(tmp));
- SILC_LOG_INFO(("Closing connection %s:%d [%s] %s", sock->hostname,
- sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router"), tmp[0] ? tmp : ""));
-
- SILC_SET_DISCONNECTED(sock);
- silc_socket_set_qos(sock, 0, 0, 0, 0, NULL);
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_close_connection_final,
- (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- server->sockets[sock->sock] = NULL;
+ // silc_socket_get_error(sock, tmp, sizeof(tmp));
+ silc_socket_stream_get_info(sock, NULL, &hostname, NULL, &port);
+ SILC_LOG_INFO(("Closing connection %s:%d [%s] %s", hostname, port,
+ SILC_CONNTYPE_STRING(idata->conn_type),
+ tmp[0] ? tmp : ""));
+
+ // silc_socket_set_qos(sock, 0, 0, 0, 0, NULL);
+
+ /* Close connection with timeout */
+ server->stat.conn_num--;
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_close_connection_final,
+ sock, 0, 1);
}
/* Sends disconnect message to remote connection and disconnects the
- connection. NOTE: If this is called from protocol callback
- then sock->protocol must be set NULL before calling this, since
- this routine dispatches protocol callbacks too. */
+ connection. */
void silc_server_disconnect_remote(SilcServer server,
- SilcSocketConnection sock,
+ SilcPacketStream sock,
SilcStatus status, ...)
{
- va_list ap;
unsigned char buf[512];
- SilcBuffer buffer;
+ va_list ap;
char *cp;
- int len;
if (!sock)
return;
- if (SILC_IS_DISCONNECTING(sock)) {
- SILC_SET_DISCONNECTED(sock);
- silc_server_close_connection(server, sock);
- return;
- }
+ SILC_LOG_DEBUG(("Disconnecting remote host"));
- memset(buf, 0, sizeof(buf));
va_start(ap, status);
cp = va_arg(ap, char *);
- if (cp) {
- vsnprintf(buf, sizeof(buf) - 1, cp, ap);
- cp = buf;
- }
- va_end(ap);
-
- SILC_LOG_DEBUG(("Disconnecting remote host"));
-
- /* Notify remote end that the conversation is over. The notify message
- is tried to be sent immediately. */
-
- len = 1;
- if (cp)
- len += silc_utf8_encoded_len(buf, strlen(buf), SILC_STRING_ASCII);
-
- buffer = silc_buffer_alloc_size(len);
- if (!buffer)
- goto out;
-
- buffer->data[0] = status;
if (cp)
- silc_utf8_encode(buf, strlen(buf), SILC_STRING_ASCII, buffer->data + 1,
- buffer->len - 1);
- silc_server_packet_send(server, sock, SILC_PACKET_DISCONNECT, 0,
- buffer->data, buffer->len, TRUE);
- silc_buffer_free(buffer);
+ silc_vsnprintf(buf, sizeof(buf), cp, ap);
+ va_end(ap);
- out:
- silc_server_packet_queue_purge(server, sock);
+ /* Send SILC_PACKET_DISCONNECT */
+ silc_packet_send_va(sock, SILC_PACKET_DISCONNECT, 0,
+ SILC_STR_UI_CHAR(status),
+ SILC_STR_UI8_STRING(cp ? buf : NULL),
+ SILC_STR_END);
- /* Mark the connection to be disconnected */
- SILC_SET_DISCONNECTING(sock);
+ /* Close connection */
silc_server_close_connection(server, sock);
}
SILC_TASK_CALLBACK(silc_server_free_client_data_timeout)
{
- SilcServer server = app_context;
SilcClientEntry client = context;
assert(!silc_hash_table_count(client->channels));
silc_idlist_del_data(client);
- silc_idcache_purge_by_context(server->local_list->clients, client);
+ // silc_idcache_purge_by_context(server->local_list->clients, client);
}
/* Frees client data and notifies about client's signoff. */
void silc_server_free_client_data(SilcServer server,
- SilcSocketConnection sock,
+ SilcPacketStream sock,
SilcClientEntry client,
int notify,
const char *signoff)
{
SILC_LOG_DEBUG(("Freeing client data"));
- /* If there is pending outgoing data for the client then purge it
- to the network before removing the client entry. */
- silc_server_packet_queue_purge(server, sock);
-
if (client->id) {
/* Check if anyone is watching this nickname */
if (server->server_type == SILC_ROUTER)
into history (for WHOWAS command) for 5 minutes, unless we're
shutting down server. */
if (!server->server_shutdown) {
- silc_schedule_task_add(server->schedule, 0,
- silc_server_free_client_data_timeout,
- client, 600, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_free_client_data_timeout,
+ client, 600, 0);
client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
client->mode = 0;
entities. */
void silc_server_free_sock_user_data(SilcServer server,
- SilcSocketConnection sock,
+ SilcPacketStream sock,
const char *signoff_message)
{
+ SilcIDListData idata = silc_packet_get_context(sock);
- /* If any protocol is active cancel its execution */
- if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
- SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
- silc_protocol_cancel(sock->protocol, server->schedule);
- sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
- silc_protocol_execute_final(sock->protocol, server->schedule);
- sock->protocol = NULL;
- if (!sock->user_data)
- return;
- }
+ if (!idata)
+ return;
- switch (sock->type) {
- case SILC_SOCKET_TYPE_CLIENT:
+ switch (idata->conn_type) {
+ case SILC_CONN_CLIENT:
{
- SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
- silc_server_free_client_data(server, sock, user_data, TRUE,
+ SilcClientEntry client_entry = (SilcClientEntry)idata;
+ silc_server_free_client_data(server, sock, client_entry, TRUE,
signoff_message);
break;
}
- case SILC_SOCKET_TYPE_SERVER:
- case SILC_SOCKET_TYPE_ROUTER:
+
+ case SILC_CONN_SERVER:
+ case SILC_CONN_ROUTER:
{
- SilcServerEntry user_data = (SilcServerEntry)sock->user_data;
+ SilcServerEntry user_data = (SilcServerEntry)idata;
SilcServerEntry backup_router = NULL;
SILC_LOG_DEBUG(("Freeing server data"));
if (!server->backup_router && server->server_type == SILC_ROUTER &&
backup_router == server->id_entry &&
- sock->type != SILC_SOCKET_TYPE_ROUTER)
+ idata->conn_type != SILC_CONN_ROUTER)
backup_router = NULL;
if (server->server_shutdown || server->backup_noswitch)
/* We stop here to take a breath */
sleep(2);
+#if 0
if (server->backup_router) {
server->server_type = SILC_ROUTER;
silc_server_backup_connected,
NULL);
}
+#endif /* 0 */
/* Mark this connection as replaced */
silc_server_backup_replaced_add(server, user_data->id,
silc_server_backup_replaced_add(server, user_data->id,
backup_router);
} else if (server->server_type == SILC_SERVER &&
- sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ idata->conn_type == SILC_CONN_ROUTER) {
/* Reconnect to the router (backup) */
if (!server->no_reconnect)
silc_server_create_connections(server);
coming from the primary router, so mark that as the owner
of this entry. */
if (server->server_type == SILC_BACKUP_ROUTER &&
- sock->type == SILC_SOCKET_TYPE_SERVER)
+ sock->type == SILC_CONN_SERVER)
silc_server_remove_clients_by_server(server, server->router,
user_data, TRUE);
else
silc_idlist_del_data(user_data);
if (!silc_idlist_del_server(server->local_list, user_data))
silc_idlist_del_server(server->global_list, user_data);
- if (sock->type == SILC_SOCKET_TYPE_SERVER) {
+ if (idata->conn_type == SILC_CONN_SERVER) {
server->stat.my_servers--;
server->stat.servers--;
} else {
}
break;
}
+
default:
{
- SilcUnknownEntry user_data = (SilcUnknownEntry)sock->user_data;
+ SilcUnknownEntry entry = (SilcUnknownEntry)idata;
SILC_LOG_DEBUG(("Freeing unknown connection data"));
- silc_idlist_del_data(user_data);
- silc_free(user_data);
+ silc_idlist_del_data(idata);
+ silc_free(entry);
break;
}
}
-
- sock->user_data = NULL;
}
/* Removes client from all channels it has joined. This is used when client
channel is removed as well. This sends the SIGNOFF notify types. */
void silc_server_remove_from_channels(SilcServer server,
- SilcSocketConnection sock,
+ SilcPacketStream sock,
SilcClientEntry client,
- bool notify,
+ SilcBool notify,
const char *signoff_message,
- bool keygen,
- bool killed)
+ SilcBool keygen,
+ SilcBool killed)
{
SilcChannelEntry channel;
SilcChannelClientEntry chl;
silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
SILC_NOTIFY_TYPE_SIGNOFF,
signoff_message ? 2 : 1,
- clidp->data, clidp->len,
+ clidp->data, silc_buffer_len(clidp),
signoff_message, signoff_message ?
strlen(signoff_message) : 0);
silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
SILC_NOTIFY_TYPE_SIGNOFF,
signoff_message ? 2 : 1,
- clidp->data, clidp->len,
+ clidp->data, silc_buffer_len(clidp),
signoff_message, signoff_message ?
strlen(signoff_message) : 0);
SilcBuffer ab;
SilcArgumentPayload iargs;
ab = silc_argument_payload_encode_one(NULL, clidp->data,
- clidp->len, 3);
- iargs = silc_argument_payload_parse(ab->data, ab->len, 1);
+ silc_buffer_len(clidp), 3);
+ iargs = silc_argument_payload_parse(ab->data, silc_buffer_len(ab), 1);
silc_server_inviteban_process(server, channel->invite_list, 1, iargs);
silc_buffer_free(ab);
silc_argument_payload_free(iargs);
last client leaves the channel. If `notify' is FALSE notify messages
are not sent. */
-bool silc_server_remove_from_one_channel(SilcServer server,
- SilcSocketConnection sock,
+SilcBool silc_server_remove_from_one_channel(SilcServer server,
+ SilcPacketStream sock,
SilcChannelEntry channel,
SilcClientEntry client,
- bool notify)
+ SilcBool notify)
{
SilcChannelClientEntry chl;
SilcBuffer clidp;
if (notify && channel->global_users)
silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
SILC_NOTIFY_TYPE_LEAVE, 1,
- clidp->data, clidp->len);
+ clidp->data, silc_buffer_len(clidp));
silc_schedule_task_del_by_context(server->schedule, channel->rekey);
silc_server_channel_delete(server, channel);
if (notify)
silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
SILC_NOTIFY_TYPE_LEAVE, 1,
- clidp->data, clidp->len);
+ clidp->data, silc_buffer_len(clidp));
silc_buffer_free(clidp);
return TRUE;
}
+#if 0
/* Timeout callback. This is called if connection is idle or for some
other reason is not responding within some period of time. This
disconnects the remote end. */
SILC_TASK_CALLBACK(silc_server_timeout_remote)
{
SilcServer server = (SilcServer)context;
- SilcSocketConnection sock = server->sockets[fd];
- SilcProtocolType protocol = 0;
+ SilcPacketStream sock = server->sockets[fd];
SILC_LOG_DEBUG(("Start"));
if (sock->user_data)
silc_server_free_sock_user_data(server, sock, NULL);
}
+#endif /* 0 */
/* Creates new channel. Sends NEW_CHANNEL packet to primary route. This
function may be used only by router. In real SILC network all channels
{
SilcChannelID *channel_id;
SilcChannelEntry entry;
- SilcCipher key;
+ SilcCipher send_key, receive_key;
SilcHmac newhmac;
SILC_LOG_DEBUG(("Creating new channel %s", channel_name));
hmac = SILC_DEFAULT_HMAC;
/* Allocate cipher */
- if (!silc_cipher_alloc(cipher, &key))
+ if (!silc_cipher_alloc(cipher, &send_key))
return NULL;
+ if (!silc_cipher_alloc(cipher, &receive_key)) {
+ silc_cipher_free(send_key);
+ return NULL;
+ }
/* Allocate hmac */
if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
- silc_cipher_free(key);
+ silc_cipher_free(send_key);
+ silc_cipher_free(receive_key);
return NULL;
}
if (!silc_id_create_channel_id(server, router_id, server->rng,
&channel_id)) {
silc_free(channel_name);
- silc_cipher_free(key);
+ silc_cipher_free(send_key);
+ silc_cipher_free(receive_key);
silc_hmac_free(newhmac);
return NULL;
}
/* Create the channel */
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
- NULL, key, newhmac, 0);
+ NULL, send_key, receive_key, newhmac);
if (!entry) {
silc_free(channel_name);
- silc_cipher_free(key);
+ silc_cipher_free(send_key);
+ silc_cipher_free(receive_key);
silc_hmac_free(newhmac);
silc_free(channel_id);
return NULL;
/* Now create the actual key material */
if (!silc_server_create_channel_key(server, entry,
- silc_cipher_get_key_len(key) / 8)) {
+ silc_cipher_get_key_len(send_key) / 8)) {
silc_idlist_del_channel(server->local_list, entry);
return NULL;
}
/* Distribute to backup routers */
if (broadcast && server->server_type == SILC_ROUTER) {
SilcBuffer packet;
- unsigned char *cid;
+ unsigned char cid[32];
SilcUInt32 name_len = strlen(channel_name);
- SilcUInt32 channel_id_len = silc_id_get_len(entry->id, SILC_ID_CHANNEL);
- cid = silc_id_id2str(entry->id, SILC_ID_CHANNEL);
+ SilcUInt32 id_len;
+ silc_id_id2str(entry->id, SILC_ID_CHANNEL, cid, sizeof(cid), &id_len);
packet = silc_channel_payload_encode(channel_name, name_len,
- cid, channel_id_len, entry->mode);
+ cid, id_len, entry->mode);
silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
- packet->data, packet->len, FALSE, TRUE);
- silc_free(cid);
+ packet->data, silc_buffer_len(packet), FALSE,
+ TRUE);
silc_buffer_free(packet);
}
int broadcast)
{
SilcChannelEntry entry;
- SilcCipher key;
+ SilcCipher send_key, receive_key;
SilcHmac newhmac;
SILC_LOG_DEBUG(("Creating new channel %s", channel_name));
hmac = SILC_DEFAULT_HMAC;
/* Allocate cipher */
- if (!silc_cipher_alloc(cipher, &key))
+ if (!silc_cipher_alloc(cipher, &send_key))
return NULL;
+ if (!silc_cipher_alloc(cipher, &receive_key)) {
+ silc_cipher_free(send_key);
+ return NULL;
+ }
/* Allocate hmac */
if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
- silc_cipher_free(key);
+ silc_cipher_free(send_key);
+ silc_cipher_free(receive_key);
return NULL;
}
/* Create the channel */
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
- NULL, key, newhmac, 0);
+ NULL, send_key, receive_key, newhmac);
if (!entry) {
- silc_cipher_free(key);
+ silc_cipher_free(send_key);
+ silc_cipher_free(receive_key);
silc_hmac_free(newhmac);
silc_free(channel_name);
return NULL;
/* Now create the actual key material */
if (!silc_server_create_channel_key(server, entry,
- silc_cipher_get_key_len(key) / 8)) {
+ silc_cipher_get_key_len(send_key) / 8)) {
silc_idlist_del_channel(server->local_list, entry);
return NULL;
}
/* Distribute to backup routers */
if (broadcast && server->server_type == SILC_ROUTER) {
SilcBuffer packet;
- unsigned char *cid;
+ unsigned char cid[32];
SilcUInt32 name_len = strlen(channel_name);
- SilcUInt32 channel_id_len = silc_id_get_len(entry->id, SILC_ID_CHANNEL);
- cid = silc_id_id2str(entry->id, SILC_ID_CHANNEL);
+ SilcUInt32 id_len;
+ silc_id_id2str(entry->id, SILC_ID_CHANNEL, cid, sizeof(cid), &id_len);
packet = silc_channel_payload_encode(channel_name, name_len,
- cid, channel_id_len, entry->mode);
+ cid, id_len, entry->mode);
silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
- packet->data, packet->len, FALSE, TRUE);
- silc_free(cid);
+ packet->data, silc_buffer_len(packet), FALSE,
+ TRUE);
silc_buffer_free(packet);
}
but also to re-generate new key for channel. If `key_len' is provided
it is the bytes of the key length. */
-bool silc_server_create_channel_key(SilcServer server,
- SilcChannelEntry channel,
- SilcUInt32 key_len)
+SilcBool silc_server_create_channel_key(SilcServer server,
+ SilcChannelEntry channel,
+ SilcUInt32 key_len)
{
int i;
unsigned char channel_key[32], hash[SILC_HASH_MAXLEN];
SILC_LOG_DEBUG(("Generating channel %s key", channel->channel_name));
- if (!channel->channel_key)
- if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key)) {
- channel->channel_key = NULL;
+ if (!channel->send_key)
+ if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->send_key)) {
+ channel->send_key = NULL;
+ return FALSE;
+ }
+ if (!channel->receive_key)
+ if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->receive_key)) {
+ silc_cipher_free(channel->send_key);
+ channel->send_key = channel->receive_key = NULL;
return FALSE;
}
else if (channel->key_len)
len = channel->key_len / 8;
else
- len = silc_cipher_get_key_len(channel->channel_key) / 8;
+ len = silc_cipher_get_key_len(channel->send_key) / 8;
/* Create channel key */
for (i = 0; i < len; i++) channel_key[i] = silc_rng_get_byte(server->rng);
/* Set the key */
- silc_cipher_set_key(channel->channel_key, channel_key, len * 8);
+ silc_cipher_set_key(channel->send_key, channel_key, len * 8, TRUE);
+ silc_cipher_set_key(channel->receive_key, channel_key, len * 8, FALSE);
/* Remove old key if exists */
if (channel->key) {
if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
memset(channel->key, 0, channel->key_len / 8);
silc_free(channel->key);
- channel->channel_key = NULL;
+ silc_cipher_free(channel->send_key);
+ silc_cipher_free(channel->receive_key);
+ channel->send_key = channel->receive_key = NULL;
return FALSE;
}
silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, len, hash);
silc_schedule_task_del(server->schedule, channel->rekey->task);
channel->rekey->task =
- silc_schedule_task_add(server->schedule, 0,
- silc_server_channel_key_rekey,
- (void *)channel->rekey,
- server->config->channel_rekey_secs, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_channel_key_rekey,
+ (void *)channel->rekey,
+ server->config->channel_rekey_secs, 0);
}
return TRUE;
SilcChannelEntry channel)
{
SilcChannelKeyPayload payload = NULL;
- SilcChannelID *id = NULL;
+ SilcChannelID id;
unsigned char *tmp, hash[SILC_HASH_MAXLEN];
SilcUInt32 tmp_len;
char *cipher;
/* Decode channel key payload */
payload = silc_channel_key_payload_parse(key_payload->data,
- key_payload->len);
+ silc_buffer_len(key_payload));
if (!payload) {
SILC_LOG_ERROR(("Bad channel key payload received, dropped"));
channel = NULL;
/* Get channel ID */
tmp = silc_channel_key_get_id(payload, &tmp_len);
- id = silc_id_str2id(tmp, tmp_len, SILC_ID_CHANNEL);
- if (!id) {
+ if (!silc_id_str2id(tmp, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
channel = NULL;
goto out;
}
- channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+ channel = silc_idlist_find_channel_by_id(server->local_list, &id, NULL);
if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+ channel = silc_idlist_find_channel_by_id(server->global_list, &id, NULL);
if (!channel) {
if (server->server_type == SILC_ROUTER)
SILC_LOG_ERROR(("Received key for non-existent channel %s",
- silc_id_render(id, SILC_ID_CHANNEL)));
+ silc_id_render(&id, SILC_ID_CHANNEL)));
goto out;
}
}
if (channel->key) {
memset(channel->key, 0, channel->key_len / 8);
silc_free(channel->key);
- silc_cipher_free(channel->channel_key);
+ silc_cipher_free(channel->send_key);
+ silc_cipher_free(channel->receive_key);
}
/* Create new cipher */
- if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
- channel->channel_key = NULL;
+ if (!silc_cipher_alloc(cipher, &channel->send_key)) {
+ channel->send_key = NULL;
+ channel = NULL;
+ goto out;
+ }
+ if (!silc_cipher_alloc(cipher, &channel->receive_key)) {
+ silc_cipher_free(channel->send_key);
+ channel->send_key = channel->receive_key = NULL;
channel = NULL;
goto out;
}
/* Save the key */
channel->key_len = tmp_len * 8;
channel->key = silc_memdup(tmp, tmp_len);
- silc_cipher_set_key(channel->channel_key, tmp, channel->key_len);
+ silc_cipher_set_key(channel->send_key, tmp, channel->key_len, TRUE);
+ silc_cipher_set_key(channel->receive_key, tmp, channel->key_len, FALSE);
/* Generate HMAC key from the channel key data and set it */
if (!channel->hmac)
if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
memset(channel->key, 0, channel->key_len / 8);
silc_free(channel->key);
- channel->channel_key = NULL;
+ silc_cipher_free(channel->send_key);
+ silc_cipher_free(channel->receive_key);
+ channel->send_key = channel->receive_key = NULL;
return FALSE;
}
silc_hash_make(silc_hmac_get_hash(channel->hmac), tmp, tmp_len, hash);
silc_schedule_task_del(server->schedule, channel->rekey->task);
channel->rekey->task =
- silc_schedule_task_add(server->schedule, 0,
- silc_server_channel_key_rekey,
- (void *)channel->rekey,
- server->config->channel_rekey_secs, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_channel_key_rekey,
+ (void *)channel->rekey,
+ server->config->channel_rekey_secs, 0);
}
out:
- silc_free(id);
if (payload)
silc_channel_key_payload_free(payload);
return channel;
}
-/* Heartbeat callback. This function is set as argument for the
- silc_socket_set_heartbeat function. The library will call this function
- at the set time interval. */
-
-void silc_server_perform_heartbeat(SilcSocketConnection sock,
- void *hb_context)
-{
- SilcServer server = hb_context;
-
- SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname,
- sock->port, sock->ip));
-
- /* Send the heartbeat */
- silc_server_send_heartbeat(server, sock);
-}
-
/* Returns assembled of all servers in the given ID list. The packet's
form is dictated by the New ID payload. */
SilcBuffer *servers,
unsigned long creation_time)
{
- SilcIDCacheList list;
+ SilcList list;
SilcIDCacheEntry id_cache;
SilcServerEntry entry;
SilcBuffer idp;
/* Go through all clients in the list */
if (silc_idcache_get_all(id_list->servers, &list)) {
- if (silc_idcache_list_first(list, &id_cache)) {
- while (id_cache) {
- entry = (SilcServerEntry)id_cache->context;
-
- /* Do not announce the one we've sending our announcements and
- do not announce ourself. Also check the creation time if it's
- provided. */
- if ((entry == remote) || (entry == server->id_entry) ||
- (creation_time && entry->data.created < creation_time)) {
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- continue;
- }
-
- idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
-
- *servers = silc_buffer_realloc(*servers,
- (*servers ?
- (*servers)->truelen + idp->len :
- idp->len));
- silc_buffer_pull_tail(*servers, ((*servers)->end - (*servers)->data));
- silc_buffer_put(*servers, idp->data, idp->len);
- silc_buffer_pull(*servers, idp->len);
- silc_buffer_free(idp);
+ silc_list_start(list);
+ while ((id_cache = silc_list_get(list))) {
+ entry = (SilcServerEntry)id_cache->context;
+
+ /* Do not announce the one we've sending our announcements and
+ do not announce ourself. Also check the creation time if it's
+ provided. */
+ if ((entry == remote) || (entry == server->id_entry) ||
+ (creation_time && entry->data.created < creation_time))
+ continue;
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- }
+ idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+
+ *servers = silc_buffer_realloc(*servers,
+ (*servers ?
+ silc_buffer_truelen((*servers)) +
+ silc_buffer_len(idp) :
+ silc_buffer_len(idp)));
+ silc_buffer_pull_tail(*servers, ((*servers)->end - (*servers)->data));
+ silc_buffer_put(*servers, idp->data, silc_buffer_len(idp));
+ silc_buffer_pull(*servers, silc_buffer_len(idp));
+ silc_buffer_free(idp);
}
-
- silc_idcache_list_free(list);
}
}
then only the servers that has been created after the `creation_time'
will be announced. */
-void silc_server_announce_servers(SilcServer server, bool global,
+void silc_server_announce_servers(SilcServer server, SilcBool global,
unsigned long creation_time,
- SilcSocketConnection remote)
+ SilcPacketStream remote)
{
SilcBuffer servers = NULL;
SILC_LOG_DEBUG(("Announcing servers"));
/* Get servers in local list */
- silc_server_announce_get_servers(server, remote->user_data,
+ silc_server_announce_get_servers(server, silc_packet_get_context(remote),
server->local_list, &servers,
creation_time);
if (global)
/* Get servers in global list */
- silc_server_announce_get_servers(server, remote->user_data,
+ silc_server_announce_get_servers(server, silc_packet_get_context(remote),
server->global_list, &servers,
creation_time);
if (servers) {
silc_buffer_push(servers, servers->data - servers->head);
- SILC_LOG_HEXDUMP(("servers"), servers->data, servers->len);
+ SILC_LOG_HEXDUMP(("servers"), servers->data, silc_buffer_len(servers));
/* Send the packet */
silc_server_packet_send(server, remote,
SILC_PACKET_NEW_ID, SILC_PACKET_FLAG_LIST,
- servers->data, servers->len, TRUE);
+ servers->data, silc_buffer_len(servers));
silc_buffer_free(servers);
}
SilcBuffer *umodes,
unsigned long creation_time)
{
- SilcIDCacheList list;
+ SilcList list;
SilcIDCacheEntry id_cache;
SilcClientEntry client;
SilcBuffer idp;
/* Go through all clients in the list */
if (silc_idcache_get_all(id_list->clients, &list)) {
- if (silc_idcache_list_first(list, &id_cache)) {
- while (id_cache) {
- client = (SilcClientEntry)id_cache->context;
+ silc_list_start(list);
+ while ((id_cache = silc_list_get(list))) {
+ client = (SilcClientEntry)id_cache->context;
- if (creation_time && client->data.created < creation_time) {
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- continue;
- }
- if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- continue;
- }
- if (!client->connection && !client->router) {
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- continue;
- }
+ if (creation_time && client->data.created < creation_time)
+ continue;
+ if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
+ continue;
+ if (!client->connection && !client->router)
+ continue;
- idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
- *clients = silc_buffer_realloc(*clients,
- (*clients ?
- (*clients)->truelen + idp->len :
- idp->len));
- silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
- silc_buffer_put(*clients, idp->data, idp->len);
- silc_buffer_pull(*clients, idp->len);
-
- SILC_PUT32_MSB(client->mode, mode);
- tmp =
- silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
- 2, idp->data, idp->len,
- mode, 4);
- *umodes = silc_buffer_realloc(*umodes,
- (*umodes ?
- (*umodes)->truelen + tmp->len :
- tmp->len));
- silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
- silc_buffer_put(*umodes, tmp->data, tmp->len);
- silc_buffer_pull(*umodes, tmp->len);
- silc_buffer_free(tmp);
-
- silc_buffer_free(idp);
-
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- }
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+ *clients = silc_buffer_realloc(*clients,
+ (*clients ?
+ silc_buffer_truelen((*clients)) +
+ silc_buffer_len(idp) :
+ silc_buffer_len(idp)));
+ silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
+ silc_buffer_put(*clients, idp->data, silc_buffer_len(idp));
+ silc_buffer_pull(*clients, silc_buffer_len(idp));
+
+ SILC_PUT32_MSB(client->mode, mode);
+ tmp =
+ silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
+ 2, idp->data, silc_buffer_len(idp),
+ mode, 4);
+ *umodes = silc_buffer_realloc(*umodes,
+ (*umodes ?
+ silc_buffer_truelen((*umodes)) +
+ silc_buffer_len(tmp) :
+ silc_buffer_len(tmp)));
+ silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
+ silc_buffer_put(*umodes, tmp->data, silc_buffer_len(tmp));
+ silc_buffer_pull(*umodes, silc_buffer_len(tmp));
+ silc_buffer_free(tmp);
+
+ silc_buffer_free(idp);
}
-
- silc_idcache_list_free(list);
}
}
void silc_server_announce_clients(SilcServer server,
unsigned long creation_time,
- SilcSocketConnection remote)
+ SilcPacketStream remote)
{
SilcBuffer clients = NULL;
SilcBuffer umodes = NULL;
if (clients) {
silc_buffer_push(clients, clients->data - clients->head);
- SILC_LOG_HEXDUMP(("clients"), clients->data, clients->len);
+ SILC_LOG_HEXDUMP(("clients"), clients->data, silc_buffer_len(clients));
/* Send the packet */
silc_server_packet_send(server, remote,
SILC_PACKET_NEW_ID, SILC_PACKET_FLAG_LIST,
- clients->data, clients->len, TRUE);
+ clients->data, silc_buffer_len(clients));
silc_buffer_free(clients);
}
if (umodes) {
silc_buffer_push(umodes, umodes->data - umodes->head);
- SILC_LOG_HEXDUMP(("umodes"), umodes->data, umodes->len);
+ SILC_LOG_HEXDUMP(("umodes"), umodes->data, silc_buffer_len(umodes));
/* Send the packet */
silc_server_packet_send(server, remote,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
- umodes->data, umodes->len, TRUE);
+ umodes->data, silc_buffer_len(umodes));
silc_buffer_free(umodes);
}
if (channel->topic) {
chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
*topic = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_TOPIC_SET, 2,
- chidp->data, chidp->len,
+ chidp->data,
+ silc_buffer_len(chidp),
channel->topic,
strlen(channel->topic));
silc_buffer_free(chidp);
SILC_PUT16_MSB(type, list->data);
silc_hash_table_list(channel->invite_list, &htl);
while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
- list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+ list = silc_argument_payload_encode_one(list, tmp2->data, silc_buffer_len(tmp2),
type);
silc_hash_table_list_reset(&htl);
idp2 = silc_id_payload_encode(server->id, SILC_ID_SERVER);
*invite =
silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_INVITE, 5,
- idp->data, idp->len,
+ idp->data, silc_buffer_len(idp),
channel->channel_name,
strlen(channel->channel_name),
- idp2->data, idp2->len,
+ idp2->data, silc_buffer_len(idp2),
a, 1,
- list->data, list->len);
+ list->data, silc_buffer_len(list));
silc_buffer_free(idp2);
silc_buffer_free(list);
}
SILC_PUT16_MSB(type, list->data);
silc_hash_table_list(channel->ban_list, &htl);
while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
- list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+ list = silc_argument_payload_encode_one(list, tmp2->data, silc_buffer_len(tmp2),
type);
silc_hash_table_list_reset(&htl);
*ban =
silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_BAN, 3,
- idp->data, idp->len,
+ idp->data, silc_buffer_len(idp),
a, 1,
- list->data, list->len);
+ list->data, silc_buffer_len(list));
silc_buffer_free(list);
}
SILC_PUT32_MSB(channel->user_limit, ulimit);
hmac = channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : NULL;
if (channel->founder_key)
- fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+ fkey = silc_public_key_payload_encode(channel->founder_key);
tmp =
silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE,
- 8, csidp->data, csidp->len,
+ 8, csidp->data,
+ silc_buffer_len(csidp),
mode, sizeof(mode),
NULL, 0,
hmac, hmac ? strlen(hmac) : 0,
channel->passphrase ?
strlen(channel->passphrase) : 0,
fkey ? fkey->data : NULL,
- fkey ? fkey->len : 0,
+ fkey ? silc_buffer_len(fkey) : 0,
chpklist ? chpklist->data : NULL,
- chpklist ? chpklist->len : 0,
+ chpklist ?
+ silc_buffer_len(chpklist) : 0,
(channel->mode &
SILC_CHANNEL_MODE_ULIMIT ?
ulimit : NULL),
(channel->mode &
SILC_CHANNEL_MODE_ULIMIT ?
sizeof(ulimit) : 0));
- len = tmp->len;
+ len = silc_buffer_len(tmp);
*channel_modes =
silc_buffer_realloc(*channel_modes,
(*channel_modes ?
- (*channel_modes)->truelen + len : len));
+ silc_buffer_truelen((*channel_modes)) + len : len));
silc_buffer_pull_tail(*channel_modes,
((*channel_modes)->end -
(*channel_modes)->data));
- silc_buffer_put(*channel_modes, tmp->data, tmp->len);
+ silc_buffer_put(*channel_modes, tmp->data, silc_buffer_len(tmp));
silc_buffer_pull(*channel_modes, len);
silc_buffer_free(tmp);
silc_buffer_free(fkey);
/* JOIN Notify */
tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_JOIN, 2,
- clidp->data, clidp->len,
- chidp->data, chidp->len);
- len = tmp->len;
+ clidp->data,
+ silc_buffer_len(clidp),
+ chidp->data,
+ silc_buffer_len(chidp));
+ len = silc_buffer_len(tmp);
*channel_users =
silc_buffer_realloc(*channel_users,
(*channel_users ?
- (*channel_users)->truelen + len : len));
+ silc_buffer_truelen((*channel_users)) + len : len));
silc_buffer_pull_tail(*channel_users,
((*channel_users)->end -
(*channel_users)->data));
- silc_buffer_put(*channel_users, tmp->data, tmp->len);
+ silc_buffer_put(*channel_users, tmp->data, silc_buffer_len(tmp));
silc_buffer_pull(*channel_users, len);
silc_buffer_free(tmp);
/* CUMODE notify for mode change on the channel */
SILC_PUT32_MSB(chl->mode, mode);
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && channel->founder_key)
- fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+ fkey = silc_public_key_payload_encode(channel->founder_key);
tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE,
- 4, csidp->data, csidp->len,
+ 4, csidp->data,
+ silc_buffer_len(csidp),
mode, sizeof(mode),
- clidp->data, clidp->len,
+ clidp->data,
+ silc_buffer_len(clidp),
fkey ? fkey->data : NULL,
- fkey ? fkey->len : 0);
- len = tmp->len;
+ fkey ? silc_buffer_len(fkey) : 0);
+ len = silc_buffer_len(tmp);
*channel_users_modes =
silc_buffer_realloc(*channel_users_modes,
(*channel_users_modes ?
- (*channel_users_modes)->truelen + len : len));
+ silc_buffer_truelen((*channel_users_modes)) +
+ len : len));
silc_buffer_pull_tail(*channel_users_modes,
((*channel_users_modes)->end -
(*channel_users_modes)->data));
- silc_buffer_put(*channel_users_modes, tmp->data, tmp->len);
+ silc_buffer_put(*channel_users_modes, tmp->data, silc_buffer_len(tmp));
silc_buffer_pull(*channel_users_modes, len);
silc_buffer_free(tmp);
silc_buffer_free(fkey);
SilcChannelID ***channel_ids,
unsigned long creation_time)
{
- SilcIDCacheList list;
+ SilcList list;
SilcIDCacheEntry id_cache;
SilcChannelEntry channel;
- unsigned char *cid;
+ unsigned char cid[32];
SilcUInt32 id_len;
SilcUInt16 name_len;
int len;
int i = *channel_users_modes_c;
- bool announce;
+ SilcBool announce;
SILC_LOG_DEBUG(("Start"));
/* Go through all channels in the list */
if (silc_idcache_get_all(id_list->channels, &list)) {
- if (silc_idcache_list_first(list, &id_cache)) {
- while (id_cache) {
- channel = (SilcChannelEntry)id_cache->context;
+ silc_list_start(list);
+ while ((id_cache = silc_list_get(list))) {
+ channel = (SilcChannelEntry)id_cache->context;
- if (creation_time && channel->created < creation_time)
- announce = FALSE;
- else
- announce = TRUE;
-
- cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
- id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
- name_len = strlen(channel->channel_name);
-
- if (announce) {
- len = 4 + name_len + id_len + 4;
- *channels =
- silc_buffer_realloc(*channels,
- (*channels ? (*channels)->truelen +
- len : len));
- silc_buffer_pull_tail(*channels,
- ((*channels)->end - (*channels)->data));
- silc_buffer_format(*channels,
- SILC_STR_UI_SHORT(name_len),
- SILC_STR_UI_XNSTRING(channel->channel_name,
- name_len),
- SILC_STR_UI_SHORT(id_len),
+ if (creation_time && channel->created < creation_time)
+ announce = FALSE;
+ else
+ announce = TRUE;
+
+ silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), &id_len);
+ name_len = strlen(channel->channel_name);
+
+ if (announce) {
+ len = 4 + name_len + id_len + 4;
+ *channels =
+ silc_buffer_realloc(*channels,
+ (*channels ?
+ silc_buffer_truelen((*channels)) +
+ len : len));
+ silc_buffer_pull_tail(*channels,
+ ((*channels)->end - (*channels)->data));
+ silc_buffer_format(*channels,
+ SILC_STR_UI_SHORT(name_len),
+ SILC_STR_UI_XNSTRING(channel->channel_name,
+ name_len),
+ SILC_STR_UI_SHORT(id_len),
SILC_STR_UI_XNSTRING(cid, id_len),
- SILC_STR_UI_INT(channel->mode),
- SILC_STR_END);
- silc_buffer_pull(*channels, len);
- }
+ SILC_STR_UI_INT(channel->mode),
+ SILC_STR_END);
+ silc_buffer_pull(*channels, len);
+ }
- if (creation_time && channel->updated < creation_time)
- announce = FALSE;
- else
- announce = TRUE;
-
- if (announce) {
- /* Channel user modes */
- *channel_users_modes = silc_realloc(*channel_users_modes,
- sizeof(**channel_users_modes) *
- (i + 1));
- (*channel_users_modes)[i] = NULL;
- *channel_modes = silc_realloc(*channel_modes,
- sizeof(**channel_modes) * (i + 1));
- (*channel_modes)[i] = NULL;
- *channel_ids = silc_realloc(*channel_ids,
+ if (creation_time && channel->updated < creation_time)
+ announce = FALSE;
+ else
+ announce = TRUE;
+
+ if (announce) {
+ /* Channel user modes */
+ *channel_users_modes = silc_realloc(*channel_users_modes,
+ sizeof(**channel_users_modes) *
+ (i + 1));
+ (*channel_users_modes)[i] = NULL;
+ *channel_modes = silc_realloc(*channel_modes,
+ sizeof(**channel_modes) * (i + 1));
+ (*channel_modes)[i] = NULL;
+ *channel_ids = silc_realloc(*channel_ids,
sizeof(**channel_ids) * (i + 1));
- (*channel_ids)[i] = NULL;
- silc_server_announce_get_channel_users(server, channel,
- &(*channel_modes)[i],
- channel_users,
- &(*channel_users_modes)[i]);
- (*channel_ids)[i] = channel->id;
-
- /* Channel's topic */
- *channel_topics = silc_realloc(*channel_topics,
- sizeof(**channel_topics) * (i + 1));
- (*channel_topics)[i] = NULL;
- silc_server_announce_get_channel_topic(server, channel,
- &(*channel_topics)[i]);
-
- /* Channel's invite and ban list */
- *channel_invites = silc_realloc(*channel_invites,
- sizeof(**channel_invites) * (i + 1));
- (*channel_invites)[i] = NULL;
- *channel_bans = silc_realloc(*channel_bans,
- sizeof(**channel_bans) * (i + 1));
- (*channel_bans)[i] = NULL;
- silc_server_announce_get_inviteban(server, channel,
- &(*channel_invites)[i],
- &(*channel_bans)[i]);
-
- (*channel_users_modes_c)++;
- silc_free(cid);
-
- i++;
- }
-
- if (!silc_idcache_list_next(list, &id_cache))
- break;
+ (*channel_ids)[i] = NULL;
+ silc_server_announce_get_channel_users(server, channel,
+ &(*channel_modes)[i],
+ channel_users,
+ &(*channel_users_modes)[i]);
+ (*channel_ids)[i] = channel->id;
+
+ /* Channel's topic */
+ *channel_topics = silc_realloc(*channel_topics,
+ sizeof(**channel_topics) * (i + 1));
+ (*channel_topics)[i] = NULL;
+ silc_server_announce_get_channel_topic(server, channel,
+ &(*channel_topics)[i]);
+
+ /* Channel's invite and ban list */
+ *channel_invites = silc_realloc(*channel_invites,
+ sizeof(**channel_invites) * (i + 1));
+ (*channel_invites)[i] = NULL;
+ *channel_bans = silc_realloc(*channel_bans,
+ sizeof(**channel_bans) * (i + 1));
+ (*channel_bans)[i] = NULL;
+ silc_server_announce_get_inviteban(server, channel,
+ &(*channel_invites)[i],
+ &(*channel_bans)[i]);
+
+ (*channel_users_modes_c)++;
+
+ i++;
}
}
-
- silc_idcache_list_free(list);
}
}
void silc_server_announce_channels(SilcServer server,
unsigned long creation_time,
- SilcSocketConnection remote)
+ SilcPacketStream remote)
{
SilcBuffer channels = NULL, *channel_modes = NULL, channel_users = NULL;
SilcBuffer *channel_users_modes = NULL;
if (channels) {
silc_buffer_push(channels, channels->data - channels->head);
- SILC_LOG_HEXDUMP(("channels"), channels->data, channels->len);
+ SILC_LOG_HEXDUMP(("channels"), channels->data, silc_buffer_len(channels));
/* Send the packet */
silc_server_packet_send(server, remote,
SILC_PACKET_NEW_CHANNEL, SILC_PACKET_FLAG_LIST,
- channels->data, channels->len,
- FALSE);
+ channels->data, silc_buffer_len(channels));
silc_buffer_free(channels);
}
if (channel_users) {
silc_buffer_push(channel_users, channel_users->data - channel_users->head);
SILC_LOG_HEXDUMP(("channel users"), channel_users->data,
- channel_users->len);
+ silc_buffer_len(channel_users));
/* Send the packet */
silc_server_packet_send(server, remote,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
- channel_users->data, channel_users->len,
- FALSE);
+ channel_users->data, silc_buffer_len(channel_users));
silc_buffer_free(channel_users);
}
channel_modes[i]->data -
channel_modes[i]->head);
SILC_LOG_HEXDUMP(("channel modes"), channel_modes[i]->data,
- channel_modes[i]->len);
+ silc_buffer_len(channel_modes[i]));
silc_server_packet_send_dest(server, remote,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel_ids[i], SILC_ID_CHANNEL,
channel_modes[i]->data,
- channel_modes[i]->len,
- FALSE);
+ silc_buffer_len(channel_modes[i]));
silc_buffer_free(channel_modes[i]);
}
silc_free(channel_modes);
channel_users_modes[i]->data -
channel_users_modes[i]->head);
SILC_LOG_HEXDUMP(("channel users modes"), channel_users_modes[i]->data,
- channel_users_modes[i]->len);
+ silc_buffer_len(channel_users_modes[i]));
silc_server_packet_send_dest(server, remote,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel_ids[i], SILC_ID_CHANNEL,
channel_users_modes[i]->data,
- channel_users_modes[i]->len,
- FALSE);
+ silc_buffer_len(channel_users_modes[i]));
silc_buffer_free(channel_users_modes[i]);
}
silc_free(channel_users_modes);
channel_topics[i]->data -
channel_topics[i]->head);
SILC_LOG_HEXDUMP(("channel topic"), channel_topics[i]->data,
- channel_topics[i]->len);
+ silc_buffer_len(channel_topics[i]));
silc_server_packet_send_dest(server, remote,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel_ids[i], SILC_ID_CHANNEL,
channel_topics[i]->data,
- channel_topics[i]->len,
- FALSE);
+ silc_buffer_len(channel_topics[i]));
silc_buffer_free(channel_topics[i]);
}
silc_free(channel_topics);
channel_invites[i]->data -
channel_invites[i]->head);
SILC_LOG_HEXDUMP(("channel invite list"), channel_invites[i]->data,
- channel_invites[i]->len);
+ silc_buffer_len(channel_invites[i]));
silc_server_packet_send_dest(server, remote,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel_ids[i], SILC_ID_CHANNEL,
channel_invites[i]->data,
- channel_invites[i]->len,
- FALSE);
+ silc_buffer_len(channel_invites[i]));
silc_buffer_free(channel_invites[i]);
}
silc_free(channel_invites);
channel_bans[i]->data -
channel_bans[i]->head);
SILC_LOG_HEXDUMP(("channel ban list"), channel_bans[i]->data,
- channel_bans[i]->len);
+ silc_buffer_len(channel_bans[i]));
silc_server_packet_send_dest(server, remote,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel_ids[i], SILC_ID_CHANNEL,
channel_bans[i]->data,
- channel_bans[i]->len,
- FALSE);
+ silc_buffer_len(channel_bans[i]));
silc_buffer_free(channel_bans[i]);
}
silc_free(channel_bans);
/* Announces WATCH list. */
void silc_server_announce_watches(SilcServer server,
- SilcSocketConnection remote)
+ SilcPacketStream remote)
{
SilcHashTableList htl;
SilcBuffer buffer, idp, args, pkp;
silc_buffer_format(args,
SILC_STR_UI_SHORT(1),
SILC_STR_END);
- pkp = silc_pkcs_public_key_payload_encode(key);
- args = silc_argument_payload_encode_one(args, pkp->data, pkp->len, 0x00);
+ pkp = silc_public_key_payload_encode(key);
+ args = silc_argument_payload_encode_one(args, pkp->data,
+ silc_buffer_len(pkp), 0x00);
buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
++server->cmd_ident, 2,
- 1, idp->data, idp->len,
- 4, args->data, args->len);
+ 1, idp->data, silc_buffer_len(idp),
+ 4, args->data,
+ silc_buffer_len(args));
/* Send command */
silc_server_packet_send(server, remote, SILC_PACKET_COMMAND, 0,
- buffer->data, buffer->len, TRUE);
+ buffer->data, silc_buffer_len(buffer));
silc_buffer_free(pkp);
silc_buffer_free(args);
/* Assembles user list and users mode list from the `channel'. */
-bool silc_server_get_users_on_channel(SilcServer server,
+SilcBool silc_server_get_users_on_channel(SilcServer server,
SilcChannelEntry channel,
SilcBuffer *user_list,
SilcBuffer *mode_list,
client_id_list = silc_buffer_alloc(len);
client_mode_list =
silc_buffer_alloc(4 * silc_hash_table_count(channel->user_list));
- silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
- silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
+ silc_buffer_pull_tail(client_id_list, silc_buffer_truelen(client_id_list));
+ silc_buffer_pull_tail(client_mode_list,
+ silc_buffer_truelen(client_mode_list));
silc_hash_table_list(channel->user_list, &htl);
while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
/* Client ID */
idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
- silc_buffer_put(client_id_list, idp->data, idp->len);
- silc_buffer_pull(client_id_list, idp->len);
+ silc_buffer_put(client_id_list, idp->data, silc_buffer_len(idp));
+ silc_buffer_pull(client_id_list, silc_buffer_len(idp));
silc_buffer_free(idp);
/* Client's mode on channel */
/* Saves users and their modes to the `channel'. */
void silc_server_save_users_on_channel(SilcServer server,
- SilcSocketConnection sock,
+ SilcPacketStream sock,
SilcChannelEntry channel,
SilcClientID *noadd,
SilcBuffer user_list,
int i;
SilcUInt16 idp_len;
SilcUInt32 mode;
- SilcClientID *client_id;
+ SilcID id;
SilcClientEntry client;
SilcIDCacheEntry cache;
SilcChannelClientEntry chl;
/* Client ID */
SILC_GET16_MSB(idp_len, user_list->data + 2);
idp_len += 4;
- client_id = silc_id_payload_parse_id(user_list->data, idp_len, NULL);
- silc_buffer_pull(user_list, idp_len);
- if (!client_id)
+ if (!silc_id_payload_parse_id(user_list->data, idp_len, &id))
continue;
+ silc_buffer_pull(user_list, idp_len);
/* Mode */
SILC_GET32_MSB(mode, mode_list->data);
silc_buffer_pull(mode_list, 4);
- if (noadd && SILC_ID_CLIENT_COMPARE(client_id, noadd)) {
- silc_free(client_id);
+ if (noadd && SILC_ID_CLIENT_COMPARE(&id.u.client_id, noadd))
continue;
- }
cache = NULL;
/* Check if we have this client cached already. */
- client = silc_idlist_find_client_by_id(server->local_list, client_id,
+ client = silc_idlist_find_client_by_id(server->local_list,
+ &id.u.client_id,
server->server_type, &cache);
if (!client)
client = silc_idlist_find_client_by_id(server->global_list,
- client_id, server->server_type,
- &cache);
+ &id.u.client_id,
+ server->server_type, &cache);
if (!client) {
/* If router did not find such Client ID in its lists then this must
be bogus client or some router in the net is buggy. */
- if (server->server_type != SILC_SERVER) {
- silc_free(client_id);
+ if (server->server_type != SILC_SERVER)
continue;
- }
/* We don't have that client anywhere, add it. The client is added
to global list since server didn't have it in the lists so it must be
global. */
client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
- silc_id_dup(client_id, SILC_ID_CLIENT),
- sock->user_data, NULL, 0);
+ silc_id_dup(&id.u.client_id,
+ SILC_ID_CLIENT),
+ silc_packet_get_context(sock),
+ NULL);
if (!client) {
SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
- silc_free(client_id);
continue;
}
client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
}
- if (cache)
- cache->expire = 0;
- silc_free(client_id);
-
if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
SILC_LOG_ERROR(("Attempting to add unregistered client to channel ",
"%s", channel->channel_name));
it has joined. */
void silc_server_save_user_channels(SilcServer server,
- SilcSocketConnection sock,
+ SilcPacketStream sock,
SilcClientEntry client,
SilcBuffer channels,
SilcBuffer channels_user_modes)
SilcUInt32 *chumodes;
SilcChannelPayload entry;
SilcChannelEntry channel;
- SilcChannelID *channel_id;
+ SilcChannelID channel_id;
SilcChannelClientEntry chl;
SilcHashTable ht = NULL;
SilcHashTableList htl;
!(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
goto out;
- ch = silc_channel_payload_parse_list(channels->data, channels->len);
+ ch = silc_channel_payload_parse_list(channels->data,
+ silc_buffer_len(channels));
if (ch && silc_get_mode_list(channels_user_modes, silc_dlist_count(ch),
&chumodes)) {
ht = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL,
while ((entry = silc_dlist_get(ch)) != SILC_LIST_END) {
/* Check if we have this channel, and add it if we don't have it.
Also add the client on the channel unless it is there already. */
- channel_id = silc_channel_get_id_parse(entry);
+ if (!silc_channel_get_id_parse(entry, &channel_id))
+ continue;
channel = silc_idlist_find_channel_by_id(server->local_list,
- channel_id, NULL);
+ &channel_id, NULL);
if (!channel)
channel = silc_idlist_find_channel_by_id(server->global_list,
- channel_id, NULL);
+ &channel_id, NULL);
if (!channel) {
if (server->server_type != SILC_SERVER) {
- silc_free(channel_id);
i++;
continue;
}
/* We don't have that channel anywhere, add it. */
name = silc_channel_get_name(entry, NULL);
channel = silc_idlist_add_channel(server->global_list, strdup(name), 0,
- channel_id, server->router,
- NULL, NULL, 0);
+ silc_id_dup(&channel_id,
+ SILC_ID_CHANNEL),
+ server->router, NULL, NULL, 0);
if (!channel) {
- silc_free(channel_id);
i++;
continue;
}
- channel_id = NULL;
}
channel->mode = silc_channel_get_mode(entry);
}
silc_hash_table_add(ht, channel, channel);
- silc_free(channel_id);
}
silc_channel_payload_list_free(ch);
silc_free(chumodes);
could not be found to the client. If the `client_id' is specified then
it is used and the `id_data' is ignored. */
-SilcSocketConnection
+SilcPacketStream
silc_server_get_client_route(SilcServer server,
unsigned char *id_data,
SilcUInt32 id_len,
SilcIDListData *idata,
SilcClientEntry *client_entry)
{
- SilcClientID *id;
+ SilcClientID *id, clid;
SilcClientEntry client;
SILC_LOG_DEBUG(("Start"));
/* Decode destination Client ID */
if (!client_id) {
- id = silc_id_str2id(id_data, id_len, SILC_ID_CLIENT);
- if (!id) {
- SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+ if (!silc_id_str2id(id_data, id_len, SILC_ID_CHANNEL, &clid, sizeof(clid)))
return NULL;
- }
+ id = silc_id_dup(&clid, SILC_ID_CLIENT);
} else {
id = silc_id_dup(client_id, SILC_ID_CLIENT);
}
client = silc_idlist_find_client_by_id(server->global_list, id,
TRUE, NULL);
if (client) {
- SilcSocketConnection dst_sock;
+ SilcPacketStream dst_sock;
dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT);
silc_free(id);
if (idata && dst_sock)
- *idata = (SilcIDListData)dst_sock->user_data;
+ *idata = silc_packet_get_context(dst_sock);
return dst_sock;
}
}
SilcBuffer silc_server_get_client_channel_list(SilcServer server,
SilcClientEntry client,
- bool get_private,
- bool get_secret,
+ SilcBool get_private,
+ SilcBool get_secret,
SilcBuffer *user_mode_list)
{
SilcBuffer buffer = NULL;
SilcChannelEntry channel;
SilcChannelClientEntry chl;
SilcHashTableList htl;
- unsigned char *cid;
+ unsigned char cid[32];
SilcUInt32 id_len;
SilcUInt16 name_len;
int len;
if (channel->mode & SILC_CHANNEL_MODE_PRIVATE && !get_private)
continue;
- cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
- id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+ silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), &id_len);
name_len = strlen(channel->channel_name);
len = 4 + name_len + id_len + 4;
buffer = silc_buffer_realloc(buffer,
- (buffer ? buffer->truelen + len : len));
+ (buffer ?
+ silc_buffer_truelen(buffer) + len : len));
silc_buffer_pull_tail(buffer, (buffer->end - buffer->data));
silc_buffer_format(buffer,
SILC_STR_UI_SHORT(name_len),
- SILC_STR_UI_XNSTRING(channel->channel_name,
- name_len),
+ SILC_STR_DATA(channel->channel_name, name_len),
SILC_STR_UI_SHORT(id_len),
- SILC_STR_UI_XNSTRING(cid, id_len),
+ SILC_STR_DATA(cid, id_len),
SILC_STR_UI_INT(chl->channel->mode),
SILC_STR_END);
silc_buffer_pull(buffer, len);
- silc_free(cid);
if (user_mode_list) {
- *user_mode_list = silc_buffer_realloc(*user_mode_list,
- (*user_mode_list ?
- (*user_mode_list)->truelen + 4 :
- 4));
+ *user_mode_list =
+ silc_buffer_realloc(*user_mode_list,
+ (*user_mode_list ?
+ silc_buffer_truelen((*user_mode_list)) + 4 : 4));
silc_buffer_pull_tail(*user_mode_list, ((*user_mode_list)->end -
(*user_mode_list)->data));
SILC_PUT32_MSB(chl->mode, (*user_mode_list)->data);
return buffer;
}
-/* Timeout callback for unsuccessful rekey. The rekey did not go through
- for some reason. */
-
-SILC_TASK_CALLBACK(silc_server_rekey_timeout)
-{
- SilcServerRekeyInternalContext *ctx = context;
- SilcServer server = app_context;
- SilcSocketConnection sock = ctx->sock;
-
- SILC_LOG_DEBUG(("Timeout occurred in rekey protocol with %s:%d [%s]",
- sock->hostname, sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
-
- SILC_LOG_WARNING(("Timeout occurred in rekey protocol with %s:%d [%s]",
- sock->hostname, sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
-
- if (sock->protocol) {
- silc_protocol_cancel(sock->protocol, server->schedule);
- silc_protocol_free(sock->protocol);
- sock->protocol = NULL;
- }
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_socket_free(sock);
- silc_free(ctx);
-
- /* Disconnect since we failed to rekey, the keys are probably wrong. */
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
-
- /* Reconnect */
- if (sock->type != SILC_SOCKET_TYPE_CLIENT)
- silc_server_create_connections(server);
-}
-
-/* A timeout callback for the re-key. We will be the initiator of the
- re-key protocol. */
-
-SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback)
-{
- SilcServer server = app_context;
- SilcSocketConnection sock = (SilcSocketConnection)context;
- SilcIDListData idata = (SilcIDListData)sock->user_data;
- SilcProtocol protocol;
- SilcServerRekeyInternalContext *proto_ctx;
-
- if (!idata)
- return;
-
- /* Do not execute rekey with disabled connections, as it would not
- go through anyway. */
- if (idata->status & SILC_IDLIST_STATUS_DISABLED)
- return;
-
- /* If rekey protocol is active already wait for it to finish */
- if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)
- return;
-
- /* If any other protocol is active do not start this protocol yet. */
- if (sock->protocol) {
- SILC_LOG_DEBUG(("Waiting for other protocol to finish before rekeying"));
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rekey_callback,
- sock, 60, 0, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- return;
- }
-
- SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s]",
- sock->hostname, sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
-
- /* Allocate internal protocol context. This is sent as context
- to the protocol. */
- proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
- proto_ctx->server = (void *)server;
- proto_ctx->sock = silc_socket_dup(sock);
- proto_ctx->responder = FALSE;
- proto_ctx->pfs = idata->rekey->pfs;
-
- /* Perform rekey protocol. Will call the final callback after the
- protocol is over. */
- silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
- &protocol, proto_ctx, silc_server_rekey_final);
- sock->protocol = protocol;
-
- /* Register timeout callback in case the rekey does not go through. */
- proto_ctx->timeout_task =
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rekey_timeout,
- proto_ctx,
- (idata->rekey->timeout >
- server->config->key_exchange_timeout ?
- idata->rekey->timeout :
- server->config->key_exchange_timeout * 4), 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
-
- /* Run the protocol */
- silc_protocol_execute(protocol, server->schedule, 0, 0);
-}
-
-/* The final callback for the REKEY protocol. This will actually take the
- new key material into use. */
-
-SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
-{
- SilcProtocol protocol = (SilcProtocol)context;
- SilcServerRekeyInternalContext *ctx =
- (SilcServerRekeyInternalContext *)protocol->context;
- SilcServer server = (SilcServer)ctx->server;
- SilcSocketConnection sock = ctx->sock;
- SilcIDListData idata = (SilcIDListData)sock->user_data;
-
- if (ctx->timeout_task)
- silc_schedule_task_del(server->schedule, ctx->timeout_task);
-
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
- protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
- /* Error occured during protocol */
- SILC_LOG_ERROR(("Error occurred during rekey protocol with "
- "%s (%s)", sock->hostname, sock->ip));
- silc_protocol_cancel(protocol, server->schedule);
- silc_protocol_free(protocol);
- sock->protocol = NULL;
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_socket_free(sock);
- silc_free(ctx);
- silc_server_disconnect_remote(server, sock,
- SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
-
- /* Reconnect */
- if (sock->type != SILC_SOCKET_TYPE_CLIENT)
- silc_server_create_connections(server);
- return;
- }
-
- SILC_LOG_DEBUG(("Rekey protocol completed with %s:%d [%s]",
- sock->hostname, sock->port,
- (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
- sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
- sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
-
- /* Purge the outgoing data queue to assure that all rekey packets really
- go to the network before we quit the protocol. */
- silc_server_packet_queue_purge(server, sock);
-
- /* Re-register re-key timeout */
- if (ctx->responder == FALSE)
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rekey_callback,
- sock, idata->rekey->timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-
- /* Cleanup */
- silc_protocol_free(protocol);
- sock->protocol = NULL;
- if (ctx->packet)
- silc_packet_context_free(ctx->packet);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- silc_socket_free(sock);
- silc_free(ctx);
-}
-
/* Task callback used to retrieve network statistical information from
router server once in a while. */
idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
++server->cmd_ident, 1,
- 1, idp->data, idp->len);
+ 1, idp->data,
+ silc_buffer_len(idp));
silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
SILC_PACKET_COMMAND, 0, packet->data,
- packet->len, FALSE);
+ silc_buffer_len(packet));
silc_buffer_free(packet);
silc_buffer_free(idp);
}
- silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
- server, 120, 0, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
+ silc_schedule_task_add_timeout(server->schedule, silc_server_get_stats,
+ server, 120, 0);
}