updates.
[silc.git] / apps / silcd / packet_receive.c
index 0bb1ddd3e51740e8b05ddb702bf535e7c1f93b44..f09bccb6dc4d7910c847e52d2d79001dc20ec545 100644 (file)
@@ -71,11 +71,13 @@ void silc_server_notify(SilcServer server,
     if (dst_sock)
       /* Relay the packet */
       silc_server_relay_packet(server, dst_sock, idata->send_key,
-                              idata->hmac_receive, packet, TRUE);
+                              idata->hmac_receive, idata->psn_send++,
+                              packet, TRUE);
   }
 
   /* Parse the Notify Payload */
-  payload = silc_notify_payload_parse(packet->buffer);
+  payload = silc_notify_payload_parse(packet->buffer->data,
+                                     packet->buffer->len);
   if (!payload)
     return;
 
@@ -194,8 +196,10 @@ void silc_server_notify(SilcServer server,
       break;
 
     /* Do not add client to channel if it is there already */
-    if (silc_server_client_on_channel(client, channel))
+    if (silc_server_client_on_channel(client, channel)) {
+      SILC_LOG_DEBUG(("Client already on channel"));
       break;
+    }
 
     /* Send to channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
@@ -508,10 +512,11 @@ void silc_server_notify(SilcServer server,
 
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
+                    channel->key_len / 8, 
                     hash);
       silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
 
@@ -823,6 +828,48 @@ void silc_server_notify(SilcServer server,
       server_entry = silc_idlist_find_server_by_id(server->local_list, 
                                                   server_id, TRUE, NULL);
       if (!server_entry) {
+       /* If we are normal server then we might not have the server. Check
+          whether router was kind enough to send the list of all clients
+          that actually was to be removed. Remove them if the list is
+          available. */
+       if (server->server_type != SILC_ROUTER &&
+           silc_argument_get_arg_num(args) > 1) {
+         int i;
+
+         for (i = 1; i < silc_argument_get_arg_num(args); i++) {
+           /* Get Client ID */
+           tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
+           if (!tmp)
+             continue;
+           client_id = silc_id_payload_parse_id(tmp, tmp_len);
+           if (!client_id)
+             continue;
+
+           /* Get client entry */
+           client = silc_idlist_find_client_by_id(server->global_list, 
+                                                  client_id, TRUE, &cache);
+           if (!client) {
+             client = silc_idlist_find_client_by_id(server->local_list, 
+                                                    client_id, TRUE, &cache);
+             if (!client) {
+               silc_free(client_id);
+               continue;
+             }
+           }
+           silc_free(client_id);
+
+           /* Remove the client from all channels. */
+           silc_server_remove_from_channels(server, NULL, client, 
+                                            TRUE, NULL, FALSE);
+           
+           client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+           cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+           server->stat.clients--;
+           if (server->server_type == SILC_ROUTER)
+             server->stat.cell_clients--;
+         }
+       }
+
        silc_free(server_id);
        goto out;
       }
@@ -1144,21 +1191,32 @@ void silc_server_private_message(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   if (packet->src_id_type != SILC_ID_CLIENT ||
-      packet->dst_id_type != SILC_ID_CLIENT)
-    return;
-
-  if (!packet->dst_id)
+      packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id)
     return;
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
                                          packet->dst_id_len, NULL, &idata);
-  if (!dst_sock)
+  if (!dst_sock) {
+    /* Send IDENTIFY command reply with error status to indicate that
+       such destination ID does not exist or is invalid */
+    SilcBuffer idp = silc_id_payload_encode_data(packet->dst_id,
+                                                packet->dst_id_len,
+                                                packet->dst_id_type);
+    if (!idp)
+      return;
+
+    silc_server_send_command_reply(server, sock, SILC_COMMAND_IDENTIFY,
+                                  SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0, 1,
+                                  2, idp, idp->len);
+    silc_buffer_free(idp);
     return;
+  }
 
   /* Send the private message */
   silc_server_send_private_message(server, dst_sock, idata->send_key,
-                                  idata->hmac_send, packet);
+                                  idata->hmac_send, idata->psn_send++,
+                                  packet);
 }
 
 /* Received private message key packet.. This packet is never for us. It is to
@@ -1190,7 +1248,7 @@ void silc_server_private_message_key(SilcServer server,
 
   /* Relay the packet */
   silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac_send, packet, FALSE);
