tmp = silc_net_create_server(server->config->listen_port->port,
server->config->listen_port->listener_ip);
- if (tmp < 0)
+ if (tmp < 0) {
+ SILC_LOG_ERROR(("Could not create server listener: %s on %d",
+ server->config->listen_port->listener_ip,
+ server->config->listen_port->port));
goto err0;
+ }
sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
sock[sock_count] = tmp;
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;
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;
+ }
+
silc_schedule_task_add(server->schedule, fd,
silc_server_connect_router,
(void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
SILC_LOG_INFO(("Connected to router %s", sock->hostname));
- /* Add the connected router to local server list */
- id_entry = silc_idlist_add_server(server->local_list, strdup(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);
+ }
+
+ SILC_LOG_DEBUG(("New server id(%s)",
+ silc_id_render(ctx->dest_id, SILC_ID_SERVER)));
+
+ /* Add the connected router to global server list */
+ 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);
}
} else {
/* Add this server to be our backup router */
- silc_server_backup_add(server, id_entry, FALSE);
+ silc_server_backup_add(server, id_entry, sconn->backup_replace_ip,
+ sconn->backup_replace_port, FALSE);
}
sock->protocol = NULL;
/* Free the temporary connection data context */
if (sconn) {
silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
silc_free(sconn);
}
silc_ske_free(ctx->ske);
silc_free(ctx->dest_id);
silc_free(ctx);
- if (sock)
- sock->protocol = NULL;
silc_schedule_task_del_by_callback(server->schedule,
silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
server. We mark ourselves as router for this server if we really
are router. */
new_server =
- silc_idlist_add_server(server->local_list, NULL,
- ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
- SILC_SERVER : SILC_ROUTER, NULL,
- ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
- server->id_entry : NULL, sock);
+ silc_idlist_add_server((ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+ server->local_list : (conn->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 : (conn->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);
/* 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 && conn->backup_router) {
- silc_server_backup_add(server, new_server, conn->backup_local);
+ silc_server_backup_add(server, new_server, conn->backup_replace_ip,
+ conn->backup_replace_port, conn->backup_local);
/* Change it back to SERVER type since that's what it really is. */
- if (conn->backup_local) {
+ if (conn->backup_local)
ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
- new_server->server_type = SILC_BACKUP_ROUTER;
- }
- }
-#if 0
- /* If the incoming connection is normal server and marked as backup
- server then it will use us as backup router. We'll disable the
- connection until it is allowed to be used. */
- if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER && conn->backup_router)
- SILC_SET_DISABLED(sock);
-#endif
+ new_server->server_type = SILC_BACKUP_ROUTER;
+ }
/* Check whether this connection is to be our primary router connection
if we do not already have the primary route. */
SilcIDListData idata;
SilcCipher cipher = NULL;
SilcHmac hmac = NULL;
+ uint32 sequence = 0;
int ret;
if (!sock)
if (ret == -1)
SILC_LOG_ERROR(("Error receiving packet from connection "
- "%s:%d [%s]", sock->hostname, sock->port,
+ "%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")));
+ "Router"), strerror(errno)));
return;
}
if (idata) {
cipher = idata->receive_key;
hmac = idata->hmac_receive;
+ sequence = idata->psn_receive;
}
/* Process the packet. This will call the parser that will then
decrypt and parse the packet. */
- silc_packet_receive_process(sock, cipher, hmac, silc_server_packet_parse,
- server);
-}
-
-/* Callback function that the silc_packet_decrypt will call to make the
- decision whether the packet is normal or special packet. We will
- return TRUE if it is normal and FALSE if it is special */
-
-static int silc_server_packet_decrypt_check(SilcPacketType packet_type,
- SilcBuffer buffer,
- SilcPacketContext *packet,
- void *context)
-{
- SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
- SilcServer server = (SilcServer)parse_ctx->context;
-
- /* Packet is normal packet, if:
-
- 1) packet is private message packet and does not have private key set
- 2) is other packet than channel message packet
- 3) is channel message packet and remote is router and we are router
-
- all other packets are special packets
- */
-
- if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
- (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
- return FALSE;
-
- if (packet_type != SILC_PACKET_CHANNEL_MESSAGE ||
- (packet_type == SILC_PACKET_CHANNEL_MESSAGE &&
- parse_ctx->sock->type == SILC_SOCKET_TYPE_ROUTER &&
- server->server_type == SILC_ROUTER))
- return TRUE;
-
- return FALSE;
+ silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, cipher, hmac, sequence,
+ silc_server_packet_parse, server);
}
/* Parses whole packet, received earlier. */
SILC_LOG_DEBUG(("Start"));
- /* Decrypt the received packet */
- ret = silc_packet_decrypt(idata ? idata->receive_key : NULL,
- idata ? idata->hmac_receive : NULL,
- packet->buffer, packet,
- silc_server_packet_decrypt_check, parse_ctx);
- if (ret < 0) {
- SILC_LOG_WARNING(("Packet decryption failed for 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")));
- goto out;
- }
-
- if (ret == 0) {
- /* Parse the packet. Packet type is returned. */
- ret = silc_packet_parse(packet);
- } else {
- /* Parse the packet header in special way as this is "special"
- packet type. */
- ret = silc_packet_parse_special(packet);
- }
+ /* 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 (ret != SILC_PACKET_RESUME_ROUTER &&
- idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+ idata && idata->status & SILC_IDLIST_STATUS_DISABLED) {
+ SILC_LOG_DEBUG(("Connection is disabled"));
goto out;
+ }
if (ret == SILC_PACKET_NONE)
goto out;
/* Parser callback called by silc_packet_receive_process. This merely
registers timeout that will handle the actual parsing when appropriate. */
-void silc_server_packet_parse(SilcPacketParserContext *parser_context)
+bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
+ void *context)
{
- SilcServer server = (SilcServer)parser_context->context;
+ SilcServer server = (SilcServer)context;
SilcSocketConnection sock = parser_context->sock;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+
+ if (idata)
+ idata->psn_receive = parser_context->packet->sequence + 1;
+
+ /* 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 ((parser_context->packet->type == SILC_PACKET_REKEY ||
+ parser_context->packet->type == SILC_PACKET_REKEY_DONE) ||
+ (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, 0, sock->sock,
+ parser_context);
+
+ /* 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)
+ silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, idata->receive_key,
+ idata->hmac_receive, idata->psn_receive,
+ silc_server_packet_parse, server);
+ else
+ silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, NULL, NULL, 0,
+ silc_server_packet_parse, server);
+ return FALSE;
+ }
switch (sock->type) {
case SILC_SOCKET_TYPE_UNKNOWN:
break;
case SILC_SOCKET_TYPE_SERVER:
case SILC_SOCKET_TYPE_ROUTER:
- /* Packets from servers are parsed as soon as possible */
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_packet_parse_real,
- (void *)parser_context, 0, 1,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ /* Packets from servers are parsed immediately */
+ silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+ parser_context);
break;
default:
- return;
+ return TRUE;
}
+
+ return TRUE;
}
/* Parses the packet type and calls what ever routines the packet type
break;
case SILC_PACKET_FTP:
- /* Ignored */
+ /* FTP packet */
+ SILC_LOG_DEBUG(("FTP packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_ftp(server, sock, packet);
break;
case SILC_PACKET_RESUME_ROUTER:
void silc_server_close_connection(SilcServer server,
SilcSocketConnection sock)
{
+ if (!server->sockets[sock->sock])
+ return;
+
SILC_LOG_INFO(("Closing connection %s:%d [%s]", sock->hostname,
sock->port,
(sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
to the network before removing the client entry. */
silc_server_packet_queue_purge(server, sock);
+ if (!client->id)
+ return;
+
/* Send SIGNOFF notify to routers. */
if (notify && !server->standalone && server->router)
silc_server_send_notify_signoff(server, server->router->connection,
server->server_type == SILC_SERVER ?
FALSE : TRUE, client->id, signoff);
-
+
/* Remove client from all channels */
if (notify)
silc_server_remove_from_channels(server, NULL, client,
else
silc_server_remove_from_channels(server, NULL, client,
FALSE, NULL, FALSE);
-
+
/* We will not delete the client entry right away. We will take it
into history (for WHOWAS command) for 5 minutes */
i->server = server;
SilcServerEntry user_data = (SilcServerEntry)sock->user_data;
SilcServerEntry backup_router = NULL;
+ if (user_data->id)
+ backup_router = silc_server_backup_get(server, user_data->id);
+
/* If this was our primary router connection then we're lost to
the outside world. */
if (server->router == user_data) {
- backup_router = silc_server_backup_get(server);
-
/* Check whether we have a backup router connection */
if (!backup_router || backup_router == user_data) {
silc_schedule_task_add(server->schedule, 0,
server->id_entry->router = backup_router;
server->router = backup_router;
server->router_connect = time(0);
+ server->backup_primary = TRUE;
if (server->server_type == SILC_BACKUP_ROUTER) {
server->server_type = SILC_ROUTER;
silc_server_backup_replaced_add(server, user_data->id,
backup_router);
}
+ } else if (backup_router) {
+ SILC_LOG_INFO(("Enabling the use of backup router %s",
+ backup_router->server_name));
+ SILC_LOG_DEBUG(("Enabling the use of backup router %s",
+ backup_router->server_name));
+
+ /* Mark this connection as replaced */
+ silc_server_backup_replaced_add(server, user_data->id,
+ backup_router);
}
if (!backup_router) {
by the primary router and went down with the router. */
silc_server_update_clients_by_server(server, user_data, backup_router,
TRUE, TRUE);
+ silc_server_update_servers_by_server(server, user_data, backup_router);
}
/* Free the server entry */
silc_server_backup_del(server, user_data);
silc_server_backup_replaced_del(server, user_data);
silc_idlist_del_data(user_data);
- silc_idlist_del_server(server->local_list, user_data);
+ if (!silc_idlist_del_server(server->local_list, user_data))
+ silc_idlist_del_server(server->global_list, user_data);
server->stat.my_servers--;
server->stat.servers--;
if (server->server_type == SILC_ROUTER)
if (backup_router) {
/* Announce all of our stuff that was created about 5 minutes ago.
The backup router knows all the other stuff already. */
- if (server->server_type == SILC_ROUTER)
- silc_server_announce_servers(server, FALSE, 0,
- server->router->connection);
-
- /* Announce our clients and channels to the router */
- silc_server_announce_clients(server, 0,
- server->router->connection);
- silc_server_announce_channels(server, 0,
- server->router->connection);
-#if 0
if (server->server_type == SILC_ROUTER)
silc_server_announce_servers(server, FALSE, time(0) - 300,
- server->router->connection);
+ backup_router->connection);
/* Announce our clients and channels to the router */
silc_server_announce_clients(server, time(0) - 300,
- server->router->connection);
+ backup_router->connection);
silc_server_announce_channels(server, time(0) - 300,
- server->router->connection);
-#endif
+ backup_router->connection);
}
break;
}
silc_hash_table_count(channel->user_list) < 2) {
if (channel->rekey)
silc_schedule_task_del_by_context(server->schedule, channel->rekey);
- if (!silc_idlist_del_channel(server->local_list, channel))
- silc_idlist_del_channel(server->global_list, channel);
- server->stat.my_channels--;
+ if (silc_idlist_del_channel(server->local_list, channel))
+ server->stat.my_channels--;
+ else
+ silc_idlist_del_channel(server->global_list, channel);
continue;
}
SilcChannelClientEntry chl2;
SilcHashTableList htl2;
- channel->id = NULL;
+ channel->disabled = TRUE;
silc_hash_table_list(channel->user_list, &htl2);
while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
}
/* Remove the channel entry */
- if (!silc_idlist_del_channel(server->local_list, channel))
- silc_idlist_del_channel(server->global_list, channel);
- server->stat.my_channels--;
+ if (silc_idlist_del_channel(server->local_list, channel))
+ server->stat.my_channels--;
+ else
+ silc_idlist_del_channel(server->global_list, channel);
continue;
}
silc_hash_table_count(channel->user_list) < 2) {
if (channel->rekey)
silc_schedule_task_del_by_context(server->schedule, channel->rekey);
- if (!silc_idlist_del_channel(server->local_list, channel))
+ if (silc_idlist_del_channel(server->local_list, channel))
+ server->stat.my_channels--;
+ else
silc_idlist_del_channel(server->global_list, channel);
silc_buffer_free(clidp);
- server->stat.my_channels--;
return FALSE;
}
SilcChannelClientEntry chl2;
SilcHashTableList htl2;
- channel->id = NULL;
+ channel->disabled = TRUE;
silc_hash_table_list(channel->user_list, &htl2);
while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
}
/* Remove the channel entry */
- if (!silc_idlist_del_channel(server->local_list, channel))
+ if (silc_idlist_del_channel(server->local_list, channel))
+ server->stat.my_channels--;
+ else
silc_idlist_del_channel(server->global_list, channel);
- server->stat.my_channels--;
return FALSE;
}
}
if (!channel->channel_key)
- if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key))
+ if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key)) {
+ channel->channel_key = NULL;
return FALSE;
+ }
if (key_len)
len = key_len;
/* Generate HMAC key from the channel key data and set it */
if (!channel->hmac)
silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
- silc_hash_make(channel->hmac->hash, channel->key, len, hash);
- silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
+ silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, len, hash);
+ silc_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
memset(hash, 0, sizeof(hash));
if (server->server_type == SILC_ROUTER) {
/* Create new cipher */
if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
+ channel->channel_key = NULL;
channel = NULL;
goto out;
}
/* Generate HMAC key from the channel key data and set it */
if (!channel->hmac)
silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
- silc_hash_make(channel->hmac->hash, tmp, tmp_len, hash);
- silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
+ silc_hash_make(silc_hmac_get_hash(channel->hmac), tmp, tmp_len, hash);
+ silc_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
memset(hash, 0, sizeof(hash));
memset(tmp, 0, tmp_len);
(*channel_ids)[i] = NULL;
silc_server_announce_get_channel_users(server, channel,
channel_users,
- channel_users_modes[i]);
+ &(*channel_users_modes)[i]);
(*channel_ids)[i] = channel->id;
i++;