updates.
[silc.git] / apps / silcd / packet_send.c
index 8a9511ddce1f3071a762c0032f04f4652057085e..814758b82a4806190b4805b4d2bcf4f8c8657f98 100644 (file)
 #include "serverincludes.h"
 #include "server_internal.h"
 
-/* Internal context that holds the packet data and packet sending function
-   callbacks when the packet is sent with timeout.  This is used when
-   the server is performing re-key protocol.  During re-key we will prevent
-   sending of any other than re-key packets so that the packets would not
-   be encrypted with wrong keys.  Other than that, this is not used at all. */
-typedef struct {
-  
-} *SilcServerSendPacket;
-
 /* Routine that sends packet or marks packet to be sent. This is used
    directly only in special cases. Normal cases should use
    silc_server_packet_send. Returns < 0 error. */
@@ -44,6 +35,11 @@ int silc_server_packet_send_real(SilcServer server,
 {
   int ret;
 
+  /* If rekey protocol is active we must assure that all packets are
+     sent through packet queue. */
+  if (SILC_SERVER_IS_REKEY(sock))
+    force_send = FALSE;
+
   /* Send the packet */
   ret = silc_packet_send(sock, force_send);
   if (ret != -2)
@@ -170,7 +166,7 @@ void silc_server_packet_send_dest(SilcServer server,
 
   if (idata) {
     cipher = idata->send_key;
-    hmac = idata->hmac;
+    hmac = idata->hmac_send;
   }
 
   /* Encrypt the packet */
@@ -266,7 +262,7 @@ void silc_server_packet_send_srcdest(SilcServer server,
 
   if (idata) {
     cipher = idata->send_key;
-    hmac = idata->hmac;
+    hmac = idata->hmac_send;
   }
 
   /* Encrypt the packet */
@@ -308,7 +304,7 @@ void silc_server_packet_broadcast(SilcServer server,
     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, 
+    silc_packet_encrypt(idata->send_key, idata->hmac_send
                        sock->outbuf, sock->outbuf->len);
 
     SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
@@ -342,7 +338,7 @@ void silc_server_packet_route(SilcServer server,
   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, 
+  silc_packet_encrypt(idata->send_key, idata->hmac_send
                      sock->outbuf, sock->outbuf->len);
 
   SILC_LOG_HEXDUMP(("Routed packet, len %d", sock->outbuf->len),
@@ -459,7 +455,8 @@ void silc_server_packet_send_to_channel(SilcServer server,
       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, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, FALSE, 
                                              force_send);
     }
@@ -493,7 +490,8 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, FALSE, 
                                              force_send);
 
@@ -522,7 +520,8 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, FALSE, 
                                              force_send);
     }
@@ -534,6 +533,50 @@ void silc_server_packet_send_to_channel(SilcServer server,
   silc_free(packetdata.dst_id);
 }
 
+/* This checks whether the relayed packet came from router. If it did
+   then we'll need to encrypt it with the channel key. This is called
+   from the silc_server_packet_relay_to_channel. */
+
+static void
+silc_server_packet_relay_to_channel_encrypt(SilcServer server,
+                                           SilcSocketConnection sock,
+                                           SilcChannelEntry channel,
+                                           unsigned char *data,
+                                           unsigned int data_len)
+{
+  /* If we are router and the packet came from router and private key
+     has not been set for the channel then we must encrypt the packet
+     as it was decrypted with the session key shared between us and the
+     router which sent it. This is so, because cells does not share the
+     same channel key. */
+  if (server->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_ROUTER &&
+      !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) &&
+      channel->channel_key) {
+    SilcBuffer chp;
+    uint32 iv_len, i;
+    uint16 data_len, flags;
+
+    iv_len = silc_cipher_get_block_len(channel->channel_key);
+    if (channel->iv[0] == '\0')
+      for (i = 0; i < iv_len; i++) channel->iv[i] = 
+                                    silc_rng_get_byte(server->rng);
+    else
+      silc_hash_make(server->md5hash, channel->iv, iv_len, channel->iv);
+    
+    /* Encode new payload. This encrypts it also. */
+    SILC_GET16_MSB(flags, data);
+    SILC_GET16_MSB(data_len, data + 2);
+    chp = silc_channel_message_payload_encode(flags, data_len, 
+                                             data + 4,
+                                             iv_len, channel->iv,
+                                             channel->channel_key,
+                                             channel->hmac);
+    memcpy(data, chp->data, chp->len);
+    silc_buffer_free(chp);
+  }
+}
+
 /* This routine is explicitly used to relay messages to some channel.
    Packets sent with this function we have received earlier and are
    totally encrypted. This just sends the packet to all clients on
@@ -548,11 +591,12 @@ void silc_server_packet_relay_to_channel(SilcServer server,
                                         SilcChannelEntry channel,
                                         void *sender, 
                                         SilcIdType sender_type,
+                                        void *sender_entry,
                                         unsigned char *data,
                                         uint32 data_len,
                                         int force_send)
 {
-  int found = FALSE;
+  bool found = FALSE;
   SilcSocketConnection sock = NULL;
   SilcPacketContext packetdata;
   SilcClientEntry client = NULL;
@@ -576,6 +620,14 @@ void silc_server_packet_relay_to_channel(SilcServer server,
                                          packetdata.src_id_len +
                                          packetdata.dst_id_len));
 
+  /* This encrypts the packet, if needed. It will be encrypted if
+     it came from the router thus it needs to be encrypted with the
+     channel key. If the channel key does not exist, then we know we
+     don't have a single local user on the channel. */
+  silc_server_packet_relay_to_channel_encrypt(server, sender_sock,
+                                             channel, data,
+                                             data_len);
+
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
   if (server->server_type == SILC_SERVER && !server->standalone &&
@@ -594,7 +646,8 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       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, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, TRUE, 
                                              force_send);
     }
@@ -608,7 +661,8 @@ void silc_server_packet_relay_to_channel(SilcServer server,
     if (client) {
 
       /* If sender is one on the channel do not send it the packet. */
-      if (!found && !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
+      if (!found && sender_type == SILC_ID_CLIENT &&
+         !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
        found = TRUE;
        continue;
       }
@@ -636,6 +690,13 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        sock = (SilcSocketConnection)client->router->connection;
        idata = (SilcIDListData)client->router;
 
+       /* Do not send to the sender. Check first whether the true
+          sender's router is same as this client's router. Also check
+          if the sender socket is the same as this client's router
+          socket. */
+       if (sender_entry && 
+           ((SilcClientEntry)sender_entry)->router == client->router)
+         continue;
        if (sender_sock && sock == sender_sock)
          continue;
 
@@ -664,7 +725,11 @@ void silc_server_packet_relay_to_channel(SilcServer server,
            memcpy(tmp, data, data_len);
 
            /* Decrypt the channel message (we don't check the MAC) */
-           if (!silc_channel_message_payload_decrypt(tmp, data_len, 
+           /* XXX this could be optimized and removed all together by
+              taking a copy of the original data before encrypting it
+              and thus would not required decrypting. */
+           if (channel->channel_key &&
+               !silc_channel_message_payload_decrypt(tmp, data_len, 
                                                      channel->channel_key,
                                                      NULL)) {
              memset(tmp, 0, data_len);
@@ -693,10 +758,11 @@ void silc_server_packet_relay_to_channel(SilcServer server,
          }
          continue;
        }
-  
+
        /* Send the packet (to normal server) */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, idata->hmac, 
+                                               idata->send_key, 
+                                               idata->hmac_send, 
                                                data, data_len, TRUE, 
                                                force_send);
 
@@ -719,7 +785,8 @@ void silc_server_packet_relay_to_channel(SilcServer server,
 
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, idata->hmac, 
+                                             idata->send_key, 
+                                             idata->hmac_send, 
                                              data, data_len, TRUE, 
                                              force_send);
     }
@@ -864,7 +931,8 @@ void silc_server_send_notify(SilcServer server,
   va_start(ap, argc);
 
   packet = silc_notify_payload_encode(type, argc, ap);
-  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, 
+  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 }
@@ -882,7 +950,8 @@ void silc_server_send_notify_args(SilcServer server,
   SilcBuffer packet;
 
   packet = silc_notify_payload_encode_args(type, argc, args);
-  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, 
+  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 }
@@ -1008,15 +1077,15 @@ void silc_server_send_notify_cumode(SilcServer server,
                                    int broadcast,
                                    SilcChannelEntry channel,
                                    uint32 mode_mask,
-                                   SilcClientID *client_id,
-                                   uint32 client_id_len,
+                                   void *id, SilcIdType id_type,
+                                   uint32 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);
+  idp1 = silc_id_payload_encode((void *)id, id_type);
   idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT);
   SILC_PUT32_MSB(mode_mask, mode);
 
@@ -1331,7 +1400,8 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, idata->hmac, 
+                                               idata->send_key, 
+                                               idata->hmac_send, 
                                                data, data_len, FALSE, 
                                                force_send);
        
@@ -1366,7 +1436,8 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, idata->hmac, 
+                                               idata->send_key, 
+                                               idata->hmac_send, 
                                                data, data_len, FALSE, 
                                                force_send);