Cleaned up some SILC_LOG_DEBUG's in backup protocol code.
[crypto.git] / apps / silcd / server.c
index b622ed877185d31d0eb2eb623ad63222c8c66ab9..15c1263c6e1bc3b22a0588fa1d503cc3e9485646 100644 (file)
@@ -28,6 +28,7 @@
 #include "server_internal.h"
 
 /* Static prototypes */
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection);
 SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
 SILC_TASK_CALLBACK(silc_server_connect_router);
 SILC_TASK_CALLBACK(silc_server_connect_to_router);
@@ -448,6 +449,31 @@ bool silc_server_init(SilcServer server)
   return FALSE;
 }
 
+/* Task callback to close a socket connection after rehash */
+
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
+{
+  SilcServer server = context;
+  SilcSocketConnection sock = server->sockets[fd];
+
+  if (!sock)
+    return;
+
+  SILC_LOG_INFO(("Closing connection %s:%d [%s]: connection is unconfigured",
+                sock->hostname, sock->port,
+                (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                 sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                 sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                 "Router")));
+  silc_schedule_task_del_by_context(server->schedule, sock);
+  silc_server_disconnect_remote(server, sock,
+                               SILC_STATUS_ERR_BANNED_FROM_SERVER,
+                               "This connection is removed from "
+                               "configuration");
+  if (sock->user_data)
+    silc_server_free_sock_user_data(server, sock, NULL);
+}
+
 /* This function basically reads the config file again and switches the config
    object pointed by the server object. After that, we have to fix various
    things such as the server_name and the listening ports.
@@ -516,6 +542,70 @@ bool silc_server_rehash(SilcServer server)
     silc_pkcs_private_key_set(server->pkcs, server->private_key);
   }
 
+  /* Check for unconfigured server and router connections and close
+     connections that were unconfigured. */
+
+  if (server->config->routers) {
+    SilcServerConfigRouter *ptr;
+    SilcServerConfigRouter *newptr;
+    bool found;
+
+    for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+      found = FALSE;
+
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
+       if (!strcmp(newptr->host, ptr->host) && newptr->port == ptr->port &&
+           newptr->initiator == ptr->initiator) {
+         found = TRUE;
+         break;
+       }
+      }
+
+      if (!found) {
+       /* Remove this connection */
+       SilcSocketConnection sock;
+       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
+                                              ptr->host, ptr->port);
+       if (sock && !SILC_IS_LISTENER(sock))
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
+      }
+    }
+  }
+
+  if (server->config->servers) {
+    SilcServerConfigServer *ptr;
+    SilcServerConfigServer *newptr;
+    bool found;
+
+    for (ptr = server->config->servers; ptr; ptr = ptr->next) {
+      found = FALSE;
+
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
+       if (!strcmp(newptr->host, ptr->host)) {
+         found = TRUE;
+         break;
+       }
+      }
+
+      if (!found) {
+       /* Remove this connection */
+       SilcSocketConnection sock;
+       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
+                                              ptr->host, 0);
+       if (sock && !SILC_IS_LISTENER(sock))
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
+      }
+    }
+  }
+
   /* Go through all configured routers after rehash */
   silc_schedule_task_add(server->schedule, 0,
                         silc_server_connect_to_router,
@@ -892,14 +982,23 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_server_config_unref(&sconn->conn);
-    silc_free(sconn->remote_host);
-    silc_free(sconn->backup_replace_ip);
-    silc_free(sconn);
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, 
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add(server->schedule, 0,
+                            silc_server_connect_to_router_retry,
+                            sconn, 0, 1, SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+      return;
+    }
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
     return;
   }
 
@@ -923,14 +1022,23 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_server_config_unref(&sconn->conn);
-    silc_free(sconn->remote_host);
-    silc_free(sconn->backup_replace_ip);
-    silc_free(sconn);
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, 
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add(server->schedule, 0,
+                            silc_server_connect_to_router_retry,
+                            sconn, 0, 1, SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+      return;
+    }
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
     return;
   }
   silc_ske_free_key_material(ctx->keymat);
