Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 1997 - 2000 Pekka Riikonen
+ Copyright (C) 1997 - 2001 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
SilcPacketType type,
SilcPacketFlags flags,
unsigned char *data,
- unsigned int data_len,
+ uint32 data_len,
int force_send)
{
void *dst_id = NULL;
void *dst_id,
SilcIdType dst_id_type,
unsigned char *data,
- unsigned int data_len,
+ uint32 data_len,
int force_send)
{
SilcPacketContext packetdata;
SilcCipher cipher = NULL;
SilcHmac hmac = NULL;
unsigned char *dst_id_data = NULL;
- unsigned int dst_id_len = 0;
+ uint32 dst_id_len = 0;
SILC_LOG_DEBUG(("Sending packet, type %d", 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_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)
+/* 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.
+ The source and destination information is sent as argument for this
+ function. */
+
+void silc_server_packet_send_srcdest(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ void *src_id,
+ SilcIdType src_id_type,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ unsigned char *data,
+ uint32 data_len,
+ int force_send)
{
+ SilcPacketContext packetdata;
SilcIDListData idata;
SilcCipher cipher = NULL;
SilcHmac hmac = NULL;
+ unsigned char *dst_id_data = NULL;
+ uint32 dst_id_len = 0;
+ unsigned char *src_id_data = NULL;
+ uint32 src_id_len = 0;
- SILC_LOG_DEBUG(("Forwarding packet"));
+ 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);
+ }
+
+ if (src_id) {
+ src_id_data = silc_id_id2str(src_id, src_id_type);
+ src_id_len = silc_id_get_len(src_id_type);
+ }
+
+ /* Set the packet context pointers */
+ packetdata.type = type;
+ packetdata.flags = flags;
+ packetdata.src_id = src_id_data;
+ packetdata.src_id_len = src_id_len;
+ packetdata.src_id_type = src_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);
+
/* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock, 0, 0, data_len);
+ 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);
- /* Add the FORWARDED flag to packet flags */
- sock->outbuf->data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED;
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
if (idata) {
cipher = idata->send_key;
/* Encrypt the packet */
silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
- SILC_LOG_HEXDUMP(("Forwarded packet, len %d", 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);
}
/* Broadcast received packet to our primary route. This function is used
/* 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);
+ id = silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type);
if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) {
idata = (SilcIDListData)sock->user_data;
silc_free(id);
}
+/* Routes received packet to `sock'. This is used to route the packets that
+ router receives but are not destined to it. */
+
+void silc_server_packet_route(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Routing received packet"));
+
+ 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(("Routed 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);
+}
+
/* 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
SilcCipher cipher,
SilcHmac hmac,
unsigned char *data,
- unsigned int data_len,
+ uint32 data_len,
int channel_message,
int force_send)
{
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. */
+ be routed anywhere (for router locally means cell wide). If `sender'
+ is provided then the packet is not sent to that connection since it
+ originally came from it. */
void silc_server_packet_send_to_channel(SilcServer server,
+ SilcSocketConnection sender,
SilcChannelEntry channel,
SilcPacketType type,
unsigned char route,
unsigned char *data,
- unsigned int data_len,
+ uint32 data_len,
int force_send)
{
SilcSocketConnection sock = NULL;
SilcServerEntry *routed = NULL;
SilcChannelClientEntry chl;
SilcIDListData idata;
- unsigned int routed_count = 0;
+ uint32 routed_count = 0;
/* This doesn't send channel message packets */
if (type == SILC_PACKET_CHANNEL_MESSAGE)
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);
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);
+ if (sock != sender) {
+ 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. */
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) {
+ we will route the message to the router set in the client. Though,
+ send locally connected server in all cases. */
+ if (server->server_type == SILC_ROUTER && client && client->router &&
+ ((!route && client->router->router == server->id_entry) || route)) {
int k;
/* Check if we have sent the packet to this route already */
sock = (SilcSocketConnection)client->router->connection;
idata = (SilcIDListData)client->router;
+ if (sender && sock == sender)
+ continue;
+
/* Send the packet */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key, idata->hmac,
continue;
}
+ if (client && client->router)
+ continue;
+
/* Send to locally connected client */
if (client) {
sock = (SilcSocketConnection)client->connection;
idata = (SilcIDListData)client;
+ if (sender && sock == sender)
+ continue;
+
/* Send the packet */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key, idata->hmac,
void *sender,
SilcIdType sender_type,
unsigned char *data,
- unsigned int data_len,
+ uint32 data_len,
int force_send)
{
int found = FALSE;
SilcClientEntry client = NULL;
SilcServerEntry *routed = NULL;
SilcChannelClientEntry chl;
- unsigned int routed_count = 0;
+ uint32 routed_count = 0;
SilcIDListData idata;
SILC_LOG_DEBUG(("Relaying packet to channel"));
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));
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);
-
+ if (sender_sock && sock == sender_sock)
+ continue;
+
+ SILC_LOG_DEBUG(("Relaying packet to client ID(%s) %s (%s)",
+ silc_id_render(client->id, SILC_ID_CLIENT),
+ sock->hostname, sock->ip));
+
/* 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[k] = client->router;
routed_count++;
+ /* If the remote connection is router then we'll decrypt the
+ channel message and re-encrypt it with the session key shared
+ between us and the remote router. This is done because the
+ channel keys are cell specific and we have different channel
+ key than the remote router has. */
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+
+ /* If private key mode is not set then decrypt the packet
+ and re-encrypt it */
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+ unsigned char *tmp = silc_calloc(data_len, sizeof(*data));
+ memcpy(tmp, data, data_len);
+
+ /* Decrypt the channel message (we don't check the MAC) */
+ if (!silc_channel_message_payload_decrypt(tmp, data_len,
+ channel->channel_key,
+ NULL)) {
+ memset(tmp, 0, data_len);
+ silc_free(tmp);
+ continue;
+ }
+
+ /* Now re-encrypt and send it to the router */
+ silc_server_packet_send_srcdest(server, sock,
+ SILC_PACKET_CHANNEL_MESSAGE, 0,
+ sender, sender_type,
+ channel->id, SILC_ID_CHANNEL,
+ tmp, data_len, force_send);
+
+ /* Free the copy of the channel message */
+ memset(tmp, 0, data_len);
+ silc_free(tmp);
+ } else {
+ /* Private key mode is set, we don't have the channel key, so
+ just re-encrypt the entire packet and send it to the router. */
+ silc_server_packet_send_srcdest(server, sock,
+ SILC_PACKET_CHANNEL_MESSAGE, 0,
+ sender, sender_type,
+ channel->id, SILC_ID_CHANNEL,
+ data, data_len, force_send);
+ }
+ continue;
+ }
+
+ /* Send the packet (to normal server) */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key, idata->hmac,
+ data, data_len, TRUE,
+ force_send);
+
continue;
}
- /* XXX Check client's mode on the channel. */
+ if (client && client->router)
+ continue;
/* 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));
+ if (sender_sock && sock == sender_sock)
+ continue;
+
+ SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)",
+ silc_id_render(client->id, SILC_ID_CLIENT),
+ sock->hostname, sock->ip));
/* Send the packet */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
SilcPacketType type,
SilcPacketFlags flags,
unsigned char *data,
- unsigned int data_len,
+ uint32 data_len,
int force_send)
{
- SilcClientEntry client;
SilcChannelClientEntry chl;
SilcSocketConnection sock = NULL;
/* 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;
+ if (chl->client && !chl->client->router) {
+ sock = (SilcSocketConnection)chl->client->connection;
/* Send the packet to the client */
- silc_server_packet_send_dest(server, sock, type, flags, client->id,
+ silc_server_packet_send_dest(server, sock, type, flags, chl->client->id,
SILC_ID_CLIENT, data, data_len,
force_send);
}
{
SilcBuffer buffer = packet->buffer;
- /* Send and re-encrypt if private messge key does not exist */
+ /* Re-encrypt and send 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
silc_server_packet_send_real(server, dst_sock, FALSE);
} else {
- /* Key exist so just send it */
+ /* Key exist so encrypt just header and 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);
+
+ /* Encrypt header */
+ silc_packet_encrypt(cipher, hmac, dst_sock->outbuf,
+ SILC_PACKET_HEADER_LEN + packet->src_id_len +
+ packet->dst_id_len + packet->padlen);
+
silc_server_packet_send_real(server, dst_sock, FALSE);
}
}
SilcSocketConnection sock)
{
char *motd;
- int motd_len;
+ uint32 motd_len;
if (server->config && server->config->motd &&
server->config->motd->motd_file) {
if (!motd)
return;
- silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1,
+ silc_server_send_notify(server, sock, FALSE, SILC_NOTIFY_TYPE_MOTD, 1,
motd, motd_len);
silc_free(motd);
}
void silc_server_send_notify(SilcServer server,
SilcSocketConnection sock,
+ int broadcast,
SilcNotifyType type,
- unsigned int argc, ...)
+ uint32 argc, ...)
{
va_list ap;
SilcBuffer packet;
silc_buffer_free(packet);
}
+/* Sends notify message and gets the arguments from the `args' Argument
+ Payloads. */
+
+void silc_server_send_notify_args(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcNotifyType type,
+ uint32 argc,
+ SilcBuffer args)
+{
+ SilcBuffer packet;
+
+ packet = silc_notify_payload_encode_args(type, argc, args);
+ silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+}
+
+/* Send CHANNEL_CHANGE notify type. This tells the receiver to replace the
+ `old_id' with the `new_id'. */
+
+void silc_server_send_notify_channel_change(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelID *old_id,
+ SilcChannelID *new_id,
+ uint32 id_len)
+{
+ SilcBuffer idp1, idp2;
+
+ idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CHANNEL);
+ idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CHANNEL);
+
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_CHANNEL_CHANGE,
+ 2, idp1->data, idp1->len, idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
+
+/* Send NICK_CHANGE notify type. This tells the receiver to replace the
+ `old_id' with the `new_id'. */
+
+void silc_server_send_notify_nick_change(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcClientID *old_id,
+ SilcClientID *new_id,
+ uint32 id_len)
+{
+ SilcBuffer idp1, idp2;
+
+ idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CLIENT);
+ idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CLIENT);
+
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_NICK_CHANGE,
+ 2, idp1->data, idp1->len, idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
+
+/* Sends JOIN notify type. This tells that new client by `client_id' ID
+ has joined to the `channel'. */
+
+void silc_server_send_notify_join(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ uint32 client_id_len)
+{
+ SilcBuffer idp1, idp2;
+
+ idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp2 = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+ silc_server_send_notify(server, sock, broadcast, SILC_NOTIFY_TYPE_JOIN,
+ 2, idp1->data, idp1->len,
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
+
+/* Sends LEAVE notify type. This tells that `client_id' has left the
+ `channel'. The Notify packet is always destined to the channel. */
+
+void silc_server_send_notify_leave(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ uint32 client_id_len)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+ SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_LEAVE,
+ 1, idp->data, idp->len);
+ silc_buffer_free(idp);
+}
+
+/* Sends CMODE_CHANGE notify type. This tells that `client_id' changed the
+ `channel' mode to `mode. The Notify packet is always destined to
+ the channel. */
+
+void silc_server_send_notify_cmode(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ uint32 mode_mask,
+ void *id, SilcIdType id_type,
+ uint32 id_len,
+ char *cipher, char *hmac)
+{
+ SilcBuffer idp;
+ unsigned char mode[4];
+
+ idp = silc_id_payload_encode((void *)id, id_type);
+ SILC_PUT32_MSB(mode_mask, mode);
+
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+ SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
+ 4, idp->data, idp->len,
+ mode, 4,
+ cipher, cipher ? strlen(cipher) : 0,
+ hmac, hmac ? strlen(hmac) : 0);
+ silc_buffer_free(idp);
+}
+
+/* Sends CUMODE_CHANGE notify type. This tells that `client_id' changed the
+ `target' client's mode on `channel'. The Notify packet is always
+ destined to the channel. */
+
+void silc_server_send_notify_cumode(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ uint32 mode_mask,
+ SilcClientID *client_id,
+ uint32 client_id_len,
+ SilcClientID *target,
+ uint32 target_len)
+{
+ SilcBuffer idp1, idp2;
+ unsigned char mode[4];
+
+ idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT);
+ SILC_PUT32_MSB(mode_mask, mode);
+
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+ SILC_ID_CHANNEL,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+ idp1->data, idp1->len,
+ mode, 4,
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
+
+/* Sends SIGNOFF notify type. This tells that `client_id' client has
+ left SILC network. This function is used only between server and router
+ traffic. This is not used to send the notify to the channel for
+ client. The `message may be NULL. */
+
+void silc_server_send_notify_signoff(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcClientID *client_id,
+ uint32 client_id_len,
+ char *message)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_SIGNOFF,
+ message ? 2 : 1, idp->data, idp->len,
+ message, message ? strlen(message): 0);
+ silc_buffer_free(idp);
+}
+
+/* Sends TOPIC_SET notify type. This tells that `client_id' changed
+ the `channel's topic to `topic'. The Notify packet is always destined
+ to the channel. This function is used to send the topic set notifies
+ between routers. */
+
+void silc_server_send_notify_topic_set(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ uint32 client_id_len,
+ char *topic)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
+ topic ? 2 : 1,
+ idp->data, idp->len,
+ topic, topic ? strlen(topic) : 0);
+ silc_buffer_free(idp);
+}
+
+/* Send KICKED notify type. This tells that the `client_id' on `channel'
+ was kicked off the channel. The `comment' may indicate the reason
+ for the kicking. This function is used only between server and router
+ traffic. */
+
+void silc_server_send_notify_kicked(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ uint32 client_id_len,
+ char *comment)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+ SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED,
+ comment ? 2 : 1, idp->data, idp->len,
+ comment, comment ? strlen(comment) : 0);
+ silc_buffer_free(idp);
+}
+
+/* Send KILLED notify type. This tells that the `client_id' client was
+ killed from the network. The `comment' may indicate the reason
+ for the killing. */
+
+void silc_server_send_notify_killed(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcClientID *client_id,
+ uint32 client_id_len,
+ char *comment)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify_dest(server, sock, broadcast, (void *)client_id,
+ SILC_ID_CLIENT, SILC_NOTIFY_TYPE_KILLED,
+ comment ? 2 : 1, idp->data, idp->len,
+ comment, comment ? strlen(comment) : 0);
+ silc_buffer_free(idp);
+}
+
+/* Sends UMODE_CHANGE notify type. This tells that `client_id' client's
+ user mode in the SILC Network was changed. This function is used to
+ send the packet between routers as broadcast packet. */
+
+void silc_server_send_notify_umode(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcClientID *client_id,
+ uint32 client_id_len,
+ uint32 mode_mask)
+{
+ SilcBuffer idp;
+ unsigned char mode[4];
+
+ idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ SILC_PUT32_MSB(mode_mask, mode);
+
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_UMODE_CHANGE, 2,
+ idp->data, idp->len,
+ mode, 4);
+ silc_buffer_free(idp);
+}
+
+/* Sends BAN notify type. This tells that ban has been either `add'ed
+ or `del'eted on the `channel. This function is used to send the packet
+ between routers as broadcast packet. */
+
+void silc_server_send_notify_ban(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ char *add, char *del)
+{
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_BAN, 3,
+ idp->data, idp->len,
+ add, add ? strlen(add) : 0,
+ del, del ? strlen(del) : 0);
+ silc_buffer_free(idp);
+}
+
+/* Sends INVITE notify type. This tells that invite has been either `add'ed
+ or `del'eted on the `channel. The sender of the invite is the `client_id'.
+ This function is used to send the packet between routers as broadcast
+ packet. */
+
+void silc_server_send_notify_invite(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ uint32 client_id_len,
+ char *add, char *del)
+{
+ SilcBuffer idp, idp2;
+
+ idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+ idp2 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_INVITE, 5,
+ idp->data, idp->len,
+ channel->channel_name, strlen(channel->channel_name),
+ idp2->data, idp2->len,
+ add, add ? strlen(add) : 0,
+ del, del ? strlen(del) : 0);
+ silc_buffer_free(idp);
+ silc_buffer_free(idp2);
+}
+
/* Sends notify message destined to specific entity. */
void silc_server_send_notify_dest(SilcServer server,
SilcSocketConnection sock,
+ int broadcast,
void *dest_id,
SilcIdType dest_id_type,
SilcNotifyType type,
- unsigned int argc, ...)
+ uint32 argc, ...)
{
va_list ap;
SilcBuffer packet;
}
/* Sends notify message to a channel. The notify message sent is
- distributed to all clients on the channel. If `router_notify' is TRUE
+ distributed to all clients on the channel. If `route_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. */
+ If FALSE it is assured that the notify is sent only locally. If `sender'
+ is provided then the packet is not sent to that connection since it
+ originally came from it. */
void silc_server_send_notify_to_channel(SilcServer server,
+ SilcSocketConnection sender,
SilcChannelEntry channel,
unsigned char route_notify,
SilcNotifyType type,
- unsigned int argc, ...)
+ uint32 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_server_packet_send_to_channel(server, sender, 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
+/* 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,
+ SilcClientEntry sender,
SilcClientEntry client,
SilcNotifyType type,
- unsigned int argc, ...)
+ uint32 argc, ...)
{
int k;
SilcSocketConnection sock = NULL;
SilcPacketContext packetdata;
SilcClientEntry c;
SilcClientEntry *sent_clients = NULL;
- unsigned int sent_clients_count = 0;
+ uint32 sent_clients_count = 0;
SilcServerEntry *routed = NULL;
- unsigned int routed_count = 0;
+ uint32 routed_count = 0;
SilcChannelEntry channel;
SilcChannelClientEntry chl, chl2;
SilcIDListData idata;
SilcBuffer packet;
unsigned char *data;
- unsigned int data_len;
+ uint32 data_len;
int force_send = FALSE;
va_list ap;
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) {
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)
continue;
}
+ if (c && c->router)
+ continue;
+
/* Send to locally connected client */
if (c) {
SilcSocketConnection sock,
int broadcast,
void *id, SilcIdType id_type,
- unsigned int id_len)
+ uint32 id_len)
{
SilcBuffer idp;
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. :) */
+/* 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_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_new_channel(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ char *channel_name,
+ void *channel_id,
+ uint32 channel_id_len,
+ uint32 mode)
{
SilcBuffer packet;
- unsigned char *oid;
- unsigned char *nid;
+ unsigned char *cid;
+ uint32 name_len = strlen(channel_name);
SILC_LOG_DEBUG(("Start"));
- oid = silc_id_id2str(old_id, old_id_type);
- if (!oid)
+ cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+ if (!cid)
return;
- nid = silc_id_id2str(new_id, new_id_type);
- if (!nid)
- return;
+ /* Encode the channel payload */
+ packet = silc_channel_payload_encode(channel_name, name_len,
+ cid, channel_id_len, mode);
- 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,
+ silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL,
broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
packet->data, packet->len, FALSE);
- silc_free(oid);
- silc_free(nid);
+
+ silc_free(cid);
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)
+/* Send Channel Key payload to distribute the new channel key. Normal server
+ sends this to router when new client joins to existing channel. Router
+ sends this to the local server who sent the join command in case where
+ the channel did not exist yet. Both normal and router servers uses this
+ also to send this to locally connected clients on the channel. This
+ must not be broadcasted packet. Routers do not send this to each other.
+ If `sender is provided then the packet is not sent to that connection since
+ it originally came from it. */
+
+void silc_server_send_channel_key(SilcServer server,
+ SilcSocketConnection sender,
+ SilcChannelEntry channel,
+ unsigned char route)
{
SilcBuffer packet;
- unsigned char *clid, *chid;
-
+ unsigned char *chid;
+ uint32 tmp_len;
+
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);
+
+ 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);
+
+ /* Encode channel key packet */
+ tmp_len = strlen(channel->channel_key->cipher->name);
+ packet = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, chid, tmp_len,
+ channel->channel_key->cipher->name,
+ channel->key_len / 8, channel->key);
+
+ silc_server_packet_send_to_channel(server, sender, channel,
+ SILC_PACKET_CHANNEL_KEY,
+ route, packet->data, packet->len, FALSE);
silc_buffer_free(packet);
+ silc_free(chid);
}
-/* 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. */
+/* Generic function to send any command. The arguments must be sent already
+ encoded into correct form in correct order. */
-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_command(SilcServer server,
+ SilcSocketConnection sock,
+ SilcCommand command,
+ uint32 argc, ...)
{
SilcBuffer packet;
- unsigned char *cid;
- unsigned int name_len = strlen(channel_name);
-
- SILC_LOG_DEBUG(("Start"));
+ va_list ap;
- cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
- if (!cid)
- return;
+ va_start(ap, argc);
- 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);
+ packet = silc_command_payload_encode_vap(command, 0, argc, ap);
+ silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+}
- silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL,
- broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
- packet->data, packet->len, FALSE);
+/* Send the heartbeat packet. */
- silc_free(cid);
- silc_buffer_free(packet);
+void silc_server_send_heartbeat(SilcServer server,
+ SilcSocketConnection sock)
+{
+ silc_server_packet_send(server, sock, SILC_PACKET_HEARTBEAT, 0,
+ NULL, 0, FALSE);
}
-/* 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. */
+/* 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_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)
+void silc_server_relay_packet(SilcServer server,
+ SilcSocketConnection dst_sock,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ SilcPacketContext *packet,
+ int force_send)
{
- SilcBuffer packet;
- unsigned char *clid, *chid;
+ silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
- SILC_LOG_DEBUG(("Start"));
+ 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, force_send);
- clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
- if (!clid)
- return;
+ silc_buffer_pull(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+}
- chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
- if (!chid)
- return;
+/* Routine used to send the connection authentication packet. */
+
+void silc_server_send_connection_auth_request(SilcServer server,
+ SilcSocketConnection sock,
+ uint16 conn_type,
+ SilcAuthMethod auth_meth)
+{
+ SilcBuffer packet;
- packet = silc_buffer_alloc(2 + 2 + channel_id_len + client_id_len);
+ packet = silc_buffer_alloc(4);
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_UI_SHORT(conn_type),
+ SILC_STR_UI_SHORT(auth_meth),
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_server_packet_send(server, sock, SILC_PACKET_CONNECTION_AUTH_REQUEST,
+ 0, packet->data, packet->len, FALSE);
silc_buffer_free(packet);
}