updates.
[silc.git] / apps / silcd / server.c
index 148e51b1aa503728592346908af7f3f7ea9f91c3..4892cd065864cae453981326a1b592d73dc6438b 100644 (file)
@@ -121,12 +121,14 @@ int silc_server_init(SilcServer server)
   assert(server->config);
 
   /* Set public and private keys */
-  server->public_key = server->config->server_keys->public_key;
-  server->private_key = server->config->server_keys->private_key;
-  if (!server->public_key || !server->private_key) {
+  if (!server->config->server_keys ||
+      !server->config->server_keys->public_key || 
+      !server->config->server_keys->private_key) {
     SILC_LOG_ERROR(("Server public key and/or private key does not exist"));
     return FALSE;
   }
+  server->public_key = server->config->server_keys->public_key;
+  server->private_key = server->config->server_keys->private_key;
 
   /* XXX After server is made as Silc Server Library this can be given
      as argument, for now this is hard coded */
@@ -237,6 +239,23 @@ int silc_server_init(SilcServer server)
                      &newsocket);
 
     server->sockets[sock[i]] = newsocket;
+    
+    /* Perform name and address lookups to resolve the listenning address
+       and port. */
+    if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname, 
+                                    &newsocket->ip)) {
+      if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
+         !newsocket->ip) {
+       SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
+                       newsocket->hostname ? newsocket->hostname :
+                       newsocket->ip ? newsocket->ip : ""));
+       server->stat.conn_failures++;
+       goto err0;
+      }
+      if (!newsocket->hostname)
+       newsocket->hostname = strdup(newsocket->ip);
+    }
+    newsocket->port = silc_net_get_local_port(sock[i]);
 
     /* Put the allocated socket pointer also to the entry allocated above 
        for fast back-referencing to the socket list. */
@@ -927,7 +946,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
   SilcServer server = (SilcServer)context;
   SilcSocketConnection newsocket;
   SilcServerKEInternalContext *proto_ctx;
-  int sock;
+  int sock, port;
+  void *cconfig, *sconfig, *rconfig;
 
   SILC_LOG_DEBUG(("Accepting new connection"));
 
@@ -975,6 +995,44 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
   }
   newsocket->port = silc_net_get_remote_port(sock);
 
+  /* Register the connection for network input and output. This sets
+     that scheduler will listen for incoming packets for this connection 
+     and sets that outgoing packets may be sent to this connection as well.
+     However, this doesn't set the scheduler for outgoing traffic, it
+     will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+     later when outgoing data is available. */
+  SILC_REGISTER_CONNECTION_FOR_IO(sock);
+
+  /* Check whether we have configred this sort of connection at all. We
+     have to check all configurations since we don't know what type of
+     connection this is. */
+  port = server->sockets[fd]->port; /* Listenning port */
+  if (!(cconfig = silc_server_config_find_client_conn(server->config,
+                                                     newsocket->ip, port)))
+    cconfig = silc_server_config_find_client_conn(server->config,
+                                                 newsocket->hostname, 
+                                                 port);
+  if (!(sconfig = silc_server_config_find_server_conn(server->config,
+                                                    newsocket->ip, 
+                                                    port)))
+    sconfig = silc_server_config_find_server_conn(server->config,
+                                                 newsocket->hostname,
+                                                 port);
+  if (!(rconfig = silc_server_config_find_router_conn(server->config,
+                                                    newsocket->ip, port)))
+    rconfig = silc_server_config_find_router_conn(server->config,
+                                                 newsocket->hostname, 
+                                                 port);
+  if (!cconfig && !sconfig && !rconfig) {
+    silc_server_disconnect_remote(server, newsocket, 
+                                 "Server closed connection: "
+                                 "Connection refused");
+    server->stat.conn_failures++;
+    return;
+  }
+
+  /* The connection is allowed */
+
   SILC_LOG_INFO(("Incoming connection from %s (%s)", newsocket->hostname,
                 newsocket->ip));
 
@@ -985,6 +1043,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
   proto_ctx->sock = newsocket;
   proto_ctx->rng = server->rng;
   proto_ctx->responder = TRUE;