+                          idata->hmac_send, idata->psn_send++, packet, FALSE);
 }
 
 /* Processes incoming command reply packet. The command reply packet may
@@ -1254,8 +1312,8 @@ void silc_server_command_reply(SilcServer server,
     idata = (SilcIDListData)client;
     
     /* Encrypt packet */
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, dst_sock->outbuf, 
-                       buffer->len);
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
+                       dst_sock->outbuf, buffer->len);
     
     /* Send the packet */
     silc_server_packet_send_real(server, dst_sock, TRUE);
@@ -1275,6 +1333,7 @@ void silc_server_channel_message(SilcServer server,
   SilcChannelID *id = NULL;
   void *sender = NULL;
   void *sender_entry = NULL;
+  bool local = TRUE;
 
   SILC_LOG_DEBUG(("Processing channel message"));
 
@@ -1306,14 +1365,25 @@ void silc_server_channel_message(SilcServer server,
   if (packet->src_id_type == SILC_ID_CLIENT) {
     sender_entry = silc_idlist_find_client_by_id(server->local_list, 
                                                 sender, TRUE, NULL);
-    if (!sender_entry)
+    if (!sender_entry) {
+      local = FALSE;
       sender_entry = silc_idlist_find_client_by_id(server->global_list, 
                                                   sender, TRUE, NULL);
+    }
     if (!sender_entry || !silc_server_client_on_channel(sender_entry, 
                                                        channel)) {
       SILC_LOG_DEBUG(("Client not on channel"));
       goto out;
     }
+
+    /* If the packet is coming from router, but the client entry is
+       local entry to us then some router is rerouting this to us and it is
+       not allowed. */
+    if (server->server_type == SILC_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_ROUTER && local) {
+      SILC_LOG_DEBUG(("Channel message rerouted to the sender, drop it"));
+      goto out;
+    }
   }
 
   /* Distribute the packet to our local clients. This will send the
@@ -1374,6 +1444,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SilcClientID *client_id;
   SilcBuffer reply;
   SilcIDListData idata;
+  SilcIDCacheEntry id_cache = NULL;
   char *username = NULL, *realname = NULL, *id_string;
   uint32 id_len;
   int ret;
@@ -1389,7 +1460,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   client = (SilcClientEntry)sock->user_data;
   idata = (SilcIDListData)client;
 
-  /* Remove the old cache entry */
+  /* Remove the old cache entry. */
   if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
     SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
@@ -1616,12 +1687,13 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                                       SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
-  SilcServerEntry new_server;
+  SilcServerEntry new_server, server_entry;
   SilcServerID *server_id;
   SilcIDListData idata;
   unsigned char *server_name, *id_string;
   uint16 id_len, name_len;
   int ret;
+  bool local = TRUE;
 
   SILC_LOG_DEBUG(("Creating new server"));
 
@@ -1634,7 +1706,10 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   idata = (SilcIDListData)new_server;
 
   /* Remove the old cache entry */
-  silc_idcache_del_by_context(server->local_list->servers, new_server);
+  if (!silc_idcache_del_by_context(server->local_list->servers, new_server)) {
+    silc_idcache_del_by_context(server->global_list->servers, new_server);
+    local = FALSE;
+  }
 
   /* Parse the incoming packet */
   ret = silc_buffer_unformat(buffer,
@@ -1668,13 +1743,29 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   }
   silc_free(id_string);
 
+  /* Check that we do not have this ID already */
+  server_entry = silc_idlist_find_server_by_id(server->local_list, 
+                                              server_id, TRUE, NULL);
+  if (server_entry) {
+    silc_idcache_del_by_context(server->local_list->servers, server_entry);
+  } else {
+    server_entry = silc_idlist_find_server_by_id(server->global_list, 
+                                                server_id, TRUE, NULL);
+    if (server_entry) 
+      silc_idcache_del_by_context(server->global_list->servers, server_entry);
+  }
+
   /* Update server entry */
   idata->status |= SILC_IDLIST_STATUS_REGISTERED;
   new_server->server_name = server_name;
   new_server->id = server_id;
+  
+  SILC_LOG_DEBUG(("New server id(%s)",
+                 silc_id_render(server_id, SILC_ID_SERVER)));
 
   /* Add again the entry to the ID cache. */
-  silc_idcache_add(server->local_list->servers, server_name, server_id, 
+  silc_idcache_add(local ? server->local_list->servers : 
+                  server->global_list->servers, server_name, server_id, 
                   new_server, FALSE);
 
   /* Distribute the information about new server in the SILC network
@@ -1700,7 +1791,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
     SilcBuffer packet = silc_buffer_alloc(2);
     silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
     silc_buffer_format(packet,
-                      SILC_STR_UI_CHAR(20),
+                      SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_REPLACED),
                       SILC_STR_UI_CHAR(0),
                       SILC_STR_END);
     silc_server_packet_send(server, sock, 
@@ -1708,9 +1799,17 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                            packet->data, packet->len, TRUE);
     silc_buffer_free(packet);
 
-    /* Mark the server disabled. The data sent earlier will go but nothing
+    /* Mark the router disabled. The data sent earlier will go but nothing
        after this does not go to this connection. */
     idata->status |= SILC_IDLIST_STATUS_DISABLED;
+  } else {
+    /* If it is router announce our stuff to it. */
+    if (sock->type == SILC_SOCKET_TYPE_ROUTER && 
+       server->server_type == SILC_ROUTER) {
+      silc_server_announce_servers(server, FALSE, 0, sock);
+      silc_server_announce_clients(server, 0, sock);
+      silc_server_announce_channels(server, 0, sock);
+    }
   }
 
   return new_server;
@@ -1726,7 +1825,7 @@ static void silc_server_new_id_real(SilcServer server,
 {
   SilcBuffer buffer = packet->buffer;
   SilcIDList id_list;
-  SilcServerEntry router;
+  SilcServerEntry router, server_entry;
   SilcSocketConnection router_sock;
   SilcIDPayload idp;
   SilcIdType id_type;
@@ -1739,31 +1838,38 @@ static void silc_server_new_id_real(SilcServer server,
       packet->src_id_type != SILC_ID_SERVER)
     return;
 
-  idp = silc_id_payload_parse(buffer);
+  idp = silc_id_payload_parse(buffer->data, buffer->len);
   if (!idp)
     return;
 
   id_type = silc_id_payload_get_type(idp);
 
   /* Normal server cannot have other normal server connections */
-  if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER)
+  server_entry = (SilcServerEntry)sock->user_data;
+  if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER &&
+      server_entry->server_type == SILC_SERVER)
     goto out;
 
   id = silc_id_payload_get_id(idp);
   if (!id)
     goto out;
 
-  if (sock->type == SILC_SOCKET_TYPE_SERVER)
-    id_list = server->local_list;
-  else
-    id_list = server->global_list;
-
   /* If the packet is coming from server then use the sender as the
      origin of the the packet. If it came from router then check the real
      sender of the packet and use that as the origin. */
   if (sock->type == SILC_SOCKET_TYPE_SERVER) {
+    id_list = server->local_list;
     router_sock = sock;
     router = sock->user_data;
+
+    /* If the sender is backup router and ID is server (and we are not
+       backup router) then switch the entry to global list. */
+    if (server_entry->server_type == SILC_BACKUP_ROUTER && 
+       id_type == SILC_ID_SERVER && 
+       server->id_entry->server_type != SILC_BACKUP_ROUTER) {
+      id_list = server->global_list;
+      router_sock = server->router ? server->router->connection : sock;
+    }
   } else {
     void *sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
                                     packet->src_id_type);
@@ -1776,6 +1882,7 @@ static void silc_server_new_id_real(SilcServer server,
     if (!router)
       goto out;
     router_sock = sock;
+    id_list = server->global_list;
   }
 
   switch(id_type) {
@@ -1997,6 +2104,7 @@ void silc_server_new_channel(SilcServer server,
   unsigned char *id;
   uint32 id_len;
   uint32 mode;
+  SilcServerEntry server_entry;
   SilcChannelEntry channel;
 
   SILC_LOG_DEBUG(("Processing New Channel"));
@@ -2007,7 +2115,8 @@ void silc_server_new_channel(SilcServer server,
     return;
 
   /* Parse the channel payload */
-  payload = silc_channel_payload_parse(packet->buffer);
+  payload = silc_channel_payload_parse(packet->buffer->data,
+                                      packet->buffer->len);
   if (!payload)
     return;
     
@@ -2024,6 +2133,8 @@ void silc_server_new_channel(SilcServer server,
 
   id = silc_channel_get_id(payload, &id_len);
 
+  server_entry = (SilcServerEntry)sock->user_data;
+
   if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
     /* Add the channel to global list as it is coming from router. It 
        cannot be our own channel as it is coming from router. */
@@ -2066,7 +2177,8 @@ void silc_server_new_channel(SilcServer server,
         on the router's IP address.  Check whether the ID is based in our
         IP and if it is not then create a new ID and enforce the server
         to switch the ID. */
-      if (!SILC_ID_COMPARE(channel_id, server->id, server->id->ip.data_len)) {
+      if (server_entry->server_type != SILC_BACKUP_ROUTER &&
+         !SILC_ID_COMPARE(channel_id, server->id, server->id->ip.data_len)) {
        SilcChannelID *tmp;
        SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
        
@@ -2108,9 +2220,6 @@ void silc_server_new_channel(SilcServer server,
         We also create a new key for the channel. */
       SilcBuffer users = NULL, users_modes = NULL;
 
-      if (!channel->id)
-       channel->id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
-
       if (!SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
        /* They don't match, send CHANNEL_CHANGE notify to the server to
           force the ID change. */
@@ -2289,7 +2398,8 @@ void silc_server_key_agreement(SilcServer server,
 
   /* Relay the packet */
   silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac_send, packet, FALSE);
+                          idata->hmac_send, idata->psn_send++,
+                          packet, FALSE);
 }
 
 /* Received connection auth request packet that is used during connection
@@ -2375,3 +2485,36 @@ void silc_server_rekey(SilcServer server,
     /* Run the protocol */
     silc_protocol_execute(protocol, server->schedule, 0, 0);
 }
+
+/* Received file transger packet. This packet is never for us. It is to
+   the client in the packet's destination ID. Sending of this sort of packet
+   equals sending private message, ie. it is sent point to point from
+   one client to another. */
+
+void silc_server_ftp(SilcServer server,
+                    SilcSocketConnection sock,
+                    SilcPacketContext *packet)
+{
+  SilcSocketConnection dst_sock;
+  SilcIDListData idata;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (packet->src_id_type != SILC_ID_CLIENT ||
+      packet->dst_id_type != SILC_ID_CLIENT)
+    return;
+
+  if (!packet->dst_id)
+    return;
+
+  /* Get the route to the client */
+  dst_sock = silc_server_get_client_route(server, packet->dst_id,
+                                         packet->dst_id_len, NULL, &idata);
+  if (!dst_sock)
+    return;
+
+  /* Relay the packet */
+  silc_server_relay_packet(server, dst_sock, idata->send_key,
+                          idata->hmac_send, idata->psn_send++,
+                          packet, FALSE);
+}