X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=cd350a8d619700a2ca89034b5a05b132df6cba36;hb=1ed49de83a335713ee437171335c93725dd19ee6;hp=731647d9cda3f5dd7576bbfbebb4e885657c8ee2;hpb=536538968c6d2cd22669d4622a83d32f95d4eb55;p=ngircd-alex.git diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 731647d9..cd350a8d 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -109,37 +109,51 @@ extern struct SSLOptions Conf_SSLOptions; static void cb_connserver_login_ssl PARAMS((int sock, short what)); static void cb_clientserver_ssl PARAMS((int sock, short what)); #endif -static void cb_Read_Resolver_Result PARAMS(( int sock, UNUSED short what)); -static void cb_Connect_to_Server PARAMS(( int sock, UNUSED short what)); +static void cb_Read_Resolver_Result PARAMS((int sock, UNUSED short what)); +static void cb_Connect_to_Server PARAMS((int sock, UNUSED short what)); static void cb_clientserver PARAMS((int sock, short what)); + +/** + * IO callback for listening sockets: handle new connections. This callback + * gets called when a new non-SSL connection should be accepted. + * @param sock Socket descriptor + * @param irrelevant (ignored IO specification) + */ static void cb_listen(int sock, short irrelevant) { (void) irrelevant; - if (New_Connection( sock ) >= 0) - NumConnections++; - LogDebug("Total number of connections now %ld.", NumConnections); + (void) New_Connection(sock); } #ifdef SSL_SUPPORT +/** + * IO callback for listening SSL sockets: handle new connections. This callback + * gets called when a new SSL-enabled connection should be accepted. + * @param sock Socket descriptor + * @param irrelevant (ignored IO specification) + */ static void cb_listen_ssl(int sock, short irrelevant) { int fd; + (void) irrelevant; fd = New_Connection(sock); if (fd < 0) return; - - NumConnections++; - LogDebug("Total number of connections now %ld.", NumConnections); io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl); } #endif +/** + * IO callback for new outgoing non-SSL server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_connserver(int sock, UNUSED short what) { @@ -213,6 +227,10 @@ cb_connserver(int sock, UNUSED short what) } +/** + * Login to a remote server. + * @param idx Connection index + */ static void server_login(CONN_ID idx) { @@ -229,6 +247,11 @@ server_login(CONN_ID idx) #ifdef SSL_SUPPORT +/** + * IO callback for new outgoing SSL-enabled server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_connserver_login_ssl(int sock, short unused) { @@ -258,6 +281,11 @@ cb_connserver_login_ssl(int sock, short unused) #endif +/** + * IO callback for established non-SSL client and server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_clientserver(int sock, short what) { @@ -270,18 +298,27 @@ cb_clientserver(int sock, short what) return; } #ifdef SSL_SUPPORT - if (what & IO_WANTREAD || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) - Read_Request( idx ); /* if TLS layer needs to write additional data, call Read_Request instead so SSL/TLS can continue */ + if (what & IO_WANTREAD + || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) { + /* if TLS layer needs to write additional data, call + * Read_Request() instead so that SSL/TLS can continue */ + Read_Request(idx); + } #else if (what & IO_WANTREAD) - Read_Request( idx ); + Read_Request(idx); #endif if (what & IO_WANTWRITE) - Handle_Write( idx ); + Handle_Write(idx); } #ifdef SSL_SUPPORT +/** + * IO callback for established SSL-enabled client and server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_clientserver_ssl(int sock, short what) { @@ -295,11 +332,13 @@ cb_clientserver_ssl(int sock, short what) } switch (ConnSSL_Accept(&My_Connections[idx])) { - case 1: break; /* OK */ - case 0: return; /* EAGAIN: this callback will be invoked again by the io layer */ - default: - Conn_Close( idx, "Socket closed!", "SSL accept error", false ); - return; + case 1: + break; /* OK */ + case 0: + return; /* EAGAIN: callback will be invoked again by IO layer */ + default: + Conn_Close(idx, "Socket closed!", "SSL accept error", false); + return; } if (what & IO_WANTREAD) Read_Request(idx); @@ -312,6 +351,9 @@ cb_clientserver_ssl(int sock, short what) #endif +/** + * Initialite connecion module. + */ GLOBAL void Conn_Init( void ) { @@ -347,6 +389,9 @@ Conn_Init( void ) } /* Conn_Init */ +/** + * Clean up connection module. + */ GLOBAL void Conn_Exit( void ) { @@ -399,6 +444,10 @@ ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short)) } +/** + * Initialize all listening sockets. + * @return Number of created listening sockets + */ GLOBAL unsigned int Conn_InitListeners( void ) { @@ -433,13 +482,12 @@ Conn_InitListeners( void ) listen_addr = strtok(NULL, ","); } - /* - * can't free() Conf_ListenAddress here. On /REHASH, if the config file + /* Can't free() Conf_ListenAddress here: on REHASH, if the config file * cannot be re-loaded, we'd end up with a NULL Conf_ListenAddress. * Instead, free() takes place in conf.c, before the config file - * is being parsed. - */ + * is being parsed. */ free(copy); + return created; } /* Conn_InitListeners */ @@ -582,6 +630,7 @@ NewListener(const char *listen_addr, UINT16 Port) return sock; } /* NewListener */ + #ifdef SSL_SUPPORT /* * SSL/TLS connections require extra treatment: @@ -1163,12 +1212,14 @@ Count_Connections(ng_ipaddr_t *a) } /* Count_Connections */ +/** + * Initialize new client connection on a listening socket. + * @param Sock Listening socket descriptor + * @return Accepted socket descriptor or -1 on error + */ static int -New_Connection( int Sock ) +New_Connection(int Sock) { - /* Neue Client-Verbindung von Listen-Socket annehmen und - * CLIENT-Struktur anlegen. */ - #ifdef TCPWRAP struct request_info req; #endif @@ -1178,10 +1229,9 @@ New_Connection( int Sock ) CLIENT *c; long cnt; - assert( Sock > NONE ); - /* Connection auf Listen-Socket annehmen */ - new_sock_len = (int)sizeof(new_addr); + assert(Sock > NONE); + new_sock_len = (int)sizeof(new_addr); new_sock = accept(Sock, (struct sockaddr *)&new_addr, (socklen_t *)&new_sock_len); if (new_sock < 0) { @@ -1198,49 +1248,56 @@ New_Connection( int Sock ) #ifdef TCPWRAP /* Validate socket using TCP Wrappers */ - request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL ); + request_init(&req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, + RQ_CLIENT_SIN, &new_addr, NULL); fromhost(&req); if (!hosts_access(&req)) { - Log (deny_severity, "Refused connection from %s (by TCP Wrappers)!", ip_str); - Simple_Message( new_sock, "ERROR :Connection refused" ); - close( new_sock ); + Log(deny_severity, + "Refused connection from %s (by TCP Wrappers)!", ip_str); + Simple_Message(new_sock, "ERROR :Connection refused"); + close(new_sock); return -1; } #endif - /* Socket initialisieren */ - if (!Init_Socket( new_sock )) + if (!Init_Socket(new_sock)) + return -1; + + /* Check global connection limit */ + if ((Conf_MaxConnections > 0) && + (NumConnections >= (size_t) Conf_MaxConnections)) { + Log(LOG_ALERT, "Can't accept connection: limit (%d) reached!", + Conf_MaxConnections); + Simple_Message(new_sock, "ERROR :Connection limit reached"); + close(new_sock); return -1; + } /* Check IP-based connection limit */ cnt = Count_Connections(&new_addr); if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) { /* Access denied, too many connections from this IP address! */ - Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP address!", ip_str, cnt); - Simple_Message( new_sock, "ERROR :Connection refused, too many connections from your IP address!" ); - close( new_sock ); - return -1; - } - - if ((Conf_MaxConnections > 0) && - (NumConnections >= (size_t) Conf_MaxConnections)) - { - Log( LOG_ALERT, "Can't accept connection: limit (%d) reached!", Conf_MaxConnections); - Simple_Message( new_sock, "ERROR :Connection limit reached" ); - close( new_sock ); + Log(LOG_ERR, + "Refused connection from %s: too may connections (%ld) from this IP address!", + ip_str, cnt); + Simple_Message(new_sock, + "ERROR :Connection refused, too many connections from your IP address!"); + close(new_sock); return -1; } - if( new_sock >= Pool_Size ) { + if (new_sock >= Pool_Size) { if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), - (size_t)new_sock)) { - Log( LOG_EMERG, "Can't allocate memory! [New_Connection]" ); - Simple_Message( new_sock, "ERROR: Internal error" ); - close( new_sock ); + (size_t) new_sock)) { + Log(LOG_EMERG, + "Can't allocate memory! [New_Connection]"); + Simple_Message(new_sock, "ERROR: Internal error"); + close(new_sock); return -1; } LogDebug("Bumped connection pool to %ld items (internal: %ld items, %ld bytes)", - new_sock, array_length(&My_ConnArray, sizeof(CONNECTION)), array_bytes(&My_ConnArray)); + new_sock, array_length(&My_ConnArray, + sizeof(CONNECTION)), array_bytes(&My_ConnArray)); /* Adjust pointer to new block */ My_Connections = array_start(&My_ConnArray); @@ -1249,22 +1306,24 @@ New_Connection( int Sock ) } /* register callback */ - if (!io_event_create( new_sock, IO_WANTREAD, cb_clientserver)) { - Log(LOG_ALERT, "Can't accept connection: io_event_create failed!"); + if (!io_event_create(new_sock, IO_WANTREAD, cb_clientserver)) { + Log(LOG_ALERT, + "Can't accept connection: io_event_create failed!"); Simple_Message(new_sock, "ERROR :Internal error"); close(new_sock); return -1; } - c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false ); - if( ! c ) { - Log(LOG_ALERT, "Can't accept connection: can't create client structure!"); + c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false); + if (!c) { + Log(LOG_ALERT, + "Can't accept connection: can't create client structure!"); Simple_Message(new_sock, "ERROR :Internal error"); io_close(new_sock); return -1; } - Init_Conn_Struct( new_sock ); + Init_Conn_Struct(new_sock); My_Connections[new_sock].sock = new_sock; My_Connections[new_sock].addr = new_addr; My_Connections[new_sock].client = c; @@ -1292,7 +1351,14 @@ New_Connection( int Sock ) if (!Conf_NoDNS) Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr, identsock, cb_Read_Resolver_Result); + + /* ngIRCd waits up to 4 seconds for the result of the asynchronous + * DNS and IDENT resolver subprocess using the "penalty" mechanism. + * If there are results earlier, the delay is aborted. */ Conn_SetPenalty(new_sock, 4); + + NumConnections++; + LogDebug("Total number of connections now %ld.", NumConnections); return new_sock; } /* New_Connection */ @@ -1811,12 +1877,13 @@ Init_Socket( int Sock ) } /* Set type of service (TOS) */ -#if defined(IP_TOS) && defined(IPTOS_LOWDELAY) +#if defined(IPPROTO_IP) && defined(IPTOS_LOWDELAY) value = IPTOS_LOWDELAY; - LogDebug("Setting option IP_TOS on socket %d to IPTOS_LOWDELAY (%d).", Sock, value ); - if( setsockopt( Sock, SOL_IP, IP_TOS, &value, (socklen_t)sizeof( value )) != 0 ) - { - Log( LOG_ERR, "Can't set socket option IP_TOS: %s!", strerror( errno )); + LogDebug("Setting IP_TOS on socket %d to IPTOS_LOWDELAY.", Sock); + if (setsockopt(Sock, IPPROTO_IP, IP_TOS, &value, + (socklen_t) sizeof(value))) { + Log(LOG_ERR, "Can't set socket option IP_TOS: %s!", + strerror(errno)); /* ignore this error */ } #endif @@ -1825,7 +1892,6 @@ Init_Socket( int Sock ) } /* Init_Socket */ - static void cb_Connect_to_Server(int fd, UNUSED short events) { @@ -1933,10 +1999,14 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) c = Conn_GetClient( i ); assert( c != NULL ); - /* Only update client information of unregistered clients */ - if( Client_Type( c ) == CLIENT_UNKNOWN ) { - strlcpy(My_Connections[i].host, readbuf, sizeof( My_Connections[i].host)); - Client_SetHostname( c, readbuf); + /* Only update client information of unregistered clients. + * Note: user commands (e. g. WEBIRC) are always read _after_ reading + * 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); #ifdef IDENTAUTH ++identptr; if (*identptr) { @@ -1972,24 +2042,34 @@ Simple_Message( int Sock, const char *Msg ) } /* Simple_Error */ +/** + * Get CLIENT structure that belongs to a local connection identified by its + * index number. Each connection belongs to a client by definition, so it is + * not required that the caller checks for NULL return values. + * @param Idx Connection index number + * @return Pointer to CLIENT structure + */ GLOBAL CLIENT * Conn_GetClient( CONN_ID Idx ) { - /* return Client-Structure that belongs to the local Connection Idx. - * If none is found, return NULL. - */ CONNECTION *c; - assert( Idx >= 0 ); + assert(Idx >= 0); c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx); - assert(c != NULL); - return c ? c->client : NULL; } + #ifdef SSL_SUPPORT -/* we cannot access My_Connections in irc-info.c */ + +/** + * Get information about used SSL chiper. + * @param Idx Connection index number + * @param buf Buffer for returned information text + * @param len Size of return buffer "buf" + * @return true on success, false otherwise + */ GLOBAL bool Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len) { @@ -2000,6 +2080,11 @@ Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len) } +/** + * Check if a connection is SSL-enabled or not. + * @param Idx Connection index number + * @return true if connection is SSL-enabled, false otherwise. + */ GLOBAL bool Conn_UsesSSL(CONN_ID Idx) { @@ -2008,6 +2093,7 @@ Conn_UsesSSL(CONN_ID Idx) assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION))); return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL); } + #endif