+ 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;
+ }
+
+ /* 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) {
+
+ 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 && ptr->backup_router &&
+ ptr->initiator == FALSE && !server->backup_router &&
+ !silc_server_config_get_backup_router(server))
+ server->wait_backup = TRUE;
+
+ if (!ptr->initiator)
+ continue;
+ if (ptr->dynamic_connection)
+ continue;
+
+ /* 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_CONN_ROUTER)) {
+ 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;
+ 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;
+ }
+ }
+
+ param = (ptr->param ? ptr->param : &server->config->param);
+
+ /* Allocate connection object for hold connection specific stuff. */
+ sconn = silc_calloc(1, sizeof(*sconn));
+ if (!sconn)
+ continue;
+ sconn->server = server;
+ 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;
+ }
+ sconn->no_reconnect = param->reconnect_keep_trying == FALSE;
+
+ SILC_LOG_DEBUG(("Created connection %p", sconn));
+
+ if (!server->router_conn && !sconn->backup)
+ server->router_conn = sconn;
+
+ /* Connect */
+ silc_server_connect_router(server->schedule, server, SILC_TASK_EXPIRE,
+ 0, sconn);
+ }
+}
+
+
+/************************ Accepting new connection **************************/
+
+/* 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)
+{
+ SilcServer server = context;
+ server->wait_backup = FALSE;
+}
+
+/* Authentication data callback */
+
+static SilcBool
+silc_server_accept_get_auth(SilcConnAuth connauth,
+ SilcConnectionType conn_type,
+ unsigned char **passphrase,
+ SilcUInt32 *passphrase_len,
+ SilcSKR *repository,
+ void *context)
+{
+ SilcPacketStream sock = context;
+ SilcUnknownEntry entry = silc_packet_get_context(sock);
+ SilcServer server = entry->server;
+
+ SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
+
+ /* Remote end is client */
+ if (conn_type == SILC_CONN_CLIENT) {
+ SilcServerConfigClient *cconfig = entry->cconfig.ref_ptr;
+ if (!cconfig)
+ return FALSE;
+
+ *passphrase = cconfig->passphrase;
+ *passphrase_len = cconfig->passphrase_len;
+ if (cconfig->publickeys)
+ *repository = server->repository;
+
+ if (cconfig->publickeys) {
+ if (server->config->prefer_passphrase_auth) {
+ *repository = NULL;
+ } else {
+ *passphrase = NULL;
+ *passphrase_len = 0;
+ }
+ }
+
+ entry->conn_type = conn_type;
+ return TRUE;
+ }
+
+ /* Remote end is server */
+ if (conn_type == SILC_CONN_SERVER) {
+ SilcServerConfigServer *sconfig;
+
+ /* If we are normal server, don't accept the connection */
+ if (server->server_type == SILC_SERVER)
+ return FALSE;
+
+ sconfig = entry->sconfig.ref_ptr;
+ if (!sconfig)
+ return FALSE;
+
+ *passphrase = sconfig->passphrase;
+ *passphrase_len = sconfig->passphrase_len;
+ if (sconfig->publickeys)
+ *repository = server->repository;
+
+ if (sconfig->publickeys) {
+ if (server->config->prefer_passphrase_auth) {
+ *repository = NULL;
+ } else {
+ *passphrase = NULL;
+ *passphrase_len = 0;
+ }
+ }
+
+ entry->conn_type = conn_type;
+ return TRUE;
+ }
+
+ /* 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;
+
+ if (rconfig->publickeys) {
+ if (server->config->prefer_passphrase_auth) {
+ *repository = NULL;
+ } else {
+ *passphrase = NULL;
+ *passphrase_len = 0;
+ }
+ }
+
+ entry->conn_type = conn_type;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Authentication completion callback. */
+
+static void
+silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
+ void *context)
+{
+ SilcPacketStream sock = context;
+ SilcUnknownEntry entry = silc_packet_get_context(sock);
+ SilcIDListData idata = (SilcIDListData)entry;
+ SilcServer server = entry->server;
+ SilcServerConfigConnParams *param = &server->config->param;
+ SilcServerConnection sconn;
+ void *id_entry;
+ const char *hostname, *ip;
+ SilcUInt16 port;
+
+ entry->op = NULL;
+ silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+ NULL, &hostname, &ip, &port);
+
+ 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);
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
+ goto out;
+ }
+
+ SILC_LOG_DEBUG(("Checking whether connection is allowed"));
+
+ switch (entry->conn_type) {
+ case SILC_CONN_CLIENT:
+ {
+ SilcClientEntry client;
+ SilcServerConfigClient *conn = entry->cconfig.ref_ptr;
+
+ /* Verify whether this connection is after all allowed to connect */
+ if (!silc_server_connection_allowed(server, sock, entry->conn_type,
+ &server->config->param,
+ conn->param,
+ silc_connauth_get_ske(connauth))) {
+ server->stat.auth_failures++;
+ goto out;
+ }
+
+ /* 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");
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
+ server->stat.auth_failures++;
+
+ /* 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;
+ }
+ }
+
+ SILC_LOG_DEBUG(("Remote host is client"));
+ SILC_LOG_INFO(("Connection %s (%s) is client", entry->hostname,
+ entry->ip));
+
+ /* 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);
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
+ goto out;
+ }
+ entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
+ entry->data.conn_type = SILC_CONN_CLIENT;
+
+ /* Statistics */
+ server->stat.my_clients++;
+ server->stat.clients++;
+ server->stat.cell_clients++;
+
+ /* Get connection parameters */
+ if (conn->param) {
+ param = conn->param;
+
+ if (!param->keepalive_secs)
+ param->keepalive_secs = server->config->param.keepalive_secs;
+
+ 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;
+ }
+
+ /* Check if to be anonymous connection */
+ if (param->anonymous)
+ client->mode |= SILC_UMODE_ANONYMOUS;
+ }
+
+ /* Add public key to repository */
+ SILC_LOG_DEBUG(("Add client public key to repository"));
+ if (!silc_server_get_public_key_by_client(server, client, NULL))
+ silc_skr_add_public_key_simple(server->repository,
+ entry->data.public_key,
+ SILC_SKR_USAGE_IDENTIFICATION, client,
+ NULL);
+
+ id_entry = (void *)client;