From b09f59fbc13dd0a57ccb8fb9c09e6171c333224b Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Wed, 22 Nov 2000 21:17:43 +0000 Subject: [PATCH] Splitted server.[ch] and created packet_send.[ch] and packet_receive.[ch]. --- apps/silcd/packet_receive.c | 1005 ++++++++++++++++++++ apps/silcd/packet_receive.h | 62 ++ apps/silcd/packet_send.c | 1089 +++++++++++++++++++++ apps/silcd/packet_send.h | 133 +++ apps/silcd/server.c | 1778 +---------------------------------- apps/silcd/server.h | 116 +-- 6 files changed, 2338 insertions(+), 1845 deletions(-) create mode 100644 apps/silcd/packet_receive.c create mode 100644 apps/silcd/packet_receive.h create mode 100644 apps/silcd/packet_send.c create mode 100644 apps/silcd/packet_send.h diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c new file mode 100644 index 00000000..65a60a72 --- /dev/null +++ b/apps/silcd/packet_receive.c @@ -0,0 +1,1005 @@ +/* + + packet_receive.c + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2000 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ +/* + * Server packet routines to handle received packets. + */ +/* $Id$ */ + +#include "serverincludes.h" +#include "server_internal.h" + +extern char *server_version; + +/* Received private message. This resolves the destination of the message + and sends the packet. This is used by both server and router. If the + destination is our locally connected client this sends the packet to + the client. This may also send the message for further routing if + the destination is not in our server (or router). */ + +void silc_server_private_message(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcClientID *id; + SilcServerEntry router; + SilcSocketConnection dst_sock; + SilcClientEntry client; + SilcIDListData idata; + + SILC_LOG_DEBUG(("Start")); + + if (!packet->dst_id) { + SILC_LOG_ERROR(("Bad Client ID in private message packet, dropped")); + goto err; + } + + /* Decode destination Client ID */ + id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT); + if (!id) { + SILC_LOG_ERROR(("Could not decode destination Client ID, dropped")); + goto err; + } + + /* If the destination belongs to our server we don't have to route + the message anywhere but to send it to the local destination. */ + client = silc_idlist_find_client_by_id(server->local_list, id); + if (client) { + /* It exists, now deliver the message to the destination */ + dst_sock = (SilcSocketConnection)client->connection; + + /* If we are router and the client has router then the client is in + our cell but not directly connected to us. */ + if (server->server_type == SILC_ROUTER && client->router) { + /* We are of course in this case the client's router thus the real + "router" of the client is the server who owns the client. Thus + we will send the packet to that server. */ + router = (SilcServerEntry)dst_sock->user_data; + idata = (SilcIDListData)router; + // assert(client->router == server->id_entry); + + silc_server_send_private_message(server, dst_sock, + idata->send_key, + idata->hmac, + packet); + return; + } + + /* Seems that client really is directly connected to us */ + idata = (SilcIDListData)client; + silc_server_send_private_message(server, dst_sock, + idata->send_key, + idata->hmac, packet); + return; + } + + /* Destination belongs to someone not in this server. If we are normal + server our action is to send the packet to our router. */ + if (server->server_type == SILC_SERVER && !server->standalone) { + router = server->router; + + /* Send to primary route */ + if (router) { + dst_sock = (SilcSocketConnection)router->connection; + idata = (SilcIDListData)router; + silc_server_send_private_message(server, dst_sock, + idata->send_key, + idata->hmac, packet); + } + return; + } + + /* We are router and we will perform route lookup for the destination + and send the message to fastest route. */ + if (server->server_type == SILC_ROUTER && !server->standalone) { + dst_sock = silc_server_get_route(server, id, SILC_ID_CLIENT); + router = (SilcServerEntry)dst_sock->user_data; + idata = (SilcIDListData)router; + + /* Get fastest route and send packet. */ + if (router) + silc_server_send_private_message(server, dst_sock, + idata->send_key, + idata->hmac, packet); + return; + } + + err: + silc_server_send_error(server, sock, + "No such nickname: Private message not sent"); +} + +/* Relays received command reply packet to the correct destination. The + destination must be one of our locally connected client or the packet + will be ignored. This is called when server has forwarded one of + client's command request to router and router has now replied to the + command. */ + +void silc_server_packet_relay_command_reply(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcBuffer buffer = packet->buffer; + SilcClientEntry client; + SilcClientID *id; + SilcSocketConnection dst_sock; + SilcIDListData idata; + + SILC_LOG_DEBUG(("Start")); + + /* Source must be server or router */ + if (packet->src_id_type != SILC_ID_SERVER && + sock->type != SILC_SOCKET_TYPE_ROUTER) + return; + + /* Destination must be client */ + if (packet->dst_id_type != SILC_ID_CLIENT) + return; + + /* Execute command reply locally for the command */ + silc_server_command_reply_process(server, sock, buffer); + + id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT); + + /* Destination must be one of ours */ + client = silc_idlist_find_client_by_id(server->local_list, id); + if (!client) { + SILC_LOG_ERROR(("Cannot relay command reply to unknown client")); + silc_free(id); + return; + } + + /* Relay the packet to the client */ + + dst_sock = (SilcSocketConnection)client->connection; + silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len + + packet->dst_id_len + packet->padlen); + + silc_packet_send_prepare(dst_sock, 0, 0, buffer->len); + silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len); + + idata = (SilcIDListData)client; + + /* Encrypt packet */ + silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf, + buffer->len); + + /* Send the packet */ + silc_server_packet_send_real(server, dst_sock, TRUE); + + silc_free(id); +} + +/* Process received channel message. The message can be originated from + client or server. */ + +void silc_server_channel_message(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcChannelEntry channel = NULL; + SilcChannelClientEntry chl; + SilcChannelID *id = NULL; + void *sender = NULL; + + SILC_LOG_DEBUG(("Processing channel message")); + + /* Sanity checks */ + if (packet->dst_id_type != SILC_ID_CHANNEL) { + SILC_LOG_ERROR(("Received bad message for channel, dropped")); + SILC_LOG_DEBUG(("Received bad message for channel, dropped")); + goto out; + } + + /* Find channel entry */ + id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL); + channel = silc_idlist_find_channel_by_id(server->local_list, id); + if (!channel) { + SILC_LOG_DEBUG(("Could not find channel")); + goto out; + } + + /* See that this client is on the channel. If the message is coming + from router we won't do the check as the message is from client that + we don't know about. Also, if the original sender is not client + (as it can be server as well) we don't do the check. */ + sender = silc_id_str2id(packet->src_id, packet->src_id_type); + if (sock->type != SILC_SOCKET_TYPE_ROUTER && + packet->src_id_type == SILC_ID_CLIENT) { + silc_list_start(channel->user_list); + while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { + if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender)) + break; + } + if (chl == SILC_LIST_END) + goto out; + } + + /* Distribute the packet to our local clients. This will send the + packet for further routing as well, if needed. */ + silc_server_packet_relay_to_channel(server, sock, channel, sender, + packet->src_id_type, + packet->buffer->data, + packet->buffer->len, FALSE); + + out: + if (sender) + silc_free(sender); + if (id) + silc_free(id); +} + +/* Received channel key packet. We distribute the key to all of our locally + connected clients on the channel. */ +/* XXX Router must accept this packet and distribute the key to all its + server that has clients on the channel */ + +void silc_server_channel_key(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcBuffer buffer = packet->buffer; + SilcChannelKeyPayload payload = NULL; + SilcChannelID *id = NULL; + SilcChannelEntry channel; + SilcChannelClientEntry chl; + unsigned char *tmp; + unsigned int tmp_len; + char *cipher; + + if (packet->src_id_type != SILC_ID_SERVER && + sock->type != SILC_SOCKET_TYPE_ROUTER) + goto out; + + /* Decode channel key payload */ + payload = silc_channel_key_payload_parse(buffer); + if (!payload) { + SILC_LOG_ERROR(("Bad channel key payload, dropped")); + goto out; + } + + /* Get channel ID */ + tmp = silc_channel_key_get_id(payload, &tmp_len); + id = silc_id_payload_parse_id(tmp, tmp_len); + if (!id) + goto out; + + /* Get the channel entry */ + channel = silc_idlist_find_channel_by_id(server->local_list, id); + if (!channel) { + SILC_LOG_ERROR(("Received key for non-existent channel")); + goto out; + } + + /* Save the key for us as well */ + tmp = silc_channel_key_get_key(payload, &tmp_len); + if (!tmp) + goto out; + cipher = silc_channel_key_get_cipher(payload, NULL);; + if (!cipher) + goto out; + if (!silc_cipher_alloc(cipher, &channel->channel_key)) + goto out; + + /* Distribute the key to all clients on the channel */ + silc_list_start(channel->user_list); + while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { + silc_server_packet_send(server, chl->client->connection, + SILC_PACKET_CHANNEL_KEY, 0, + buffer->data, buffer->len, TRUE); + } + + channel->key_len = tmp_len * 8; + channel->key = silc_calloc(tmp_len, sizeof(unsigned char)); + memcpy(channel->key, tmp, tmp_len); + channel->channel_key->cipher->set_key(channel->channel_key->context, + tmp, tmp_len); + out: + if (id) + silc_free(id); + if (payload) + silc_channel_key_payload_free(payload); +} + +/* Received packet to replace a ID. This checks that the requested ID + exists and replaces it with the new one. */ + +void silc_server_replace_id(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcBuffer buffer = packet->buffer; + unsigned char *old_id = NULL, *new_id = NULL; + SilcIdType old_id_type, new_id_type; + unsigned short old_id_len, new_id_len; + void *id = NULL, *id2 = NULL; + + if (sock->type == SILC_SOCKET_TYPE_CLIENT || + packet->src_id_type == SILC_ID_CLIENT) + return; + + SILC_LOG_DEBUG(("Replacing ID")); + + silc_buffer_unformat(buffer, + SILC_STR_UI_SHORT(&old_id_type), + SILC_STR_UI16_NSTRING_ALLOC(&old_id, &old_id_len), + SILC_STR_UI_SHORT(&new_id_type), + SILC_STR_UI16_NSTRING_ALLOC(&new_id, &new_id_len), + SILC_STR_END); + + if (old_id_type != new_id_type) + goto out; + + if (old_id_len != silc_id_get_len(old_id_type) || + new_id_len != silc_id_get_len(new_id_type)) + goto out; + + id = silc_id_str2id(old_id, old_id_type); + if (!id) + goto out; + + id2 = silc_id_str2id(new_id, new_id_type); + if (!id2) + goto out; + + /* If we are router and this packet is not already broadcast packet + we will broadcast it. The sending socket really cannot be router or + the router is buggy. If this packet is coming from router then it must + have the broadcast flag set already and we won't do anything. */ + if (server->server_type == SILC_ROUTER && + sock->type == SILC_SOCKET_TYPE_SERVER && + !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { + SILC_LOG_DEBUG(("Broadcasting received Replace ID packet")); + silc_server_packet_send(server, server->router->connection, packet->type, + packet->flags | SILC_PACKET_FLAG_BROADCAST, + buffer->data, buffer->len, FALSE); + } + + /* Replace the old ID */ + switch(old_id_type) { + case SILC_ID_CLIENT: + if (silc_idlist_replace_client_id(server->local_list, id, id2) == NULL) + if (server->server_type == SILC_ROUTER) + silc_idlist_replace_client_id(server->global_list, id, id2); + break; + + case SILC_ID_SERVER: + if (silc_idlist_replace_server_id(server->local_list, id, id2) == NULL) + if (server->server_type == SILC_ROUTER) + silc_idlist_replace_server_id(server->global_list, id, id2); + break; + + case SILC_ID_CHANNEL: + /* XXX Hmm... Basically this cannot occur. Channel ID's cannot be + re-generated. */ + silc_free(id2); + break; + + default: + silc_free(id2); + break; + } + + out: + if (id) + silc_free(id); + if (old_id) + silc_free(old_id); + if (new_id) + silc_free(new_id); +} + + +/* Received New Client packet and processes it. Creates Client ID for the + client. Client becomes registered after calling this functions. */ + +SilcClientEntry silc_server_new_client(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcBuffer buffer = packet->buffer; + SilcClientEntry client; + SilcIDCacheEntry cache; + SilcClientID *client_id; + SilcBuffer reply; + SilcIDListData idata; + char *username = NULL, *realname = NULL, *id_string; + + SILC_LOG_DEBUG(("Creating new client")); + + if (sock->type != SILC_SOCKET_TYPE_CLIENT) + return NULL; + + /* Take client entry */ + client = (SilcClientEntry)sock->user_data; + idata = (SilcIDListData)client; + + /* Fetch the old client cache entry so that we can update it. */ + if (!silc_idcache_find_by_context(server->local_list->clients, + sock->user_data, &cache)) { + SILC_LOG_ERROR(("Lost client's cache entry - bad thing")); + return NULL; + } + + /* Parse incoming packet */ + silc_buffer_unformat(buffer, + SILC_STR_UI16_STRING_ALLOC(&username), + SILC_STR_UI16_STRING_ALLOC(&realname), + SILC_STR_END); + + /* Create Client ID */ + silc_id_create_client_id(server->id, server->rng, server->md5hash, + username, &client_id); + + /* Update client entry */ + idata->registered = TRUE; + client->nickname = strdup(username); + client->username = username; + client->userinfo = realname; + client->id = client_id; + + /* Update the cache entry */ + cache->id = (void *)client_id; + cache->type = SILC_ID_CLIENT; + cache->data = username; + silc_idcache_sort_by_data(server->local_list->clients); + + /* Notify our router about new client on the SILC network */ + if (!server->standalone) + silc_server_send_new_id(server, (SilcSocketConnection) + server->router->connection, + server->server_type == SILC_ROUTER ? TRUE : FALSE, + client->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN); + + /* Send the new client ID to the client. */ + id_string = silc_id_id2str(client->id, SILC_ID_CLIENT); + reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN); + silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply)); + silc_buffer_format(reply, + SILC_STR_UI_SHORT(SILC_ID_CLIENT), + SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN), + SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN), + SILC_STR_END); + silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0, + reply->data, reply->len, FALSE); + silc_free(id_string); + silc_buffer_free(reply); + + /* Send some nice info to the client */ + SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE, + ("Welcome to the SILC Network %s@%s", + username, sock->hostname)); + SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE, + ("Your host is %s, running version %s", + server->config->server_info->server_name, + server_version)); + SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE, + ("Your connection is secured with %s cipher, " + "key length %d bits", + idata->send_key->cipher->name, + idata->send_key->cipher->key_len)); + SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE, + ("Your current nickname is %s", + client->nickname)); + + /* Send motd */ + silc_server_send_motd(server, sock); + + return client; +} + +/* Create new server. This processes received New Server packet and + saves the received Server ID. The server is our locally connected + server thus we save all the information and save it to local list. + This funtion can be used by both normal server and router server. + If normal server uses this it means that its router has connected + to the server. If router uses this it means that one of the cell's + servers is connected to the router. */ + +SilcServerEntry silc_server_new_server(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcBuffer buffer = packet->buffer; + SilcServerEntry new_server; + SilcIDCacheEntry cache; + SilcServerID *server_id; + SilcIDListData idata; + unsigned char *server_name, *id_string; + unsigned short id_len; + + SILC_LOG_DEBUG(("Creating new server")); + + if (sock->type != SILC_SOCKET_TYPE_SERVER && + sock->type != SILC_SOCKET_TYPE_ROUTER) + return NULL; + + /* Take server entry */ + new_server = (SilcServerEntry)sock->user_data; + idata = (SilcIDListData)new_server; + + /* Fetch the old server cache entry so that we can update it. */ + if (!silc_idcache_find_by_context(server->local_list->servers, + sock->user_data, &cache)) { + SILC_LOG_ERROR(("Lost server's cache entry - bad thing")); + return NULL; + } + + /* Parse the incoming packet */ + silc_buffer_unformat(buffer, + SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len), + SILC_STR_UI16_STRING_ALLOC(&server_name), + SILC_STR_END); + + if (id_len > buffer->len) { + silc_free(id_string); + silc_free(server_name); + return NULL; + } + + /* Get Server ID */ + server_id = silc_id_str2id(id_string, SILC_ID_SERVER); + silc_free(id_string); + + /* Update client entry */ + idata->registered = TRUE; + new_server->server_name = server_name; + new_server->id = server_id; + + /* Update the cache entry */ + cache->id = (void *)server_id; + cache->type = SILC_ID_SERVER; + cache->data = server_name; + silc_idcache_sort_by_data(server->local_list->servers); + + /* Distribute the information about new server in the SILC network + to our router. If we are normal server we won't send anything + since this connection must be our router connection. */ + if (server->server_type == SILC_ROUTER && !server->standalone && + server->router->connection != sock) + silc_server_send_new_id(server, server->router->connection, + TRUE, new_server->id, SILC_ID_SERVER, + SILC_ID_SERVER_LEN); + + return new_server; +} + +/* Processes incoming New ID packet. New ID Payload is used to distribute + information about newly registered clients, servers and created + channels. */ + +void silc_server_new_id(SilcServer server, SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcBuffer buffer = packet->buffer; + SilcIDList id_list; + SilcServerEntry tmpserver, router; + SilcSocketConnection router_sock; + SilcIDPayload idp; + SilcIdType id_type; + void *id, *tmpid; + + SILC_LOG_DEBUG(("Processing new ID")); + + if (sock->type == SILC_SOCKET_TYPE_CLIENT || + server->server_type == SILC_SERVER || + packet->src_id_type != SILC_ID_SERVER) + return; + + idp = silc_id_payload_parse(buffer); + if (!idp) + return; + + id_type = silc_id_payload_get_type(idp); + + /* Normal server cannot have other normal server connections */ + if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER) + goto out; + + id = silc_id_payload_get_id(idp); + if (!id) + goto out; + + /* If the sender of this packet is server and we are router we need to + broadcast this packet to other routers in the network. */ + if (!server->standalone && server->server_type == SILC_ROUTER && + sock->type == SILC_SOCKET_TYPE_SERVER && + !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { + SILC_LOG_DEBUG(("Broadcasting received New ID packet")); + silc_server_packet_send(server, server->router->connection, + packet->type, + packet->flags | SILC_PACKET_FLAG_BROADCAST, + buffer->data, buffer->len, FALSE); + } + + /* If the packet is originated from the one who sent it to us we know + that the ID belongs to our cell, unless the sender was router. */ + tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER); + tmpserver = (SilcServerEntry)sock->user_data; + + if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) && + sock->type == SILC_SOCKET_TYPE_SERVER) { + id_list = server->local_list; + router_sock = sock; + router = sock->user_data; + /* router = server->id_entry; */ + } else { + id_list = server->global_list; + router_sock = (SilcSocketConnection)server->router->connection; + router = server->router; + } + + silc_free(tmpid); + + switch(id_type) { + case SILC_ID_CLIENT: + { + SilcClientEntry idlist; + + SILC_LOG_DEBUG(("New client id(%s) from [%s] %s", + silc_id_render(id, SILC_ID_CLIENT), + sock->type == SILC_SOCKET_TYPE_SERVER ? + "Server" : "Router", sock->hostname)); + + /* Add the client to our local list. We are router and we keep + cell specific local database of all clients in the cell. */ + idlist = silc_idlist_add_client(id_list, NULL, NULL, NULL, + id, router, router_sock); + } + break; + + case SILC_ID_SERVER: + { + SilcServerEntry idlist; + + SILC_LOG_DEBUG(("New server id(%s) from [%s] %s", + silc_id_render(id, SILC_ID_SERVER), + sock->type == SILC_SOCKET_TYPE_SERVER ? + "Server" : "Router", sock->hostname)); + + /* Add the server to our local list. We are router and we keep + cell specific local database of all servers in the cell. */ + idlist = silc_idlist_add_server(id_list, NULL, 0, id, router, + router_sock); + } + break; + + case SILC_ID_CHANNEL: + SILC_LOG_ERROR(("Channel cannot be registered with NEW_ID packet")); +#if 0 + SILC_LOG_DEBUG(("New channel id(%s) from [%s] %s", + silc_id_render(id, SILC_ID_CHANNEL), + sock->type == SILC_SOCKET_TYPE_SERVER ? + "Server" : "Router", sock->hostname)); + + /* Add the channel to our local list. We are router and we keep + cell specific local database of all channels in the cell. */ + silc_idlist_add_channel(id_list, NULL, 0, id, router, NULL); +#endif + break; + + default: + break; + } + + out: + silc_id_payload_free(idp); +} + +/* Received Remove Channel User packet to remove a user from a channel. + Routers notify other routers that user has left a channel. Client must + not send this packet.. Normal server may send this packet but must not + receive it. */ + +void silc_server_remove_channel_user(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcBuffer buffer = packet->buffer; + unsigned char *tmp1 = NULL, *tmp2 = NULL; + SilcClientID *client_id = NULL; + SilcChannelID *channel_id = NULL; + SilcChannelEntry channel; + SilcClientEntry client; + + SILC_LOG_DEBUG(("Removing user from channel")); + + if (sock->type == SILC_SOCKET_TYPE_CLIENT || + server->server_type == SILC_SERVER) + return; + + silc_buffer_unformat(buffer, + SILC_STR_UI16_STRING_ALLOC(&tmp1), + SILC_STR_UI16_STRING_ALLOC(&tmp2), + SILC_STR_END); + + if (!tmp1 || !tmp2) + goto out; + + client_id = silc_id_str2id(tmp1, SILC_ID_CLIENT); + channel_id = silc_id_str2id(tmp2, SILC_ID_CHANNEL); + if (!client_id || !channel_id) + goto out; + + /* If we are router and this packet is not already broadcast packet + we will broadcast it. The sending socket really cannot be router or + the router is buggy. If this packet is coming from router then it must + have the broadcast flag set already and we won't do anything. */ + if (!server->standalone && server->server_type == SILC_ROUTER && + sock->type == SILC_SOCKET_TYPE_SERVER && + !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { + SILC_LOG_DEBUG(("Broadcasting received Remove Channel User packet")); + silc_server_packet_send(server, server->router->connection, packet->type, + packet->flags | SILC_PACKET_FLAG_BROADCAST, + buffer->data, buffer->len, FALSE); + } + + /* XXX routers should check server->global_list as well */ + /* Get channel entry */ + channel = silc_idlist_find_channel_by_id(server->local_list, channel_id); + if (!channel) + goto out; + + /* XXX routers should check server->global_list as well */ + /* Get client entry */ + client = silc_idlist_find_client_by_id(server->local_list, client_id); + if (!client) + goto out; + + /* Remove from channel */ + silc_server_remove_from_one_channel(server, sock, channel, client, FALSE); + + out: + if (tmp1) + silc_free(tmp1); + if (tmp2) + silc_free(tmp2); + if (client_id) + silc_free(client_id); + if (channel_id) + silc_free(channel_id); +} + +/* Received New Channel packet. Information about new channels in the + network are distributed using this packet. Save the information about + the new channel. */ + +void silc_server_new_channel(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + unsigned char *id; + SilcChannelID *channel_id; + unsigned short channel_id_len; + char *channel_name; + + SILC_LOG_DEBUG(("Processing New Channel")); + + if (sock->type != SILC_SOCKET_TYPE_ROUTER || + server->server_type == SILC_SERVER || + packet->src_id_type != SILC_ID_SERVER) + return; + + /* Parse payload */ + if (!silc_buffer_unformat(packet->buffer, + SILC_STR_UI16_STRING_ALLOC(&channel_name), + SILC_STR_UI16_NSTRING_ALLOC(&id, &channel_id_len), + SILC_STR_END)) + return; + + if (!channel_name || !id) + return; + + /* Decode the channel ID */ + channel_id = silc_id_str2id(id, SILC_ID_CHANNEL); + if (!channel_id) + return; + silc_free(id); + + SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s", + silc_id_render(channel_id, SILC_ID_CHANNEL), + sock->hostname)); + + /* Add the new channel. Add it always to global list since if we receive + this packet then it cannot be created by ourselves but some other + router hence global channel. */ + silc_idlist_add_channel(server->global_list, channel_name, 0, channel_id, + server->router->connection, NULL); +} + +/* Received notify packet. Server can receive notify packets from router. + Server then relays the notify messages to clients if needed. */ + +void silc_server_notify(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcNotifyPayload payload; + SilcNotifyType type; + SilcArgumentPayload args; + int i; + + if (sock->type == SILC_SOCKET_TYPE_CLIENT || + packet->src_id_type != SILC_ID_SERVER) + return; + + /* For now we expect that the we are normal server and that the + sender is router. Server could send (protocol allows it) notify to + router but we don't support it yet. XXX! */ + if (server->server_type != SILC_SERVER && + sock->type != SILC_SOCKET_TYPE_ROUTER) + return; + + payload = silc_notify_payload_parse(packet->buffer); + if (!payload) + return; + + type = silc_notify_get_type(payload); + args = silc_notify_get_args(payload); + if (!args) + goto out; + + switch(type) { + case SILC_NOTIFY_TYPE_JOIN: + break; + + case SILC_NOTIFY_TYPE_LEAVE: + break; + + case SILC_NOTIFY_TYPE_SIGNOFF: + break; + + /* Ignore rest notify types for now */ + case SILC_NOTIFY_TYPE_NONE: + case SILC_NOTIFY_TYPE_INVITE: + case SILC_NOTIFY_TYPE_TOPIC_SET: + case SILC_NOTIFY_TYPE_CMODE_CHANGE: + case SILC_NOTIFY_TYPE_CUMODE_CHANGE: + case SILC_NOTIFY_TYPE_MOTD: + default: + break; + } + + out: + silc_notify_payload_free(payload); +} + +/* Received new channel user packet. Information about new users on a + channel are distributed between routers using this packet. The + router receiving this will redistribute it and also sent JOIN notify + to local clients on the same channel. Normal server sends JOIN notify + to its local clients on the channel. */ + +void silc_server_new_channel_user(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + unsigned char *tmpid1, *tmpid2; + SilcClientID *client_id = NULL; + SilcChannelID *channel_id = NULL; + unsigned short channel_id_len; + unsigned short client_id_len; + SilcClientEntry client; + SilcChannelEntry channel; + SilcChannelClientEntry chl; + SilcIDList id_list; + SilcServerEntry tmpserver, router; + SilcSocketConnection router_sock; + SilcBuffer clidp; + void *tmpid; + + if (sock->type == SILC_SOCKET_TYPE_CLIENT || + server->server_type != SILC_ROUTER || + packet->src_id_type != SILC_ID_SERVER) + return; + + /* Parse payload */ + if (!silc_buffer_unformat(packet->buffer, + SILC_STR_UI16_NSTRING_ALLOC(&tmpid1, + &channel_id_len), + SILC_STR_UI16_NSTRING_ALLOC(&tmpid2, + &client_id_len), + SILC_STR_END)) + return; + + if (!tmpid1 || !tmpid2) + return; + + /* Decode the channel ID */ + channel_id = silc_id_str2id(tmpid1, SILC_ID_CHANNEL); + if (!channel_id) + goto out; + + /* Decode the client ID */ + client_id = silc_id_str2id(tmpid1, SILC_ID_CLIENT); + if (!client_id) + goto out; + + /* If the packet is originated from the one who sent it to us we know + that the ID belongs to our cell, unless the sender was router. */ + tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER); + tmpserver = (SilcServerEntry)sock->user_data; + + if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) && + sock->type == SILC_SOCKET_TYPE_SERVER) { + id_list = server->local_list; + router_sock = sock; + router = sock->user_data; + } else { + id_list = server->global_list; + router_sock = (SilcSocketConnection)server->router->connection; + router = server->router; + } + silc_free(tmpid); + + /* Find the channel */ + channel = silc_idlist_find_channel_by_id(id_list, channel_id); + if (!channel) { + SILC_LOG_ERROR(("Received channel user for non-existent channel")); + goto out; + } + + /* If we are router and this packet is not already broadcast packet + we will broadcast it. */ + if (!server->standalone && server->server_type == SILC_ROUTER && + !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { + SILC_LOG_DEBUG(("Broadcasting received New Channel User packet")); + silc_server_packet_send(server, server->router->connection, packet->type, + packet->flags | SILC_PACKET_FLAG_BROADCAST, + packet->buffer->data, packet->buffer->len, FALSE); + } + + /* Get client entry */ + client = silc_idlist_find_client_by_id(id_list, client_id); + if (!client) { + /* This is new client to us, add entry to ID list */ + client = silc_idlist_add_client(id_list, NULL, NULL, NULL, + client_id, router, router_sock); + if (!client) + goto out; + } + + /* Join the client to the channel by adding it to channel's user list. + Add also the channel to client entry's channels list for fast cross- + referencing. */ + chl = silc_calloc(1, sizeof(*chl)); + chl->client = client; + chl->channel = channel; + silc_list_add(channel->user_list, chl); + silc_list_add(client->channels, chl); + + /* Send JOIN notify to local clients on the channel. As we are router + it is assured that this is sent only to our local clients and locally + connected servers if needed. */ + clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT); + silc_server_send_notify_to_channel(server, channel, TRUE, + SILC_NOTIFY_TYPE_JOIN, + 1, clidp->data, clidp->len); + silc_buffer_free(clidp); + + client_id = NULL; + + out: + if (client_id) + silc_free(client_id); + if (channel_id) + silc_free(channel_id); + silc_free(tmpid1); + silc_free(tmpid2); +} diff --git a/apps/silcd/packet_receive.h b/apps/silcd/packet_receive.h new file mode 100644 index 00000000..710e88a0 --- /dev/null +++ b/apps/silcd/packet_receive.h @@ -0,0 +1,62 @@ +/* + + packet_receive.h + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2000 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef PACKET_RECEIVE_H +#define PACKET_RECEIVE_H + +/* Prototypes */ + +void silc_server_private_message(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_packet_relay_command_reply(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_channel_message(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_channel_key(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_replace_id(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +SilcClientEntry silc_server_new_client(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +SilcServerEntry silc_server_new_server(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_new_id(SilcServer server, SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_remove_channel_user(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_new_channel(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_notify(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_new_channel_user(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); + +#endif diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c new file mode 100644 index 00000000..3b72d89a --- /dev/null +++ b/apps/silcd/packet_send.c @@ -0,0 +1,1089 @@ +/* + + packet_send.c + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2000 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ +/* + * Server packet routines to send packets. + */ +/* $Id$ */ + +#include "serverincludes.h" +#include "server_internal.h" + +/* Routine that sends packet or marks packet to be sent. This is used + directly only in special cases. Normal cases should use + silc_server_packet_send. Returns < 0 error. */ + +int silc_server_packet_send_real(SilcServer server, + SilcSocketConnection sock, + int force_send) +{ + int ret; + + /* Send the packet */ + ret = silc_packet_send(sock, force_send); + if (ret != -2) + return ret; + + /* Mark that there is some outgoing data available for this connection. + This call sets the connection both for input and output (the input + is set always and this call keeps the input setting, actually). + Actual data sending is performed by silc_server_packet_process. */ + SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock); + + /* Mark to socket that data is pending in outgoing buffer. This flag + is needed if new data is added to the buffer before the earlier + put data is sent to the network. */ + SILC_SET_OUTBUF_PENDING(sock); + + return 0; +} + +/* Assembles a new packet to be sent out to network. This doesn't actually + send the packet but creates the packet and fills the outgoing data + buffer and marks the packet ready to be sent to network. However, If + argument force_send is TRUE the packet is sent immediately and not put + to queue. Normal case is that the packet is not sent immediately. */ + +void silc_server_packet_send(SilcServer server, + SilcSocketConnection sock, + SilcPacketType type, + SilcPacketFlags flags, + unsigned char *data, + unsigned int data_len, + int force_send) +{ + void *dst_id = NULL; + SilcIdType dst_id_type = SILC_ID_NONE; + + if (!sock) + return; + + /* Get data used in the packet sending, keys and stuff */ + switch(sock->type) { + case SILC_SOCKET_TYPE_CLIENT: + dst_id = ((SilcClientEntry)sock->user_data)->id; + dst_id_type = SILC_ID_CLIENT; + break; + case SILC_SOCKET_TYPE_SERVER: + case SILC_SOCKET_TYPE_ROUTER: + dst_id = ((SilcServerEntry)sock->user_data)->id; + dst_id_type = SILC_ID_SERVER; + break; + default: + break; + } + + silc_server_packet_send_dest(server, sock, type, flags, dst_id, + dst_id_type, data, data_len, force_send); +} + +/* Assembles a new packet to be sent out to network. This doesn't actually + send the packet but creates the packet and fills the outgoing data + buffer and marks the packet ready to be sent to network. However, If + argument force_send is TRUE the packet is sent immediately and not put + to queue. Normal case is that the packet is not sent immediately. + Destination information is sent as argument for this function. */ + +void silc_server_packet_send_dest(SilcServer server, + SilcSocketConnection sock, + SilcPacketType type, + SilcPacketFlags flags, + void *dst_id, + SilcIdType dst_id_type, + unsigned char *data, + unsigned int data_len, + int force_send) +{ + SilcPacketContext packetdata; + SilcIDListData idata; + SilcCipher cipher = NULL; + SilcHmac hmac = NULL; + unsigned char *dst_id_data = NULL; + unsigned int dst_id_len = 0; + + SILC_LOG_DEBUG(("Sending packet, type %d", type)); + + /* Get data used in the packet sending, keys and stuff */ + idata = (SilcIDListData)sock->user_data; + + if (dst_id) { + dst_id_data = silc_id_id2str(dst_id, dst_id_type); + dst_id_len = silc_id_get_len(dst_id_type); + } + + /* Set the packet context pointers */ + packetdata.type = type; + packetdata.flags = flags; + packetdata.src_id = silc_id_id2str(server->id, server->id_type); + packetdata.src_id_len = SILC_ID_SERVER_LEN; + packetdata.src_id_type = server->id_type; + packetdata.dst_id = dst_id_data; + packetdata.dst_id_len = dst_id_len; + packetdata.dst_id_type = dst_id_type; + packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + + packetdata.src_id_len + dst_id_len; + packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); + packetdata.rng = server->rng; + + /* Prepare outgoing data buffer for packet sending */ + silc_packet_send_prepare(sock, + SILC_PACKET_HEADER_LEN + + packetdata.src_id_len + + packetdata.dst_id_len, + packetdata.padlen, + data_len); + + SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len)); + + packetdata.buffer = sock->outbuf; + + /* Put the data to the buffer */ + if (data && data_len) + silc_buffer_put(sock->outbuf, data, data_len); + + /* Create the outgoing packet */ + silc_packet_assemble(&packetdata); + + if (idata) { + cipher = idata->send_key; + hmac = idata->hmac; + } + + /* Encrypt the packet */ + silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); + + SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len), + sock->outbuf->data, sock->outbuf->len); + + /* Now actually send the packet */ + silc_server_packet_send_real(server, sock, force_send); + + if (packetdata.src_id) + silc_free(packetdata.src_id); + if (packetdata.dst_id) + silc_free(packetdata.dst_id); +} + +/* Forwards packet. Packets sent with this function will be marked as + forwarded (in the SILC header flags) so that the receiver knows that + we have forwarded the packet to it. Forwarded packets are handled + specially by the receiver as they are not destined to the receiver + originally. However, the receiver knows this because the forwarded + flag has been set (and the flag is authenticated). */ + +void silc_server_packet_forward(SilcServer server, + SilcSocketConnection sock, + unsigned char *data, unsigned int data_len, + int force_send) +{ + SilcIDListData idata; + SilcCipher cipher = NULL; + SilcHmac hmac = NULL; + + SILC_LOG_DEBUG(("Forwarding packet")); + + /* Get data used in the packet sending, keys and stuff */ + idata = (SilcIDListData)sock->user_data; + + /* Prepare outgoing data buffer for packet sending */ + silc_packet_send_prepare(sock, 0, 0, data_len); + + /* Put the data to the buffer */ + if (data && data_len) + silc_buffer_put(sock->outbuf, data, data_len); + + /* Add the FORWARDED flag to packet flags */ + sock->outbuf->data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED; + + if (idata) { + cipher = idata->send_key; + hmac = idata->hmac; + } + + /* Encrypt the packet */ + silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); + + SILC_LOG_HEXDUMP(("Forwarded packet, len %d", sock->outbuf->len), + sock->outbuf->data, sock->outbuf->len); + + /* Now actually send the packet */ + silc_server_packet_send_real(server, sock, force_send); +} + +/* Broadcast received packet to our primary route. This function is used + by router to further route received broadcast packet. It is expected + that the broadcast flag from the packet is checked before calling this + function. This does not test or set the broadcast flag. */ + +void silc_server_packet_broadcast(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcBuffer buffer = packet->buffer; + SilcIDListData idata; + void *id; + + SILC_LOG_DEBUG(("Broadcasting received broadcast packet")); + + /* If the packet is originated from our primary route we are + not allowed to send the packet. */ + id = silc_id_str2id(packet->src_id, packet->src_id_type); + if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) { + idata = (SilcIDListData)sock->user_data; + + silc_buffer_push(buffer, buffer->data - buffer->head); + silc_packet_send_prepare(sock, 0, 0, buffer->len); + silc_buffer_put(sock->outbuf, buffer->data, buffer->len); + silc_packet_encrypt(idata->send_key, idata->hmac, + sock->outbuf, sock->outbuf->len); + + SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len), + sock->outbuf->data, sock->outbuf->len); + + /* Now actually send the packet */ + silc_server_packet_send_real(server, sock, TRUE); + silc_free(id); + return; + } + + SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the " + "original sender of this packet")); + silc_free(id); +} + +/* Internal routine to actually create the channel packet and send it + to network. This is common function in channel message sending. If + `channel_message' is TRUE this encrypts the message as it is strictly + a channel message. If FALSE normal encryption process is used. */ + +static void +silc_server_packet_send_to_channel_real(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet, + SilcCipher cipher, + SilcHmac hmac, + unsigned char *data, + unsigned int data_len, + int channel_message, + int force_send) +{ + packet->truelen = data_len + SILC_PACKET_HEADER_LEN + + packet->src_id_len + packet->dst_id_len; + + /* Prepare outgoing data buffer for packet sending */ + silc_packet_send_prepare(sock, + SILC_PACKET_HEADER_LEN + + packet->src_id_len + + packet->dst_id_len, + packet->padlen, + data_len); + + packet->buffer = sock->outbuf; + + /* Put the data to buffer, assemble and encrypt the packet. The packet + is encrypted with normal session key shared with the client. */ + silc_buffer_put(sock->outbuf, data, data_len); + silc_packet_assemble(packet); + if (channel_message) + silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + + packet->src_id_len + packet->dst_id_len + + packet->padlen); + else + silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); + + SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len), + sock->outbuf->data, sock->outbuf->len); + + /* Now actually send the packet */ + silc_server_packet_send_real(server, sock, force_send); +} + +/* This routine is used by the server to send packets to channel. The + packet sent with this function is distributed to all clients on + the channel. Usually this is used to send notify messages to the + channel, things like notify about new user joining to the channel. + If `route' is FALSE then the packet is sent only locally and will not + be routed anywhere. */ + +void silc_server_packet_send_to_channel(SilcServer server, + SilcChannelEntry channel, + SilcPacketType type, + unsigned char route, + unsigned char *data, + unsigned int data_len, + int force_send) +{ + SilcSocketConnection sock = NULL; + SilcPacketContext packetdata; + SilcClientEntry client = NULL; + SilcServerEntry *routed = NULL; + SilcChannelClientEntry chl; + SilcIDListData idata; + unsigned int routed_count = 0; + + /* This doesn't send channel message packets */ + if (type == SILC_PACKET_CHANNEL_MESSAGE) + return; + + SILC_LOG_DEBUG(("Sending packet to channel")); + + /* Set the packet context pointers. */ + packetdata.flags = 0; + packetdata.type = type; + packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER); + packetdata.src_id_len = SILC_ID_SERVER_LEN; + packetdata.src_id_type = SILC_ID_SERVER; + packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL); + packetdata.dst_id_len = SILC_ID_CHANNEL_LEN; + packetdata.dst_id_type = SILC_ID_CHANNEL; + packetdata.rng = server->rng; + packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + + packetdata.src_id_len + packetdata.dst_id_len; + packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); + + /* If there are global users in the channel we will send the message + first to our router for further routing. */ + if (route && server->server_type == SILC_SERVER && !server->standalone && + channel->global_users) { + SilcServerEntry router; + + /* Get data used in packet header encryption, keys and stuff. */ + router = server->router; + sock = (SilcSocketConnection)router->connection; + idata = (SilcIDListData)router; + + SILC_LOG_DEBUG(("Sending channel message to router for routing")); + + silc_server_packet_send_to_channel_real(server, sock, &packetdata, + idata->send_key, idata->hmac, + data, data_len, FALSE, force_send); + } + + /* Send the message to clients on the channel's client list. */ + silc_list_start(channel->user_list); + while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { + client = chl->client; + + /* If client has router set it is not locally connected client and + we will route the message to the router set in the client. */ + if (route && client && client->router && + server->server_type == SILC_ROUTER) { + int k; + + /* Check if we have sent the packet to this route already */ + for (k = 0; k < routed_count; k++) + if (routed[k] == client->router) + break; + if (k < routed_count) + continue; + + /* Get data used in packet header encryption, keys and stuff. */ + sock = (SilcSocketConnection)client->router->connection; + idata = (SilcIDListData)client->router; + + /* Send the packet */ + silc_server_packet_send_to_channel_real(server, sock, &packetdata, + idata->send_key, idata->hmac, + data, data_len, FALSE, + force_send); + + /* We want to make sure that the packet is routed to same router + only once. Mark this route as sent route. */ + k = routed_count; + routed = silc_realloc(routed, sizeof(*routed) * (k + 1)); + routed[k] = client->router; + routed_count++; + + continue; + } + + /* Send to locally connected client */ + if (client) { + + /* Get data used in packet header encryption, keys and stuff. */ + sock = (SilcSocketConnection)client->connection; + idata = (SilcIDListData)client; + + /* Send the packet */ + silc_server_packet_send_to_channel_real(server, sock, &packetdata, + idata->send_key, idata->hmac, + data, data_len, FALSE, + force_send); + } + } + + if (routed_count) + silc_free(routed); + silc_free(packetdata.src_id); + silc_free(packetdata.dst_id); +} + +/* This routine is explicitly used to relay messages to some channel. + Packets sent with this function we have received earlier and are + totally encrypted. This just sends the packet to all clients on + the channel. If the sender of the packet is someone on the channel + the message will not be sent to that client. The SILC Packet header + is encrypted with the session key shared between us and the client. + MAC is also computed before encrypting the header. Rest of the + packet will be untouched. */ + +void silc_server_packet_relay_to_channel(SilcServer server, + SilcSocketConnection sender_sock, + SilcChannelEntry channel, + void *sender, + SilcIdType sender_type, + unsigned char *data, + unsigned int data_len, + int force_send) +{ + int found = FALSE; + SilcSocketConnection sock = NULL; + SilcPacketContext packetdata; + SilcClientEntry client = NULL; + SilcServerEntry *routed = NULL; + SilcChannelClientEntry chl; + unsigned int routed_count = 0; + SilcIDListData idata; + + SILC_LOG_DEBUG(("Relaying packet to channel")); + + /* Set the packet context pointers. */ + packetdata.flags = 0; + packetdata.type = SILC_PACKET_CHANNEL_MESSAGE; + packetdata.src_id = silc_id_id2str(sender, sender_type); + packetdata.src_id_len = silc_id_get_len(sender_type); + packetdata.src_id_type = sender_type; + packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL); + packetdata.dst_id_len = SILC_ID_CHANNEL_LEN; + packetdata.dst_id_type = SILC_ID_CHANNEL; + packetdata.rng = server->rng; + packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + + packetdata.src_id_len + + packetdata.dst_id_len)); + + /* If there are global users in the channel we will send the message + first to our router for further routing. */ + if (server->server_type == SILC_SERVER && !server->standalone && + channel->global_users) { + SilcServerEntry router; + + router = server->router; + + /* Check that the sender is not our router. */ + if (sender_sock != (SilcSocketConnection)router->connection) { + + /* Get data used in packet header encryption, keys and stuff. */ + sock = (SilcSocketConnection)router->connection; + idata = (SilcIDListData)router; + + SILC_LOG_DEBUG(("Sending channel message to router for routing")); + + silc_server_packet_send_to_channel_real(server, sock, &packetdata, + idata->send_key, idata->hmac, + data, data_len, TRUE, + force_send); + } + } + + /* Send the message to clients on the channel's client list. */ + silc_list_start(channel->user_list); + while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { + client = chl->client; + + if (client) { + + /* If sender is one on the channel do not send it the packet. */ + if (!found && !SILC_ID_CLIENT_COMPARE(client->id, sender)) { + found = TRUE; + continue; + } + + /* If the client has set router it means that it is not locally + connected client and we will route the packet further. */ + if (server->server_type == SILC_ROUTER && client->router) { + int k; + + /* Sender maybe server as well so we want to make sure that + we won't send the message to the server it came from. */ + if (!found && !SILC_ID_SERVER_COMPARE(client->router->id, sender)) { + found = TRUE; + continue; + } + + /* Check if we have sent the packet to this route already */ + for (k = 0; k < routed_count; k++) + if (routed[k] == client->router) + break; + if (k < routed_count) + continue; + + /* Get data used in packet header encryption, keys and stuff. */ + sock = (SilcSocketConnection)client->router->connection; + idata = (SilcIDListData)client->router; + + /* Send the packet */ + silc_server_packet_send_to_channel_real(server, sock, &packetdata, + idata->send_key, idata->hmac, + data, data_len, TRUE, + force_send); + + /* We want to make sure that the packet is routed to same router + only once. Mark this route as sent route. */ + k = routed_count; + routed = silc_realloc(routed, sizeof(*routed) * (k + 1)); + routed[k] = client->router; + routed_count++; + + continue; + } + + /* XXX Check client's mode on the channel. */ + + /* Get data used in packet header encryption, keys and stuff. */ + sock = (SilcSocketConnection)client->connection; + idata = (SilcIDListData)client; + + SILC_LOG_DEBUG(("Sending packet to client %s", + sock->hostname ? sock->hostname : sock->ip)); + + /* Send the packet */ + silc_server_packet_send_to_channel_real(server, sock, &packetdata, + idata->send_key, idata->hmac, + data, data_len, TRUE, + force_send); + } + } + + silc_free(packetdata.src_id); + silc_free(packetdata.dst_id); +} + +/* This function is used to send packets strictly to all local clients + on a particular channel. This is used for example to distribute new + channel key to all our locally connected clients on the channel. + The packets are always encrypted with the session key shared between + the client, this means these are not _to the channel_ but _to the client_ + on the channel. */ + +void silc_server_packet_send_local_channel(SilcServer server, + SilcChannelEntry channel, + SilcPacketType type, + SilcPacketFlags flags, + unsigned char *data, + unsigned int data_len, + int force_send) +{ + SilcClientEntry client; + SilcChannelClientEntry chl; + SilcSocketConnection sock = NULL; + + SILC_LOG_DEBUG(("Start")); + + /* Send the message to clients on the channel's client list. */ + silc_list_start(channel->user_list); + while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { + client = chl->client; + + if (client) { + sock = (SilcSocketConnection)client->connection; + + /* Send the packet to the client */ + silc_server_packet_send_dest(server, sock, type, flags, client->id, + SILC_ID_CLIENT, data, data_len, + force_send); + } + } +} + +/* Routine used to send (relay, route) private messages to some destination. + If the private message key does not exist then the message is re-encrypted, + otherwise we just pass it along. This really is not used to send new + private messages (as server does not send them) but to relay received + private messages. */ + +void silc_server_send_private_message(SilcServer server, + SilcSocketConnection dst_sock, + SilcCipher cipher, + SilcHmac hmac, + SilcPacketContext *packet) +{ + SilcBuffer buffer = packet->buffer; + + /* Send and re-encrypt if private messge key does not exist */ + if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) { + + silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len + + packet->dst_id_len + packet->padlen); + silc_packet_send_prepare(dst_sock, 0, 0, buffer->len); + silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len); + + /* Re-encrypt packet */ + silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len); + + /* Send the packet */ + silc_server_packet_send_real(server, dst_sock, FALSE); + + } else { + /* Key exist so just send it */ + silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len + + packet->dst_id_len + packet->padlen); + silc_packet_send_prepare(dst_sock, 0, 0, buffer->len); + silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len); + silc_server_packet_send_real(server, dst_sock, FALSE); + } +} + +/* Sends current motd to client */ + +void silc_server_send_motd(SilcServer server, + SilcSocketConnection sock) +{ + char *motd; + int motd_len; + + if (server->config && server->config->motd && + server->config->motd->motd_file) { + + motd = silc_file_read(server->config->motd->motd_file, &motd_len); + if (!motd) + return; + + silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1, + motd, motd_len); + silc_free(motd); + } +} + +/* Sends error message. Error messages may or may not have any + implications. */ + +void silc_server_send_error(SilcServer server, + SilcSocketConnection sock, + const char *fmt, ...) +{ + va_list ap; + unsigned char buf[4096]; + + memset(buf, 0, sizeof(buf)); + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0, + buf, strlen(buf), FALSE); +} + +/* Sends notify message. If format is TRUE the variable arguments are + formatted and the formatted string is sent as argument payload. If it is + FALSE then each argument is sent as separate argument and their format + in the argument list must be { argument data, argument length }. */ + +void silc_server_send_notify(SilcServer server, + SilcSocketConnection sock, + SilcNotifyType type, + unsigned int argc, ...) +{ + va_list ap; + SilcBuffer packet; + + va_start(ap, argc); + + packet = silc_notify_payload_encode(type, argc, ap); + silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, + packet->data, packet->len, FALSE); + silc_buffer_free(packet); +} + +/* Sends notify message destined to specific entity. */ + +void silc_server_send_notify_dest(SilcServer server, + SilcSocketConnection sock, + void *dest_id, + SilcIdType dest_id_type, + SilcNotifyType type, + unsigned int argc, ...) +{ + va_list ap; + SilcBuffer packet; + + va_start(ap, argc); + + packet = silc_notify_payload_encode(type, argc, ap); + silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, + dest_id, dest_id_type, + packet->data, packet->len, FALSE); + silc_buffer_free(packet); +} + +/* Sends notify message to a channel. The notify message sent is + distributed to all clients on the channel. If `router_notify' is TRUE + then the notify may be routed to primary route or to some other routers. + If FALSE it is assured that the notify is sent only locally. */ + +void silc_server_send_notify_to_channel(SilcServer server, + SilcChannelEntry channel, + unsigned char route_notify, + SilcNotifyType type, + unsigned int argc, ...) +{ + va_list ap; + SilcBuffer packet; + + va_start(ap, argc); + + packet = silc_notify_payload_encode(type, argc, ap); + silc_server_packet_send_to_channel(server, channel, + SILC_PACKET_NOTIFY, route_notify, + packet->data, packet->len, FALSE); + silc_buffer_free(packet); +} + +/* Send notify message to all clients the client has joined. It is quaranteed + that the message is sent only once to a client (ie. if a client is joined + on two same channel it will receive only one notify message). Also, this + sends only to local clients (locally connected if we are server, and to + local servers if we are router). */ + +void silc_server_send_notify_on_channels(SilcServer server, + SilcClientEntry client, + SilcNotifyType type, + unsigned int argc, ...) +{ + int k; + SilcSocketConnection sock = NULL; + SilcPacketContext packetdata; + SilcClientEntry c; + SilcClientEntry *sent_clients = NULL; + unsigned int sent_clients_count = 0; + SilcServerEntry *routed = NULL; + unsigned int routed_count = 0; + SilcChannelEntry channel; + SilcChannelClientEntry chl, chl2; + SilcIDListData idata; + SilcBuffer packet; + unsigned char *data; + unsigned int data_len; + int force_send = FALSE; + va_list ap; + + SILC_LOG_DEBUG(("Start")); + + if (!silc_list_count(client->channels)) + return; + + va_start(ap, argc); + packet = silc_notify_payload_encode(type, argc, ap); + data = packet->data; + data_len = packet->len; + + /* Set the packet context pointers. */ + packetdata.flags = 0; + packetdata.type = SILC_PACKET_NOTIFY; + packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER); + packetdata.src_id_len = SILC_ID_SERVER_LEN; + packetdata.src_id_type = SILC_ID_SERVER; + packetdata.rng = server->rng; + + silc_list_start(client->channels); + while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) { + channel = chl->channel; + + /* Send the message to all clients on the channel's client list. */ + silc_list_start(channel->user_list); + while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) { + c = chl2->client; + + /* Check if we have sent the packet to this client already */ + for (k = 0; k < sent_clients_count; k++) + if (sent_clients[k] == c) + break; + if (k < sent_clients_count) + continue; + + /* If we are router and if this client has router set it is not + locally connected client and we will route the message to the + router set in the client. */ + if (c && c->router && server->server_type == SILC_ROUTER) { + /* Check if we have sent the packet to this route already */ + for (k = 0; k < routed_count; k++) + if (routed[k] == c->router) + break; + if (k < routed_count) + continue; + + /* Get data used in packet header encryption, keys and stuff. */ + sock = (SilcSocketConnection)c->router->connection; + idata = (SilcIDListData)c->router; + + packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER); + packetdata.dst_id_len = SILC_ID_SERVER_LEN; + packetdata.dst_id_type = SILC_ID_SERVER; + packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + + packetdata.src_id_len + packetdata.dst_id_len; + packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); + + /* Send the packet */ + silc_server_packet_send_to_channel_real(server, sock, &packetdata, + idata->send_key, idata->hmac, + data, data_len, FALSE, + force_send); + + silc_free(packetdata.dst_id); + + /* We want to make sure that the packet is routed to same router + only once. Mark this route as sent route. */ + k = routed_count; + routed = silc_realloc(routed, sizeof(*routed) * (k + 1)); + routed[k] = c->router; + routed_count++; + + continue; + } + + /* Send to locally connected client */ + if (c) { + + /* Get data used in packet header encryption, keys and stuff. */ + sock = (SilcSocketConnection)c->connection; + idata = (SilcIDListData)c; + + packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT); + packetdata.dst_id_len = SILC_ID_CLIENT_LEN; + packetdata.dst_id_type = SILC_ID_CLIENT; + packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + + packetdata.src_id_len + packetdata.dst_id_len; + packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); + + /* Send the packet */ + silc_server_packet_send_to_channel_real(server, sock, &packetdata, + idata->send_key, idata->hmac, + data, data_len, FALSE, + force_send); + + silc_free(packetdata.dst_id); + + /* Make sure that we send the notify only once per client. */ + sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) * + (sent_clients_count + 1)); + sent_clients[sent_clients_count] = c; + sent_clients_count++; + } + } + } + + if (routed_count) + silc_free(routed); + if (sent_clients_count) + silc_free(sent_clients); + silc_free(packetdata.src_id); +} + +/* Sends New ID Payload to remote end. The packet is used to distribute + information about new registered clients, servers, channel etc. usually + to routers so that they can keep these information up to date. + If the argument `broadcast' is TRUE then the packet is sent as + broadcast packet. */ + +void silc_server_send_new_id(SilcServer server, + SilcSocketConnection sock, + int broadcast, + void *id, SilcIdType id_type, + unsigned int id_len) +{ + SilcBuffer idp; + + SILC_LOG_DEBUG(("Start")); + + idp = silc_id_payload_encode(id, id_type); + silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, + broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, + idp->data, idp->len, FALSE); + silc_buffer_free(idp); +} + +/* Sends Replace ID payload to remote end. This is used to replace old + ID with new ID sent in the packet. This is called for example when + user changes nickname and we create new ID for the user. If the + argument `broadcast' is TRUE then the packet is sent as + broadcast packet. */ +/* XXX It would be expected that the new id is same type as the old + ID. :) */ + +void silc_server_send_replace_id(SilcServer server, + SilcSocketConnection sock, + int broadcast, + void *old_id, SilcIdType old_id_type, + unsigned int old_id_len, + void *new_id, SilcIdType new_id_type, + unsigned int new_id_len) +{ + SilcBuffer packet; + unsigned char *oid; + unsigned char *nid; + + SILC_LOG_DEBUG(("Start")); + + oid = silc_id_id2str(old_id, old_id_type); + if (!oid) + return; + + nid = silc_id_id2str(new_id, new_id_type); + if (!nid) + return; + + packet = silc_buffer_alloc(2 + 2 + 2 + 2 + old_id_len + new_id_len); + silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); + silc_buffer_format(packet, + SILC_STR_UI_SHORT(old_id_type), + SILC_STR_UI_SHORT(old_id_len), + SILC_STR_UI_XNSTRING(oid, old_id_len), + SILC_STR_UI_SHORT(new_id_type), + SILC_STR_UI_SHORT(new_id_len), + SILC_STR_UI_XNSTRING(nid, new_id_len), + SILC_STR_END); + + silc_server_packet_send(server, sock, SILC_PACKET_REPLACE_ID, + broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, + packet->data, packet->len, FALSE); + silc_free(oid); + silc_free(nid); + silc_buffer_free(packet); +} + +/* This function is used to send Remove Channel User payload. This may sent + by server but is usually used only by router to notify other routers that + user has left a channel. Normal server sends this packet to its router + to notify that the router should not hold a record about this client + on a channel anymore. Router distributes it further to other routers. */ + +void silc_server_send_remove_channel_user(SilcServer server, + SilcSocketConnection sock, + int broadcast, + void *client_id, void *channel_id) +{ + SilcBuffer packet; + unsigned char *clid, *chid; + + SILC_LOG_DEBUG(("Start")); + + clid = silc_id_id2str(client_id, SILC_ID_CLIENT); + if (!clid) + return; + + chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL); + if (!chid) + return; + + packet = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN + SILC_ID_CHANNEL_LEN); + silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); + silc_buffer_format(packet, + SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN), + SILC_STR_UI_XNSTRING(clid, SILC_ID_CLIENT_LEN), + SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN), + SILC_STR_UI_XNSTRING(chid, SILC_ID_CHANNEL_LEN), + SILC_STR_END); + + silc_server_packet_send(server, sock, SILC_PACKET_REMOVE_CHANNEL_USER, + broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, + packet->data, packet->len, FALSE); + silc_free(clid); + silc_free(chid); + silc_buffer_free(packet); +} + +/* Send New Channel Payload to notify about newly created channel in the + SILC network. Normal server nevers sends this packet. Router uses this + to notify other routers in the network about new channel. This packet + is broadcasted. */ + +void silc_server_send_new_channel(SilcServer server, + SilcSocketConnection sock, + int broadcast, + char *channel_name, + void *channel_id, + unsigned int channel_id_len) +{ + SilcBuffer packet; + unsigned char *cid; + unsigned int name_len = strlen(channel_name); + + SILC_LOG_DEBUG(("Start")); + + cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL); + if (!cid) + return; + + packet = silc_buffer_alloc(2 + 2 + name_len + channel_id_len); + silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); + silc_buffer_format(packet, + SILC_STR_UI_SHORT(name_len), + SILC_STR_UI_XNSTRING(channel_name, name_len), + SILC_STR_UI_SHORT(channel_id_len), + SILC_STR_UI_XNSTRING(cid, channel_id_len), + SILC_STR_END); + + silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL, + broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, + packet->data, packet->len, FALSE); + + silc_free(cid); + silc_buffer_free(packet); +} + +/* Send New Channel User payload to notify routers in the network about new + user on the channel. The packet is may be broadcasted. Normal server + can send this but must not receive. Router can send and receive it. */ + +void silc_server_send_new_channel_user(SilcServer server, + SilcSocketConnection sock, + int broadcast, + void *channel_id, + unsigned int channel_id_len, + void *client_id, + unsigned int client_id_len) +{ + SilcBuffer packet; + unsigned char *clid, *chid; + + SILC_LOG_DEBUG(("Start")); + + clid = silc_id_id2str(client_id, SILC_ID_CLIENT); + if (!clid) + return; + + chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL); + if (!chid) + return; + + packet = silc_buffer_alloc(2 + 2 + channel_id_len + client_id_len); + silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); + silc_buffer_format(packet, + SILC_STR_UI_SHORT(channel_id_len), + SILC_STR_UI_XNSTRING(chid, channel_id_len), + SILC_STR_UI_SHORT(client_id_len), + SILC_STR_UI_XNSTRING(clid, client_id_len), + SILC_STR_END); + + silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL_USER, + broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, + packet->data, packet->len, FALSE); + silc_free(clid); + silc_free(chid); + silc_buffer_free(packet); +} diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h new file mode 100644 index 00000000..760095ce --- /dev/null +++ b/apps/silcd/packet_send.h @@ -0,0 +1,133 @@ +/* + + packet_send.h + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2000 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef PACKET_SEND_H +#define PACKET_SEND_H + +/* Prototypes */ + +int silc_server_packet_send_real(SilcServer server, + SilcSocketConnection sock, + int force_send); +void silc_server_packet_send(SilcServer server, + SilcSocketConnection sock, + SilcPacketType type, + SilcPacketFlags flags, + unsigned char *data, + unsigned int data_len, + int force_send); +void silc_server_packet_send_dest(SilcServer server, + SilcSocketConnection sock, + SilcPacketType type, + SilcPacketFlags flags, + void *dst_id, + SilcIdType dst_id_type, + unsigned char *data, + unsigned int data_len, + int force_send); +void silc_server_packet_forward(SilcServer server, + SilcSocketConnection sock, + unsigned char *data, unsigned int data_len, + int force_send); +void silc_server_packet_broadcast(SilcServer server, + SilcSocketConnection sock, + SilcPacketContext *packet); +void silc_server_packet_send_to_channel(SilcServer server, + SilcChannelEntry channel, + SilcPacketType type, + unsigned char route, + unsigned char *data, + unsigned int data_len, + int force_send); +void silc_server_packet_relay_to_channel(SilcServer server, + SilcSocketConnection sender_sock, + SilcChannelEntry channel, + void *sender, + SilcIdType sender_type, + unsigned char *data, + unsigned int data_len, + int force_send); +void silc_server_packet_send_local_channel(SilcServer server, + SilcChannelEntry channel, + SilcPacketType type, + SilcPacketFlags flags, + unsigned char *data, + unsigned int data_len, + int force_send); +void silc_server_send_private_message(SilcServer server, + SilcSocketConnection dst_sock, + SilcCipher cipher, + SilcHmac hmac, + SilcPacketContext *packet); +void silc_server_send_motd(SilcServer server, + SilcSocketConnection sock); +void silc_server_send_error(SilcServer server, + SilcSocketConnection sock, + const char *fmt, ...); +void silc_server_send_notify(SilcServer server, + SilcSocketConnection sock, + SilcNotifyType type, + unsigned int argc, ...); +void silc_server_send_notify_dest(SilcServer server, + SilcSocketConnection sock, + void *dest_id, + SilcIdType dest_id_type, + SilcNotifyType type, + unsigned int argc, ...); +void silc_server_send_notify_to_channel(SilcServer server, + SilcChannelEntry channel, + unsigned char route_notify, + SilcNotifyType type, + unsigned int argc, ...); +void silc_server_send_notify_on_channels(SilcServer server, + SilcClientEntry client, + SilcNotifyType type, + unsigned int argc, ...); +void silc_server_send_new_id(SilcServer server, + SilcSocketConnection sock, + int broadcast, + void *id, SilcIdType id_type, + unsigned int id_len); +void silc_server_send_replace_id(SilcServer server, + SilcSocketConnection sock, + int broadcast, + void *old_id, SilcIdType old_id_type, + unsigned int old_id_len, + void *new_id, SilcIdType new_id_type, + unsigned int new_id_len); +void silc_server_send_remove_channel_user(SilcServer server, + SilcSocketConnection sock, + int broadcast, + void *client_id, void *channel_id); +void silc_server_send_new_channel(SilcServer server, + SilcSocketConnection sock, + int broadcast, + char *channel_name, + void *channel_id, + unsigned int channel_id_len); +void silc_server_send_new_channel_user(SilcServer server, + SilcSocketConnection sock, + int broadcast, + void *channel_id, + unsigned int channel_id_len, + void *client_id, + unsigned int client_id_len); + +#endif diff --git a/apps/silcd/server.c b/apps/silcd/server.c index f2b7e17a..b9336a86 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -39,8 +39,6 @@ SILC_TASK_CALLBACK(silc_server_packet_process); SILC_TASK_CALLBACK(silc_server_packet_parse_real); SILC_TASK_CALLBACK(silc_server_timeout_remote); -extern char *server_version; - /* 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 @@ -1036,43 +1034,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) sock->protocol = NULL; } -/* Internal routine that sends packet or marks packet to be sent. This - is used directly only in special cases. Normal cases should use - silc_server_packet_send. Returns < 0 error. */ - -static int silc_server_packet_send_real(SilcServer server, - SilcSocketConnection sock, - int force_send) -{ - int ret; - - /* Send the packet */ - ret = silc_packet_send(sock, force_send); - if (ret != -2) - return ret; - - /* Mark that there is some outgoing data available for this connection. - This call sets the connection both for input and output (the input - is set always and this call keeps the input setting, actually). - Actual data sending is performed by silc_server_packet_process. */ - SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock); - - /* Mark to socket that data is pending in outgoing buffer. This flag - is needed if new data is added to the buffer before the earlier - put data is sent to the network. */ - SILC_SET_OUTBUF_PENDING(sock); - - return 0; -} - -typedef struct { - SilcPacketContext *packetdata; - SilcServer server; - SilcSocketConnection sock; - SilcCipher cipher; - SilcHmac hmac; -} SilcServerInternalPacket; - /* This function is used to read packets from network and send packets to network. This is usually a generic task. */ @@ -1294,9 +1255,11 @@ void silc_server_packet_parse_type(SilcServer server, case SILC_PACKET_NOTIFY: /* - * Received notify packet. + * Received notify packet. Server can receive notify packets from + * router. Server then relays the notify messages to clients if needed. */ SILC_LOG_DEBUG(("Notify packet")); + silc_server_notify(server, sock, packet); break; /* @@ -1358,6 +1321,9 @@ void silc_server_packet_parse_type(SilcServer server, break; case SILC_PACKET_PRIVATE_MESSAGE_KEY: + /* + * XXX + */ break; /* @@ -1497,15 +1463,40 @@ void silc_server_packet_parse_type(SilcServer server, break; case SILC_PACKET_NEW_CHANNEL: + /* + * Received new channel packet. Information about new channel in the + * network are distributed using this packet. + */ + SILC_LOG_DEBUG(("New Channel packet")); + silc_server_new_channel(server, sock, packet); break; case SILC_PACKET_NEW_CHANNEL_USER: + /* + * Received new channel user packet. Information about new users on a + * channel are distributed between routers using this packet. The + * router receiving this will redistribute it and also sent JOIN notify + * to local clients on the same channel. Normal server sends JOIN notify + * to its local clients on the channel. + */ + SILC_LOG_DEBUG(("New Channel User packet")); + silc_server_new_channel_user(server, sock, packet); break; case SILC_PACKET_NEW_CHANNEL_LIST: + /* + * List of new channel packets received. This is usually received when + * existing server or router connects to us and distributes information + * of all channels it has. + */ break; case SILC_PACKET_NEW_CHANNEL_USER_LIST: + /* + * List of new channel user packets received. This is usually received + * when existing server or router connects to us and distributes + * information of all channel users it has. + */ break; case SILC_PACKET_REPLACE_ID: @@ -1541,620 +1532,6 @@ void silc_server_packet_parse_type(SilcServer server, } -/* Assembles a new packet to be sent out to network. This doesn't actually - send the packet but creates the packet and fills the outgoing data - buffer and marks the packet ready to be sent to network. However, If - argument force_send is TRUE the packet is sent immediately and not put - to queue. Normal case is that the packet is not sent immediately. */ - -void silc_server_packet_send(SilcServer server, - SilcSocketConnection sock, - SilcPacketType type, - SilcPacketFlags flags, - unsigned char *data, - unsigned int data_len, - int force_send) -{ - void *dst_id = NULL; - SilcIdType dst_id_type = SILC_ID_NONE; - - if (!sock) - return; - - /* Get data used in the packet sending, keys and stuff */ - switch(sock->type) { - case SILC_SOCKET_TYPE_CLIENT: - dst_id = ((SilcClientEntry)sock->user_data)->id; - dst_id_type = SILC_ID_CLIENT; - break; - case SILC_SOCKET_TYPE_SERVER: - case SILC_SOCKET_TYPE_ROUTER: - dst_id = ((SilcServerEntry)sock->user_data)->id; - dst_id_type = SILC_ID_SERVER; - break; - default: - break; - } - - silc_server_packet_send_dest(server, sock, type, flags, dst_id, - dst_id_type, data, data_len, force_send); -} - -/* Assembles a new packet to be sent out to network. This doesn't actually - send the packet but creates the packet and fills the outgoing data - buffer and marks the packet ready to be sent to network. However, If - argument force_send is TRUE the packet is sent immediately and not put - to queue. Normal case is that the packet is not sent immediately. - Destination information is sent as argument for this function. */ - -void silc_server_packet_send_dest(SilcServer server, - SilcSocketConnection sock, - SilcPacketType type, - SilcPacketFlags flags, - void *dst_id, - SilcIdType dst_id_type, - unsigned char *data, - unsigned int data_len, - int force_send) -{ - SilcPacketContext packetdata; - SilcIDListData idata; - SilcCipher cipher = NULL; - SilcHmac hmac = NULL; - unsigned char *dst_id_data = NULL; - unsigned int dst_id_len = 0; - - SILC_LOG_DEBUG(("Sending packet, type %d", type)); - - /* Get data used in the packet sending, keys and stuff */ - idata = (SilcIDListData)sock->user_data; - - if (dst_id) { - dst_id_data = silc_id_id2str(dst_id, dst_id_type); - dst_id_len = silc_id_get_len(dst_id_type); - } - - /* Set the packet context pointers */ - packetdata.type = type; - packetdata.flags = flags; - packetdata.src_id = silc_id_id2str(server->id, server->id_type); - packetdata.src_id_len = SILC_ID_SERVER_LEN; - packetdata.src_id_type = server->id_type; - packetdata.dst_id = dst_id_data; - packetdata.dst_id_len = dst_id_len; - packetdata.dst_id_type = dst_id_type; - packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); - packetdata.rng = server->rng; - - /* Prepare outgoing data buffer for packet sending */ - silc_packet_send_prepare(sock, - SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + - packetdata.dst_id_len, - packetdata.padlen, - data_len); - - SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len)); - - packetdata.buffer = sock->outbuf; - - /* Put the data to the buffer */ - if (data && data_len) - silc_buffer_put(sock->outbuf, data, data_len); - - /* Create the outgoing packet */ - silc_packet_assemble(&packetdata); - - if (idata) { - cipher = idata->send_key; - hmac = idata->hmac; - } - - /* Encrypt the packet */ - silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); - - SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len), - sock->outbuf->data, sock->outbuf->len); - - /* Now actually send the packet */ - silc_server_packet_send_real(server, sock, force_send); - - if (packetdata.src_id) - silc_free(packetdata.src_id); - if (packetdata.dst_id) - silc_free(packetdata.dst_id); -} - -/* Forwards packet. Packets sent with this function will be marked as - forwarded (in the SILC header flags) so that the receiver knows that - we have forwarded the packet to it. Forwarded packets are handled - specially by the receiver as they are not destined to the receiver - originally. However, the receiver knows this because the forwarded - flag has been set (and the flag is authenticated). */ - -void silc_server_packet_forward(SilcServer server, - SilcSocketConnection sock, - unsigned char *data, unsigned int data_len, - int force_send) -{ - SilcIDListData idata; - SilcCipher cipher = NULL; - SilcHmac hmac = NULL; - - SILC_LOG_DEBUG(("Forwarding packet")); - - /* Get data used in the packet sending, keys and stuff */ - idata = (SilcIDListData)sock->user_data; - - /* Prepare outgoing data buffer for packet sending */ - silc_packet_send_prepare(sock, 0, 0, data_len); - - /* Put the data to the buffer */ - if (data && data_len) - silc_buffer_put(sock->outbuf, data, data_len); - - /* Add the FORWARDED flag to packet flags */ - sock->outbuf->data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED; - - if (idata) { - cipher = idata->send_key; - hmac = idata->hmac; - } - - /* Encrypt the packet */ - silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); - - SILC_LOG_HEXDUMP(("Forwarded packet, len %d", sock->outbuf->len), - sock->outbuf->data, sock->outbuf->len); - - /* Now actually send the packet */ - silc_server_packet_send_real(server, sock, force_send); -} - -/* Broadcast received packet to our primary route. This function is used - by router to further route received broadcast packet. It is expected - that the broadcast flag from the packet is checked before calling this - function. This does not test or set the broadcast flag. */ - -void silc_server_packet_broadcast(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcBuffer buffer = packet->buffer; - SilcIDListData idata; - void *id; - - SILC_LOG_DEBUG(("Broadcasting received broadcast packet")); - - /* If the packet is originated from our primary route we are - not allowed to send the packet. */ - id = silc_id_str2id(packet->src_id, packet->src_id_type); - if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) { - idata = (SilcIDListData)sock->user_data; - - silc_buffer_push(buffer, buffer->data - buffer->head); - silc_packet_send_prepare(sock, 0, 0, buffer->len); - silc_buffer_put(sock->outbuf, buffer->data, buffer->len); - silc_packet_encrypt(idata->send_key, idata->hmac, - sock->outbuf, sock->outbuf->len); - - SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len), - sock->outbuf->data, sock->outbuf->len); - - /* Now actually send the packet */ - silc_server_packet_send_real(server, sock, TRUE); - silc_free(id); - return; - } - - SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the " - "original sender of this packet")); - silc_free(id); -} - -/* Internal routine to actually create the channel packet and send it - to network. This is common function in channel message sending. If - `channel_message' is TRUE this encrypts the message as it is strictly - a channel message. If FALSE normal encryption process is used. */ - -static void -silc_server_packet_send_to_channel_real(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet, - SilcCipher cipher, - SilcHmac hmac, - unsigned char *data, - unsigned int data_len, - int channel_message, - int force_send) -{ - packet->truelen = data_len + SILC_PACKET_HEADER_LEN + - packet->src_id_len + packet->dst_id_len; - - /* Prepare outgoing data buffer for packet sending */ - silc_packet_send_prepare(sock, - SILC_PACKET_HEADER_LEN + - packet->src_id_len + - packet->dst_id_len, - packet->padlen, - data_len); - - packet->buffer = sock->outbuf; - - /* Put the data to buffer, assemble and encrypt the packet. The packet - is encrypted with normal session key shared with the client. */ - silc_buffer_put(sock->outbuf, data, data_len); - silc_packet_assemble(packet); - if (channel_message) - silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + - packet->src_id_len + packet->dst_id_len + - packet->padlen); - else - silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); - - SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len), - sock->outbuf->data, sock->outbuf->len); - - /* Now actually send the packet */ - silc_server_packet_send_real(server, sock, force_send); -} - -/* This routine is used by the server to send packets to channel. The - packet sent with this function is distributed to all clients on - the channel. Usually this is used to send notify messages to the - channel, things like notify about new user joining to the channel. */ - -void silc_server_packet_send_to_channel(SilcServer server, - SilcChannelEntry channel, - SilcPacketType type, - unsigned char *data, - unsigned int data_len, - int force_send) -{ - SilcSocketConnection sock = NULL; - SilcPacketContext packetdata; - SilcClientEntry client = NULL; - SilcServerEntry *routed = NULL; - SilcChannelClientEntry chl; - SilcIDListData idata; - unsigned int routed_count = 0; - - /* This doesn't send channel message packets */ - if (type == SILC_PACKET_CHANNEL_MESSAGE) - return; - - SILC_LOG_DEBUG(("Sending packet to channel")); - - /* Set the packet context pointers. */ - packetdata.flags = 0; - packetdata.type = type; - packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER); - packetdata.src_id_len = SILC_ID_SERVER_LEN; - packetdata.src_id_type = SILC_ID_SERVER; - packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL); - packetdata.dst_id_len = SILC_ID_CHANNEL_LEN; - packetdata.dst_id_type = SILC_ID_CHANNEL; - packetdata.rng = server->rng; - packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); - - /* If there are global users in the channel we will send the message - first to our router for further routing. */ - if (server->server_type == SILC_SERVER && !server->standalone && - channel->global_users) { - SilcServerEntry router; - - /* Get data used in packet header encryption, keys and stuff. */ - router = server->router; - sock = (SilcSocketConnection)router->connection; - idata = (SilcIDListData)router; - - SILC_LOG_DEBUG(("Sending channel message to router for routing")); - - silc_server_packet_send_to_channel_real(server, sock, &packetdata, - idata->send_key, idata->hmac, - data, data_len, FALSE, force_send); - } - - /* Send the message to clients on the channel's client list. */ - silc_list_start(channel->user_list); - while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { - client = chl->client; - - /* If client has router set it is not locally connected client and - we will route the message to the router set in the client. */ - if (client && client->router && server->server_type == SILC_ROUTER) { - int k; - - /* Check if we have sent the packet to this route already */ - for (k = 0; k < routed_count; k++) - if (routed[k] == client->router) - break; - if (k < routed_count) - continue; - - /* Get data used in packet header encryption, keys and stuff. */ - sock = (SilcSocketConnection)client->router->connection; - idata = (SilcIDListData)client->router; - - /* Send the packet */ - silc_server_packet_send_to_channel_real(server, sock, &packetdata, - idata->send_key, idata->hmac, - data, data_len, FALSE, - force_send); - - /* We want to make sure that the packet is routed to same router - only once. Mark this route as sent route. */ - k = routed_count; - routed = silc_realloc(routed, sizeof(*routed) * (k + 1)); - routed[k] = client->router; - routed_count++; - - continue; - } - - /* Send to locally connected client */ - if (client) { - - /* Get data used in packet header encryption, keys and stuff. */ - sock = (SilcSocketConnection)client->connection; - idata = (SilcIDListData)client; - - /* Send the packet */ - silc_server_packet_send_to_channel_real(server, sock, &packetdata, - idata->send_key, idata->hmac, - data, data_len, FALSE, - force_send); - } - } - - if (routed_count) - silc_free(routed); - silc_free(packetdata.src_id); - silc_free(packetdata.dst_id); -} - -/* This routine is explicitly used to relay messages to some channel. - Packets sent with this function we have received earlier and are - totally encrypted. This just sends the packet to all clients on - the channel. If the sender of the packet is someone on the channel - the message will not be sent to that client. The SILC Packet header - is encrypted with the session key shared between us and the client. - MAC is also computed before encrypting the header. Rest of the - packet will be untouched. */ - -void silc_server_packet_relay_to_channel(SilcServer server, - SilcSocketConnection sender_sock, - SilcChannelEntry channel, - void *sender, - SilcIdType sender_type, - unsigned char *data, - unsigned int data_len, - int force_send) -{ - int found = FALSE; - SilcSocketConnection sock = NULL; - SilcPacketContext packetdata; - SilcClientEntry client = NULL; - SilcServerEntry *routed = NULL; - SilcChannelClientEntry chl; - unsigned int routed_count = 0; - SilcIDListData idata; - - SILC_LOG_DEBUG(("Relaying packet to channel")); - - /* Set the packet context pointers. */ - packetdata.flags = 0; - packetdata.type = SILC_PACKET_CHANNEL_MESSAGE; - packetdata.src_id = silc_id_id2str(sender, sender_type); - packetdata.src_id_len = silc_id_get_len(sender_type); - packetdata.src_id_type = sender_type; - packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL); - packetdata.dst_id_len = SILC_ID_CHANNEL_LEN; - packetdata.dst_id_type = SILC_ID_CHANNEL; - packetdata.rng = server->rng; - packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + - packetdata.dst_id_len)); - - /* If there are global users in the channel we will send the message - first to our router for further routing. */ - if (server->server_type == SILC_SERVER && !server->standalone && - channel->global_users) { - SilcServerEntry router; - - router = server->router; - - /* Check that the sender is not our router. */ - if (sender_sock != (SilcSocketConnection)router->connection) { - - /* Get data used in packet header encryption, keys and stuff. */ - sock = (SilcSocketConnection)router->connection; - idata = (SilcIDListData)router; - - SILC_LOG_DEBUG(("Sending channel message to router for routing")); - - silc_server_packet_send_to_channel_real(server, sock, &packetdata, - idata->send_key, idata->hmac, - data, data_len, TRUE, - force_send); - } - } - - /* Send the message to clients on the channel's client list. */ - silc_list_start(channel->user_list); - while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { - client = chl->client; - - if (client) { - - /* If sender is one on the channel do not send it the packet. */ - if (!found && !SILC_ID_CLIENT_COMPARE(client->id, sender)) { - found = TRUE; - continue; - } - - /* If the client has set router it means that it is not locally - connected client and we will route the packet further. */ - if (server->server_type == SILC_ROUTER && client->router) { - int k; - - /* Sender maybe server as well so we want to make sure that - we won't send the message to the server it came from. */ - if (!found && !SILC_ID_SERVER_COMPARE(client->router->id, sender)) { - found = TRUE; - continue; - } - - /* Check if we have sent the packet to this route already */ - for (k = 0; k < routed_count; k++) - if (routed[k] == client->router) - break; - if (k < routed_count) - continue; - - /* Get data used in packet header encryption, keys and stuff. */ - sock = (SilcSocketConnection)client->router->connection; - idata = (SilcIDListData)client->router; - - /* Send the packet */ - silc_server_packet_send_to_channel_real(server, sock, &packetdata, - idata->send_key, idata->hmac, - data, data_len, TRUE, - force_send); - - /* We want to make sure that the packet is routed to same router - only once. Mark this route as sent route. */ - k = routed_count; - routed = silc_realloc(routed, sizeof(*routed) * (k + 1)); - routed[k] = client->router; - routed_count++; - - continue; - } - - /* XXX Check client's mode on the channel. */ - - /* Get data used in packet header encryption, keys and stuff. */ - sock = (SilcSocketConnection)client->connection; - idata = (SilcIDListData)client; - - SILC_LOG_DEBUG(("Sending packet to client %s", - sock->hostname ? sock->hostname : sock->ip)); - - /* Send the packet */ - silc_server_packet_send_to_channel_real(server, sock, &packetdata, - idata->send_key, idata->hmac, - data, data_len, TRUE, - force_send); - } - } - - silc_free(packetdata.src_id); - silc_free(packetdata.dst_id); -} - -/* This function is used to send packets strictly to all local clients - on a particular channel. This is used for example to distribute new - channel key to all our locally connected clients on the channel. - The packets are always encrypted with the session key shared between - the client, this means these are not _to the channel_ but _to the client_ - on the channel. */ - -void silc_server_packet_send_local_channel(SilcServer server, - SilcChannelEntry channel, - SilcPacketType type, - SilcPacketFlags flags, - unsigned char *data, - unsigned int data_len, - int force_send) -{ - SilcClientEntry client; - SilcChannelClientEntry chl; - SilcSocketConnection sock = NULL; - - SILC_LOG_DEBUG(("Start")); - - /* Send the message to clients on the channel's client list. */ - silc_list_start(channel->user_list); - while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { - client = chl->client; - - if (client) { - sock = (SilcSocketConnection)client->connection; - - /* Send the packet to the client */ - silc_server_packet_send_dest(server, sock, type, flags, client->id, - SILC_ID_CLIENT, data, data_len, - force_send); - } - } -} - -/* Relays received command reply packet to the correct destination. The - destination must be one of our locally connected client or the packet - will be ignored. This is called when server has forwarded one of - client's command request to router and router has now replied to the - command. */ - -void silc_server_packet_relay_command_reply(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcBuffer buffer = packet->buffer; - SilcClientEntry client; - SilcClientID *id; - SilcSocketConnection dst_sock; - SilcIDListData idata; - - SILC_LOG_DEBUG(("Start")); - - /* Source must be server or router */ - if (packet->src_id_type != SILC_ID_SERVER && - sock->type != SILC_SOCKET_TYPE_ROUTER) - return; - - /* Destination must be client */ - if (packet->dst_id_type != SILC_ID_CLIENT) - return; - - /* Execute command reply locally for the command */ - silc_server_command_reply_process(server, sock, buffer); - - id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT); - - /* Destination must be one of ours */ - client = silc_idlist_find_client_by_id(server->local_list, id); - if (!client) { - SILC_LOG_ERROR(("Cannot relay command reply to unknown client")); - silc_free(id); - return; - } - - /* Relay the packet to the client */ - - dst_sock = (SilcSocketConnection)client->connection; - silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len - + packet->dst_id_len + packet->padlen); - - silc_packet_send_prepare(dst_sock, 0, 0, buffer->len); - silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len); - - idata = (SilcIDListData)client; - - /* Encrypt packet */ - silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf, - buffer->len); - - /* Send the packet */ - silc_server_packet_send_real(server, dst_sock, TRUE); - - silc_free(id); -} - /* Closes connection to socket connection */ void silc_server_close_connection(SilcServer server, @@ -2285,7 +1662,7 @@ void silc_server_remove_from_channels(SilcServer server, channel globally from SILC network, in this case we will notify that this client has left the channel. */ if (channel->global_users) - silc_server_send_notify_to_channel(server, channel, + silc_server_send_notify_to_channel(server, channel, TRUE, SILC_NOTIFY_TYPE_SIGNOFF, 1, clidp->data, clidp->len); @@ -2299,7 +1676,7 @@ void silc_server_remove_from_channels(SilcServer server, /* Send notify to channel about client leaving SILC and thus the entire channel. */ - silc_server_send_notify_to_channel(server, channel, + silc_server_send_notify_to_channel(server, channel, TRUE, SILC_NOTIFY_TYPE_SIGNOFF, 1, clidp->data, clidp->len); silc_buffer_free(chidp); @@ -2346,7 +1723,7 @@ int silc_server_remove_from_one_channel(SilcServer server, /* Notify about leaving client if this channel has global users, ie. the channel is not created locally. */ if (notify && channel->global_users) - silc_server_send_notify_to_channel(server, channel, + silc_server_send_notify_to_channel(server, channel, TRUE, SILC_NOTIFY_TYPE_LEAVE, 1, clidp->data, clidp->len); @@ -2361,7 +1738,7 @@ int silc_server_remove_from_one_channel(SilcServer server, /* Send notify to channel about client leaving the channel */ if (notify) - silc_server_send_notify_to_channel(server, channel, + silc_server_send_notify_to_channel(server, channel, TRUE, SILC_NOTIFY_TYPE_LEAVE, 1, clidp->data, clidp->len); break; @@ -2406,712 +1783,15 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote) "Connection timeout"); } -/* Internal routine used to send (relay, route) private messages to some - destination. If the private message key does not exist then the message - is re-encrypted, otherwise we just pass it along. */ - -static void -silc_server_private_message_send_internal(SilcServer server, - SilcSocketConnection dst_sock, - SilcCipher cipher, - SilcHmac hmac, - SilcPacketContext *packet) -{ - SilcBuffer buffer = packet->buffer; - - /* Send and re-encrypt if private messge key does not exist */ - if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) { - - silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len - + packet->dst_id_len + packet->padlen); - silc_packet_send_prepare(dst_sock, 0, 0, buffer->len); - silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len); - - /* Re-encrypt packet */ - silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len); - - /* Send the packet */ - silc_server_packet_send_real(server, dst_sock, FALSE); - - } else { - /* Key exist so just send it */ - silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len - + packet->dst_id_len + packet->padlen); - silc_packet_send_prepare(dst_sock, 0, 0, buffer->len); - silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len); - silc_server_packet_send_real(server, dst_sock, FALSE); - } -} - -/* Received private message. This resolves the destination of the message - and sends the packet. This is used by both server and router. If the - destination is our locally connected client this sends the packet to - the client. This may also send the message for further routing if - the destination is not in our server (or router). */ - -void silc_server_private_message(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcClientID *id; - SilcServerEntry router; - SilcSocketConnection dst_sock; - SilcClientEntry client; - SilcIDListData idata; - - SILC_LOG_DEBUG(("Start")); - - if (!packet->dst_id) { - SILC_LOG_ERROR(("Bad Client ID in private message packet, dropped")); - goto err; - } - - /* Decode destination Client ID */ - id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT); - if (!id) { - SILC_LOG_ERROR(("Could not decode destination Client ID, dropped")); - goto err; - } - - /* If the destination belongs to our server we don't have to route - the message anywhere but to send it to the local destination. */ - client = silc_idlist_find_client_by_id(server->local_list, id); - if (client) { - /* It exists, now deliver the message to the destination */ - dst_sock = (SilcSocketConnection)client->connection; - - /* If we are router and the client has router then the client is in - our cell but not directly connected to us. */ - if (server->server_type == SILC_ROUTER && client->router) { - /* We are of course in this case the client's router thus the real - "router" of the client is the server who owns the client. Thus - we will send the packet to that server. */ - router = (SilcServerEntry)dst_sock->user_data; - idata = (SilcIDListData)router; - // assert(client->router == server->id_entry); - - silc_server_private_message_send_internal(server, dst_sock, - idata->send_key, - idata->hmac, - packet); - return; - } - - /* Seems that client really is directly connected to us */ - idata = (SilcIDListData)client; - silc_server_private_message_send_internal(server, dst_sock, - idata->send_key, - idata->hmac, packet); - return; - } - - /* Destination belongs to someone not in this server. If we are normal - server our action is to send the packet to our router. */ - if (server->server_type == SILC_SERVER && !server->standalone) { - router = server->router; - - /* Send to primary route */ - if (router) { - dst_sock = (SilcSocketConnection)router->connection; - idata = (SilcIDListData)router; - silc_server_private_message_send_internal(server, dst_sock, - idata->send_key, - idata->hmac, packet); - } - return; - } - - /* We are router and we will perform route lookup for the destination - and send the message to fastest route. */ - if (server->server_type == SILC_ROUTER && !server->standalone) { - dst_sock = silc_server_get_route(server, id, SILC_ID_CLIENT); - router = (SilcServerEntry)dst_sock->user_data; - idata = (SilcIDListData)router; - - /* Get fastest route and send packet. */ - if (router) - silc_server_private_message_send_internal(server, dst_sock, - idata->send_key, - idata->hmac, packet); - return; - } - - err: - silc_server_send_error(server, sock, - "No such nickname: Private message not sent"); -} - -/* Process received channel message. The message can be originated from - client or server. */ - -void silc_server_channel_message(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcChannelEntry channel = NULL; - SilcChannelClientEntry chl; - SilcChannelID *id = NULL; - void *sender = NULL; - - SILC_LOG_DEBUG(("Processing channel message")); - - /* Sanity checks */ - if (packet->dst_id_type != SILC_ID_CHANNEL) { - SILC_LOG_ERROR(("Received bad message for channel, dropped")); - SILC_LOG_DEBUG(("Received bad message for channel, dropped")); - goto out; - } - - /* Find channel entry */ - id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL); - channel = silc_idlist_find_channel_by_id(server->local_list, id); - if (!channel) { - SILC_LOG_DEBUG(("Could not find channel")); - goto out; - } - - /* See that this client is on the channel. If the message is coming - from router we won't do the check as the message is from client that - we don't know about. Also, if the original sender is not client - (as it can be server as well) we don't do the check. */ - sender = silc_id_str2id(packet->src_id, packet->src_id_type); - if (sock->type != SILC_SOCKET_TYPE_ROUTER && - packet->src_id_type == SILC_ID_CLIENT) { - silc_list_start(channel->user_list); - while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { - if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender)) - break; - } - if (chl == SILC_LIST_END) - goto out; - } - - /* Distribute the packet to our local clients. This will send the - packet for further routing as well, if needed. */ - silc_server_packet_relay_to_channel(server, sock, channel, sender, - packet->src_id_type, - packet->buffer->data, - packet->buffer->len, FALSE); - - out: - if (sender) - silc_free(sender); - if (id) - silc_free(id); -} - -/* Received channel key packet. We distribute the key to all of our locally - connected clients on the channel. */ -/* XXX Router must accept this packet and distribute the key to all its - server that has clients on the channel */ - -void silc_server_channel_key(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcBuffer buffer = packet->buffer; - SilcChannelKeyPayload payload = NULL; - SilcChannelID *id = NULL; - SilcChannelEntry channel; - SilcChannelClientEntry chl; - unsigned char *tmp; - unsigned int tmp_len; - char *cipher; - - if (packet->src_id_type != SILC_ID_SERVER && - sock->type != SILC_SOCKET_TYPE_ROUTER) - goto out; - - /* Decode channel key payload */ - payload = silc_channel_key_payload_parse(buffer); - if (!payload) { - SILC_LOG_ERROR(("Bad channel key payload, dropped")); - goto out; - } - - /* Get channel ID */ - tmp = silc_channel_key_get_id(payload, &tmp_len); - id = silc_id_payload_parse_id(tmp, tmp_len); - if (!id) - goto out; - - /* Get the channel entry */ - channel = silc_idlist_find_channel_by_id(server->local_list, id); - if (!channel) { - SILC_LOG_ERROR(("Received key for non-existent channel")); - goto out; - } - - /* Save the key for us as well */ - tmp = silc_channel_key_get_key(payload, &tmp_len); - if (!tmp) - goto out; - cipher = silc_channel_key_get_cipher(payload, NULL);; - if (!cipher) - goto out; - if (!silc_cipher_alloc(cipher, &channel->channel_key)) - goto out; - - /* Distribute the key to all clients on the channel */ - silc_list_start(channel->user_list); - while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) { - silc_server_packet_send(server, chl->client->connection, - SILC_PACKET_CHANNEL_KEY, 0, - buffer->data, buffer->len, TRUE); - } - - channel->key_len = tmp_len * 8; - channel->key = silc_calloc(tmp_len, sizeof(unsigned char)); - memcpy(channel->key, tmp, tmp_len); - channel->channel_key->cipher->set_key(channel->channel_key->context, - tmp, tmp_len); - out: - if (id) - silc_free(id); - if (payload) - silc_channel_key_payload_free(payload); -} - -/* Sends current motd to client */ - -void silc_server_send_motd(SilcServer server, - SilcSocketConnection sock) -{ - char *motd; - int motd_len; - - if (server->config && server->config->motd && - server->config->motd->motd_file) { - - motd = silc_file_read(server->config->motd->motd_file, &motd_len); - if (!motd) - return; - - silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1, - motd, motd_len); - silc_free(motd); - } -} - -/* Sends error message. Error messages may or may not have any - implications. */ - -void silc_server_send_error(SilcServer server, - SilcSocketConnection sock, - const char *fmt, ...) -{ - va_list ap; - unsigned char buf[4096]; - - memset(buf, 0, sizeof(buf)); - va_start(ap, fmt); - vsprintf(buf, fmt, ap); - va_end(ap); - - silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0, - buf, strlen(buf), FALSE); -} - -/* Sends notify message. If format is TRUE the variable arguments are - formatted and the formatted string is sent as argument payload. If it is - FALSE then each argument is sent as separate argument and their format - in the argument list must be { argument data, argument length }. */ - -void silc_server_send_notify(SilcServer server, - SilcSocketConnection sock, - SilcNotifyType type, - unsigned int argc, ...) -{ - va_list ap; - SilcBuffer packet; - - va_start(ap, argc); - - packet = silc_notify_payload_encode(type, argc, ap); - silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, - packet->data, packet->len, FALSE); - silc_buffer_free(packet); -} - -/* Sends notify message destined to specific entity. */ - -void silc_server_send_notify_dest(SilcServer server, - SilcSocketConnection sock, - void *dest_id, - SilcIdType dest_id_type, - SilcNotifyType type, - unsigned int argc, ...) -{ - va_list ap; - SilcBuffer packet; - - va_start(ap, argc); - - packet = silc_notify_payload_encode(type, argc, ap); - silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, - dest_id, dest_id_type, - packet->data, packet->len, FALSE); - silc_buffer_free(packet); -} - -/* Sends notify message to a channel. The notify message sent is - distributed to all clients on the channel. */ - -void silc_server_send_notify_to_channel(SilcServer server, - SilcChannelEntry channel, - SilcNotifyType type, - unsigned int argc, ...) -{ - va_list ap; - SilcBuffer packet; - - va_start(ap, argc); - - packet = silc_notify_payload_encode(type, argc, ap); - silc_server_packet_send_to_channel(server, channel, - SILC_PACKET_NOTIFY, - packet->data, packet->len, FALSE); - silc_buffer_free(packet); -} - -/* Send notify message to all clients the client has joined. It is quaranteed - that the message is sent only once to a client (ie. if a client is joined - on two same channel it will receive only one notify message). Also, this - sends only to local clients (locally connected if we are server, and to - local servers if we are router). */ +/* Creates new channel. Sends NEW_CHANNEL packet to primary route. This + function may be used only by router. In real SILC network all channels + are created by routers thus this function is never used by normal + server. */ -void silc_server_send_notify_on_channels(SilcServer server, - SilcClientEntry client, - SilcNotifyType type, - unsigned int argc, ...) -{ - int k; - SilcSocketConnection sock = NULL; - SilcPacketContext packetdata; - SilcClientEntry c; - SilcClientEntry *sent_clients = NULL; - unsigned int sent_clients_count = 0; - SilcServerEntry *routed = NULL; - unsigned int routed_count = 0; - SilcChannelEntry channel; - SilcChannelClientEntry chl, chl2; - SilcIDListData idata; - SilcBuffer packet; - unsigned char *data; - unsigned int data_len; - int force_send = FALSE; - va_list ap; - - if (!silc_list_count(client->channels)) - return; - - va_start(ap, argc); - packet = silc_notify_payload_encode(type, argc, ap); - data = packet->data; - data_len = packet->len; - - /* Set the packet context pointers. */ - packetdata.flags = 0; - packetdata.type = SILC_PACKET_NOTIFY; - packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER); - packetdata.src_id_len = SILC_ID_SERVER_LEN; - packetdata.src_id_type = SILC_ID_SERVER; - packetdata.rng = server->rng; - - silc_list_start(client->channels); - while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) { - channel = chl->channel; - - /* Send the message to all clients on the channel's client list. */ - silc_list_start(channel->user_list); - while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) { - c = chl2->client; - - /* Check if we have sent the packet to this client already */ - for (k = 0; k < sent_clients_count; k++) - if (sent_clients[k] == c) - break; - if (k < sent_clients_count) - continue; - - /* If we are router and if this client has router set it is not - locally connected client and we will route the message to the - router set in the client. */ - if (c && c->router && server->server_type == SILC_ROUTER) { - /* Check if we have sent the packet to this route already */ - for (k = 0; k < routed_count; k++) - if (routed[k] == c->router) - break; - if (k < routed_count) - continue; - - /* Get data used in packet header encryption, keys and stuff. */ - sock = (SilcSocketConnection)c->router->connection; - idata = (SilcIDListData)c->router; - - packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER); - packetdata.dst_id_len = SILC_ID_SERVER_LEN; - packetdata.dst_id_type = SILC_ID_SERVER; - packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); - - /* Send the packet */ - silc_server_packet_send_to_channel_real(server, sock, &packetdata, - idata->send_key, idata->hmac, - data, data_len, FALSE, - force_send); - - silc_free(packetdata.dst_id); - - /* We want to make sure that the packet is routed to same router - only once. Mark this route as sent route. */ - k = routed_count; - routed = silc_realloc(routed, sizeof(*routed) * (k + 1)); - routed[k] = c->router; - routed_count++; - - continue; - } - - /* Send to locally connected client */ - if (c) { - - /* Get data used in packet header encryption, keys and stuff. */ - sock = (SilcSocketConnection)c->connection; - idata = (SilcIDListData)c; - - packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT); - packetdata.dst_id_len = SILC_ID_CLIENT_LEN; - packetdata.dst_id_type = SILC_ID_CLIENT; - packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); - - /* Send the packet */ - silc_server_packet_send_to_channel_real(server, sock, &packetdata, - idata->send_key, idata->hmac, - data, data_len, FALSE, - force_send); - - silc_free(packetdata.dst_id); - - /* Make sure that we send the notify only once per client. */ - sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) * - (sent_clients_count + 1)); - sent_clients[sent_clients_count] = c; - sent_clients_count++; - } - } - } - - if (routed_count) - silc_free(routed); - if (sent_clients_count) - silc_free(sent_clients); - silc_free(packetdata.src_id); -} - -/* Sends New ID Payload to remote end. The packet is used to distribute - information about new registered clients, servers, channel etc. usually - to routers so that they can keep these information up to date. - If the argument `broadcast' is TRUE then the packet is sent as - broadcast packet. */ - -void silc_server_send_new_id(SilcServer server, - SilcSocketConnection sock, - int broadcast, - void *id, SilcIdType id_type, - unsigned int id_len) -{ - SilcBuffer idp; - - idp = silc_id_payload_encode(id, id_type); - silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, - broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, - idp->data, idp->len, FALSE); - silc_buffer_free(idp); -} - -/* Sends Replace ID payload to remote end. This is used to replace old - ID with new ID sent in the packet. This is called for example when - user changes nickname and we create new ID for the user. If the - argument `broadcast' is TRUE then the packet is sent as - broadcast packet. */ -/* XXX It would be expected that the new id is same type as the old - ID. :) */ - -void silc_server_send_replace_id(SilcServer server, - SilcSocketConnection sock, - int broadcast, - void *old_id, SilcIdType old_id_type, - unsigned int old_id_len, - void *new_id, SilcIdType new_id_type, - unsigned int new_id_len) -{ - SilcBuffer packet; - unsigned char *oid; - unsigned char *nid; - - oid = silc_id_id2str(old_id, old_id_type); - if (!oid) - return; - - nid = silc_id_id2str(new_id, new_id_type); - if (!nid) - return; - - packet = silc_buffer_alloc(2 + 2 + 2 + 2 + old_id_len + new_id_len); - silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); - silc_buffer_format(packet, - SILC_STR_UI_SHORT(old_id_type), - SILC_STR_UI_SHORT(old_id_len), - SILC_STR_UI_XNSTRING(oid, old_id_len), - SILC_STR_UI_SHORT(new_id_type), - SILC_STR_UI_SHORT(new_id_len), - SILC_STR_UI_XNSTRING(nid, new_id_len), - SILC_STR_END); - - silc_server_packet_send(server, sock, SILC_PACKET_REPLACE_ID, - broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, - packet->data, packet->len, FALSE); - silc_free(oid); - silc_free(nid); - silc_buffer_free(packet); -} - -/* This function is used to send Remove Channel User payload. This may sent - by server but is usually used only by router to notify other routers that - user has left a channel. Normal server sends this packet to its router - to notify that the router should not hold a record about this client - on a channel anymore. Router distributes it further to other routers. */ - -void silc_server_send_remove_channel_user(SilcServer server, - SilcSocketConnection sock, - int broadcast, - void *client_id, void *channel_id) -{ - SilcBuffer packet; - unsigned char *clid, *chid; - - clid = silc_id_id2str(client_id, SILC_ID_CLIENT); - if (!clid) - return; - - chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL); - if (!chid) - return; - - packet = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN + SILC_ID_CHANNEL_LEN); - silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); - silc_buffer_format(packet, - SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN), - SILC_STR_UI_XNSTRING(clid, SILC_ID_CLIENT_LEN), - SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN), - SILC_STR_UI_XNSTRING(chid, SILC_ID_CHANNEL_LEN), - SILC_STR_END); - - silc_server_packet_send(server, sock, SILC_PACKET_REMOVE_CHANNEL_USER, - broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, - packet->data, packet->len, FALSE); - silc_free(clid); - silc_free(chid); - silc_buffer_free(packet); -} - -/* Received packet to replace a ID. This checks that the requested ID - exists and replaces it with the new one. */ - -void silc_server_replace_id(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcBuffer buffer = packet->buffer; - unsigned char *old_id = NULL, *new_id = NULL; - SilcIdType old_id_type, new_id_type; - unsigned short old_id_len, new_id_len; - void *id = NULL, *id2 = NULL; - - if (sock->type == SILC_SOCKET_TYPE_CLIENT || - packet->src_id_type == SILC_ID_CLIENT) - return; - - SILC_LOG_DEBUG(("Replacing ID")); - - silc_buffer_unformat(buffer, - SILC_STR_UI_SHORT(&old_id_type), - SILC_STR_UI16_NSTRING_ALLOC(&old_id, &old_id_len), - SILC_STR_UI_SHORT(&new_id_type), - SILC_STR_UI16_NSTRING_ALLOC(&new_id, &new_id_len), - SILC_STR_END); - - if (old_id_type != new_id_type) - goto out; - - if (old_id_len != silc_id_get_len(old_id_type) || - new_id_len != silc_id_get_len(new_id_type)) - goto out; - - id = silc_id_str2id(old_id, old_id_type); - if (!id) - goto out; - - id2 = silc_id_str2id(new_id, new_id_type); - if (!id2) - goto out; - - /* If we are router and this packet is not already broadcast packet - we will broadcast it. The sending socket really cannot be router or - the router is buggy. If this packet is coming from router then it must - have the broadcast flag set already and we won't do anything. */ - if (server->server_type == SILC_ROUTER && - sock->type == SILC_SOCKET_TYPE_SERVER && - !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { - SILC_LOG_DEBUG(("Broadcasting received Replace ID packet")); - silc_server_packet_send(server, server->router->connection, packet->type, - packet->flags | SILC_PACKET_FLAG_BROADCAST, - buffer->data, buffer->len, FALSE); - } - - /* Replace the old ID */ - switch(old_id_type) { - case SILC_ID_CLIENT: - if (silc_idlist_replace_client_id(server->local_list, id, id2) == NULL) - if (server->server_type == SILC_ROUTER) - silc_idlist_replace_client_id(server->global_list, id, id2); - break; - - case SILC_ID_SERVER: - if (silc_idlist_replace_server_id(server->local_list, id, id2) == NULL) - if (server->server_type == SILC_ROUTER) - silc_idlist_replace_server_id(server->global_list, id, id2); - break; - - case SILC_ID_CHANNEL: - /* XXX Hmm... Basically this cannot occur. Channel ID's cannot be - re-generated. */ - silc_free(id2); - break; - - default: - silc_free(id2); - break; - } - - out: - if (id) - silc_free(id); - if (old_id) - silc_free(old_id); - if (new_id) - silc_free(new_id); -} - -/* Creates new channel. */ - -SilcChannelEntry silc_server_new_channel(SilcServer server, - SilcServerID *router_id, - char *cipher, char *channel_name) +SilcChannelEntry silc_server_create_new_channel(SilcServer server, + SilcServerID *router_id, + char *cipher, + char *channel_name) { int i, key_len; SilcChannelID *channel_id; @@ -3152,377 +1832,9 @@ SilcChannelEntry silc_server_new_channel(SilcServer server, /* Notify other routers about the new channel. We send the packet to our primary route. */ if (server->standalone == FALSE) { - silc_server_send_new_id(server, server->router->connection, - server->server_type == SILC_SERVER ? FALSE : TRUE, - entry->id, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN); + silc_server_send_new_channel(server, server->router->connection, TRUE, + channel_name, entry->id, SILC_ID_CHANNEL_LEN); } return entry; } - -/* Create new client. This processes incoming NEW_CLIENT packet and creates - Client ID for the client. Client becomes registered after calling this - functions. */ - -SilcClientEntry silc_server_new_client(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcBuffer buffer = packet->buffer; - SilcClientEntry client; - SilcIDCacheEntry cache; - SilcClientID *client_id; - SilcBuffer reply; - SilcIDListData idata; - char *username = NULL, *realname = NULL, *id_string; - - SILC_LOG_DEBUG(("Creating new client")); - - if (sock->type != SILC_SOCKET_TYPE_CLIENT) - return NULL; - - /* Take client entry */ - client = (SilcClientEntry)sock->user_data; - idata = (SilcIDListData)client; - - /* Fetch the old client cache entry so that we can update it. */ - if (!silc_idcache_find_by_context(server->local_list->clients, - sock->user_data, &cache)) { - SILC_LOG_ERROR(("Lost client's cache entry - bad thing")); - return NULL; - } - - /* Parse incoming packet */ - silc_buffer_unformat(buffer, - SILC_STR_UI16_STRING_ALLOC(&username), - SILC_STR_UI16_STRING_ALLOC(&realname), - SILC_STR_END); - - /* Create Client ID */ - silc_id_create_client_id(server->id, server->rng, server->md5hash, - username, &client_id); - - /* Update client entry */ - idata->registered = TRUE; - client->nickname = strdup(username); - client->username = username; - client->userinfo = realname; - client->id = client_id; - - /* Update the cache entry */ - cache->id = (void *)client_id; - cache->type = SILC_ID_CLIENT; - cache->data = username; - silc_idcache_sort_by_data(server->local_list->clients); - - /* Notify our router about new client on the SILC network */ - if (!server->standalone) - silc_server_send_new_id(server, (SilcSocketConnection) - server->router->connection, - server->server_type == SILC_ROUTER ? TRUE : FALSE, - client->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN); - - /* Send the new client ID to the client. */ - id_string = silc_id_id2str(client->id, SILC_ID_CLIENT); - reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN); - silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply)); - silc_buffer_format(reply, - SILC_STR_UI_SHORT(SILC_ID_CLIENT), - SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN), - SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN), - SILC_STR_END); - silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0, - reply->data, reply->len, FALSE); - silc_free(id_string); - silc_buffer_free(reply); - - /* Send some nice info to the client */ - SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE, - ("Welcome to the SILC Network %s@%s", - username, sock->hostname)); - SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE, - ("Your host is %s, running version %s", - server->config->server_info->server_name, - server_version)); - SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE, - ("Your connection is secured with %s cipher, " - "key length %d bits", - idata->send_key->cipher->name, - idata->send_key->cipher->key_len)); - SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE, - ("Your current nickname is %s", - client->nickname)); - - /* Send motd */ - silc_server_send_motd(server, sock); - - return client; -} - -/* Create new server. This processes incoming NEW_SERVER packet and - saves the received Server ID. The server is our locally connected - server thus we save all the information and save it to local list. - This funtion can be used by both normal server and router server. - If normal server uses this it means that its router has connected - to the server. If router uses this it means that one of the cell's - servers is connected to the router. */ - -SilcServerEntry silc_server_new_server(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcBuffer buffer = packet->buffer; - SilcServerEntry new_server; - SilcIDCacheEntry cache; - SilcServerID *server_id; - SilcIDListData idata; - unsigned char *server_name, *id_string; - unsigned short id_len; - - SILC_LOG_DEBUG(("Creating new server")); - - if (sock->type != SILC_SOCKET_TYPE_SERVER && - sock->type != SILC_SOCKET_TYPE_ROUTER) - return NULL; - - /* Take server entry */ - new_server = (SilcServerEntry)sock->user_data; - idata = (SilcIDListData)new_server; - - /* Fetch the old server cache entry so that we can update it. */ - if (!silc_idcache_find_by_context(server->local_list->servers, - sock->user_data, &cache)) { - SILC_LOG_ERROR(("Lost server's cache entry - bad thing")); - return NULL; - } - - /* Parse the incoming packet */ - silc_buffer_unformat(buffer, - SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len), - SILC_STR_UI16_STRING_ALLOC(&server_name), - SILC_STR_END); - - if (id_len > buffer->len) { - silc_free(id_string); - silc_free(server_name); - return NULL; - } - - /* Get Server ID */ - server_id = silc_id_str2id(id_string, SILC_ID_SERVER); - silc_free(id_string); - - /* Update client entry */ - idata->registered = TRUE; - new_server->server_name = server_name; - new_server->id = server_id; - - /* Update the cache entry */ - cache->id = (void *)server_id; - cache->type = SILC_ID_SERVER; - cache->data = server_name; - silc_idcache_sort_by_data(server->local_list->servers); - - /* Distribute the information about new server in the SILC network - to our router. If we are normal server we won't send anything - since this connection must be our router connection. */ - if (server->server_type == SILC_ROUTER && !server->standalone && - server->router->connection != sock) - silc_server_send_new_id(server, server->router->connection, - TRUE, new_server->id, SILC_ID_SERVER, - SILC_ID_SERVER_LEN); - - return new_server; -} - -/* Processes incoming New ID Payload. New ID Payload is used to distribute - information about newly registered clients, servers and created - channels. */ - -void silc_server_new_id(SilcServer server, SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcBuffer buffer = packet->buffer; - SilcIDList id_list; - SilcServerEntry tmpserver, router; - SilcSocketConnection router_sock; - SilcIDPayload idp; - SilcIdType id_type; - void *id, *tmpid; - - SILC_LOG_DEBUG(("Processing new ID")); - - if (sock->type == SILC_SOCKET_TYPE_CLIENT || - server->server_type == SILC_SERVER || - packet->src_id_type != SILC_ID_SERVER) - return; - - idp = silc_id_payload_parse(buffer); - if (!idp) - return; - - id_type = silc_id_payload_get_type(idp); - - /* Normal server cannot have other normal server connections */ - if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER) - goto out; - - id = silc_id_payload_get_id(idp); - if (!id) - goto out; - - /* If the sender of this packet is server and we are router we need to - broadcast this packet to other routers in the network. */ - if (!server->standalone && server->server_type == SILC_ROUTER && - sock->type == SILC_SOCKET_TYPE_SERVER && - !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { - SILC_LOG_DEBUG(("Broadcasting received New ID packet")); - silc_server_packet_send(server, server->router->connection, - packet->type, - packet->flags | SILC_PACKET_FLAG_BROADCAST, - buffer->data, buffer->len, FALSE); - } - - /* If the packet is originated from the one who sent it to us we know - that the ID belongs to our cell, unless the sender was router. */ - tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER); - tmpserver = (SilcServerEntry)sock->user_data; - - if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) && - sock->type == SILC_SOCKET_TYPE_SERVER) { - id_list = server->local_list; - router_sock = sock; - router = sock->user_data; - /* router = server->id_entry; */ - } else { - id_list = server->global_list; - router_sock = (SilcSocketConnection)server->router->connection; - router = server->router; - } - - silc_free(tmpid); - - switch(id_type) { - case SILC_ID_CLIENT: - { - SilcClientEntry idlist; - - SILC_LOG_DEBUG(("New client id(%s) from [%s] %s", - silc_id_render(id, SILC_ID_CLIENT), - sock->type == SILC_SOCKET_TYPE_SERVER ? - "Server" : "Router", sock->hostname)); - - /* Add the client to our local list. We are router and we keep - cell specific local database of all clients in the cell. */ - idlist = silc_idlist_add_client(id_list, NULL, NULL, NULL, - id, router, router_sock); - } - break; - - case SILC_ID_SERVER: - { - SilcServerEntry idlist; - - SILC_LOG_DEBUG(("New server id(%s) from [%s] %s", - silc_id_render(id, SILC_ID_SERVER), - sock->type == SILC_SOCKET_TYPE_SERVER ? - "Server" : "Router", sock->hostname)); - - /* Add the server to our local list. We are router and we keep - cell specific local database of all servers in the cell. */ - idlist = silc_idlist_add_server(id_list, NULL, 0, id, router, - router_sock); - } - break; - - case SILC_ID_CHANNEL: - SILC_LOG_DEBUG(("New channel id(%s) from [%s] %s", - silc_id_render(id, SILC_ID_CHANNEL), - sock->type == SILC_SOCKET_TYPE_SERVER ? - "Server" : "Router", sock->hostname)); - - /* Add the channel to our local list. We are router and we keep - cell specific local database of all channels in the cell. */ - silc_idlist_add_channel(id_list, NULL, 0, id, router, NULL); - break; - - default: - break; - } - - out: - silc_id_payload_free(idp); -} - -/* Received packet to remove a user from a channel. Routers notify other - routers that user has left a channel. Client must not send this packet. - Normal server may send this packet but ignores if it receives one. */ - -void silc_server_remove_channel_user(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet) -{ - SilcBuffer buffer = packet->buffer; - unsigned char *tmp1 = NULL, *tmp2 = NULL; - SilcClientID *client_id = NULL; - SilcChannelID *channel_id = NULL; - SilcChannelEntry channel; - SilcClientEntry client; - - SILC_LOG_DEBUG(("Removing user from channel")); - - if (sock->type == SILC_SOCKET_TYPE_CLIENT || - server->server_type == SILC_SERVER) - return; - - silc_buffer_unformat(buffer, - SILC_STR_UI16_STRING_ALLOC(&tmp1), - SILC_STR_UI16_STRING_ALLOC(&tmp2), - SILC_STR_END); - - if (!tmp1 || !tmp2) - goto out; - - client_id = silc_id_str2id(tmp1, SILC_ID_CLIENT); - channel_id = silc_id_str2id(tmp2, SILC_ID_CHANNEL); - if (!client_id || !channel_id) - goto out; - - /* If we are router and this packet is not already broadcast packet - we will broadcast it. The sending socket really cannot be router or - the router is buggy. If this packet is coming from router then it must - have the broadcast flag set already and we won't do anything. */ - if (!server->standalone && server->server_type == SILC_ROUTER && - sock->type == SILC_SOCKET_TYPE_SERVER && - !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { - SILC_LOG_DEBUG(("Broadcasting received Remove Channel User packet")); - silc_server_packet_send(server, server->router->connection, packet->type, - packet->flags | SILC_PACKET_FLAG_BROADCAST, - buffer->data, buffer->len, FALSE); - } - - /* XXX routers should check server->global_list as well */ - /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->local_list, channel_id); - if (!channel) - goto out; - - /* XXX routers should check server->global_list as well */ - /* Get client entry */ - client = silc_idlist_find_client_by_id(server->local_list, client_id); - if (!client) - goto out; - - /* Remove from channel */ - silc_server_remove_from_one_channel(server, sock, channel, client, FALSE); - - out: - if (tmp1) - silc_free(tmp1); - if (tmp2) - silc_free(tmp2); - if (client_id) - silc_free(client_id); - if (channel_id) - silc_free(channel_id); -} diff --git a/apps/silcd/server.h b/apps/silcd/server.h index f6dd8e39..7df7c010 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -83,53 +83,6 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context); void silc_server_packet_parse_type(SilcServer server, SilcSocketConnection sock, SilcPacketContext *packet); -void silc_server_packet_send(SilcServer server, - SilcSocketConnection sock, - SilcPacketType type, - SilcPacketFlags flags, - unsigned char *data, - unsigned int data_len, - int force_send); -void silc_server_packet_send_dest(SilcServer server, - SilcSocketConnection sock, - SilcPacketType type, - SilcPacketFlags flags, - void *dst_id, - SilcIdType dst_id_type, - unsigned char *data, - unsigned int data_len, - int force_send); -void silc_server_packet_forward(SilcServer server, - SilcSocketConnection sock, - unsigned char *data, unsigned int data_len, - int force_send); -void silc_server_packet_broadcast(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet); -void silc_server_packet_send_to_channel(SilcServer server, - SilcChannelEntry channel, - SilcPacketType type, - unsigned char *data, - unsigned int data_len, - int force_send); -void silc_server_packet_relay_to_channel(SilcServer server, - SilcSocketConnection sender_sock, - SilcChannelEntry channel, - void *sender, - SilcIdType sender_type, - unsigned char *data, - unsigned int data_len, - int force_send); -void silc_server_packet_send_local_channel(SilcServer server, - SilcChannelEntry channel, - SilcPacketType type, - SilcPacketFlags flags, - unsigned char *data, - unsigned int data_len, - int force_send); -void silc_server_packet_relay_command_reply(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet); void silc_server_close_connection(SilcServer server, SilcSocketConnection sock); void silc_server_free_sock_user_data(SilcServer server, @@ -147,70 +100,9 @@ int silc_server_client_on_channel(SilcClientEntry client, void silc_server_disconnect_remote(SilcServer server, SilcSocketConnection sock, const char *fmt, ...); -void silc_server_private_message(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet); -void silc_server_channel_message(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet); -void silc_server_channel_key(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet); -void silc_server_send_motd(SilcServer server, - SilcSocketConnection sock); -void silc_server_send_error(SilcServer server, - SilcSocketConnection sock, - const char *fmt, ...); -void silc_server_send_notify(SilcServer server, - SilcSocketConnection sock, - SilcNotifyType type, - unsigned int argc, ...); -void silc_server_send_notify_dest(SilcServer server, - SilcSocketConnection sock, - void *dest_id, - SilcIdType dest_id_type, - SilcNotifyType type, - unsigned int argc, ...); -void silc_server_send_notify_to_channel(SilcServer server, - SilcChannelEntry channel, - SilcNotifyType type, - unsigned int argc, ...); -void silc_server_send_notify_on_channels(SilcServer server, - SilcClientEntry client, - SilcNotifyType type, - unsigned int argc, ...); -void silc_server_send_new_id(SilcServer server, - SilcSocketConnection sock, - int broadcast, - void *id, SilcIdType id_type, - unsigned int id_len); -void silc_server_send_replace_id(SilcServer server, - SilcSocketConnection sock, - int broadcast, - void *old_id, SilcIdType old_id_type, - unsigned int old_id_len, - void *new_id, SilcIdType new_id_type, - unsigned int new_id_len); -void silc_server_send_remove_channel_user(SilcServer server, - SilcSocketConnection sock, - int broadcast, - void *client_id, void *channel_id); -void silc_server_replace_id(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet); -SilcChannelEntry silc_server_new_channel(SilcServer server, - SilcServerID *router_id, - char *cipher, char *channel_name); -SilcClientEntry silc_server_new_client(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet); -SilcServerEntry silc_server_new_server(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet); -void silc_server_new_id(SilcServer server, SilcSocketConnection sock, - SilcPacketContext *packet); -void silc_server_remove_channel_user(SilcServer server, - SilcSocketConnection sock, - SilcPacketContext *packet); +SilcChannelEntry silc_server_create_new_channel(SilcServer server, + SilcServerID *router_id, + char *cipher, + char *channel_name); #endif -- 2.24.0