From 5abf57fab042a9f9e4ea497cea5cdf6bb170ef62 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 11 Nov 2001 16:48:20 +0000 Subject: [PATCH] updates. --- CHANGES | 79 +++++++++++ TODO | 16 --- .../irssi/src/fe-common/silc/module-formats.c | 9 +- .../irssi/src/fe-common/silc/module-formats.h | 1 + apps/irssi/src/silc/core/client_ops.c | 16 ++- apps/irssi/src/silc/core/silc-channels.c | 9 ++ apps/irssi/src/silc/core/silc-core.c | 7 +- apps/silcd/command.c | 127 +++++++++++------- apps/silcd/command_reply.c | 71 +++++++++- apps/silcd/command_reply.h | 1 + apps/silcd/idlist.c | 1 + apps/silcd/idlist.h | 1 + apps/silcd/protocol.c | 6 +- apps/silcd/protocol.h | 3 +- apps/silcd/server.c | 22 ++- apps/silcd/server_backup.c | 15 ++- apps/silcd/server_util.c | 51 +++++++ apps/silcd/server_util.h | 9 ++ apps/silcd/serverid.c | 2 +- apps/silcd/silcd.c | 5 + doc/draft-riikonen-silc-commands-02.nroff | 2 +- doc/draft-riikonen-silc-pp-04.nroff | 120 ++++++++++------- lib/silcclient/client.c | 51 +++++-- lib/silcclient/client_notify.c | 6 + lib/silcclient/command.c | 38 +++++- lib/silcclient/command_reply.c | 6 +- lib/silcclient/idlist.c | 2 +- lib/silcclient/protocol.c | 16 +-- lib/silccore/silcchannel.c | 2 +- lib/silccore/silcid.h | 8 +- lib/silccore/silcprivate.c | 4 +- lib/silccrypt/silchash.c | 23 +--- lib/silcutil/silclog.c | 27 ++-- lib/silcutil/silcnet.h | 18 +-- lib/silcutil/silcutil.c | 34 ++++- lib/silcutil/silcutil.h | 1 + lib/silcutil/unix/silcunixnet.c | 19 --- lib/silcutil/win32/silcwin32net.c | 18 --- lib/silcutil/win32/silcwin32util.c | 21 +++ prepare | 2 +- silc_optimize | 70 ++++++++++ 41 files changed, 668 insertions(+), 271 deletions(-) create mode 100644 silc_optimize diff --git a/CHANGES b/CHANGES index f65dc8c9..c9244687 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,82 @@ +Sun Nov 11 10:49:10 EET 2001 Pekka Riikonen + + * Use ++server->cmd_ident when sending commands in server, + instead of random number. Affected file silcd/command.c. + + * Fixed GETKEY command reply to call actually GETKEY pending + command callbacks. Affected file silcd/command_reply.c. + + * A bit stricter check for nicknames. Check for same nickname + in NICK command also. Affected file silcd/command.c. + + * Do not call INFO command everytime client ID changes, only + during first connecting. Affected file lib/silcclient/client.c. + + * Set the new nickname only after successful command reply for + NICK command is returned by server. Affected file + lib/silcclient/command.c. + + * Remove nicknames from nicklist during server_signoff notify. + Should fix /NAMES bit more. The affected file is + irssi/src/silc/core/silc-channels.c. + + * Added `fingerprint' field to the SilcIDListData in the + silcd/idlist.h to hold the fingerprint of the client's + public key. + + Send the fingerprint of the client's public key in WHOIS + command reply. + + Affected files silcd/command.c, and silcd/idlist.[ch]. + + * Added silc_fingerprint into lib/silcutil/silcutil.[ch] to + create fingerprint from given data. + + * Show the fingerprint of the client's public key in WHOIS. + Affected files irssi/src/module-formats.[ch] and + irssi/src/silc/core/client_ops.c. + + * Format the multiple same nicknames also during JOIN and + NICK_CHANGE notifys. Affected file is + lib/silcclient/client_notify.c. + + * Do not print error on screen for invalid private message + payload since it can come if someone is sending private + messages with wrong key. Affected file + lib/silccore/silcprivate.c. + + * Fixed multiple concurrent /PING crash. Affected file + lib/silcclient/command.c. + + * Changed the wrong ID encoding. All IP addresses must be + in MSB first order in encoded format. They were encoded + wrong and was in LSB format. Affected files are + silcd/serverid.c, lib/silcutil/silcutil.c. + + * Remove silc_net_addr2bin_ne from lib/silcutil/silcnet.[ch]. + + * Call the `connect' client operation through the scheduler + in case of error. Affected file lib/silcclient/client.c. + + * Call the `failure' client operation even if the error + occurred locally during a protocol. Affected file is + lib/silcclient/protocol.c. + + * Added support of sending LIST command to router from normal + server. This way normal server can get list of all channels + in the network too. Fixed the channel list sending in the + server too. Affected files are silcd/command.c, and + silcd/command_reply.[ch]. + + * Added silc_server_update_channels_by_server and + silc_server_remove_channels_by_server. They are used during + disconnection of primary router and in backup router protocol. + Affected file silcd/server_util.[ch], silcd/server.c and + silcd/server_backup.c. + + * Fixed channel adding to global list in IDENTIFY command + reply in server. Affected file silcd/command_reply.c. + Sat Nov 10 21:39:22 EET 2001 Pekka Riikonen * If the incoming packet type is REKEY or REKEY_DONE process diff --git a/TODO b/TODO index 15baff85..c631c660 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,6 @@ TODO/bugs in Irssi SILC client ============================== - o /NAMES kees showing things wrong after JOIN and after ppl has left - channel. - o Add local command to switch the channel's private key when channel has several private keys. Currently sending channel messages with many keys is not possible because changing the key is not possible by the @@ -38,14 +35,6 @@ TODO/bugs in Irssi SILC client TODO/bugs In SILC Client Library ================================ - o key agreement with itself causes the packet sequence numbers go grazy. - - o WHOIS shows the formatted nickname wrong in some circumstances. - - o Set incrorrect key and /MSG him, screen gets screwed. - - o Crashes if lots of concurrent /PING's. - o JOIN command's argument handling is buggy. See the XXX in the code. @@ -90,11 +79,6 @@ TODO/bugs In SILC Server If it is, there is no reason to send it to the router, since the server knows it best. - o Add support for sending the LIST command to primary router on normal - server to receive all the created channels. Currently the command - returns only the channels the server knows about. The protocol spec - does not prohibit of sending the LIST to the router. - o Incomplete IPv6 support: o silcd/serverid.c and its routines supports only IPv4. diff --git a/apps/irssi/src/fe-common/silc/module-formats.c b/apps/irssi/src/fe-common/silc/module-formats.c index d2c62f23..690ff07d 100644 --- a/apps/irssi/src/fe-common/silc/module-formats.c +++ b/apps/irssi/src/fe-common/silc/module-formats.c @@ -52,10 +52,11 @@ FORMAT_REC fecommon_silc_formats[] = { { NULL, "Who Queries", 0 }, { "whois", "{nick $0} {nickhost $1@$2}%: nickname : $3 ($4)", 5, { 0, 0, 0, 0, 0 } }, - { "whois_realname", " realname : $0", 1, { 0 } }, - { "whois_channels", " channels : $0", 1, { 0 } }, - { "whois_modes", " modes : $0", 1, { 0 } }, - { "whois_idle", " idle : $0", 1, { 0 } }, + { "whois_realname", " realname : $0", 1, { 0 } }, + { "whois_channels", " channels : $0", 1, { 0 } }, + { "whois_modes", " modes : $0", 1, { 0 } }, + { "whois_idle", " idle : $0", 1, { 0 } }, + { "whois_fingerprint", " fingerprint : $0", 1, { 0 } }, { "whowas", "{nick $0} was {nickhost $1} ($2)", 3, { 0, 0, 0 } }, { "users_header", "Users on {channelhilight $0}", 1, { 0 } }, { "users", " %|{nick $[!20]0} $[!5]1 $2@$3 {comment {hilight $4}}", 5, { 0, 0, 0, 0, 0 } }, diff --git a/apps/irssi/src/fe-common/silc/module-formats.h b/apps/irssi/src/fe-common/silc/module-formats.h index c1d94a34..ce4595c3 100644 --- a/apps/irssi/src/fe-common/silc/module-formats.h +++ b/apps/irssi/src/fe-common/silc/module-formats.h @@ -52,6 +52,7 @@ enum { SILCTXT_WHOIS_CHANNELS, SILCTXT_WHOIS_MODES, SILCTXT_WHOIS_IDLE, + SILCTXT_WHOIS_FINGERPRINT, SILCTXT_WHOWAS_USERINFO, SILCTXT_USERS_HEADER, SILCTXT_USERS, diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index a3af5d41..4104b4bd 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -205,7 +205,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn, /* Called to indicate that connection was either successfully established or connecting failed. This is also the first time application receives - the SilcClientConnection objecet which it should save somewhere. */ + the SilcClientConnection object which it should save somewhere. */ void silc_connect(SilcClient client, SilcClientConnection conn, int success) { @@ -401,6 +401,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, case SILC_COMMAND_WHOIS: { char buf[1024], *nickname, *username, *realname, *nick; + unsigned char *fingerprint; uint32 idle, mode; SilcBuffer channels; SilcClientEntry client_entry; @@ -426,6 +427,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, channels = va_arg(vp, SilcBuffer); mode = va_arg(vp, uint32); idle = va_arg(vp, uint32); + fingerprint = va_arg(vp, unsigned char *); silc_parse_userfqdn(nickname, &nick, NULL); printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, @@ -486,6 +488,13 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_WHOIS_IDLE, buf); } + + if (fingerprint) { + fingerprint = silc_fingerprint(fingerprint, 20); + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_WHOIS_FINGERPRINT, fingerprint); + silc_free(fingerprint); + } } break; @@ -633,7 +642,10 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_LIST_HEADER); - snprintf(users, sizeof(users) - 1, "%d", usercount); + if (!usercount) + snprintf(users, sizeof(users) - 1, "N/A"); + else + snprintf(users, sizeof(users) - 1, "%d", usercount); printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_LIST, name, users, topic ? topic : ""); diff --git a/apps/irssi/src/silc/core/silc-channels.c b/apps/irssi/src/silc/core/silc-channels.c index c02d61d2..da14bcdd 100644 --- a/apps/irssi/src/silc/core/silc-channels.c +++ b/apps/irssi/src/silc/core/silc-channels.c @@ -449,6 +449,8 @@ static void event_server_signoff(SILC_SERVER_REC *server, va_list va) clients_count = va_arg(va, uint32); for (i = 0; i < clients_count; i++) { + GSList *nicks, *tmp; + memset(userhost, 0, sizeof(userhost)); if (clients[i]->username) snprintf(userhost, sizeof(userhost) - 1, "%s@%s", @@ -456,6 +458,13 @@ static void event_server_signoff(SILC_SERVER_REC *server, va_list va) signal_emit("message quit", 4, server, clients[i]->nickname, clients[i]->username ? userhost : "", "server signoff"); + + nicks = nicklist_get_same_unique(SERVER(server), clients[i]); + for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) { + CHANNEL_REC *channel = tmp->data; + NICK_REC *nickrec = tmp->next->data; + nicklist_remove(channel, nickrec); + } } } diff --git a/apps/irssi/src/silc/core/silc-core.c b/apps/irssi/src/silc/core/silc-core.c index d66a0595..c5de944d 100644 --- a/apps/irssi/src/silc/core/silc-core.c +++ b/apps/irssi/src/silc/core/silc-core.c @@ -195,7 +195,7 @@ void silc_core_init(void) { "list-pkcs", 'P', POPT_ARG_NONE, &opt_list_pkcs, 0, "List supported PKCSs", NULL }, { "debug", 'd', POPT_ARG_STRING, &opt_debug, 0, - "Enable debugging", NULL }, + "Enable debugging", "STRING" }, { "version", 'V', POPT_ARG_NONE, &opt_version, 0, "Show version", NULL }, { NULL, '\0', 0, NULL } @@ -275,6 +275,11 @@ void silc_core_init_finish(void) silc_log_set_debug_string(opt_debug); silc_log_set_callbacks(silc_log_info, silc_log_warning, silc_log_error, NULL); +#ifndef SILC_DEBUG + fprintf(stdout, + "Run-time debugging is not enabled. To enable it recompile\n" + "the client with --enable-debug configuration option.\n"); +#endif } /* Do some irssi initializing */ diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 31fe32bd..803b0dc9 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -675,6 +675,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd, uint16 ident = silc_command_get_ident(cmd->payload); char nh[256], uh[256]; unsigned char idle[4], mode[4]; + unsigned char *fingerprint; SilcSocketConnection hsock; len = 0; @@ -772,6 +773,11 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd, } channels = silc_server_get_client_channel_list(server, entry); + + if (entry->data.fingerprint[0] != 0 && entry->data.fingerprint[1] != 0) + fingerprint = entry->data.fingerprint; + else + fingerprint = NULL; SILC_PUT32_MSB(entry->mode, mode); @@ -779,29 +785,21 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd, SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle); } - if (channels) - packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS, - status, ident, 7, - 2, idp->data, idp->len, - 3, nh, strlen(nh), - 4, uh, strlen(uh), - 5, entry->userinfo, - strlen(entry->userinfo), - 6, channels->data, - channels->len, - 7, mode, 4, - 8, idle, 4); - else - packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS, - status, ident, 6, - 2, idp->data, idp->len, - 3, nh, strlen(nh), - 4, uh, strlen(uh), - 5, entry->userinfo, - strlen(entry->userinfo), - 7, mode, 4, - 8, idle, 4); - + packet = + silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS, + status, ident, 8, + 2, idp->data, idp->len, + 3, nh, strlen(nh), + 4, uh, strlen(uh), + 5, entry->userinfo, + strlen(entry->userinfo), + 6, channels ? channels->data : NULL, + channels ? channels->len : 0, + 7, mode, 4, + 8, idle, 4, + 9, fingerprint, + fingerprint ? 20 : 0); + silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, packet->data, packet->len, FALSE); @@ -837,7 +835,7 @@ silc_server_command_whois_process(SilcServerCommandContext cmd) uint16 old_ident; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); /* Send WHOIS command to our router */ @@ -1021,7 +1019,7 @@ silc_server_command_whowas_check(SilcServerCommandContext cmd, continue; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); /* Send WHOWAS command */ @@ -1172,7 +1170,7 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd) uint16 old_ident; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); /* Send WHOWAS command to our router */ @@ -1857,7 +1855,7 @@ silc_server_command_identify_process(SilcServerCommandContext cmd) uint16 old_ident; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); /* Send IDENTIFY command to our router */ @@ -1945,6 +1943,14 @@ static int silc_server_command_bad_chars(char *nick) if (nick[i] == '?') return TRUE; if (nick[i] == ',') return TRUE; if (nick[i] == '@') return TRUE; + if (nick[i] == ':') return TRUE; + if (nick[i] == '/') return TRUE; + if (nick[i] == '[') return TRUE; + if (nick[i] == '[') return TRUE; + if (nick[i] == '(') return TRUE; + if (nick[i] == ')') return TRUE; + if (nick[i] == '{') return TRUE; + if (nick[i] == '}') return TRUE; } return FALSE; @@ -1959,7 +1965,7 @@ SILC_SERVER_CMD_FUNC(nick) SilcServerCommandContext cmd = (SilcServerCommandContext)context; SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; SilcServer server = cmd->server; - SilcBuffer packet, nidp, oidp; + SilcBuffer packet, nidp, oidp = NULL; SilcClientID *new_id; char *nick; uint16 ident = silc_command_get_ident(cmd->payload); @@ -1981,6 +1987,12 @@ SILC_SERVER_CMD_FUNC(nick) if (strlen(nick) > 128) nick[128] = '\0'; + /* Check for same nickname */ + if (!strcmp(client->nickname, nick)) { + nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); + goto send_reply; + } + /* Create new Client ID */ while (!silc_id_create_client_id(cmd->server, cmd->server->id, cmd->server->rng, @@ -2025,6 +2037,7 @@ SILC_SERVER_CMD_FUNC(nick) oidp->data, oidp->len, nidp->data, nidp->len); + send_reply: /* Send the new Client ID as reply command back to client */ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, SILC_STATUS_OK, ident, 1, @@ -2034,7 +2047,8 @@ SILC_SERVER_CMD_FUNC(nick) silc_buffer_free(packet); silc_buffer_free(nidp); - silc_buffer_free(oidp); + if (oidp) + silc_buffer_free(oidp); out: silc_server_command_free(cmd); @@ -2079,9 +2093,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd, if (i >= 1) status = SILC_STATUS_LIST_ITEM; - if (i == lch_count - 1 && gch_count) - break; - if (lch_count > 1 && i == lch_count - 1) + if (lch_count > 1 && i == lch_count - 1 && !gch_count) status = SILC_STATUS_LIST_END; idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL); @@ -2185,7 +2197,33 @@ SILC_SERVER_CMD_FUNC(list) SilcChannelEntry *lchannels = NULL, *gchannels = NULL; uint32 lch_count = 0, gch_count = 0; - SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 2); + SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 1); + + /* If we are normal server, send the command to router, since we + want to know all channels in the network. */ + if (!cmd->pending && server->server_type == SILC_SERVER && + !server->standalone) { + SilcBuffer tmpbuf; + uint16 old_ident; + + old_ident = silc_command_get_ident(cmd->payload); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); + tmpbuf = silc_command_payload_encode_payload(cmd->payload); + silc_server_packet_send(server, server->router->connection, + SILC_PACKET_COMMAND, cmd->packet->flags, + tmpbuf->data, tmpbuf->len, TRUE); + + /* Reprocess this packet after received reply from router */ + silc_server_command_pending(server, SILC_COMMAND_LIST, + silc_command_get_ident(cmd->payload), + silc_server_command_destructor, + silc_server_command_list, + silc_server_command_dup(cmd)); + cmd->pending = TRUE; + silc_command_set_ident(cmd->payload, old_ident); + silc_buffer_free(tmpbuf); + return; + } /* Get Channel ID */ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); @@ -2202,10 +2240,9 @@ SILC_SERVER_CMD_FUNC(list) lchannels = silc_idlist_get_channels(server->local_list, channel_id, &lch_count); - /* Get the channels from global list if we are router */ - if (server->server_type != SILC_SERVER) - gchannels = silc_idlist_get_channels(server->global_list, channel_id, - &gch_count); + /* Get the channels from global list */ + gchannels = silc_idlist_get_channels(server->global_list, channel_id, + &gch_count); /* Send the reply */ silc_server_command_list_send_reply(cmd, lchannels, lch_count, @@ -2823,7 +2860,7 @@ SILC_SERVER_CMD_FUNC(info) uint16 old_ident; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); silc_server_packet_send(server, entry->connection, @@ -2848,7 +2885,7 @@ SILC_SERVER_CMD_FUNC(info) uint16 old_ident; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); silc_server_packet_send(server, server->router->connection, @@ -3299,7 +3336,7 @@ SILC_SERVER_CMD_FUNC(join) goto out; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); /* Send JOIN command to our router */ @@ -3465,7 +3502,7 @@ SILC_SERVER_CMD_FUNC(motd) uint16 old_ident; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); silc_server_packet_send(server, entry->connection, @@ -3490,7 +3527,7 @@ SILC_SERVER_CMD_FUNC(motd) uint16 old_ident; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); silc_server_packet_send(server, server->router->connection, @@ -5045,7 +5082,7 @@ SILC_SERVER_CMD_FUNC(users) !cmd->pending) { SilcBuffer tmpbuf; - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); /* Send USERS command */ @@ -5188,7 +5225,7 @@ SILC_SERVER_CMD_FUNC(getkey) goto out; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); silc_server_packet_send(server, dest_sock, @@ -5254,7 +5291,7 @@ SILC_SERVER_CMD_FUNC(getkey) uint16 old_ident; old_ident = silc_command_get_ident(cmd->payload); - silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng)); + silc_command_set_ident(cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(cmd->payload); silc_server_packet_send(server, server->router->connection, diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index cb6c6973..76b641cc 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -57,6 +57,7 @@ SilcServerCommandReply silc_command_reply_list[] = SILC_SERVER_CMD_REPLY(join, JOIN), SILC_SERVER_CMD_REPLY(users, USERS), SILC_SERVER_CMD_REPLY(getkey, GETKEY), + SILC_SERVER_CMD_REPLY(list, LIST), { NULL, 0 }, }; @@ -537,7 +538,7 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) /* We don't have that server anywhere, add it. */ channel = silc_idlist_add_channel(server->global_list, strdup(name), SILC_CHANNEL_MODE_NONE, channel_id, - server->router->connection, + server->router, NULL, NULL); if (!channel) { silc_free(channel_id); @@ -1065,8 +1066,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) } out: - SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS); - SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS); + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY); + SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY); if (idp) silc_id_payload_free(idp); silc_free(client_id); @@ -1075,3 +1076,67 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) silc_pkcs_public_key_free(public_key); silc_server_command_reply_free(cmd); } + +SILC_SERVER_CMD_REPLY_FUNC(list) +{ + SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; + SilcServer server = cmd->server; + SilcCommandStatus status; + SilcChannelID *channel_id = NULL; + SilcChannelEntry channel; + uint32 len; + unsigned char *tmp, *name, *topic; + uint32 usercount = 0; + + COMMAND_CHECK_STATUS_LIST; + + tmp = silc_argument_get_arg_type(cmd->args, 2, &len); + channel_id = silc_id_payload_parse_id(tmp, len); + if (!channel_id) + goto out; + + name = silc_argument_get_arg_type(cmd->args, 3, NULL); + topic = silc_argument_get_arg_type(cmd->args, 4, NULL); + tmp = silc_argument_get_arg_type(cmd->args, 5, NULL); + if (tmp) + SILC_GET32_MSB(usercount, tmp); + + /* Add the channel entry if we do not have it already */ + channel = silc_idlist_find_channel_by_id(server->local_list, + channel_id, NULL); + if (!channel) + channel = silc_idlist_find_channel_by_id(server->global_list, + channel_id, NULL); + if (!channel) { + /* If router did not find such Channel ID in its lists then this must + be bogus channel or some router in the net is buggy. */ + if (server->server_type != SILC_SERVER) + goto out; + + channel = silc_idlist_add_channel(server->global_list, strdup(name), + SILC_CHANNEL_MODE_NONE, channel_id, + server->router, + NULL, NULL); + if (!channel) + goto out; + channel_id = NULL; + } + + if (topic) { + silc_free(channel->topic); + channel->topic = strdup(topic); + } + + /* Pending callbacks are not executed if this was an list entry */ + if (status != SILC_STATUS_OK && + status != SILC_STATUS_LIST_END) { + silc_server_command_reply_free(cmd); + return; + } + + out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY); + SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY); + silc_free(channel_id); + silc_server_command_reply_free(cmd); +} diff --git a/apps/silcd/command_reply.h b/apps/silcd/command_reply.h index eb5b53d4..3b824843 100644 --- a/apps/silcd/command_reply.h +++ b/apps/silcd/command_reply.h @@ -75,5 +75,6 @@ SILC_SERVER_CMD_REPLY_FUNC(motd); SILC_SERVER_CMD_REPLY_FUNC(join); SILC_SERVER_CMD_REPLY_FUNC(users); SILC_SERVER_CMD_REPLY_FUNC(getkey); +SILC_SERVER_CMD_REPLY_FUNC(list); #endif diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 4a72bcb9..4dbe844d 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -42,6 +42,7 @@ void silc_idlist_add_data(void *entry, SilcIDListData idata) data->psn_receive = idata->psn_receive; data->hash = idata->hash; data->public_key = idata->public_key; + memcpy(data->fingerprint, idata->fingerprint, sizeof(data->fingerprint)); data->rekey = idata->rekey; data->last_receive = idata->last_receive; data->last_sent = idata->last_sent; diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index 0436d9a4..37d3e9bb 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -93,6 +93,7 @@ typedef struct { /* Public key */ SilcPublicKey public_key; + unsigned char fingerprint[20]; /* Re-key context */ SilcServerRekey rekey; diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index 061894be..50caf240 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -206,7 +206,8 @@ static void silc_server_protocol_ke_send_packet(SilcSKE ske, /* Sets the negotiated key material into use for particular connection. */ -int silc_server_protocol_ke_set_keys(SilcSKE ske, +int silc_server_protocol_ke_set_keys(SilcServer server, + SilcSKE ske, SilcSocketConnection sock, SilcSKEKeyMaterial *keymat, SilcCipher cipher, @@ -300,6 +301,9 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, /* Save the remote host's public key */ silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, ske->ke1_payload->pk_len, &idata->public_key); + if (ske->prop->flags & SILC_SKE_SP_FLAG_MUTUAL) + silc_hash_make(server->sha1hash, ske->ke1_payload->pk_data, + ske->ke1_payload->pk_len, idata->fingerprint); sock->user_data = (void *)conn_data; diff --git a/apps/silcd/protocol.h b/apps/silcd/protocol.h index 21c3d193..303fdc93 100644 --- a/apps/silcd/protocol.h +++ b/apps/silcd/protocol.h @@ -106,7 +106,8 @@ typedef struct { /* Prototypes */ void silc_server_protocols_register(void); void silc_server_protocols_unregister(void); -int silc_server_protocol_ke_set_keys(SilcSKE ske, +int silc_server_protocol_ke_set_keys(SilcServer server, + SilcSKE ske, SilcSocketConnection sock, SilcSKEKeyMaterial *keymat, SilcCipher cipher, diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 3a227c50..2d76a24a 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -726,7 +726,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) /* We now have the key material as the result of the key exchange protocol. Take the key material into use. Free the raw key material as soon as we've set them into use. */ - if (!silc_server_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat, + if (!silc_server_protocol_ke_set_keys(server, ctx->ske, + ctx->sock, ctx->keymat, ctx->ske->prop->cipher, ctx->ske->prop->pkcs, ctx->ske->prop->hash, @@ -1183,7 +1184,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second) /* We now have the key material as the result of the key exchange protocol. Take the key material into use. Free the raw key material as soon as we've set them into use. */ - if (!silc_server_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat, + if (!silc_server_protocol_ke_set_keys(server, ctx->ske, + ctx->sock, ctx->keymat, ctx->ske->prop->cipher, ctx->ske->prop->pkcs, ctx->ske->prop->hash, @@ -2390,6 +2392,8 @@ void silc_server_free_sock_user_data(SilcServer server, become invalid now as well. */ if (user_data->id) 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); } else { /* Update the client entries of this server to the new backup router. This also removes the clients that *really* was owned @@ -2397,6 +2401,9 @@ void silc_server_free_sock_user_data(SilcServer server, silc_server_update_clients_by_server(server, user_data, backup_router, TRUE, TRUE); silc_server_update_servers_by_server(server, user_data, backup_router); + if (server->server_type == SILC_SERVER) + silc_server_update_channels_by_server(server, user_data, + backup_router); } /* Free the server entry */ @@ -3420,11 +3427,12 @@ void silc_server_announce_channels(SilcServer server, &channel_ids, creation_time); /* Get channels and channel users in global list */ - silc_server_announce_get_channels(server, server->global_list, - &channels, &channel_users, - &channel_users_modes, - &channel_users_modes_c, - &channel_ids, creation_time); + if (server->server_type != SILC_SERVER) + silc_server_announce_get_channels(server, server->global_list, + &channels, &channel_users, + &channel_users_modes, + &channel_users_modes_c, + &channel_ids, creation_time); if (channels) { silc_buffer_push(channels, channels->data - channels->head); diff --git a/apps/silcd/server_backup.c b/apps/silcd/server_backup.c index 423710f9..4bcf0b11 100644 --- a/apps/silcd/server_backup.c +++ b/apps/silcd/server_backup.c @@ -90,8 +90,8 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server, server->backup->servers[i].local = local; memset(server->backup->servers[i].ip.data, 0, sizeof(server->backup->servers[i].ip.data)); - silc_net_addr2bin_ne(ip, server->backup->servers[i].ip.data, - sizeof(server->backup->servers[i].ip.data)); + silc_net_addr2bin(ip, server->backup->servers[i].ip.data, + sizeof(server->backup->servers[i].ip.data)); //server->backup->servers[i].port = port; return; } @@ -105,8 +105,8 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server, server->backup->servers[i].local = local; memset(server->backup->servers[i].ip.data, 0, sizeof(server->backup->servers[i].ip.data)); - silc_net_addr2bin_ne(ip, server->backup->servers[i].ip.data, - sizeof(server->backup->servers[i].ip.data)); + silc_net_addr2bin(ip, server->backup->servers[i].ip.data, + sizeof(server->backup->servers[i].ip.data)); //server->backup->servers[i].port = server_id->port; server->backup->servers_count++; } @@ -987,6 +987,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup) server->router); silc_server_update_clients_by_server(server, ctx->sock->user_data, server->router, TRUE, FALSE); + if (server->server_type == SILC_SERVER) + silc_server_update_channels_by_server(server, ctx->sock->user_data, + server->router); packet = silc_buffer_alloc(2); silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); @@ -1125,7 +1128,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup) silc_server_update_servers_by_server(server, backup_router, router); silc_server_update_clients_by_server(server, backup_router, router, TRUE, FALSE); - silc_server_backup_replaced_del(server, backup_router); + if (server->server_type == SILC_SERVER) + silc_server_update_channels_by_server(server, backup_router, router); + silc_server_backup_replaced_del(server, backup_router); silc_server_backup_add(server, backup_router, ctx->sock->ip, ctx->sock->port, backup_router->server_type != SILC_ROUTER ? diff --git a/apps/silcd/server_util.c b/apps/silcd/server_util.c index d0488095..a29c2fd3 100644 --- a/apps/silcd/server_util.c +++ b/apps/silcd/server_util.c @@ -622,6 +622,57 @@ void silc_server_update_servers_by_server(SilcServer server, } } +/* Removes channels that are from `from. */ + +void silc_server_remove_channels_by_server(SilcServer server, + SilcServerEntry from) +{ + SilcIDCacheList list = NULL; + SilcIDCacheEntry id_cache = NULL; + SilcChannelEntry channel = NULL; + + SILC_LOG_DEBUG(("Start")); + + if (silc_idcache_get_all(server->global_list->channels, &list)) { + if (silc_idcache_list_first(list, &id_cache)) { + while (id_cache) { + channel = (SilcChannelEntry)id_cache->context; + if (channel->router == from) + silc_idlist_del_channel(server->global_list, channel); + if (!silc_idcache_list_next(list, &id_cache)) + break; + } + } + silc_idcache_list_free(list); + } +} + +/* Updates channels that are from `from' to be originated from `to'. */ + +void silc_server_update_channels_by_server(SilcServer server, + SilcServerEntry from, + SilcServerEntry to) +{ + SilcIDCacheList list = NULL; + SilcIDCacheEntry id_cache = NULL; + SilcChannelEntry channel = NULL; + + SILC_LOG_DEBUG(("Start")); + + if (silc_idcache_get_all(server->global_list->channels, &list)) { + if (silc_idcache_list_first(list, &id_cache)) { + while (id_cache) { + channel = (SilcChannelEntry)id_cache->context; + if (channel->router == from) + channel->router = to; + if (!silc_idcache_list_next(list, &id_cache)) + break; + } + } + silc_idcache_list_free(list); + } +} + /* Checks whether given channel has global users. If it does this returns TRUE and FALSE if there is only locally connected clients on the channel. */ diff --git a/apps/silcd/server_util.h b/apps/silcd/server_util.h index 00f740ba..8ac40c45 100644 --- a/apps/silcd/server_util.h +++ b/apps/silcd/server_util.h @@ -50,6 +50,15 @@ void silc_server_update_servers_by_server(SilcServer server, SilcServerEntry from, SilcServerEntry to); +/* Removes channels that are from `from. */ +void silc_server_remove_channels_by_server(SilcServer server, + SilcServerEntry from); + +/* Updates channels that are from `from' to be originated from `to'. */ +void silc_server_update_channels_by_server(SilcServer server, + SilcServerEntry from, + SilcServerEntry to); + /* Checks whether given channel has global users. If it does this returns TRUE and FALSE if there is only locally connected clients on the channel. */ bool silc_server_channel_has_global(SilcChannelEntry channel); diff --git a/apps/silcd/serverid.c b/apps/silcd/serverid.c index ff0c551b..2d153f32 100644 --- a/apps/silcd/serverid.c +++ b/apps/silcd/serverid.c @@ -46,7 +46,7 @@ void silc_id_create_server_id(int sock, SilcRng rng, SilcServerID **new_id) /* Create the ID */ /* XXX Does not support IPv6 */ - SILC_PUT32_MSB(server.sin_addr.s_addr, (*new_id)->ip.data); + memcpy((*new_id)->ip.data, &server.sin_addr.s_addr, 4); (*new_id)->ip.data_len = 4; (*new_id)->port = server.sin_port; (*new_id)->rnd = silc_rng_get_rn16(rng); diff --git a/apps/silcd/silcd.c b/apps/silcd/silcd.c index a6f76db1..bfb50ca7 100644 --- a/apps/silcd/silcd.c +++ b/apps/silcd/silcd.c @@ -127,6 +127,11 @@ int main(int argc, char **argv) silc_debug = TRUE; silc_debug_hexdump = TRUE; silc_log_set_debug_string(optarg); +#ifndef SILC_DEBUG + fprintf(stdout, + "Run-time debugging is not enabled. To enable it recompile\n" + "the server with --enable-debug configuration option.\n"); +#endif break; case 'f': config_file = strdup(optarg); diff --git a/doc/draft-riikonen-silc-commands-02.nroff b/doc/draft-riikonen-silc-commands-02.nroff index 0d9dd30c..f9575ad5 100644 --- a/doc/draft-riikonen-silc-commands-02.nroff +++ b/doc/draft-riikonen-silc-commands-02.nroff @@ -293,7 +293,7 @@ List of all defined commands in SILC follows. binary hash digest of the public key. The fingerprint MUST NOT be sent if the server has not verified the proof of posession of the corresponding private key. Server can do this during the - SILC Key Exchange protocol. + SILC Key Exchange protocol. The is SHA1 digest. Status messages: diff --git a/doc/draft-riikonen-silc-pp-04.nroff b/doc/draft-riikonen-silc-pp-04.nroff index 1b0666c4..3ea6a3b4 100644 --- a/doc/draft-riikonen-silc-pp-04.nroff +++ b/doc/draft-riikonen-silc-pp-04.nroff @@ -66,7 +66,6 @@ authenticated. - .ti 0 Table of Contents @@ -79,45 +78,45 @@ Table of Contents 2.3 SILC Packet Types ......................................... 7 2.3.1 SILC Packet Payloads ................................ 16 2.3.2 Generic payloads .................................... 16 - 2.3.2.1 ID Payload .................................. 16 - 2.3.2.2 Argument Payload ............................ 17 + 2.3.2.1 ID Payload .................................. 17 + 2.3.2.2 Argument Payload ............................ 18 2.3.2.3 Channel Payload ............................. 18 2.3.2.4 Public Key Payload .......................... 19 - 2.3.3 Disconnect Payload .................................. 19 - 2.3.4 Success Payload ..................................... 19 - 2.3.5 Failure Payload ..................................... 20 - 2.3.6 Reject Payload ...................................... 21 + 2.3.3 Disconnect Payload .................................. 20 + 2.3.4 Success Payload ..................................... 21 + 2.3.5 Failure Payload ..................................... 21 + 2.3.6 Reject Payload ...................................... 22 2.3.7 Notify Payload ...................................... 22 - 2.3.8 Error Payload ....................................... 21 - 2.3.9 Channel Message Payload ............................. 28 - 2.3.10 Channel Key Payload ................................ 31 - 2.3.11 Private Message Payload ............................ 33 - 2.3.12 Private Message Key Payload ........................ 34 - 2.3.13 Command Payload .................................... 36 - 2.3.14 Command Reply Payload .............................. 37 - 2.3.15 Connection Auth Request Payload .................... 37 - 2.3.16 New ID Payload ..................................... 38 - 2.3.17 New Client Payload ................................. 39 - 2.3.18 New Server Payload ................................. 40 - 2.3.19 New Channel Payload ................................ 41 - 2.3.20 Key Agreement Payload .............................. 42 - 2.3.21 Resume Router Payload .............................. 43 - 2.3.22 File Transfer Payload .............................. 43 - 2.4 SILC ID Types ............................................. 44 - 2.5 Packet Encryption And Decryption .......................... 44 - 2.5.1 Normal Packet Encryption And Decryption ............. 45 - 2.5.2 Channel Message Encryption And Decryption ........... 45 - 2.5.3 Private Message Encryption And Decryption ........... 46 - 2.6 Packet MAC Generation ..................................... 47 - 2.7 Packet Padding Generation ................................. 47 - 2.8 Packet Compression ........................................ 48 - 2.9 Packet Sending ............................................ 48 - 2.10 Packet Reception ......................................... 49 - 2.11 Packet Routing ........................................... 49 - 2.12 Packet Broadcasting ...................................... 50 -3 Security Considerations ....................................... 50 -4 References .................................................... 50 -5 Author's Address .............................................. 52 + 2.3.8 Error Payload ....................................... 28 + 2.3.9 Channel Message Payload ............................. 29 + 2.3.10 Channel Key Payload ................................ 32 + 2.3.11 Private Message Payload ............................ 34 + 2.3.12 Private Message Key Payload ........................ 35 + 2.3.13 Command Payload .................................... 37 + 2.3.14 Command Reply Payload .............................. 38 + 2.3.15 Connection Auth Request Payload .................... 38 + 2.3.16 New ID Payload ..................................... 39 + 2.3.17 New Client Payload ................................. 40 + 2.3.18 New Server Payload ................................. 41 + 2.3.19 New Channel Payload ................................ 42 + 2.3.20 Key Agreement Payload .............................. 43 + 2.3.21 Resume Router Payload .............................. 44 + 2.3.22 File Transfer Payload .............................. 44 + 2.4 SILC ID Types ............................................. 46 + 2.5 Packet Encryption And Decryption .......................... 46 + 2.5.1 Normal Packet Encryption And Decryption ............. 46 + 2.5.2 Channel Message Encryption And Decryption ........... 47 + 2.5.3 Private Message Encryption And Decryption ........... 48 + 2.6 Packet MAC Generation ..................................... 48 + 2.7 Packet Padding Generation ................................. 49 + 2.8 Packet Compression ........................................ 50 + 2.9 Packet Sending ............................................ 50 + 2.10 Packet Reception ......................................... 51 + 2.11 Packet Routing ........................................... 51 + 2.12 Packet Broadcasting ...................................... 52 +3 Security Considerations ....................................... 53 +4 References .................................................... 53 +5 Author's Address .............................................. 54 .ti 0 List of Figures @@ -569,6 +568,8 @@ List of SILC Packet types are defined as follows. Payload + + 13 SILC_PACKET_KEY_EXCHANGE This packet is used to start SILC Key Exchange Protocol, @@ -824,17 +825,6 @@ packet payloads. This payload can be used to send an ID. ID's are variable in length thus this payload provides a way to send variable length ID's. - - - - - - - - - - - The following diagram represents the ID Payload. .in 5 @@ -875,6 +865,12 @@ needs the arguments. Argument Payloads MUST always reside right after the packet payload needing the arguments. Incorrect amount of argument payloads MUST cause rejection of the packet. + + + + + + The following diagram represents the Argument Payload. .in 5 @@ -920,6 +916,16 @@ its name, the Channel ID and a mode. The following diagram represents the Channel Payload. + + + + + + + + + + .in 5 .nf 1 2 3 @@ -972,6 +978,9 @@ public keys and certificates. The following diagram represents the Public Key Payload. + + + .in 5 .nf 1 2 3 @@ -1148,6 +1157,9 @@ The payload may only be sent with SILC_PACKET_NOTIFY packet. It MUST not be sent in any other packet type. The following diagram represents the Notify Payload. + + + .in 5 .nf 1 2 3 @@ -1750,6 +1762,12 @@ packet. It MUST NOT be sent in any other packet type. The following diagram represents the Private Message Payload. + + + + + + .in 5 .nf 1 2 3 @@ -2343,6 +2361,8 @@ o Data (variable length) - Arbitrary file transfer data. The .in 3 + + .ti 0 2.4 SILC ID Types @@ -2371,6 +2391,10 @@ network. this ID in [SILC1]. .in 3 +When encoding different IDs into the ID Payload, all fields are always +in MSB first order. The IP address, port, and/or the random number +are encoded in the MSB first order. + .ti 0 2.5 Packet Encryption And Decryption diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 687341ec..305e9c7d 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -397,6 +397,19 @@ bool silc_client_start_key_exchange(SilcClient client, return TRUE; } +/* Callback called when error has occurred during connecting to the server. + The `connect' client operation will be called. */ + +SILC_TASK_CALLBACK(silc_client_connect_failure) +{ + SilcClientKEInternalContext *ctx = + (SilcClientKEInternalContext *)context; + SilcClient client = (SilcClient)ctx->client; + + client->ops->connect(client, ctx->sock->user_data, FALSE); + silc_free(ctx); +} + /* Start of the connection to the remote server. This is called after succesful TCP/IP connection has been established to the remote host. */ @@ -485,8 +498,9 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second) silc_socket_free(ctx->sock); /* Notify application of failure */ - client->ops->connect(client, ctx->sock->user_data, FALSE); - silc_free(ctx); + silc_schedule_task_add(client->schedule, ctx->sock->sock, + silc_client_connect_failure, ctx, + 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); return; } @@ -591,8 +605,9 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) silc_socket_free(ctx->sock); /* Notify application of failure */ - client->ops->connect(client, ctx->sock->user_data, FALSE); - silc_free(ctx); + silc_schedule_task_add(client->schedule, ctx->sock->sock, + silc_client_connect_failure, ctx, + 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); return; } @@ -1408,6 +1423,7 @@ void silc_client_receive_new_id(SilcClient client, { SilcClientConnection conn = (SilcClientConnection)sock->user_data; int connecting = FALSE; + SilcClientID *client_id = silc_id_payload_get_id(idp); SilcBuffer sidp; if (!conn->local_entry) @@ -1415,6 +1431,12 @@ void silc_client_receive_new_id(SilcClient client, /* Delete old ID from ID cache */ if (conn->local_id) { + /* Check whether they are different */ + if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) { + silc_free(client_id); + return; + } + silc_idcache_del_by_context(conn->client_cache, conn->local_entry); silc_free(conn->local_id); } @@ -1424,7 +1446,7 @@ void silc_client_receive_new_id(SilcClient client, if (conn->local_id_data) silc_free(conn->local_id_data); - conn->local_id = silc_id_payload_get_id(idp); + conn->local_id = client_id; conn->local_id_data = silc_id_payload_get_data(idp); conn->local_id_data_len = silc_id_payload_get_len(idp);; @@ -1444,17 +1466,18 @@ void silc_client_receive_new_id(SilcClient client, silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id, (void *)conn->local_entry, FALSE); - /* Issue INFO command to fetch the real server name and server information - and other stuff. */ - sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); - silc_client_send_command(client, conn, SILC_COMMAND_INFO, - ++conn->cmd_ident, 1, 2, sidp->data, sidp->len); - silc_buffer_free(sidp); + if (connecting) { + /* Issue INFO comqmand to fetch the real server name and server information + and other stuff. */ + sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); + silc_client_send_command(client, conn, SILC_COMMAND_INFO, + ++conn->cmd_ident, 1, 2, sidp->data, sidp->len); + silc_buffer_free(sidp); - /* Notify application of successful connection. We do it here now that - we've received the Client ID and are allowed to send traffic. */ - if (connecting) + /* Notify application of successful connection. We do it here now that + we've received the Client ID and are allowed to send traffic. */ client->ops->connect(client, conn, TRUE); + } } /* Processed received Channel ID for a channel. This is called when client diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index 5b508e5c..1b7c3972 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -204,6 +204,9 @@ void silc_client_notify_by_server(SilcClient client, client_entry->status |= SILC_CLIENT_STATUS_RESOLVING; silc_client_notify_by_server_resolve(client, conn, packet, client_id); goto out; + } else { + if (client_entry != conn->local_entry) + silc_client_nickname_format(client, conn, client_entry); } /* Get Channel ID */ @@ -406,6 +409,9 @@ void silc_client_notify_by_server(SilcClient client, if (!client_entry2) { silc_client_notify_by_server_resolve(client, conn, packet, client_id); goto out; + } else { + if (client_entry2 != conn->local_entry) + silc_client_nickname_format(client, conn, client_entry2); } /* Remove the old from cache */ diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index bdb818f5..0164d764 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -349,6 +349,29 @@ SILC_CLIENT_CMD_FUNC(identify) silc_client_command_free(cmd); } +/* Pending callbcak that will be called after the NICK command was + replied by the server. This sets the nickname if there were no + errors. */ + +SILC_CLIENT_CMD_FUNC(nick_change) +{ + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClientConnection conn = cmd->conn; + SilcClientCommandReplyContext reply = + (SilcClientCommandReplyContext)context2; + SilcCommandStatus status; + + SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL)); + if (status == SILC_STATUS_OK) { + /* Set the nickname */ + if (conn->nickname) + silc_free(conn->nickname); + conn->nickname = strdup(cmd->argv[1]); + } + + silc_client_command_free(cmd); +} + /* Command NICK. Shows current nickname/sets new nickname on current window. */ @@ -392,7 +415,7 @@ SILC_CLIENT_CMD_FUNC(nick) if (cmd->argv_lens[1] > 128) cmd->argv_lens[1] = 128; - /* Set new nickname */ + /* Send the NICK command */ buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1, &cmd->argv[1], &cmd->argv_lens[1], @@ -402,9 +425,15 @@ SILC_CLIENT_CMD_FUNC(nick) SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); - if (conn->nickname) - silc_free(conn->nickname); - conn->nickname = strdup(cmd->argv[1]); + + /* Register pending callback that will actually set the new nickname + if there were no errors returned by the server. */ + silc_client_command_pending(conn, SILC_COMMAND_NICK, + cmd->conn->cmd_ident, + silc_client_command_destructor, + silc_client_command_nick_change, + silc_client_command_dup(cmd)); + cmd->pending = 1; /* Notify application */ COMMAND; @@ -933,7 +962,6 @@ SILC_CLIENT_CMD_FUNC(ping) conn->ping[i].start_time = time(NULL); conn->ping[i].dest_id = id; conn->ping[i].dest_name = strdup(conn->remote_host); - conn->ping_count++; break; } } diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index b3c3f791..29cfc2bb 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -311,7 +311,7 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd, /* Notify application */ if (!cmd->callback) COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, - channels, mode, idle)); + channels, mode, idle, fingerprint)); if (channels) silc_buffer_free(channels); @@ -598,7 +598,11 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick) silc_client_receive_new_id(cmd->client, cmd->sock, idp); /* Notify application */ + SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK); COMMAND_REPLY((ARGS, conn->local_entry)); + SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK); + silc_client_command_reply_free(cmd); + return; out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK); diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index 34448198..8ec66929 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -917,7 +917,7 @@ void silc_client_nickname_format(SilcClient client, len = 0; for (i = 0; i < clients_count; i++) - if (clients[i]->valid) + if (clients[i]->valid && clients[i] != client_entry) len++; if (!len) return; diff --git a/lib/silcclient/protocol.c b/lib/silcclient/protocol.c index 991d8653..40bffdf8 100644 --- a/lib/silcclient/protocol.c +++ b/lib/silcclient/protocol.c @@ -244,20 +244,8 @@ static void silc_client_protocol_ke_continue(SilcSKE ske, SILC_LOG_DEBUG(("Start")); if (ske->status != SILC_SKE_STATUS_OK) { - if (ske->status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) { - client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, - "Received unsupported server %s public key", - ctx->sock->hostname); - } else if (ske->status == SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED) { - client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, - "Remote host did not send its public key, even though " - "it must send it"); - } else { - client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, - "Error during key exchange protocol with server %s", - ctx->sock->hostname); - } - + /* Call failure client operation */ + client->ops->failure(client, conn, protocol, (void *)ske->status); protocol->state = SILC_PROTOCOL_STATE_ERROR; silc_protocol_execute(protocol, client->schedule, 0, 0); return; diff --git a/lib/silccore/silcchannel.c b/lib/silccore/silcchannel.c index 9ba67a7c..0a3e2dc3 100644 --- a/lib/silccore/silcchannel.c +++ b/lib/silccore/silcchannel.c @@ -287,7 +287,7 @@ silc_channel_message_payload_parse(SilcBuffer buffer, /* Decrypt the payload */ ret = silc_channel_message_payload_decrypt(buffer->data, buffer->len, - cipher, hmac); + cipher, hmac); if (ret == FALSE) return NULL; diff --git a/lib/silccore/silcid.h b/lib/silccore/silcid.h index 23978883..ae71ecba 100644 --- a/lib/silccore/silcid.h +++ b/lib/silccore/silcid.h @@ -52,10 +52,10 @@ typedef uint16 SilcIdType; /* The SILC ID Types */ -#define SILC_ID_NONE 0 -#define SILC_ID_SERVER 1 -#define SILC_ID_CLIENT 2 -#define SILC_ID_CHANNEL 3 +#define SILC_ID_NONE 0 +#define SILC_ID_SERVER 1 +#define SILC_ID_CLIENT 2 +#define SILC_ID_CHANNEL 3 /***/ /* The ID Lenghts. These are IPv4 based and should be noted if used directly diff --git a/lib/silccore/silcprivate.c b/lib/silccore/silcprivate.c index db835878..60534f6b 100644 --- a/lib/silccore/silcprivate.c +++ b/lib/silccore/silcprivate.c @@ -64,12 +64,12 @@ silc_private_message_payload_parse(SilcBuffer buffer, SilcCipher cipher) &new->message_len), SILC_STR_END); if (ret == -1) { - SILC_LOG_ERROR(("Incorrect private message payload")); + SILC_LOG_DEBUG(("Incorrect private message payload")); goto err; } if ((new->message_len < 1 || new->message_len > buffer->len)) { - SILC_LOG_ERROR(("Incorrect private message payload in packet, " + SILC_LOG_DEBUG(("Incorrect private message payload in packet, " "packet dropped")); goto err; } diff --git a/lib/silccrypt/silchash.c b/lib/silccrypt/silchash.c index 4d0d2706..4ec556bc 100644 --- a/lib/silccrypt/silchash.c +++ b/lib/silccrypt/silchash.c @@ -209,34 +209,13 @@ void silc_hash_make(SilcHash hash, const unsigned char *data, char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data, uint32 data_len) { - char fingerprint[64], *cp; unsigned char h[32]; - int i; if (!hash) silc_hash_alloc("sha1", &hash); silc_hash_make(hash, data, data_len, h); - - memset(fingerprint, 0, sizeof(fingerprint)); - cp = fingerprint; - for (i = 0; i < hash->hash->hash_len; i++) { - snprintf(cp, sizeof(fingerprint), "%02X", h[i]); - cp += 2; - - if ((i + 1) % 2 == 0) - snprintf(cp++, sizeof(fingerprint), " "); - - if ((i + 1) % 10 == 0) - snprintf(cp++, sizeof(fingerprint), " "); - } - i--; - if ((i + 1) % 2 == 0) - cp[-2] = 0; - if ((i + 1) % 10 == 0) - cp[-1] = 0; - - return strdup(fingerprint); + return silc_fingerprint(h, hash->hash->hash_len); } static const char vo[]= "aeiouy"; diff --git a/lib/silcutil/silclog.c b/lib/silcutil/silclog.c index 0ffb3694..5e3cee08 100644 --- a/lib/silcutil/silclog.c +++ b/lib/silcutil/silclog.c @@ -157,12 +157,11 @@ void silc_log_output_debug(char *file, char *function, return; } - if (debug_cb) - { - (*debug_cb)(file, function, line, string); - silc_free(string); - return; - } + if (debug_cb) { + (*debug_cb)(file, function, line, string); + silc_free(string); + return; + } fprintf(stderr, "%s:%d: %s\n", function, line, string); fflush(stderr); @@ -191,12 +190,11 @@ void silc_log_output_hexdump(char *file, char *function, return; } - if (debug_hexdump_cb) - { - (*debug_hexdump_cb)(file, function, line, data_in, len, string); - silc_free(string); - return; - } + if (debug_hexdump_cb) { + (*debug_hexdump_cb)(file, function, line, data_in, len, string); + silc_free(string); + return; + } fprintf(stderr, "%s:%d: %s\n", function, line, string); silc_free(string); @@ -316,8 +314,9 @@ void silc_log_reset_debug_callbacks() void silc_log_set_debug_string(const char *debug_string) { silc_free(silc_debug_string); - if (strchr(debug_string, '(') && - strchr(debug_string, ')')) + if ((strchr(debug_string, '(') && + strchr(debug_string, ')')) || + strchr(debug_string, '$')) silc_debug_string = strdup(debug_string); else silc_debug_string = silc_string_regexify(debug_string); diff --git a/lib/silcutil/silcnet.h b/lib/silcutil/silcnet.h index 8659cc54..b9978d6e 100644 --- a/lib/silcutil/silcnet.h +++ b/lib/silcutil/silcnet.h @@ -200,26 +200,10 @@ bool silc_net_is_ip(const char *addr); * DESCRIPTION * * Converts the IP number string from numbers-and-dots notation to - * binary form. - * - ***/ -bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len); - -/****f* silcutil/SilcNetAPI/silc_net_addr2bin_ne - * - * SYNOPSIS - * - * bool silc_net_addr2bin_ne(const char *addr, unsigned char *bin, - * uint32 bin_len); - * - * DESCRIPTION - * - * Converts the IP number string from numbers-and-dots notation to * binary form in network byte order. * ***/ -bool silc_net_addr2bin_ne(const char *addr, unsigned char *bin, - uint32 bin_len); +bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len); /****f* silcutil/SilcNetAPI/silc_net_check_host_by_sock * diff --git a/lib/silcutil/silcutil.c b/lib/silcutil/silcutil.c index c61e70ce..c37ec4e5 100644 --- a/lib/silcutil/silcutil.c +++ b/lib/silcutil/silcutil.c @@ -544,7 +544,7 @@ char *silc_id_render(void *id, uint16 type) if (server_id->ip.data_len > 4) { } else { - SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data); + memcpy(&ipv4.s_addr, server_id->ip.data, 4); strcat(rid, inet_ntoa(ipv4)); } @@ -565,7 +565,7 @@ char *silc_id_render(void *id, uint16 type) if (client_id->ip.data_len > 4) { } else { - SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data); + memcpy(&ipv4.s_addr, client_id->ip.data, 4); strcat(rid, inet_ntoa(ipv4)); } @@ -587,7 +587,7 @@ char *silc_id_render(void *id, uint16 type) if (channel_id->ip.data_len > 4) { } else { - SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data); + memcpy(&ipv4.s_addr, channel_id->ip.data, 4); strcat(rid, inet_ntoa(ipv4)); } @@ -904,3 +904,31 @@ char *silc_client_chumode_char(uint32 mode) return strdup(string); } + +/* Creates fingerprint from data, usually used with SHA1 digests */ + +char *silc_fingerprint(const unsigned char *data, uint32 data_len) +{ + char fingerprint[64], *cp; + int i; + + memset(fingerprint, 0, sizeof(fingerprint)); + cp = fingerprint; + for (i = 0; i < data_len; i++) { + snprintf(cp, sizeof(fingerprint), "%02X", data[i]); + cp += 2; + + if ((i + 1) % 2 == 0) + snprintf(cp++, sizeof(fingerprint), " "); + + if ((i + 1) % 10 == 0) + snprintf(cp++, sizeof(fingerprint), " "); + } + i--; + if ((i + 1) % 2 == 0) + cp[-2] = 0; + if ((i + 1) % 10 == 0) + cp[-1] = 0; + + return strdup(fingerprint); +} diff --git a/lib/silcutil/silcutil.h b/lib/silcutil/silcutil.h index 1c467a56..03071194 100644 --- a/lib/silcutil/silcutil.h +++ b/lib/silcutil/silcutil.h @@ -67,5 +67,6 @@ char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac); char *silc_client_chumode(uint32 mode); char *silc_client_chumode_char(uint32 mode); int silc_gettimeofday(struct timeval *p); +char *silc_fingerprint(const unsigned char *data, uint32 data_len); #endif diff --git a/lib/silcutil/unix/silcunixnet.c b/lib/silcutil/unix/silcunixnet.c index 12b28b77..72d47641 100644 --- a/lib/silcutil/unix/silcunixnet.c +++ b/lib/silcutil/unix/silcunixnet.c @@ -284,22 +284,3 @@ bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len) memcpy(bin, (unsigned char *)&tmp.s_addr, 4); return ret != 0; } - -/* Converts the IP number string from numbers-and-dots notation to - binary form in network byte order. */ - -bool silc_net_addr2bin_ne(const char *addr, unsigned char *bin, - uint32 bin_len) -{ - struct in_addr tmp; - int ret; - - ret = inet_aton(addr, &tmp); - - if (bin_len < 4) - return FALSE; - - SILC_PUT32_MSB(tmp.s_addr, bin); - - return ret != 0; -} diff --git a/lib/silcutil/win32/silcwin32net.c b/lib/silcutil/win32/silcwin32net.c index 0ff72b33..ed7818c5 100644 --- a/lib/silcutil/win32/silcwin32net.c +++ b/lib/silcutil/win32/silcwin32net.c @@ -235,24 +235,6 @@ bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len); return ret != INADDR_NONE; } -/* Converts the IP number string from numbers-and-dots notation to - binary form in network byte order. */ - -bool silc_net_addr2bin_ne(const char *addr, unsigned char *bin, - uint32 bin_len) -{ - unsigned long ret; - - ret = inet_addr(addr); - - if (bin_len < 4) - return FALSE; - - SILC_PUT32_MSB(ret, bin); - - return ret != INADDR_NONE; -} - /* Set socket to non-blocking mode. */ int silc_net_set_socket_nonblock(int sock) diff --git a/lib/silcutil/win32/silcwin32util.c b/lib/silcutil/win32/silcwin32util.c index afe441ff..c8d9c9bf 100644 --- a/lib/silcutil/win32/silcwin32util.c +++ b/lib/silcutil/win32/silcwin32util.c @@ -21,6 +21,27 @@ #include "silcincludes.h" +/* XXX GNU regex may work on Win32 too!! */ +char *silc_string_regexify(const char *string) +{ + return strdup(string); +} + +char *silc_string_regex_combine(const char *string1, const char *string2) +{ + return strdup(string1); +} + +int silc_string_regex_match(const char *regex, const char *string) +{ + return TRUE; +} + +int silc_string_match(const char *string1, const char *string2) +{ + return TRUE; +} + #define FILETIME_1970 0x019db1ded53e8000 const BYTE DWLEN = sizeof(DWORD) * 8; diff --git a/prepare b/prepare index 8942bf63..4d4af282 100755 --- a/prepare +++ b/prepare @@ -37,7 +37,7 @@ # SILC Distribution versions. Set here or give the version on the command # line as argument. # -SILC_VERSION=0.6.1 # Base version +SILC_VERSION=0.6.2 # Base version ############################################################################# diff --git a/silc_optimize b/silc_optimize new file mode 100644 index 00000000..655ac714 --- /dev/null +++ b/silc_optimize @@ -0,0 +1,70 @@ +SILC Optimizations: +=================== + +o Library + + o There is currently three (3) allocations per packet in the + silc_packet_receive_process, which is used to process and + dispatch all packets in the packet queue to the parser callback + function. First allocation is for parse_ctx, second for the + SilcPacketContext, and third for packet->buffer where the actual + data is saved. + + The parse_ctx allocation can be removed by adding it as a + structure to the SilcPacketContext. When the SilcPacketContext + is allocated there is space for the parse context already. + + The silc_packet_context_alloc should have a free list of + packet contexts. If free packet context is found from the list + it is returned instead of allocating a new one. The library + could at first allocate them and save them to the free list + until enough contexts for smooth processing exists in the list. + This would remove a big allocation since the structure is + quite big, and even bigger if it would include the parse_ctx. + + The packet->buffer can be optimized too if the SilcBuffer + interface would support free lists as well. Maybe such could + be done in the same way as for SilcPacketContext. The + silc_buffer_alloc would check free list before actually + allocating new memory. Since the packets in the SILC protocol + usually are about the same size (due to padding) it would be + easy to find suitable size buffer from the free list very + quickly. + + These naturally cause the overal memory consumption to grow + but would take away many allocations that can be done several + times in a second. + + o Move the actual file descriptor task callback (the callback that + handles the incoming data, outgoing data etc, that is implemnted + in server and client separately (silc_server_packet_process and + silc_client_packet_proces)) to the low level socket connection + handling routines, and create an interface where the application + can register a callbacks for incoming data, outoing data and EOF + receiving and maybe sending too, which the library will call + when necessary. This way we can move the data handling in one + place. + +o Server + + o When processing the decrypted and parsed packet we call the + silc_server_packet_parse_type function. This function has a + huge switch statement. Replace this switch statment with pre- + defined table of function pointers where each of the slot + in the table represents the packet type (1 for packet type + value 1, 2 for value 2 and so on), and call the callback + found in the slot. In this case we can do one-to-one mapping + of packet types to correct function. + + o Same optimizations could be done with notify packets which + has huge switch statement too. Same kind of table of notify + callbacks would be very easy to do, and achieve one-to-one + mapping of notify types. + + o The parser callback in the server will add a timeout task for + all packets. It will require registering and allocating a + new task to the SilcSchedule. Maybe, at least, for server + and router packets the parser would be called immediately + instead of adding it to the scheduler with 0 timeout. It + should be analyzed too how slow the task registering process + actually is, and find out ways to optimize it. -- 2.24.0