@@ -1049,6 +1157,16 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     silc_free(ctx->dest_id);
     silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
                                  NULL);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add(server->schedule, 0,
+                            silc_server_connect_to_router_retry,
+                            sconn, 0, 1, SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+      goto out2;
+    }
+
     goto out;
   }
 
@@ -1156,12 +1274,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server));
       silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
 
-#ifdef BACKUP_SINGLE_ROUTER
       /* If we are backup router then this primary router is whom we are
         backing up. */
       if (server->server_type == SILC_BACKUP_ROUTER)
        silc_server_backup_add(server, server->id_entry, sock->ip, 0, TRUE);
-#endif /* BACKUP_SINGLE_ROUTER */
     }
   } else {
     /* Add this server to be our backup router */
@@ -1187,6 +1303,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   if (sconn == server->router_conn)
     server->router_conn = NULL;
 
+ out2:
   /* Free the protocol object */
   if (sock->protocol == protocol)
     sock->protocol = NULL;
@@ -1601,12 +1718,30 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       SilcServerConfigServer *sconn = ctx->sconfig.ref_ptr;
       SilcServerConfigRouter *rconn = ctx->rconfig.ref_ptr;
 
+      /* If we are backup router and this is incoming server connection
+        and we do not have connection to primary router, do not allow
+        the connection. */
+      if (server->server_type == SILC_BACKUP_ROUTER &&
+         ctx->conn_type == SILC_SOCKET_TYPE_SERVER &&
+         !SILC_PRIMARY_ROUTE(server)) {
+       SILC_LOG_INFO(("Will not accept server connection because we do "
+                      "not have primary router connection established"));
+       silc_server_disconnect_remote(server, sock, 
+                                     SILC_STATUS_ERR_PERM_DENIED,
+                                     "We do not have connection to primary "
+                                     "router established, try later");
+       silc_free(sock->user_data);
+       server->stat.auth_failures++;
+       goto out;
+      }
+
       if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
        /* Verify whether this connection is after all allowed to connect */
        if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
                                            &server->config->param,
                                            rconn ? rconn->param : NULL,
                                            ctx->ske)) {
+         silc_free(sock->user_data);
          server->stat.auth_failures++;
          goto out;
        }
@@ -1631,6 +1766,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
                                            &server->config->param,
                                            sconn ? sconn->param : NULL,
                                            ctx->ske)) {
+         silc_free(sock->user_data);
          server->stat.auth_failures++;
          goto out;
        }
@@ -1680,15 +1816,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       }
       entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
 
-      /* Statistics */
-      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
-       server->stat.my_servers++;
-      } else {
-       server->stat.my_routers++;
-       server->stat.routers++;
-      }
-      server->stat.servers++;
-
       id_entry = (void *)new_server;
 
       /* If the incoming connection is router and marked as backup router
@@ -1704,6 +1831,15 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
        new_server->server_type = SILC_BACKUP_ROUTER;
       }
 
+      /* Statistics */
+      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
+       server->stat.my_servers++;
+      } else {
+       server->stat.my_routers++;
+       server->stat.routers++;
+      }
+      server->stat.servers++;
+
       /* Check whether this connection is to be our primary router connection
         if we do not already have the primary route. */
       if (!backup_router &&
@@ -2089,10 +2225,10 @@ void silc_server_packet_parse_type(SilcServer server,
        message = silc_memdup(packet->buffer->data + 1,
                              packet->buffer->len - 1);
 
-      SILC_LOG_ERROR(("Disconnected by %s (%s): %s (%d) %s", 
-                     sock->ip, sock->hostname,
-                     silc_get_status_message(status), status,
-                     message ? message : ""));
+      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s", 
+                    sock->ip, sock->hostname,
+                    silc_get_status_message(status), status,
+                    message ? message : ""));
       silc_free(message);
     }
     break;
@@ -2515,7 +2651,7 @@ void silc_server_create_connection(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_close_connection_final)
 {
-  silc_socket_free((SilcSocketConnection)context);
+  silc_socket_free(context);
 }
 
 /* Closes connection to socket connection */
