/*
- id.c
+ serverid.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2000 Pekka Riikonen
+ Copyright (C) 1997 - 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1 2000/06/27 11:36:56 priikone
- * Initial revision
- *
- *
- */
+/* $Id$ */
#include "serverincludes.h"
+#include "server_internal.h"
/* Creates a Server ID. Newly created Server ID is returned to the
new_id argument. */
-void silc_id_create_server_id(int sock, SilcRng rng, SilcServerID **new_id)
+void silc_id_create_server_id(const char *ip, SilcUInt16 port, SilcRng rng,
+ SilcServerID **new_id)
{
- struct sockaddr_in server;
- int rval, len;
-
SILC_LOG_DEBUG(("Creating new Server ID"));
*new_id = silc_calloc(1, sizeof(**new_id));
- if (*new_id == NULL) {
- SILC_LOG_ERROR(("Could not allocate new Server ID"));
- return;
- }
- /* Get IP address */
- len = sizeof(server);
- rval = getsockname(sock, (struct sockaddr *)&server, &len);
- if (rval < 0) {
- SILC_LOG_ERROR(("Could not get IP address: %s", strerror(errno)));
+ /* Create the ID */
+
+ if (!silc_net_addr2bin(ip, (*new_id)->ip.data,
+ sizeof((*new_id)->ip.data))) {
silc_free(*new_id);
*new_id = NULL;
return;
}
- /* Create the ID */
- (*new_id)->ip = server.sin_addr;
- (*new_id)->port = server.sin_port;
- (*new_id)->rnd = silc_rng_get_rn16(rng);
-}
+ (*new_id)->ip.data_len = silc_net_is_ip4(ip) ? 4 : 16;
+ (*new_id)->port = SILC_SWAB_16(port);
+ (*new_id)->rnd = 0xff;
-/* Creates Client ID */
+ SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(*new_id, SILC_ID_SERVER)));
+}
-void silc_id_create_client_id(SilcServerID *server_id, SilcRng rng,
- SilcHash md5hash, char *nickname,
- SilcClientID **new_id)
+/* Creates Client ID. This assures that there are no collisions in the
+ created Client IDs. If the collision would occur (meaning that there
+ are 2^8 occurences of the `nickname' this will return FALSE, and the
+ caller must recall the function with different nickname. If this returns
+ TRUE the new ID was created successfully. */
+
+SilcBool silc_id_create_client_id(SilcServer server,
+ SilcServerID *server_id, SilcRng rng,
+ SilcHash md5hash,
+ unsigned char *nickname, SilcUInt32 nick_len,
+ SilcClientID **new_id)
{
unsigned char hash[16];
+ SilcBool finding = FALSE;
SILC_LOG_DEBUG(("Creating new Client ID"));
*new_id = silc_calloc(1, sizeof(**new_id));
- if (*new_id == NULL) {
- SILC_LOG_ERROR(("Could not allocate new Client ID"));
- return;
- }
- /* Create hash of the nickanem */
- silc_hash_make(md5hash, nickname, strlen(nickname), hash);
+ /* Create hash of the nickname (it's already checked as valid identifier
+ string). */
+ silc_hash_make(md5hash, nickname, nick_len, hash);
/* Create the ID */
- (*new_id)->ip.s_addr = server_id->ip.s_addr;
+ memcpy((*new_id)->ip.data, server_id->ip.data, server_id->ip.data_len);
+ (*new_id)->ip.data_len = server_id->ip.data_len;
(*new_id)->rnd = silc_rng_get_byte(rng);
memcpy((*new_id)->hash, hash, CLIENTID_HASH_LEN);
+
+ /* Assure that the ID does not exist already */
+ while (1) {
+ if (!silc_idlist_find_client_by_id(server->local_list,
+ *new_id, FALSE, NULL))
+ if (!silc_idlist_find_client_by_id(server->global_list,
+ *new_id, FALSE, NULL))
+ break;
+
+ /* The ID exists, start increasing the rnd from 0 until we find a
+ ID that does not exist. If we wrap and it still exists then we
+ will return FALSE and the caller must send some other nickname
+ since this cannot be used anymore. */
+ (*new_id)->rnd++;
+
+ if (finding && (*new_id)->rnd == 0)
+ return FALSE;
+
+ if (!finding) {
+ (*new_id)->rnd = 0;
+ finding = TRUE;
+ }
+ }
+
+ SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(*new_id, SILC_ID_CLIENT)));
+
+ return TRUE;
}
/* Creates Channel ID */
-void silc_id_create_channel_id(SilcServerID *router_id, SilcRng rng,
- SilcChannelID **new_id)
+SilcBool silc_id_create_channel_id(SilcServer server,
+ SilcServerID *router_id, SilcRng rng,
+ SilcChannelID **new_id)
{
+ SilcBool finding = TRUE;
+
SILC_LOG_DEBUG(("Creating new Channel ID"));
*new_id = silc_calloc(1, sizeof(**new_id));
- if (*new_id == NULL) {
- SILC_LOG_ERROR(("Could not allocate new Channel ID"));
- return;
- }
/* Create the ID */
- (*new_id)->ip.s_addr = router_id->ip.s_addr;
+ memcpy((*new_id)->ip.data, router_id->ip.data, router_id->ip.data_len);
+ (*new_id)->ip.data_len = router_id->ip.data_len;
(*new_id)->port = router_id->port;
(*new_id)->rnd = silc_rng_get_rn16(rng);
+
+ /* Assure that the ID does not exist already */
+ while (1) {
+ if (!silc_idlist_find_channel_by_id(server->local_list,
+ *new_id, NULL))
+ break;
+
+ (*new_id)->rnd++;
+
+ if (finding && (*new_id)->rnd == 0)
+ return FALSE;
+
+ if (!finding) {
+ (*new_id)->rnd = 0;
+ finding = TRUE;
+ }
+ }
+
+ SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(*new_id, SILC_ID_CHANNEL)));
+
+ return TRUE;
+}
+
+/* Checks whether the `server_id' is valid. It must be based to the
+ IP address provided in the `remote' socket connection. */
+
+SilcBool silc_id_is_valid_server_id(SilcServer server,
+ SilcServerID *server_id,
+ SilcPacketStream remote)
+{
+ unsigned char ip[16];
+ const char *remote_ip;
+ SilcStream stream = silc_packet_stream_get_stream(remote);
+
+ silc_socket_stream_get_info(stream, NULL, NULL, &remote_ip, NULL);
+ if (!silc_net_addr2bin(remote_ip, ip, sizeof(ip)))
+ return FALSE;
+
+ if (silc_net_is_ip4(remote_ip)) {
+ if (!memcmp(server_id->ip.data, ip, 4))
+ return TRUE;
+ } else {
+ if (!memcmp(server_id->ip.data, ip, 16))
+ return TRUE;
+ }
+
+ return FALSE;
}