X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=f62e96754fa9ef610ef556f246f7b6f3711648cd;hb=HEAD;hp=e8ef68f36c7ec32642b806c78e5f70d4dc01feea;hpb=8fdb8f90b1756520f173a0dc11a2320cb63c0a4e;p=ngircd-alex.git diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index e8ef68f3..68a901d0 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2019 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2024 Alexander Barton (alex@barton.de) and Contributors. * * 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 @@ -66,6 +66,7 @@ #include "ng_ipaddr.h" #include "parse.h" #include "resolve.h" +#include "sighandlers.h" #define SERVER_WAIT (NONE - 1) /** "Wait for outgoing connection" flag */ @@ -479,6 +480,15 @@ Conn_InitListeners( void ) /* not using systemd socket activation, initialize listening sockets: */ +#ifdef SSL_SUPPORT + if (!Conf_SSLOptions.KeyFile && + array_length(&Conf_SSLOptions.ListenPorts, sizeof (UINT16))) { + Log(LOG_ERR, + "Ignoring SSL-enabled listening ports: No key file set!"); + array_free(&Conf_SSLOptions.ListenPorts); + } +#endif + /* can't use Conf_ListenAddress directly, see below */ copy = strdup(Conf_ListenAddress); if (!copy) { @@ -566,7 +576,7 @@ InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port /** * Set a socket to "IPv6 only". If the given socket doesn't belong to the * AF_INET6 family, or the operating system doesn't support this functionality, - * this function retruns silently. + * this function returns silently. * * @param af Address family of the socket. * @param sock Socket handle. @@ -659,11 +669,13 @@ Conn_Handler(void) int i; size_t wdatalen; struct timeval tv; - time_t t; + time_t t, notify_t = 0; bool command_available; + char status[200]; Log(LOG_NOTICE, "Server \"%s\" (on \"%s\") ready.", Client_ID(Client_ThisServer()), Client_Hostname(Client_ThisServer())); + Signal_NotifySvcMgr("READY=1\n"); while (!NGIRCd_SignalQuit && !NGIRCd_SignalRestart) { t = time(NULL); @@ -772,20 +784,34 @@ Conn_Handler(void) exit(1); } - /* Should ngIRCd timeout when idle? */ + t = time(NULL); if (Conf_IdleTimeout > 0 && NumConnectionsAccepted > 0 - && idle_t > 0 && time(NULL) - idle_t >= Conf_IdleTimeout) { + && idle_t > 0 && t - idle_t >= Conf_IdleTimeout) { + /* Should ngIRCd timeout when idle? */ LogDebug("Server idle timeout reached: %d second%s. Initiating shutdown ...", Conf_IdleTimeout, Conf_IdleTimeout == 1 ? "" : "s"); NGIRCd_SignalQuit = true; + } else if (Signal_NotifySvcMgr_Possible() && t - notify_t > 3) { + /* Send the current status to the service manager. */ + snprintf(status, sizeof(status), + "WATCHDOG=1\nSTATUS=%ld connection%s established (%ld user%s, %ld server%s), %ld maximum. %ld accepted in total.\n", + (long)NumConnections, NumConnections == 1 ? "" : "s", + Client_MyUserCount(), Client_MyUserCount() == 1 ? "" : "s", + Client_MyServerCount(), Client_MyServerCount() == 1 ? "" : "s", + (long)NumConnectionsMax, (long)NumConnectionsAccepted); + Signal_NotifySvcMgr(status); + notify_t = t; } } - if (NGIRCd_SignalQuit) + if (NGIRCd_SignalQuit) { Log(LOG_NOTICE | LOG_snotice, "Server going down NOW!"); - else if (NGIRCd_SignalRestart) + Signal_NotifySvcMgr("STOPPING=1\n"); + } else if (NGIRCd_SignalRestart) { Log(LOG_NOTICE | LOG_snotice, "Server restarting NOW!"); + Signal_NotifySvcMgr("RELOADING=1\n"); + } } /* Conn_Handler */ /** @@ -795,7 +821,7 @@ Conn_Handler(void) * the result is a valid IRC message (oversized messages are shortened, for * example). Then it calls the Conn_Write() function to do the actual sending. * - * @param Idx Index fo the connection. + * @param Idx Index of the connection. * @param Format Format string, see printf(). * @returns true on success, false otherwise. */ @@ -1177,7 +1203,7 @@ Conn_CountMax(void) } /* Conn_CountMax */ /** - * Get number of connections accepted since the daemon startet. + * Get number of connections accepted since the daemon started. * * @returns Number of connections accepted. */ @@ -1291,14 +1317,12 @@ Handle_Write( CONN_ID Idx ) if (errno == EAGAIN || errno == EINTR) return true; - /* Log write errors but do not close the connection yet. - * Calling Conn_Close() now could result in too many recursive calls. - */ - if (!Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ISCLOSING)) + if (!Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ISCLOSING)) { Log(LOG_ERR, "Write error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror(errno)); - else + Conn_Close(Idx, "Write error", NULL, false); + } else LogDebug("Recursive write error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror(errno)); @@ -1478,10 +1502,6 @@ Conn_StartLogin(CONN_ID Idx) assert(Idx >= 0); - /* Nothing to do if DNS (and resolver subprocess) is disabled */ - if (!Conf_DNS) - return; - #ifdef IDENTAUTH /* Should we make an IDENT request? */ if (Conf_Ident) @@ -1491,13 +1511,21 @@ Conn_StartLogin(CONN_ID Idx) if (Conf_NoticeBeforeRegistration) { /* Send "NOTICE *" messages to the client */ #ifdef IDENTAUTH - if (Conf_Ident) - (void)Conn_WriteStr(Idx, - "NOTICE * :*** Looking up your hostname and checking ident"); - else + if (Conf_Ident) { + if (Conf_DNS) + (void)Conn_WriteStr(Idx, + "NOTICE * :*** Looking up your hostname and checking ident"); + else + (void)Conn_WriteStr(Idx, + "NOTICE * :*** Checking ident"); + } else #endif + if(Conf_DNS) (void)Conn_WriteStr(Idx, "NOTICE * :*** Looking up your hostname"); + else + (void)Conn_WriteStr(Idx, + "NOTICE * :*** Processing your connection"); /* Send buffered data to the client, but break on errors * because Handle_Write() would have closed the connection * again in this case! */ @@ -1505,8 +1533,9 @@ Conn_StartLogin(CONN_ID Idx) return; } - Resolve_Addr(&My_Connections[Idx].proc_stat, &My_Connections[Idx].addr, - ident_sock, cb_Read_Resolver_Result); + Resolve_Addr_Ident(&My_Connections[Idx].proc_stat, + &My_Connections[Idx].addr, + ident_sock, cb_Read_Resolver_Result); } /** @@ -1528,7 +1557,7 @@ Account_Connection(void) * a 1:1 mapping today) and enlarge the "connection pool" accordingly. * * @param Sock Socket handle. - * @returns Connecion index or NONE when the pool is too small. + * @returns Connection index or NONE when the pool is too small. */ static CONN_ID Socket2Index( int Sock ) @@ -2291,13 +2320,16 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) * the resolver results, so we don't have to worry to override settings * from these commands here. */ if(Client_Type(c) == CLIENT_UNKNOWN) { - strlcpy(My_Connections[i].host, readbuf, - sizeof(My_Connections[i].host)); - Client_SetHostname(c, readbuf); - if (Conf_NoticeBeforeRegistration) - (void)Conn_WriteStr(i, + if (readbuf[0]) { + /* We got a hostname */ + strlcpy(My_Connections[i].host, readbuf, + sizeof(My_Connections[i].host)); + Client_SetHostname(c, readbuf); + if (Conf_NoticeBeforeRegistration) + (void)Conn_WriteStr(i, "NOTICE * :*** Found your hostname: %s", My_Connections[i].host); + } #ifdef IDENTAUTH ++identptr; if (*identptr) { @@ -2541,6 +2573,13 @@ cb_listen_ssl(int sock, short irrelevant) /** * IO callback for new outgoing SSL-enabled server connections. * + * IMPORTANT: The SSL session has been validated before, but all errors have + * been ignored so far! The reason for this is that the generic SSL code has no + * idea if the new session actually belongs to a server, as this only becomes + * clear when the remote peer sends its PASS command (and we have to handle + * invalid client certificates!). Therefore, it is important to check the + * status of the SSL session first before continuing the server handshake here! + * * @param sock Socket descriptor. * @param unused (ignored IO specification) */ @@ -2548,6 +2587,7 @@ static void cb_connserver_login_ssl(int sock, short unused) { CONN_ID idx = Socket2Index(sock); + int serveridx; (void) unused; @@ -2566,9 +2606,26 @@ cb_connserver_login_ssl(int sock, short unused) return; } - Log( LOG_INFO, "SSL connection %d with \"%s:%d\" established.", idx, - My_Connections[idx].host, Conf_Server[Conf_GetServer( idx )].port ); + serveridx = Conf_GetServer(idx); + assert(serveridx >= 0); + /* The SSL handshake is done, but validation results were ignored so + * far, so let's see where we are: */ + LogDebug("SSL handshake on socket %d done.", idx); + if (!Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_PEERCERT_OK)) { + if (Conf_Server[serveridx].SSLVerify) { + Log(LOG_ERR, + "Peer certificate check failed for \"%s\" on connection %d!", + My_Connections[idx].host, idx); + Conn_Close(idx, "Valid certificate required", + NULL, false); + return; + } + Log(LOG_WARNING, + "Peer certificate check failed for \"%s\" on connection %d, but \"SSLVerify\" is disabled. Continuing ...", + My_Connections[idx].host, idx); + } + LogDebug("Server certificate accepted, continuing server login ..."); server_login(idx); }