SilcIDListData idata = (SilcIDListData)sock->user_data;
SilcCipher cipher = NULL;
SilcHmac hmac = NULL;
+ uint32 sequence = 0;
unsigned char *dst_id_data = NULL;
uint32 dst_id_len = 0;
+ int block_len = 0;
/* If disconnecting, ignore the data */
if (SILC_IS_DISCONNECTING(sock))
dst_id_len = silc_id_get_len(dst_id, dst_id_type);
}
+ if (idata) {
+ cipher = idata->send_key;
+ hmac = idata->hmac_send;
+ sequence = idata->psn_send++;
+ block_len = silc_cipher_get_block_len(cipher);
+ }
+
/* Set the packet context pointers */
packetdata.type = type;
packetdata.flags = flags;
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.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
/* Prepare outgoing data buffer for packet sending */
silc_packet_send_prepare(sock,
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_send;
- }
+ silc_packet_assemble(&packetdata, cipher);
/* Encrypt the packet */
- silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+ silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
- SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+ SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence,
+ sock->outbuf->len),
sock->outbuf->data, sock->outbuf->len);
/* Now actually send the packet */
SilcIDListData idata;
SilcCipher cipher = NULL;
SilcHmac hmac = NULL;
+ uint32 sequence = 0;
unsigned char *dst_id_data = NULL;
uint32 dst_id_len = 0;
unsigned char *src_id_data = NULL;
uint32 src_id_len = 0;
+ int block_len = 0;
SILC_LOG_DEBUG(("Sending packet, type %d", type));
src_id_len = silc_id_get_len(src_id, src_id_type);
}
+ if (idata) {
+ cipher = idata->send_key;
+ hmac = idata->hmac_send;
+ sequence = idata->psn_send++;
+ block_len = silc_cipher_get_block_len(cipher);
+ }
+
/* Set the packet context pointers */
packetdata.type = type;
packetdata.flags = flags;
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.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
/* Prepare outgoing data buffer for packet sending */
silc_packet_send_prepare(sock,
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_send;
- }
+ silc_packet_assemble(&packetdata, cipher);
/* Encrypt the packet */
- silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+ silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
- SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+ SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence,
+ sock->outbuf->len),
sock->outbuf->data, sock->outbuf->len);
/* Now actually send the packet */
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_send,
+ silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
sock->outbuf, sock->outbuf->len);
- SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
+ SILC_LOG_HEXDUMP(("Broadcasted packet (%d), len %d", idata->psn_send - 1,
+ sock->outbuf->len),
sock->outbuf->data, sock->outbuf->len);
/* Now actually send the packet */
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_send,
+ silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
sock->outbuf, sock->outbuf->len);
- SILC_LOG_HEXDUMP(("Routed packet, len %d", sock->outbuf->len),
+ SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1,
+ sock->outbuf->len),
sock->outbuf->data, sock->outbuf->len);
/* Now actually send the packet */
silc_server_packet_send_real(server, sock, TRUE);
}
+/* This routine can be used to send a packet to table of clients provided
+ in `clients'. If `route' is FALSE the packet is routed only to local
+ clients (for server locally connected, and for router local cell). */
+
+void silc_server_packet_send_clients(SilcServer server,
+ SilcClientEntry *clients,
+ uint32 clients_count,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ bool route,
+ unsigned char *data,
+ uint32 data_len,
+ bool force_send)
+{
+ SilcSocketConnection sock = NULL;
+ SilcClientEntry client = NULL;
+ SilcServerEntry *routed = NULL;
+ uint32 routed_count = 0;
+ bool gone = FALSE;
+ int i, k;
+
+ SILC_LOG_DEBUG(("Sending packet to list of clients"));
+
+ /* Send to all clients in table */
+ for (i = 0; i < clients_count; i++) {
+ client = clients[i];
+
+ /* If client has router set it is not locally connected client and
+ 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->router &&
+ ((!route && client->router->router == server->id_entry) || route)) {
+
+ /* 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;
+
+ /* Route only once to router */
+ sock = (SilcSocketConnection)client->router->connection;
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ if (gone)
+ continue;
+ gone = TRUE;
+ }
+
+ /* Send the packet */
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->router->id, SILC_ID_SERVER,
+ data, data_len, force_send);
+
+ /* Mark this route routed already */
+ routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+ routed[routed_count++] = client->router;
+ continue;
+ }
+
+ if (client->router)
+ continue;
+
+ /* Send to locally connected client */
+ sock = (SilcSocketConnection)client->connection;
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+ }
+
+ silc_free(routed);
+}
+
/* 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
SilcPacketContext *packet,
SilcCipher cipher,
SilcHmac hmac,
+ uint32 sequence,
unsigned char *data,
uint32 data_len,
- int channel_message,
+ bool channel_message,
bool force_send)
{
+ int block_len;
+
+ if (!sock)
+ return;
+
packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
packet->src_id_len + packet->dst_id_len;
+ block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
+ if (channel_message)
+ packet->padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+ packet->src_id_len +
+ packet->dst_id_len), block_len);
+ else
+ packet->padlen = SILC_PACKET_PADLEN(packet->truelen, block_len);
+
/* Prepare outgoing data buffer for packet sending */
silc_packet_send_prepare(sock,
SILC_PACKET_HEADER_LEN +
is encrypted with normal session key shared with the client, unless
the `channel_message' is TRUE. */
silc_buffer_put(sock->outbuf, data, data_len);
- silc_packet_assemble(packet);
+ silc_packet_assemble(packet, cipher);
if (channel_message)
- silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
- packet->src_id_len + packet->dst_id_len +
- packet->padlen);
+ silc_packet_encrypt(cipher, hmac, sequence, 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_packet_encrypt(cipher, hmac, sequence, sock->outbuf,
+ sock->outbuf->len);
- SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+ SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence,
+ sock->outbuf->len),
sock->outbuf->data, sock->outbuf->len);
/* Now actually send the packet */
If `route' is FALSE then the packet is sent only locally and will not
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. */
+ originally came from it. If `send_to_clients' is FALSE then the
+ packet is not sent clients, only servers. */
void silc_server_packet_send_to_channel(SilcServer server,
SilcSocketConnection sender,
packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
packetdata.dst_id_type = SILC_ID_CHANNEL;
- 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. */
idata = (SilcIDListData)router;
if (sock != sender) {
- SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+ SILC_LOG_DEBUG(("Sending packet to router for routing"));
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key,
idata->hmac_send,
+ idata->psn_send++,
data, data_len, FALSE,
force_send);
}
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key,
idata->hmac_send,
+ idata->psn_send++,
data, data_len, FALSE,
force_send);
if (sender && sock == sender)
continue;
- /* Send the packet */
+ /* Send the packet */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key,
idata->hmac_send,
+ idata->psn_send++,
data, data_len, FALSE,
force_send);
}
+ silc_hash_table_list_reset(&htl);
silc_free(routed);
silc_free(packetdata.src_id);
silc_free(packetdata.dst_id);
packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
packetdata.dst_id_type = SILC_ID_CHANNEL;
- 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. */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key,
idata->hmac_send,
+ idata->psn_send++,
data, data_len, TRUE,
force_send);
}
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key,
idata->hmac_send,
+ idata->psn_send++,
data, data_len, TRUE,
force_send);
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key,
idata->hmac_send,
+ idata->psn_send++,
data, data_len, TRUE,
force_send);
}
+ silc_hash_table_list_reset(&htl);
silc_free(routed);
silc_free(packetdata.src_id);
silc_free(packetdata.dst_id);
force_send);
}
}
+ silc_hash_table_list_reset(&htl);
}
/* Routine used to send (relay, route) private messages to some destination.
SilcSocketConnection dst_sock,
SilcCipher cipher,
SilcHmac hmac,
+ uint32 sequence,
SilcPacketContext *packet)
{
SilcBuffer buffer = packet->buffer;
silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
/* Re-encrypt packet */
- silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
+ silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, buffer->len);
/* Send the packet */
silc_server_packet_send_real(server, dst_sock, FALSE);
silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
/* Encrypt header */
- silc_packet_encrypt(cipher, hmac, dst_sock->outbuf,
+ silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf,
SILC_PACKET_HEADER_LEN + packet->src_id_len +
packet->dst_id_len + packet->padlen);
void silc_server_send_motd(SilcServer server,
SilcSocketConnection sock)
{
- char *motd;
+ char *motd, *motd_file = NULL;
uint32 motd_len;
- if (server->config && server->config->motd &&
- server->config->motd->motd_file) {
+ if (server->config)
+ motd_file = server->config->server_info->motd_file;
- motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+ if (motd_file) {
+ motd = silc_file_readfile(motd_file, &motd_len);
if (!motd)
return;
SilcChannelEntry channel,
uint32 mode_mask,
void *id, SilcIdType id_type,
- char *cipher, char *hmac)
+ char *cipher, char *hmac,
+ char *passphrase)
{
SilcBuffer idp;
unsigned char mode[4];
silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
- 4, idp->data, idp->len,
+ 5, idp->data, idp->len,
mode, 4,
cipher, cipher ? strlen(cipher) : 0,
- hmac, hmac ? strlen(hmac) : 0);
+ hmac, hmac ? strlen(hmac) : 0,
+ passphrase, passphrase ?
+ strlen(passphrase) : 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
+ `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,
bool broadcast,
SilcClientID *client_id,
- char *message)
+ const char *message)
{
SilcBuffer idp;
silc_buffer_free(idp);
}
-/* Sends TOPIC_SET notify type. This tells that `client_id' changed
+/* Sends TOPIC_SET notify type. This tells that `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. */
SilcSocketConnection sock,
bool broadcast,
SilcChannelEntry channel,
- SilcClientID *client_id,
+ void *id, SilcIdType id_type,
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_TOPIC_SET,
- topic ? 2 : 1,
- idp->data, idp->len,
- topic, topic ? strlen(topic) : 0);
+ idp = silc_id_payload_encode(id, id_type);
+ silc_server_send_notify_dest(server, sock, broadcast,
+ (void *)channel->id, SILC_ID_CHANNEL,
+ SILC_NOTIFY_TYPE_TOPIC_SET,
+ topic ? 2 : 1,
+ idp->data, idp->len,
+ topic, topic ? strlen(topic) : 0);
silc_buffer_free(idp);
}
bool broadcast,
SilcChannelEntry channel,
SilcClientID *client_id,
+ SilcClientID *kicker,
char *comment)
{
- SilcBuffer idp;
+ SilcBuffer idp1;
+ SilcBuffer idp2;
- idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp2 = silc_id_payload_encode((void *)kicker, 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);
+ SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED, 3,
+ idp1->data, idp1->len,
+ comment, comment ? strlen(comment) : 0,
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
}
/* Send KILLED notify type. This tells that the `client_id' client was
void silc_server_send_notify_to_channel(SilcServer server,
SilcSocketConnection sender,
SilcChannelEntry channel,
- unsigned char route_notify,
+ bool route_notify,
SilcNotifyType type,
uint32 argc, ...)
{
/* Get data used in packet header encryption, keys and stuff. */
sock = (SilcSocketConnection)c->router->connection;
idata = (SilcIDListData)c->router;
-
+
+ {
+ SILC_LOG_DEBUG(("*****************"));
+ SILC_LOG_DEBUG(("client->router->id %s",
+ silc_id_render(c->router->id, SILC_ID_SERVER)));
+ SILC_LOG_DEBUG(("client->router->connection->user_data->id %s",
+ silc_id_render(((SilcServerEntry)sock->user_data)->id, SILC_ID_SERVER)));
+ }
+
packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
packetdata.dst_id_len = silc_id_get_len(c->router->id, SILC_ID_SERVER);
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_send,
+ idata->psn_send++,
data, data_len, FALSE,
force_send);
packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
packetdata.dst_id_len = silc_id_get_len(c->id, SILC_ID_CLIENT);
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_send,
+ idata->psn_send++,
data, data_len, FALSE,
force_send);
sent_clients[sent_clients_count++] = c;
}
}
+ silc_hash_table_list_reset(&htl2);
}
+ silc_hash_table_list_reset(&htl);
silc_free(routed);
silc_free(sent_clients);
silc_free(packetdata.src_id);
+ silc_buffer_free(packet);
va_end(ap);
}
}
/* 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. */
+ SILC network. Router uses this to notify other routers in the network
+ about new channel. This packet is broadcasted by router. */
void silc_server_send_new_channel(SilcServer server,
SilcSocketConnection sock,
/* Send to backup routers if this is being broadcasted to primary
router. */
- if (server->router && server->router->connection &&
+ if (server->server_type == SILC_ROUTER &&
+ server->router && server->router->connection &&
sock == server->router->connection && broadcast)
silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
packet->data, packet->len, FALSE, TRUE);
unsigned char *chid;
uint32 tmp_len;
- SILC_LOG_DEBUG(("Start"));
+ SILC_LOG_DEBUG(("Sending key to channel %s", channel->channel_name));
chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
if (!chid)
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);
+ route, packet->data, packet->len,
+ FALSE);
silc_buffer_free(packet);
silc_free(chid);
}
va_end(ap);
}
+/* Generic function to send any command reply. The arguments must be sent
+ already encoded into correct form in correct order. */
+
+void silc_server_send_command_reply(SilcServer server,
+ SilcSocketConnection sock,
+ SilcCommand command,
+ SilcCommandStatus status,
+ uint16 ident,
+ uint32 argc, ...)
+{
+ SilcBuffer packet;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ packet = silc_command_reply_payload_encode_vap(command, status, ident,
+ argc, ap);
+ silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+ va_end(ap);
+}
+
+/* Generic function to send any command reply. The arguments must be sent
+ already encoded into correct form in correct order. */
+
+void silc_server_send_dest_command_reply(SilcServer server,
+ SilcSocketConnection sock,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ SilcCommand command,
+ SilcCommandStatus status,
+ uint16 ident,
+ uint32 argc, ...)
+{
+ SilcBuffer packet;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ packet = silc_command_reply_payload_encode_vap(command, status, ident,
+ argc, ap);
+ silc_server_packet_send_dest(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+ dst_id, dst_id_type, packet->data,
+ packet->len, TRUE);
+ silc_buffer_free(packet);
+ va_end(ap);
+}
+
/* Send the heartbeat packet. */
void silc_server_send_heartbeat(SilcServer server,
SilcSocketConnection dst_sock,
SilcCipher cipher,
SilcHmac hmac,
+ uint32 sequence,
SilcPacketContext *packet,
bool force_send)
{
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);
+ silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf,
+ packet->buffer->len);
/* Send the packet */
silc_server_packet_send_real(server, dst_sock, force_send);