+  proto_ctx->cconfig = cconfig;
+  proto_ctx->sconfig = sconfig;
+  proto_ctx->rconfig = rconfig;
 
   /* Prepare the connection for key exchange protocol. We allocate the
      protocol but will not start it yet. The connector will be the
@@ -1005,14 +1066,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
                       context, 60, 0,
                       SILC_TASK_TIMEOUT,
                       SILC_TASK_PRI_LOW);
-
-  /* Register the connection for network input and output. This sets
-     that scheduler will listen for incoming packets for this connection 
-     and sets that outgoing packets may be sent to this connection as well.
-     However, this doesn't set the scheduler for outgoing traffic, it
-     will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
-     later when outgoing data is available. */
-  SILC_REGISTER_CONNECTION_FOR_IO(sock);
 }
 
 /* Second part of accepting new connection. Key exchange protocol has been
@@ -1091,6 +1144,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
   proto_ctx->responder = TRUE;
   proto_ctx->dest_id_type = ctx->dest_id_type;
   proto_ctx->dest_id = ctx->dest_id;
+  proto_ctx->cconfig = ctx->cconfig;
+  proto_ctx->sconfig = ctx->sconfig;
+  proto_ctx->rconfig = ctx->rconfig;
 
   /* Free old protocol as it is finished now */
   silc_protocol_free(protocol);