@@ -2751,24 +2887,19 @@ void silc_server_free_sock_user_data(SilcServer server,
          server->standalone = TRUE;
          backup_router = NULL;
        } else {
-         SILC_LOG_INFO(("New primary router is backup router %s",
-                        backup_router->server_name));
-         SILC_LOG_DEBUG(("New primary router is backup router %s",
-                         backup_router->server_name));
-#ifdef BACKUP_SINGLE_ROUTER
          if (server->id_entry != backup_router) {
-#endif /* BACKUP_SINGLE_ROUTER */
+           SILC_LOG_INFO(("New primary router is backup router %s",
+                          backup_router->server_name));
            server->id_entry->router = backup_router;
            server->router = backup_router;
            server->router_connect = time(0);
            server->backup_primary = TRUE;
-#ifdef BACKUP_SINGLE_ROUTER
          } else {
+           SILC_LOG_INFO(("We are now new router in this cell"));
            server->id_entry->router = NULL;
            server->router = NULL;
            server->standalone = TRUE;
          }
-#endif /* BACKUP_SINGLE_ROUTER */
 
          if (server->server_type == SILC_BACKUP_ROUTER) {
            server->server_type = SILC_ROUTER;
@@ -2796,22 +2927,42 @@ void silc_server_free_sock_user_data(SilcServer server,
       }
 
       if (!backup_router) {
-       /* Free all client entries that this server owns as they will
-          become invalid now as well. */
-       if (user_data->id)
+       /* As router, remove clients and channels always.  As normal server
+          remove only if it is our primary router.  Other connections
+          may be backup routers and these normal server don't handle here. */
+       if (server->server_type != SILC_SERVER ||
+           server->standalone || sock == SILC_PRIMARY_ROUTE(server)) {
+         /* Free all client entries that this server owns as they will
+            become invalid now as well. */
          silc_server_remove_clients_by_server(server, user_data, TRUE);
-       if (server->server_type == SILC_SERVER)
-         silc_server_remove_channels_by_server(server, user_data);
+         if (server->server_type == SILC_SERVER)
+           silc_server_remove_channels_by_server(server, user_data);
+       }
       } else {
        /* Update the client entries of this server to the new backup
           router. This also removes the clients that *really* was owned
           by the primary router and went down with the router.  */
        silc_server_update_clients_by_server(server, user_data, backup_router,
                                             TRUE, TRUE);
-       silc_server_update_servers_by_server(server, user_data, backup_router);
+       silc_server_update_servers_by_server(server, user_data, backup_router,
+                                            TRUE);
        if (server->server_type == SILC_SERVER)
          silc_server_update_channels_by_server(server, user_data,
                                                backup_router);
+
+       /* Send notify about primary router going down to local operators */
+       if (server->backup_router)
+         SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+                                SILC_NOTIFY_TYPE_NONE,
+                                ("%s switched to backup router %s "
+                                 "(we are primary router now)",
+                                 server->server_name, server->server_name));
+       else
+         SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+                                SILC_NOTIFY_TYPE_NONE,
+                                ("%s switched to backup router %s",
+                                 server->server_name,
+                                 server->router->server_name));
       }
 
       /* Free the server entry */
@@ -2830,7 +2981,7 @@ void silc_server_free_sock_user_data(SilcServer server,
       if (server->server_type == SILC_ROUTER)
        server->stat.cell_servers--;
 
-      if (backup_router) {
+      if (backup_router && backup_router != server->id_entry) {
        /* Announce all of our stuff that was created about 5 minutes ago.
           The backup router knows all the other stuff already. */
        if (server->server_type == SILC_ROUTER)
@@ -3652,9 +3803,10 @@ static void silc_server_announce_get_clients(SilcServer server,
        silc_buffer_pull(*clients, idp->len);
 
        SILC_PUT32_MSB(client->mode, mode);
-       tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
-                                                2, idp->data, idp->len,
-                                                mode, 4);
+       tmp =
+         silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
+                                            2, idp->data, idp->len,
+                                            mode, 4);
        *umodes = silc_buffer_realloc(*umodes,
                                      (*umodes ?
                                       (*umodes)->truelen + tmp->len :