From c4404f118fffc9777f5e2166ef22dc720e16d571 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 24 Jun 2002 18:55:39 +0000 Subject: [PATCH] Added silc_server_send_opers[_notify] to send packets to operators. Fixed UMODE_CHANGE notify handling. Fixed backup router issues after resuming protocol is completed. Connections that were unconfigured in rehash are now closed automatically. --- CHANGES | 26 ++++++ TODO | 4 - apps/silcd/packet_receive.c | 6 -- apps/silcd/packet_send.c | 180 ++++++++++++++++++++++++++++++++++++ apps/silcd/packet_send.h | 14 ++- apps/silcd/server.c | 104 +++++++++++++++++++++ apps/silcd/server.h | 11 ++- apps/silcd/server_backup.c | 11 ++- apps/silcd/server_util.c | 109 ++++++++++++++-------- apps/silcd/server_util.h | 12 ++- 10 files changed, 423 insertions(+), 54 deletions(-) diff --git a/CHANGES b/CHANGES index 837f2525..b7f4ad81 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,29 @@ +Mon Jun 24 17:47:52 EEST 2002 Pekka Riikonen + + * Added functions silc_server_send_opers and + silc_server_send_opers_notify to send packets stricly + to operators. Added macro SILC_SERVER_SEND_OPERS macro + to send variable argument notify to operators. + Affected files silcd/packet_send.[ch] and silcd/server.h. + + * Removed UMODE rights checking with UMODE_CHANGE notify. + Affected file silcd/packet_receive.c. + + * Server/router operator now receives notify when network + switches to backup router and when it resumes the use of + primary router. Affected file silcd/server.c and + silcd/server_backup.c. + + * Fixed the updating of client information after backup + resuming protocol is over; update all except local clients + to the new primary router. The affected file is + silcd/server_util.c. + + * Added support for closing active connections in rehash + that were unconfigured by the user. Supports currently + closing server and router connections. Affected file + silcd/server.c. + Sun Jun 23 17:32:31 EEST 2002 Pekka Riikonen * Don't do SILC_STRING_LANGUAGE encoding if the outbuffer diff --git a/TODO b/TODO index 71863c8a..0c4fa20d 100644 --- a/TODO +++ b/TODO @@ -35,10 +35,6 @@ TODO/bugs In SILC Server cell use it. When primary goes down, also those that are not using it (are not connected locally) are signoffed. - o Configure use of backup router on normal server using HUP. - - o Configure use of backup router on router using HUP. - o Rewrite SILC_LOG_DEBUG's in silcd/server_backup.c. o Testing diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index a9f3f267..4abfcfb8 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -1551,12 +1551,6 @@ void silc_server_notify(SilcServer server, goto out; SILC_GET32_MSB(mode, tmp); - /* Check that mode changing is allowed. */ - if (!silc_server_check_umode_rights(server, client, mode)) { - SILC_LOG_DEBUG(("UMODE change is not allowed")); - goto out; - } - /* Remove internal resumed flag if client is marked detached now */ if (mode & SILC_UMODE_DETACHED) client->data.status &= ~SILC_IDLIST_STATUS_RESUMED; diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 818ec0f0..5a60a9f9 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -1911,3 +1911,183 @@ void silc_server_packet_queue_purge(SilcServer server, silc_buffer_clear(sock->outbuf); } } + +/* Send packet to clients that are known to be operators. If server + is router and `route' is TRUE then the packet would go to all operators + in the SILC network. If `route' is FALSE then only local operators + (local for server and cell wide for router). If `local' is TRUE then + only locally connected operators receive the packet. If `local' is + TRUE then `route' is ignored. If server is normal server and `route' + is FALSE it is equivalent to `local' being TRUE. */ + +void silc_server_send_opers(SilcServer server, + SilcPacketType type, + SilcPacketFlags flags, + bool route, bool local, + unsigned char *data, + SilcUInt32 data_len, + bool force_send) +{ + SilcIDCacheList list = NULL; + SilcIDCacheEntry id_cache = NULL; + SilcClientEntry client = NULL; + SilcSocketConnection sock; + SilcServerEntry *routed = NULL; + SilcUInt32 routed_count = 0; + bool gone = FALSE; + int k; + + SILC_LOG_DEBUG(("Sending %s packet to operators", + silc_get_packet_name(type))); + + /* If local was requested send only locally connected operators. */ + if (local || (server->server_type == SILC_SERVER && !route)) { + if (!silc_idcache_get_all(server->local_list->clients, &list) || + !silc_idcache_list_first(list, &id_cache)) + return; + while (id_cache) { + client = (SilcClientEntry)id_cache->context; + if (!client->router && SILC_IS_LOCAL(client) && + (client->mode & SILC_UMODE_SERVER_OPERATOR || + client->mode & SILC_UMODE_ROUTER_OPERATOR)) { + + /* Send the packet to locally connected operator */ + silc_server_packet_send_dest(server, client->connection, type, flags, + client->id, SILC_ID_CLIENT, + data, data_len, force_send); + } + + if (!silc_idcache_list_next(list, &id_cache)) + break; + } + silc_idcache_list_free(list); + return; + } + + if (!silc_idcache_get_all(server->local_list->clients, &list) || + !silc_idcache_list_first(list, &id_cache)) + return; + while (id_cache) { + client = (SilcClientEntry)id_cache->context; + if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) && + !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) + goto next; + + if (server->server_type != SILC_SERVER && 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) + goto next; + + /* Route only once to router */ + sock = (SilcSocketConnection)client->router->connection; + if (sock->type == SILC_SOCKET_TYPE_ROUTER) { + if (gone) + goto next; + gone = TRUE; + } + + /* Send the packet */ + silc_server_packet_send_dest(server, sock, type, flags, + client->id, SILC_ID_CLIENT, + data, data_len, force_send); + + /* Mark this route routed already */ + routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1)); + routed[routed_count++] = client->router; + goto next; + } + + if (client->router || !client->connection) + goto next; + + /* 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); + + next: + if (!silc_idcache_list_next(list, &id_cache)) + break; + } + silc_idcache_list_free(list); + + if (!silc_idcache_get_all(server->global_list->clients, &list) || + !silc_idcache_list_first(list, &id_cache)) + return; + while (id_cache) { + client = (SilcClientEntry)id_cache->context; + if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) && + !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) + goto nextg; + + if (server->server_type != SILC_SERVER && 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) + goto nextg; + + /* Route only once to router */ + sock = (SilcSocketConnection)client->router->connection; + if (sock->type == SILC_SOCKET_TYPE_ROUTER) { + if (gone) + goto nextg; + gone = TRUE; + } + + /* Send the packet */ + silc_server_packet_send_dest(server, sock, type, flags, + client->id, SILC_ID_CLIENT, + data, data_len, force_send); + + /* Mark this route routed already */ + routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1)); + routed[routed_count++] = client->router; + goto nextg; + } + + if (client->router || !client->connection) + goto nextg; + + /* 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); + + nextg: + if (!silc_idcache_list_next(list, &id_cache)) + break; + } + silc_idcache_list_free(list); + silc_free(routed); +} + +/* Send a notify packet to operators */ + +void silc_server_send_opers_notify(SilcServer server, + bool route, + bool local, + SilcNotifyType type, + SilcUInt32 argc, ...) +{ + va_list ap; + SilcBuffer packet; + + va_start(ap, argc); + packet = silc_notify_payload_encode(type, argc, ap); + silc_server_send_opers(server, SILC_PACKET_NOTIFY, 0, + route, local, packet->data, packet->len, + FALSE); + silc_buffer_free(packet); + va_end(ap); +} diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index ca0779e9..ec3d1f46 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -61,7 +61,7 @@ void silc_server_packet_route(SilcServer server, SilcPacketContext *packet); void silc_server_packet_send_clients(SilcServer server, SilcHashTable clients, - SilcPacketType type, + SilcPacketType type, SilcPacketFlags flags, bool route, unsigned char *data, @@ -267,5 +267,17 @@ void silc_server_send_connection_auth_request(SilcServer server, SilcAuthMethod auth_meth); void silc_server_packet_queue_purge(SilcServer server, SilcSocketConnection sock); +void silc_server_send_opers(SilcServer server, + SilcPacketType type, + SilcPacketFlags flags, + bool route, bool local, + unsigned char *data, + SilcUInt32 data_len, + bool force_send); +void silc_server_send_opers_notify(SilcServer server, + bool route, + bool local, + SilcNotifyType type, + SilcUInt32 argc, ...); #endif diff --git a/apps/silcd/server.c b/apps/silcd/server.c index fb135c4c..0a8921c3 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -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, @@ -2865,6 +2955,20 @@ void silc_server_free_sock_user_data(SilcServer server, 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 */ diff --git a/apps/silcd/server.h b/apps/silcd/server.h index d318233e..5ba6a0ba 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -98,7 +98,16 @@ do { \ silc_server_send_notify(server, sock, FALSE, \ type, 1, __fmt__, strlen(__fmt__)); \ silc_free(__fmt__); \ -} while(0); +} while(0) + +/* Send notify to operators */ +#define SILC_SERVER_SEND_OPERS(server, route, local, type, fmt) \ +do { \ + char *__fmt__ = silc_format fmt; \ + silc_server_send_opers_notify(server, route, local, \ + type, 1, __fmt__, strlen(__fmt__)); \ + silc_free(__fmt__); \ +} while(0) /* Check whether rekey protocol is active */ #define SILC_SERVER_IS_REKEY(sock) \ diff --git a/apps/silcd/server_backup.c b/apps/silcd/server_backup.c index 299f1eee..4c262c7b 100644 --- a/apps/silcd/server_backup.c +++ b/apps/silcd/server_backup.c @@ -1144,8 +1144,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup) router */ silc_server_update_servers_by_server(server, backup_router, router, FALSE); - silc_server_update_clients_by_server(server, backup_router, - router, TRUE, FALSE); + silc_server_update_clients_by_server(server, NULL, router, + FALSE, FALSE); if (server->server_type == SILC_SERVER) silc_server_update_channels_by_server(server, backup_router, router); silc_server_backup_replaced_del(server, backup_router); @@ -1163,6 +1163,13 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup) silc_server_announce_channels(server, 0, router->connection); } + /* Send notify about primary router going down to local operators */ + SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, + SILC_NOTIFY_TYPE_NONE, + ("%s resumed the use of primary router %s", + server->server_name, + server->router->server_name)); + /* Protocol has ended, call the final callback */ if (protocol->final_callback) silc_protocol_execute_final(protocol, server->schedule); diff --git a/apps/silcd/server_util.c b/apps/silcd/server_util.c index a09a9d90..121bb8d8 100644 --- a/apps/silcd/server_util.c +++ b/apps/silcd/server_util.c @@ -462,7 +462,8 @@ silc_server_update_clients_by_real_server(SilcServer server, be the new source. This function also removes the clients that are *really* originated from `from' if `remove_from' is TRUE. These are clients that the `from' owns, and not just clients that are behind - the `from'. */ + the `from'. If `from' is NULL then all non-local clients are switched + to `to'. */ void silc_server_update_clients_by_server(SilcServer server, SilcServerEntry from, @@ -506,26 +507,31 @@ void silc_server_update_clients_by_server(SilcServer server, SILC_LOG_DEBUG(("Client->router (global) %s", silc_id_render(client->router->id, SILC_ID_SERVER))); - if (client->router == from) { - /* Skip clients that are *really* owned by the `from' */ - if (remove_from && SILC_ID_COMPARE(from->id, client->id, - client->id->ip.data_len)) { - SILC_LOG_DEBUG(("Found really owned client, skip it")); - if (!silc_idcache_list_next(list, &id_cache)) - break; - else - continue; - } - - if (resolve_real_server) { - client->router = - silc_server_update_clients_by_real_server(server, from, client, - local, id_cache); - if (!client->router) + if (from) { + if (client->router == from) { + /* Skip clients that are *really* owned by the `from' */ + if (remove_from && SILC_ID_COMPARE(from->id, client->id, + client->id->ip.data_len)) { + SILC_LOG_DEBUG(("Found really owned client, skip it")); + if (!silc_idcache_list_next(list, &id_cache)) + break; + else + continue; + } + + if (resolve_real_server) { + client->router = + silc_server_update_clients_by_real_server(server, from, client, + local, id_cache); + if (!client->router) + client->router = to; + } else { client->router = to; - } else { - client->router = to; + } } + } else { + /* All are changed */ + client->router = to; } if (!silc_idcache_list_next(list, &id_cache)) @@ -557,26 +563,31 @@ void silc_server_update_clients_by_server(SilcServer server, SILC_LOG_DEBUG(("Client->router (local) %s", silc_id_render(client->router->id, SILC_ID_SERVER))); - if (client->router == from) { - /* Skip clients that are *really* owned by the `from' */ - if (remove_from && SILC_ID_COMPARE(from->id, client->id, - client->id->ip.data_len)) { - SILC_LOG_DEBUG(("Found really owned client, skip it")); - if (!silc_idcache_list_next(list, &id_cache)) - break; - else - continue; - } - - if (resolve_real_server) { - client->router = - silc_server_update_clients_by_real_server(server, from, client, - local, id_cache); - if (!client->router) - client->router = from; /* on local list put old from */ - } else { - client->router = to; + if (from) { + if (client->router == from) { + /* Skip clients that are *really* owned by the `from' */ + if (remove_from && SILC_ID_COMPARE(from->id, client->id, + client->id->ip.data_len)) { + SILC_LOG_DEBUG(("Found really owned client, skip it")); + if (!silc_idcache_list_next(list, &id_cache)) + break; + else + continue; + } + + if (resolve_real_server) { + client->router = + silc_server_update_clients_by_real_server(server, from, client, + local, id_cache); + if (!client->router) + client->router = from; /* on local list put old from */ + } else { + client->router = to; + } } + } else { + /* All are changed */ + client->router = to; } if (!silc_idcache_list_next(list, &id_cache)) @@ -1527,3 +1538,25 @@ bool silc_server_force_cumode_change(SilcServer server, return TRUE; } + +/* Find active socket connection by the IP address and port indicated by + `ip' and `port', and socket connection type of `type'. */ + +SilcSocketConnection +silc_server_find_socket_by_host(SilcServer server, + SilcSocketType type, + const char *ip, SilcUInt16 port) +{ + int i; + + for (i = 0; i < server->config->param.connections_max; i++) { + if (!server->sockets[i]) + continue; + if (!strcmp(server->sockets[i]->ip, ip) && + (!port || server->sockets[i]->port == port) && + server->sockets[i]->type == type) + return server->sockets[i]; + } + + return NULL; +} diff --git a/apps/silcd/server_util.h b/apps/silcd/server_util.h index 6f67e25c..ec434bc2 100644 --- a/apps/silcd/server_util.h +++ b/apps/silcd/server_util.h @@ -37,7 +37,8 @@ bool silc_server_remove_clients_by_server(SilcServer server, be the new source. This function also removes the clients that are *really* originated from `from' if `remove_from' is TRUE. These are clients that the `from' owns, and not just clients that are behind - the `from'. */ + the `from'. If `from' is NULL then all non-local clients are switched + to `to'. */ void silc_server_update_clients_by_server(SilcServer server, SilcServerEntry from, SilcServerEntry to, @@ -97,7 +98,7 @@ char *silc_server_name_modify_bad(const char *name, SilcUInt32 name_len); SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip, SilcSocketType type); -/* Find number of sockets by IP address indicated by remote host, indicatd +/* Find number of sockets by IP address indicated by remote host, indicated by `ip' or `hostname', `port', and `type'. Returns 0 if socket connections does not exist. If `ip' is provided then `hostname' is ignored. */ SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server, @@ -180,4 +181,11 @@ bool silc_server_force_cumode_change(SilcServer server, SilcChannelClientEntry chl, SilcUInt32 forced_mode); +/* Find active socket connection by the IP address and port indicated by + `ip' and `port', and socket connection type of `type'. */ +SilcSocketConnection +silc_server_find_socket_by_host(SilcServer server, + SilcSocketType type, + const char *ip, SilcUInt16 port); + #endif /* SERVER_UTIL_H */ -- 2.24.0