@@ -1190,6 +1246,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   case SILC_SOCKET_TYPE_ROUTER:
     {
       SilcServerEntry new_server;
+      SilcServerConfigSectionServerConnection *conn = 
+       sock->type == SILC_SOCKET_TYPE_SERVER ? ctx->sconfig : ctx->rconfig;
 
       SILC_LOG_DEBUG(("Remote host is %s", 
                      sock->type == SILC_SOCKET_TYPE_SERVER ? 
@@ -1222,12 +1280,14 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       server->stat.servers++;
 
       id_entry = (void *)new_server;
-      
-      /* There is connection to other server now, if it is router then
-        we will have connection to outside world.  If we are router but
-        normal server connected to us then we will remain standalone,
-        if we are standlone. */
+
+      /* Check whether this connection is to be our primary router connection
+        if we dont' already have the primary route. */
       if (server->standalone && sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       if (silc_server_config_is_primary_route(server->config) &&
+           !conn->initiator)
+         break;
+
        SILC_LOG_DEBUG(("We are not standalone server anymore"));
        server->standalone = FALSE;
        if (!server->id_entry->router) {
@@ -1235,6 +1295,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
          server->router = id_entry;
        }
       }
+
       break;
     }
   default:
@@ -1378,7 +1439,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   if (idata) {
     idata->last_receive = time(NULL);
     cipher = idata->receive_key;
-    hmac = idata->hmac;
+    hmac = idata->hmac_receive;
   }
  
   /* Process the packet. This will call the parser that will then
@@ -1420,7 +1481,7 @@ static int silc_server_packet_decrypt_check(SilcPacketType packet_type,
 
   return FALSE;
 }
-
+  
 /* Parses whole packet, received earlier. */
 
 SILC_TASK_CALLBACK(silc_server_packet_parse_real)
@@ -1429,12 +1490,14 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
   SilcServer server = (SilcServer)parse_ctx->context;
   SilcSocketConnection sock = parse_ctx->sock;
   SilcPacketContext *packet = parse_ctx->packet;
+  SilcIDListData idata = (SilcIDListData)sock->user_data;
   int ret;
 
   SILC_LOG_DEBUG(("Start"));
 
   /* Decrypt the received packet */
-  ret = silc_packet_decrypt(parse_ctx->cipher, parse_ctx->hmac, 
+  ret = silc_packet_decrypt(idata ? idata->receive_key : NULL, 
+                           idata ? idata->hmac_receive : NULL, 
                            packet->buffer, packet,
                            silc_server_packet_decrypt_check, parse_ctx);
   if (ret < 0)
@@ -1469,7 +1532,8 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
   if (server->server_type == SILC_ROUTER) {
     /* Route the packet if it is not destined to us. Other ID types but
        server are handled separately after processing them. */
-    if (packet->dst_id_type == SILC_ID_SERVER && 
+    if (!(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
+       packet->dst_id_type == SILC_ID_SERVER && 
        sock->type != SILC_SOCKET_TYPE_CLIENT &&
        SILC_ID_SERVER_COMPARE(packet->dst_id, server->id_string)) {
       
@@ -1485,18 +1549,21 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
       silc_free(id);
       goto out;
     }
-    
+  }
+
+  /* Parse the incoming packet type */
+  silc_server_packet_parse_type(server, sock, packet);
+
+  if (server->server_type == SILC_ROUTER) {
     /* Broadcast packet if it is marked as broadcast packet and it is
        originated from router and we are router. */
     if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
-       packet->flags & SILC_PACKET_FLAG_BROADCAST) {
+       packet->flags & SILC_PACKET_FLAG_BROADCAST &&
+       !server->standalone) {
       silc_server_packet_broadcast(server, server->router->connection, packet);
     }
   }
 
-  /* Parse the incoming packet type */
-  silc_server_packet_parse_type(server, sock, packet);
-
  out:
   /*  silc_buffer_clear(sock->inbuf); */
   silc_packet_context_free(packet);
@@ -1513,6 +1580,7 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context)
 
   switch (sock->type) {
   case SILC_SOCKET_TYPE_UNKNOWN:
+  case SILC_SOCKET_TYPE_CLIENT:
     /* Parse the packet with timeout */
     silc_task_register(server->timeout_queue, sock->sock,
                       silc_server_packet_parse_real,
@@ -1520,15 +1588,6 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context)
                       SILC_TASK_TIMEOUT,
                       SILC_TASK_PRI_NORMAL);
     break;
-  case SILC_SOCKET_TYPE_CLIENT:
-    /* Parse the packet with timeout (unless protocol is active) */
-    silc_task_register(server->timeout_queue, sock->sock,
-                      silc_server_packet_parse_real,
-                      (void *)parser_context, 0, 
-                      (sock->protocol ? 1 : 100000),
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_NORMAL);
-    break;
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
     /* Packets from servers are parsed as soon as possible */
@@ -1955,8 +2014,7 @@ void silc_server_packet_parse_type(SilcServer server,
 
       /* Let the protocol handle the packet */
       sock->protocol->execute(server->timeout_queue, 0, 
-                             sock->protocol, sock->sock,
-                             0, 100000);
+                             sock->protocol, sock->sock, 0, 0);
     } else {
       SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
                      "protocol active, packet dropped."));
@@ -2093,7 +2151,7 @@ void silc_server_free_client_data(SilcServer server,
     if (sock->outbuf->data - sock->outbuf->head)
      silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
 
-    silc_server_packet_send_real(server, sock, TRUE);
+    silc_packet_send(sock, TRUE);
 
     SILC_SET_CONNECTION_FOR_INPUT(sock->sock);
     SILC_UNSET_OUTBUF_PENDING(sock);
@@ -2155,7 +2213,8 @@ void silc_server_free_sock_user_data(SilcServer server,
 
       /* Free all client entries that this server owns as they will
         become invalid now as well. */
-      silc_server_remove_clients_by_server(server, user_data, TRUE);
+      if (user_data->id)
+       silc_server_remove_clients_by_server(server, user_data, TRUE);
 
       /* If this was our primary router connection then we're lost to
         the outside world. */
@@ -2339,8 +2398,8 @@ int silc_server_remove_clients_by_server(SilcServer server,
                                          argv_types);
       silc_server_send_notify_args(server, 
                                   server->router->connection,
-                                  server->server_type == 
-                                  SILC_SERVER ? FALSE : TRUE, 
+                                  server->server_type == SILC_SERVER ? 
+                                  FALSE : TRUE, 
                                   SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
                                   argc, args);
       silc_buffer_free(args);
@@ -2480,8 +2539,6 @@ void silc_server_remove_from_channels(SilcServer server,
                                           signoff_message, signoff_message ?
                                           strlen(signoff_message) : 0);
 
-      server->stat.my_channels--;
-
       if (channel->rekey)
        silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
 
@@ -2502,6 +2559,7 @@ void silc_server_remove_from_channels(SilcServer server,
 
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
+      server->stat.my_channels--;
       continue;
     }
 
@@ -2595,7 +2653,6 @@ int silc_server_remove_from_one_channel(SilcServer server,
                                           SILC_NOTIFY_TYPE_LEAVE, 1,
                                           clidp->data, clidp->len);
 
-      server->stat.my_channels--;
       silc_buffer_free(clidp);
 
       if (channel->rekey)
@@ -2618,6 +2675,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
 
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
+      server->stat.my_channels--;
       return FALSE;
     }
 
@@ -3677,12 +3735,6 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
     return;
   }
 
-  /* Take the keys into use */
-  if (ctx->pfs == TRUE)
-    silc_server_protocol_rekey_generate_pfs(server, ctx);
-  else
-    silc_server_protocol_rekey_generate(server, ctx);
-
   /* Cleanup */
   silc_protocol_free(protocol);
   sock->protocol = NULL;