+Mon Mar 19 16:13:07 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_server_get_client_route to resolve the route to
+ the client indicated by the client ID. Affected file is
+ silcd/server.[ch].
+
+ * Added silc_server_relay_packet as general function to relay
+ packet to arbitrary destination. This deprecates functions
+ like _send_private_message_key, _relay_notify etc. Affected
+ file is silcd/packet_send.[ch].
+
+ Removed silc_server_send_key_agreement,
+ silc_server_send_private_message_key and
+ silc_server_packet_relay_notify functions from the file
+ silcd/packet_send.[ch].
+
+ * Updated TODO.
+
+ * Implemented the SILC_NOTIFY_TYPE_KILLED notify handling in the
+ server. Affected file silcd/packet_receive.[ch].
+
+ * Implemented the KILL command to the client. Implemented the
+ SILC_NOTIFY_TYPE_KILLED notify handling in the client library.
+ Affected files lib/silcclient/command[_reply].c and
+ lib/silcclient/client_notify.c. Implemented the KILL notify
+ printing in the user inteface.
+
+ * Fixed a lot silc_parse_nick memory leaks from the client
+ library in the file lib/silcclient/command.c.
+
+ * Changed the silc_server_send_notify_on_channels's `sender'
+ argument from SilcSocketConnection to SilcClientEntry to
+ check the sender as entry and not as connection object and not
+ to send to the client provided as argument. The affected file
+ is silcd/packet_send.[ch].
+
+ * The notify packets that are destined directly to the client used
+ to not to be processed by the server. Now changed that and the
+ server processes all notify packets. After relaying the packet
+ to the client the notify packet is processed in the server.
+
+ * The silc_server_free_client_data now checks whether there is
+ pending outgoing traffic for the client and purges the data to
+ the network before removing the client entry.
+
Sun Mar 18 21:02:47 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Added SILC_NOTIFY_TYPE_KILLED notify type. It is sent when
whereto relay the notify. Affected file is
silcd/packet_receive.[ch].
- * Implemented KILL command to the server.
+ * Implemented the KILL command to the server.
* Updated TODO.
TODO In SILC Server
===================
- o Functions such as silc_server_private_message,
- silc_server_private_message_key and
- silc_server_packet_process_relay_notify can be optimized. I don't think
- we need such a big lookups to lookup the router to the destination,
- it is already provided in the client entry.
-
- o silc_server_send_key_agreement and silc_server_send_private_message_key
- are one and same function (also silc_server_send_private_message is
- almost same function). These should be unified to one generic named
- function and use that (silc_server_packet_relay_notify is also
- same function).
-
o Packet processing can be made faster. All packet function in the
packet_receive.c has same prototypes. Instead of calling those from
huge switch() make a table of callback functions that can be called
}
break;
+ case SILC_NOTIFY_TYPE_KILLED:
+ client_entry = va_arg(vp, SilcClientEntry);
+ tmp = va_arg(vp, char *);
+ channel_entry = va_arg(vp, SilcChannelEntry);
+
+ if (client_entry == conn->local_entry) {
+ snprintf(message, sizeof(message),
+ "You have been killed from the SILC Network %s%s%s",
+ tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
+ } else {
+ snprintf(message, sizeof(message),
+ "%s%s%s has been killed from the SILC Network %s%s%s",
+ client_entry->nickname,
+ client_entry->server ? "@" : "",
+ client_entry->server ? client_entry->server : "",
+ tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
+ }
+ break;
+
default:
break;
}
/* Free all client specific data, such as client entry and entires
on channels this client may be on. */
silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
- q->signoff);
+ TRUE, q->signoff);
q->sock->user_data = NULL;
/* Close the connection on our side */
SilcClientEntry remote_client;
SilcClientID *client_id;
unsigned char *tmp, *comment;
- unsigned int tmp_len;
- SilcBuffer idp;
+ unsigned int tmp_len, tmp_len2;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_KILL, cmd, 1, 2);
if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
- if (server->server_type != SILC_ROUTER)
+ /* KILL command works only on router */
+ if (server->server_type != SILC_ROUTER) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+ SILC_STATUS_ERR_NO_ROUTER_PRIV);
goto out;
+ }
/* Check whether client has the permissions. */
if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
}
/* Get comment */
- comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
+ if (tmp_len2 > 128)
+ comment = NULL;
/* Send reply to the sender */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
SILC_STATUS_OK);
+ /* Send the KILL notify packets. First send it to the channel, then
+ to our primary router and then directly to the client who is being
+ killed right now. */
+
/* Send KILLED notify to the channels. It is not sent to the client
as it will be sent differently destined directly to the client and not
to the channel. */
- idp = silc_id_payload_encode(remote_client->id, SILC_ID_CLIENT);
- silc_server_send_notify_on_channels(server, remote_client->connection,
+ silc_server_send_notify_on_channels(server, remote_client,
remote_client, SILC_NOTIFY_TYPE_KILLED,
comment ? 2 : 1,
- idp->data, idp->len,
- comment, comment ? strlen(comment) : 0);
- silc_buffer_free(idp);
+ tmp, tmp_len,
+ comment, comment ? tmp_len2 : 0);
- /* Remove the client from all channels. This generates new keys to the
- channels as well. */
- silc_server_remove_from_channels(server, NULL, remote_client, FALSE,
- NULL, TRUE);
+ /* Send KILLED notify to primary route */
+ if (!server->standalone)
+ silc_server_send_notify_killed(server, server->router->connection, TRUE,
+ remote_client->id, SILC_ID_CLIENT_LEN,
+ comment);
/* Send KILLED notify to the client directly */
silc_server_send_notify_killed(server, remote_client->connection ?
remote_client->id, SILC_ID_CLIENT_LEN,
comment);
- /* Send KILLED notify to primary route */
- if (!server->standalone)
- silc_server_send_notify_killed(server, server->router->connection,
- server->server_type == SILC_ROUTER ?
- TRUE : FALSE,
- remote_client->id, SILC_ID_CLIENT_LEN,
- comment);
+ /* Remove the client from all channels. This generates new keys to the
+ channels as well. */
+ silc_server_remove_from_channels(server, NULL, remote_client, FALSE,
+ NULL, TRUE);
+
+ /* Remove the client entry, If it is locally connected then we will also
+ disconnect the client here */
+ if (remote_client->data.registered && remote_client->connection) {
+ /* Remove locally conneted client */
+ SilcSocketConnection sock = remote_client->connection;
+ silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
+ silc_server_close_connection(server, sock);
+ } else {
+ /* Remove remote client */
+ if (!silc_idlist_del_client(server->global_list, remote_client))
+ silc_idlist_del_client(server->local_list, remote_client);
+ }
out:
silc_server_command_free(cmd);
/* Send reply */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
- SILC_STATUS_OK, 0, 4,
+ SILC_STATUS_OK, ident, 4,
2, channel_id, channel_id_len,
3, lc, 4,
4, client_id_list->data,
extern char *server_version;
-/* Check whereto relay the received notify packet that was destined
- to a client. */
-
-static void
-silc_server_packet_process_relay_notify(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcClientID *id;
- SilcServerEntry router;
- SilcSocketConnection dst_sock;
- SilcClientEntry client;
- SilcIDListData idata;
-
- SILC_LOG_DEBUG(("Start"));
-
- /* Decode destination Client ID */
- id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT);
- if (!id) {
- SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
- return;
- }
-
- /* If the destination belongs to our server we don't have to route
- the packet anywhere but to send it to the local destination. */
- client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
- if (client) {
- /* It exists, now deliver the packet 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)client->router;
- idata = (SilcIDListData)router;
- silc_server_packet_relay_notify(server, router->connection,
- idata->send_key,
- idata->hmac,
- packet);
- silc_free(id);
- return;
- }
-
- /* Seems that client really is directly connected to us */
- idata = (SilcIDListData)client;
- silc_server_packet_relay_notify(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- silc_free(id);
- 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_packet_relay_notify(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- }
- silc_free(id);
- return;
- }
-
- /* We are router and we will perform route lookup for the destination
- and send the packet to fastest route. */
- if (server->server_type == SILC_ROUTER && !server->standalone) {
- /* Check first that the ID is valid */
- client = silc_idlist_find_client_by_id(server->global_list, id, NULL);
- if (client) {
- dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT);
- router = (SilcServerEntry)dst_sock->user_data;
- idata = (SilcIDListData)router;
-
- /* Get fastest route and send packet. */
- if (router)
- silc_server_packet_relay_notify(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- silc_free(id);
- return;
- }
- }
-}
-
/* Received notify packet. Server can receive notify packets from router.
Server then relays the notify messages to clients if needed. */
packet->src_id_type != SILC_ID_SERVER)
return;
- /* If the packet is destined directly to a client, then we don't
- process the packet at all but just relay it to the client. */
- if (packet->dst_id_type == SILC_ID_CLIENT) {
- silc_server_packet_process_relay_notify(server, sock, packet);
+ if (!packet->dst_id)
return;
+
+ /* If the packet is destined directly to a client then relay the packet
+ before processing it. */
+ if (packet->dst_id_type == SILC_ID_CLIENT) {
+ SilcIDListData idata;
+ SilcSocketConnection dst_sock;
+
+ /* Get the route to the client */
+ dst_sock = silc_server_get_client_route(server, packet->dst_id,
+ packet->dst_id_len, &idata);
+ if (dst_sock)
+ /* Relay the packet */
+ silc_server_relay_packet(server, dst_sock, idata->send_key,
+ idata->hmac, packet, TRUE);
}
/* If we are router and this packet is not already broadcast packet
break;
case SILC_NOTIFY_TYPE_KILLED:
- /*
- * Distribute the notify to local clients on channels
- */
+ {
+ /*
+ * Distribute the notify to local clients on channels
+ */
+ unsigned char *id;
+ unsigned int id_len;
- SILC_LOG_DEBUG(("KILLED notify"));
+ SILC_LOG_DEBUG(("KILLED notify"));
- break;
+ /* Get client ID */
+ id = silc_argument_get_arg_type(args, 1, &id_len);
+ if (!id)
+ goto out;
+ client_id = silc_id_payload_parse_id(id, id_len);
+ if (!client_id)
+ goto out;
+
+ /* If the the client is not in local list we check global list */
+ client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, NULL);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, NULL);
+ if (!client) {
+ silc_free(client_id);
+ goto out;
+ }
+ }
+ silc_free(client_id);
+
+ /* If the client is one of ours, then close the connection to the
+ client now. This removes the client from all channels as well. */
+ if (packet->dst_id_type == SILC_ID_CLIENT && client->data.registered &&
+ client->connection) {
+ sock = client->connection;
+ silc_server_free_client_data(server, NULL, client, FALSE, NULL);
+ silc_server_close_connection(server, sock);
+ break;
+ }
+
+ /* Get comment */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp_len > 128)
+ tmp = NULL;
+
+ /* Send the notify to local clients on the channels except to the
+ client who is killed. */
+ silc_server_send_notify_on_channels(server, client, client,
+ SILC_NOTIFY_TYPE_KILLED,
+ tmp ? 2 : 1,
+ id, id_len,
+ tmp, tmp_len);
+
+ /* Remove the client from all channels */
+ silc_server_remove_from_channels(server, NULL, client, FALSE, NULL,
+ FALSE);
+
+ break;
+ }
/* Ignore rest of the notify types for now */
case SILC_NOTIFY_TYPE_NONE:
SilcSocketConnection sock,
SilcPacketContext *packet)
{
- SilcClientID *id;
- SilcServerEntry router;
SilcSocketConnection dst_sock;
- SilcClientEntry client;
SilcIDListData idata;
SILC_LOG_DEBUG(("Start"));
if (!packet->dst_id)
return;
- /* Decode destination Client ID */
- id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT);
- if (!id) {
- SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+ /* Get the route to the client */
+ dst_sock = silc_server_get_client_route(server, packet->dst_id,
+ packet->dst_id_len, &idata);
+ if (!dst_sock)
return;
- }
-
- /* 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, NULL);
- 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)client->router;
- idata = (SilcIDListData)router;
-
- silc_server_send_private_message(server, router->connection,
- idata->send_key,
- idata->hmac,
- packet);
- silc_free(id);
- 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);
- silc_free(id);
- 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);
- }
- silc_free(id);
- 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) {
- /* Check first that the ID is valid */
- client = silc_idlist_find_client_by_id(server->global_list, id, NULL);
- if (client) {
- dst_sock = silc_server_route_get(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);
- silc_free(id);
- return;
- }
- }
+ /* Send the private message */
+ silc_server_send_private_message(server, dst_sock, idata->send_key,
+ idata->hmac, packet);
}
/* Received private message key packet.. This packet is never for us. It is to
SilcSocketConnection sock,
SilcPacketContext *packet)
{
- SilcClientID *id;
- SilcServerEntry router;
SilcSocketConnection dst_sock;
- SilcClientEntry client;
SilcIDListData idata;
SILC_LOG_DEBUG(("Start"));
if (!packet->dst_id)
return;
- /* Decode destination Client ID */
- id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT);
- if (!id) {
- SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+ /* Get the route to the client */
+ dst_sock = silc_server_get_client_route(server, packet->dst_id,
+ packet->dst_id_len, &idata);
+ if (!dst_sock)
return;
- }
-
- /* 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, NULL);
- 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)client->router;
- idata = (SilcIDListData)router;
- silc_server_send_private_message_key(server, router->connection,
- idata->send_key,
- idata->hmac,
- packet);
- silc_free(id);
- return;
- }
-
- /* Seems that client really is directly connected to us */
- idata = (SilcIDListData)client;
- silc_server_send_private_message_key(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- silc_free(id);
- 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_key(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- }
- silc_free(id);
- return;
- }
-
- /* We are router and we will perform route lookup for the destination
- and send the packet to fastest route. */
- if (server->server_type == SILC_ROUTER && !server->standalone) {
- /* Check first that the ID is valid */
- client = silc_idlist_find_client_by_id(server->global_list, id, NULL);
- if (client) {
- dst_sock = silc_server_route_get(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_key(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- silc_free(id);
- return;
- }
- }
+ /* Relay the packet */
+ silc_server_relay_packet(server, dst_sock, idata->send_key,
+ idata->hmac, packet, FALSE);
}
/* Processes incoming command reply packet. The command reply packet may
SilcSocketConnection sock,
SilcPacketContext *packet)
{
- SilcClientID *id;
- SilcServerEntry router;
SilcSocketConnection dst_sock;
- SilcClientEntry client;
SilcIDListData idata;
SILC_LOG_DEBUG(("Start"));
if (!packet->dst_id)
return;
- /* Decode destination Client ID */
- id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT);
- if (!id) {
- SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
- return;
- }
-
- /* If the destination belongs to our server we don't have to route
- the packet anywhere but to send it to the local destination. */
- client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
- if (client) {
- /* It exists, now deliver the packet 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)client->router;
- idata = (SilcIDListData)router;
- silc_server_send_key_agreement(server, router->connection,
- idata->send_key,
- idata->hmac,
- packet);
- silc_free(id);
- return;
- }
-
- /* Seems that client really is directly connected to us */
- idata = (SilcIDListData)client;
- silc_server_send_key_agreement(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- silc_free(id);
- 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_key_agreement(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- }
- silc_free(id);
+ /* Get the route to the client */
+ dst_sock = silc_server_get_client_route(server, packet->dst_id,
+ packet->dst_id_len, &idata);
+ if (!dst_sock)
return;
- }
- /* We are router and we will perform route lookup for the destination
- and send the packet to fastest route. */
- if (server->server_type == SILC_ROUTER && !server->standalone) {
- /* Check first that the ID is valid */
- client = silc_idlist_find_client_by_id(server->global_list, id, NULL);
- if (client) {
- dst_sock = silc_server_route_get(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_key_agreement(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- silc_free(id);
- return;
- }
- }
+ /* Relay the packet */
+ silc_server_relay_packet(server, dst_sock, idata->send_key,
+ idata->hmac, packet, FALSE);
}
silc_buffer_free(packet);
}
-/* Send notify message to all clients the client has joined. It is quaranteed
+/* Send notify message to all channels 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). */
+ local servers if we are router). If `sender' is provided the packet is
+ not sent to that client at all. */
void silc_server_send_notify_on_channels(SilcServer server,
- SilcSocketConnection sender,
+ SilcClientEntry sender,
SilcClientEntry client,
SilcNotifyType type,
unsigned int argc, ...)
while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
c = chl2->client;
+ if (sender && c == sender)
+ continue;
+
/* Check if we have sent the packet to this client already */
for (k = 0; k < sent_clients_count; k++)
if (sent_clients[k] == c)
sock = (SilcSocketConnection)c->router->connection;
idata = (SilcIDListData)c->router;
- if (sender && sock == sender)
- continue;
-
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;
sock = (SilcSocketConnection)c->connection;
idata = (SilcIDListData)c;
- if (sender && sock == sender)
- continue;
-
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;
NULL, 0, FALSE);
}
-/* Routine used to send (relay, route) key agreement packets to some
- destination. */
+/* Generic function to relay packet we've received. This is used to relay
+ packets to a client but generally can be used to other purposes as well. */
-void silc_server_send_key_agreement(SilcServer server,
- SilcSocketConnection dst_sock,
- SilcCipher cipher,
- SilcHmac hmac,
- SilcPacketContext *packet)
+void silc_server_relay_packet(SilcServer server,
+ SilcSocketConnection dst_sock,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ SilcPacketContext *packet,
+ int force_send)
{
silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ packet->dst_id_len + packet->padlen);
- silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len);
- silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len);
-
- /* Re-encrypt packet */
- silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, packet->buffer->len);
-
- /* Send the packet */
- silc_server_packet_send_real(server, dst_sock, FALSE);
-}
-
-/* Routine used to send (relay, route) private message key packets to some
- destination. */
-void silc_server_send_private_message_key(SilcServer server,
- SilcSocketConnection dst_sock,
- SilcCipher cipher,
- SilcHmac hmac,
- SilcPacketContext *packet)
-{
- silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
- + packet->dst_id_len + packet->padlen);
silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len);
silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len);
silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, packet->buffer->len);
/* Send the packet */
- silc_server_packet_send_real(server, dst_sock, FALSE);
-}
+ silc_server_packet_send_real(server, dst_sock, force_send);
-/* Routine used to relay notify packets to a client. The notify packets
- may be destined directly to a client and this routine is used to do
- that. */
-
-void silc_server_packet_relay_notify(SilcServer server,
- SilcSocketConnection dst_sock,
- SilcCipher cipher,
- SilcHmac hmac,
- SilcPacketContext *packet)
-{
- silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ silc_buffer_pull(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ packet->dst_id_len + packet->padlen);
- silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len);
- silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len);
-
- /* Re-encrypt packet */
- silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, packet->buffer->len);
-
- /* Send the packet */
- silc_server_packet_send_real(server, dst_sock, FALSE);
}
SilcNotifyType type,
unsigned int argc, ...);
void silc_server_send_notify_on_channels(SilcServer server,
- SilcSocketConnection sender,
+ SilcClientEntry sender,
SilcClientEntry client,
SilcNotifyType type,
unsigned int argc, ...);
unsigned int argc, ...);
void silc_server_send_heartbeat(SilcServer server,
SilcSocketConnection sock);
-void silc_server_send_key_agreement(SilcServer server,
- SilcSocketConnection dst_sock,
- SilcCipher cipher,
- SilcHmac hmac,
- SilcPacketContext *packet);
-void silc_server_send_private_message_key(SilcServer server,
- SilcSocketConnection dst_sock,
- SilcCipher cipher,
- SilcHmac hmac,
- SilcPacketContext *packet);
-void silc_server_packet_relay_notify(SilcServer server,
- SilcSocketConnection dst_sock,
- SilcCipher cipher,
- SilcHmac hmac,
- SilcPacketContext *packet);
+void silc_server_relay_packet(SilcServer server,
+ SilcSocketConnection dst_sock,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ SilcPacketContext *packet,
+ int force_send);
#endif
server->stat.packets_sent++;
if (sock->outbuf->data - sock->outbuf->head)
- silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
+ silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
ret = silc_server_packet_send_real(server, sock, TRUE);
void silc_server_free_client_data(SilcServer server,
SilcSocketConnection sock,
- SilcClientEntry client, char *signoff)
+ SilcClientEntry client,
+ int notify,
+ char *signoff)
{
FreeClientInternal i = silc_calloc(1, sizeof(*i));
+ /* If there is pending outgoing data for the client then purge it
+ to the network before removing the client entry. */
+ if (SILC_IS_OUTBUF_PENDING(sock) && (SILC_IS_DISCONNECTED(sock) == FALSE)) {
+ server->stat.packets_sent++;
+
+ if (sock->outbuf->data - sock->outbuf->head)
+ silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
+
+ silc_server_packet_send_real(server, sock, TRUE);
+
+ SILC_SET_CONNECTION_FOR_INPUT(sock->sock);
+ SILC_UNSET_OUTBUF_PENDING(sock);
+ silc_buffer_clear(sock->outbuf);
+ }
+
/* Send SIGNOFF notify to routers. */
- if (!server->standalone && server->router)
+ if (notify && !server->standalone && server->router)
silc_server_send_notify_signoff(server, server->router->connection,
server->server_type == SILC_SERVER ?
FALSE : TRUE, client->id,
SILC_ID_CLIENT_LEN, signoff);
/* Remove client from all channels */
- silc_server_remove_from_channels(server, sock, client, TRUE, signoff, TRUE);
+ if (notify)
+ silc_server_remove_from_channels(server, NULL, client,
+ TRUE, signoff, TRUE);
+ else
+ silc_server_remove_from_channels(server, NULL, client,
+ FALSE, NULL, FALSE);
/* We will not delete the client entry right away. We will take it
into history (for WHOWAS command) for 5 minutes */
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
- silc_server_free_client_data(server, sock, user_data, NULL);
+ silc_server_free_client_data(server, sock, user_data, TRUE, NULL);
break;
}
case SILC_SOCKET_TYPE_SERVER:
}
}
}
+
+/* Lookups route to the client indicated by `id' client ID. The connection
+ object and internal data object is returned. Returns NULL if route
+ could not be found to the client. */
+
+SilcSocketConnection silc_server_get_client_route(SilcServer server,
+ unsigned char *id_data,
+ unsigned int id_len,
+ SilcIDListData *idata)
+{
+ SilcClientID *id;
+ SilcClientEntry client;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Decode destination Client ID */
+ id = silc_id_str2id(id_data, id_len, SILC_ID_CLIENT);
+ if (!id) {
+ SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+ return NULL;
+ }
+
+ /* If the destination belongs to our server we don't have to route
+ the packet anywhere but to send it to the local destination. */
+ client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
+ if (client) {
+ silc_free(id);
+
+ if (client && client->data.registered == FALSE)
+ return NULL;
+
+ /* 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. */
+ *idata = (SilcIDListData)client->router;
+ return client->router->connection;
+ }
+
+ /* Seems that client really is directly connected to us */
+ *idata = (SilcIDListData)client;
+ return client->connection;
+ }
+
+ /* 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) {
+ silc_free(id);
+ *idata = (SilcIDListData)server->router;
+ return server->router->connection;
+ }
+
+ /* We are router and we will perform route lookup for the destination
+ and send the packet to fastest route. */
+ if (server->server_type == SILC_ROUTER && !server->standalone) {
+ /* Check first that the ID is valid */
+ client = silc_idlist_find_client_by_id(server->global_list, id, NULL);
+ if (client) {
+ SilcSocketConnection dst_sock;
+
+ dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT);
+
+ silc_free(id);
+ *idata = (SilcIDListData)dst_sock->user_data;
+ return dst_sock;
+ }
+ }
+
+ silc_free(id);
+ return NULL;
+}
SilcSocketConnection sock);
void silc_server_free_client_data(SilcServer server,
SilcSocketConnection sock,
- SilcClientEntry client, char *signoff);
+ SilcClientEntry client,
+ int notify,
+ char *signoff);
void silc_server_free_sock_user_data(SilcServer server,
SilcSocketConnection sock);
int silc_server_channel_has_global(SilcChannelEntry channel);
SilcBuffer user_list,
SilcBuffer mode_list,
unsigned int user_count);
+SilcSocketConnection silc_server_get_client_route(SilcServer server,
+ unsigned char *id_data,
+ unsigned int id_len,
+ SilcIDListData *idata);
#endif
[Cipher]
-aes-256-cbc:../lib/silcsim/modules/aes.sim.so:32:16
-aes-192-cbc:../lib/silcsim/modules/aes.sim.so:24:16
-aes-128-cbc:../lib/silcsim/modules/aes.sim.so:16:16
-twofish-256-cbc:../lib/silcsim/modules/twofish.sim.so:32:16
-twofish-192-cbc:../lib/silcsim/modules/twofish.sim.so:24:16
-twofish-128-cbc:../lib/silcsim/modules/twofish.sim.so:16:16
-mars-256-cbc:../lib/silcsim/modules/mars.sim.so:32:16
-mars-192-cbc:../lib/silcsim/modules/mars.sim.so:24:16
-mars-128-cbc:../lib/silcsim/modules/mars.sim.so:16:16
+rc6:../lib/silcsim/modules/rc6.sim.so:16:16
+twofish:../lib/silcsim/modules/twofish.sim.so:16:16
+mars:../lib/silcsim/modules/mars.sim.so:16:16
none:../lib/silcsim/modules/none.sim.so:0:0
-[Hash]
+[Hash]
md5::64:16
sha1::64:20
[hmac]
hmac-sha1-96:sha1:12
hmac-md5-96:md5:12
-hmac-sha1:sha1:20
+hmac-sha1:sha1:20
hmac-md5:md5:16
#[PKCS]
Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
[ServerInfo]
-lassi.kuo.fi.ssh.com:212.146.42.253:Kuopio, Finland:1334
+lassi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
[ListenPort]
-212.146.42.253:212.146.42.253:1334
+10.2.1.7:10.2.1.7:1334
[Logging]
infologfile:silcd2.log:10000
:::1336:1
[AdminConnection]
+*:silc:silc:passwd:testi
[ServerConnection]
-212.146.42.253:passwd:priikone:1336:1:1
+10.2.1.7:passwd:priikone:1333:1:1
[RouterConnection]
-212.146.42.253:passwd:priikone:1335:1:1:0
+10.2.1.7:passwd:priikone:1334:1:1:0
[DenyConnection]
[RedirectClient]
silc_cipher_free(client_entry->send_key);
if (client_entry->receive_key)
silc_cipher_free(client_entry->receive_key);
+ silc_free(client_entry);
break;
case SILC_NOTIFY_TYPE_CMODE_CHANGE:
goto out;
/* Find Client entry */
- client_entry =
- silc_client_get_client_by_id(client, conn, client_id);
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
silc_free(channel);
}
break;
+
+ case SILC_NOTIFY_TYPE_KILLED:
+ /*
+ * A client (maybe me) was killed from the network.
+ */
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
+
+ /* Find Client entry */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry)
+ goto out;
+
+ /* Get comment */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, tmp);
+
+ if (client_entry != conn->local_entry) {
+ silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
+ client_entry->id);
+ if (client_entry->nickname)
+ silc_free(client_entry->nickname);
+ if (client_entry->server)
+ silc_free(client_entry->server);
+ if (client_entry->id)
+ silc_free(client_entry->id);
+ if (client_entry->send_key)
+ silc_cipher_free(client_entry->send_key);
+ if (client_entry->receive_key)
+ silc_cipher_free(client_entry->receive_key);
+ silc_free(client_entry);
+ }
+
+ break;
default:
break;
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3),
SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN",
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 1),
- SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
+ SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER",
SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
cmd->argc - 1, ++cmd->argv,
++cmd->argv_lens, ++cmd->argv_types,
- 0);
+ ++conn->cmd_ident);
silc_client_packet_send(cmd->client, cmd->conn->sock,
SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
buffer->data, buffer->len, TRUE);
/* Client entry not found, it was requested thus mark this to be
pending command. */
- silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 0,
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
silc_client_command_destructor,
silc_client_command_invite,
silc_client_command_dup(cmd));
COMMAND;
out:
+ if (nickname)
+ silc_free(nickname);
+ if (server)
+ silc_free(server);
silc_client_command_free(cmd);
}
silc_client_command_free(cmd);
}
+/* Command KILL. Router operator can use this command to remove an client
+ fromthe SILC Network. */
+
SILC_CLIENT_CMD_FUNC(kill)
{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer, idp;
+ SilcClientEntry target;
+ unsigned int num = 0;
+ char *nickname = NULL, *server = NULL;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argc < 2) {
+ cmd->client->ops->say(cmd->client, conn,
+ "Usage: /KILL <nickname> [<comment>]");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ /* Parse the typed nickname. */
+ if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
+ cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ /* Get the target client */
+ target = silc_idlist_get_client(cmd->client, conn, nickname,
+ server, num, TRUE);
+ if (!target) {
+ silc_free(nickname);
+ if (server)
+ silc_free(server);
+
+ /* Client entry not found, it was requested thus mark this to be
+ pending command. */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ silc_client_command_destructor,
+ silc_client_command_kill,
+ silc_client_command_dup(cmd));
+ cmd->pending = 1;
+ return;
+ }
+
+ /* Send the KILL command to the server */
+ idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
+ if (cmd->argc == 2)
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1,
+ 1, idp->data, idp->len);
+ else
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2,
+ 1, idp->data, idp->len,
+ 2, cmd->argv[2],
+ strlen(cmd->argv[2]));
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
+
+ /* Notify application */
+ COMMAND;
+
+ /* Remove the client entry to be killed */
+ silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
+ target->id);
+ if (target->nickname)
+ silc_free(target->nickname);
+ if (target->server)
+ silc_free(target->server);
+ if (target->id)
+ silc_free(target->id);
+ if (target->send_key)
+ silc_cipher_free(target->send_key);
+ if (target->receive_key)
+ silc_cipher_free(target->receive_key);
+ silc_free(target);
+
+ out:
+ if (nickname)
+ silc_free(nickname);
+ if (server)
+ silc_free(server);
+ silc_client_command_free(cmd);
}
/* Command INFO. Request information about specific server. If specific
if (!client_entry) {
/* Client entry not found, it was requested thus mark this to be
pending command. */
- silc_client_command_pending(conn, SILC_COMMAND_CUMODE, 0,
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
silc_client_command_destructor,
silc_client_command_cumode,
silc_client_command_dup(cmd));
COMMAND;
out:
+ if (nickname)
+ silc_free(nickname);
+ if (server)
+ silc_free(server);
silc_client_command_free(cmd);
}
if (cmd->argc < 3) {
cmd->client->ops->say(cmd->client, conn,
- "Usage: /KICK <channel> <client> [<comment>]");
+ "Usage: /KICK <channel> <nickname> [<comment>]");
COMMAND_ERROR;
goto out;
}
COMMAND;
out:
+ if (nickname)
+ silc_free(nickname);
+ if (server)
+ silc_free(server);
silc_client_command_free(cmd);
}
if (!cmd->pending) {
/* Send USERS command to the server */
idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
- buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 0, 1,
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
+ ++conn->cmd_ident, 1,
1, idp->data, idp->len);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
NULL, 0, NULL, NULL, buffer->data,
/* Register pending callback which will recall this command callback with
same context and reprocesses the command. When reprocessing we actually
display the information on the screen. */
- silc_client_command_pending(conn, SILC_COMMAND_USERS, 0,
+ silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
silc_client_command_destructor,
silc_client_command_users,
silc_client_command_dup(cmd));
SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
silc_client_command_reply_free(cmd);
}
+
+/* Received reply to the KILL command. */
SILC_CLIENT_CMD_REPLY_FUNC(kill)
{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcCommandStatus status;
+ unsigned char *tmp;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+ if (status != SILC_STATUS_OK) {
+ cmd->client->ops->say(cmd->client, conn,
+ "%s", silc_client_command_status_message(status));
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Notify application */
+ COMMAND_REPLY((ARGS));
+
+ /* Execute any pending command callbacks */
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
+
+ out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
+ silc_client_command_reply_free(cmd);
}
/* Received reply to INFO command. We receive the server ID and some
/* Generic manipulation of flags */
#define SF_SET(x, f) (x)->flags |= (1L << (f))
#define SF_UNSET(x, f) (x)->flags &= ~(1L << (f))
-#define SF_IS(x, f) (x)->flags & (1L << (f))
+#define SF_IS(x, f) ((x)->flags & (1L << (f)))
/* Setting/Unsetting flags */
#define SILC_SET_OUTBUF_PENDING(x) SF_SET((x), SILC_SF_OUTBUF_PENDING)