X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=7c4c8d23782cc995fc11c41baeee9041e0ae1416;hp=1696d5c5f62968d8d495576b4e1bc67947db66ee;hb=4ed2cb1a0248130f476ff9afd4fd4ed887fee376;hpb=22fa782be7840dae825be43e9ac8d8476d80f08c diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 1696d5c5..7c4c8d23 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -88,7 +88,7 @@ static void Init_Conn_Struct PARAMS(( CONN_ID Idx )); static bool Init_Socket PARAMS(( int Sock )); static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest )); static void Simple_Message PARAMS(( int Sock, const char *Msg )); -static int NewListener PARAMS(( int af, const UINT16 Port )); +static int NewListener PARAMS(( const char *listen_addr, UINT16 Port )); static array My_Listeners; static array My_ConnArray; @@ -272,7 +272,7 @@ Conn_Exit( void ) static unsigned int -ports_initlisteners(array *a, int af, void (*func)(int,short)) +ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short)) { unsigned int created = 0; size_t len; @@ -281,15 +281,15 @@ ports_initlisteners(array *a, int af, void (*func)(int,short)) len = array_length(a, sizeof (UINT16)); port = array_start(a); - while(len--) { - fd = NewListener(af, *port); + while (len--) { + fd = NewListener(listen_addr, *port); if (fd < 0) { port++; continue; } if (!io_event_create( fd, IO_WANTREAD, func )) { Log( LOG_ERR, "io_event_create(): Could not add listening fd %d (port %u): %s!", - fd, (unsigned int) *port, strerror(errno)); + fd, (unsigned int) *port, strerror(errno)); close(fd); port++; continue; @@ -297,7 +297,6 @@ ports_initlisteners(array *a, int af, void (*func)(int,short)) created++; port++; } - return created; } @@ -306,21 +305,39 @@ GLOBAL unsigned int Conn_InitListeners( void ) { /* Initialize ports on which the server should accept connections */ - unsigned int created = 0; + char *copy, *listen_addr; if (!io_library_init(CONNECTION_POOL)) { Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno)); return -1; } -#ifdef WANT_IPV6 - if (Conf_ListenIPv6) - created = ports_initlisteners(&Conf_ListenPorts, AF_INET6, cb_listen); -#endif - if (Conf_ListenIPv4) - created += ports_initlisteners(&Conf_ListenPorts, AF_INET, cb_listen); + assert(Conf_ListenAddress); + + /* can't use Conf_ListenAddress directly, see below */ + copy = strdup(Conf_ListenAddress); + if (!copy) { + Log(LOG_CRIT, "Cannot copy %s: %s", Conf_ListenAddress, strerror(errno)); + return 0; + } + listen_addr = strtok(copy, ","); + + while (listen_addr) { + ngt_TrimStr(listen_addr); + if (*listen_addr) + created += ports_initlisteners(&Conf_ListenPorts, listen_addr, cb_listen); + + listen_addr = strtok(NULL, ","); + } + /* + * 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. + */ + free(copy); return created; } /* Conn_InitListeners */ @@ -350,25 +367,15 @@ Conn_ExitListeners( void ) static bool -InitSinaddrListenAddr(int af, ng_ipaddr_t *addr, UINT16 Port) +InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port) { bool ret; - const char *listen_addrstr = NULL; -#ifdef WANT_IPV6 - if (af == AF_INET) - listen_addrstr = "0.0.0.0"; -#else - (void)af; -#endif - if (Conf_ListenAddress[0]) /* overrides V4/V6 atm */ - listen_addrstr = Conf_ListenAddress; ret = ng_ipaddr_init(addr, listen_addrstr, Port); if (!ret) { - if (!listen_addrstr) - listen_addrstr = ""; - Log(LOG_CRIT, "Can't bind to %s:%u: can't convert ip address \"%s\"", - listen_addrstr, Port, listen_addrstr); + assert(listen_addrstr); + Log(LOG_CRIT, "Can't bind to [%s]:%u: can't convert ip address \"%s\"", + listen_addrstr, Port, listen_addrstr); } return ret; } @@ -394,32 +401,33 @@ set_v6_only(int af, int sock) /* return new listening port file descriptor or -1 on failure */ static int -NewListener(int af, const UINT16 Port) +NewListener(const char *listen_addr, UINT16 Port) { /* Create new listening socket on specified port */ ng_ipaddr_t addr; - int sock; + int sock, af; #ifdef ZEROCONF char name[CLIENT_ID_LEN], *info; #endif - if (!InitSinaddrListenAddr(af, &addr, Port)) + if (!InitSinaddrListenAddr(&addr, listen_addr, Port)) return -1; - sock = socket(ng_ipaddr_af(&addr), SOCK_STREAM, 0); + af = ng_ipaddr_af(&addr); + sock = socket(af, SOCK_STREAM, 0); if( sock < 0 ) { - Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno )); + Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af, strerror(errno)); return -1; } - af = ng_ipaddr_af(&addr); - set_v6_only(af, sock); - if( ! Init_Socket( sock )) return -1; + if (!Init_Socket(sock)) + return -1; if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) { - Log( LOG_CRIT, "Can't bind socket (port %d) : %s!", Port, strerror( errno )); - close( sock ); + Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s", + ng_ipaddr_tostr(&addr), Port, strerror(errno)); + close(sock); return -1; } @@ -436,12 +444,7 @@ NewListener(int af, const UINT16 Port) return -1; } -#ifdef WANT_IPV6 - if (af == AF_INET6) - Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock); - else -#endif - Log(LOG_INFO, "Now listening on %s:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock); + Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock); #ifdef ZEROCONF /* Get best server description text */ @@ -1218,11 +1221,13 @@ Read_Request( CONN_ID Idx ) } /* Read_Request */ +/** + * Handle data in connection read-buffer. + * @return true if a reuqest was handled, false otherwise (and on errors). + */ static bool -Handle_Buffer( CONN_ID Idx ) +Handle_Buffer(CONN_ID Idx) { - /* Handle Data in Connections Read-Buffer. - * Return true if a reuqest was handled, false otherwise (also returned on errors). */ #ifndef STRICT_RFC char *ptr1, *ptr2; #endif @@ -1238,86 +1243,104 @@ Handle_Buffer( CONN_ID Idx ) result = false; for (;;) { /* Check penalty */ - if( My_Connections[Idx].delaytime > starttime) return result; + if (My_Connections[Idx].delaytime > starttime) + return result; #ifdef ZLIB - /* unpack compressed data */ - if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) - if( ! Unzip_Buffer( Idx )) return false; + /* Unpack compressed data, if compression is in use */ + if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) { + if (!Unzip_Buffer(Idx)) + return false; + } #endif if (0 == array_bytes(&My_Connections[Idx].rbuf)) break; - if (!array_cat0_temporary(&My_Connections[Idx].rbuf)) /* make sure buf is NULL terminated */ + /* Make sure that the buffer is NULL terminated */ + if (!array_cat0_temporary(&My_Connections[Idx].rbuf)) return false; - /* A Complete Request end with CR+LF, see RFC 2812. */ - ptr = strstr( array_start(&My_Connections[Idx].rbuf), "\r\n" ); + /* RFC 2812, section "2.3 Messages", 5th paragraph: + * "IRC messages are always lines of characters terminated + * with a CR-LF (Carriage Return - Line Feed) pair [...]". */ + delta = 2; + ptr = strstr(array_start(&My_Connections[Idx].rbuf), "\r\n"); - if( ptr ) delta = 2; /* complete request */ #ifndef STRICT_RFC - else { - /* Check for non-RFC-compliant request (only CR or LF)? Unfortunately, - * there are quite a few clients that do this (incl. "mIRC" :-( */ - ptr1 = strchr( array_start(&My_Connections[Idx].rbuf), '\r' ); - ptr2 = strchr( array_start(&My_Connections[Idx].rbuf), '\n' ); + if (!ptr) { + /* Check for non-RFC-compliant request (only CR or + * LF)? Unfortunately, there are quite a few clients + * out there that do this -- incl. "mIRC" :-( */ delta = 1; - if( ptr1 && ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1; - else if( ptr1 ) ptr = ptr1; - else if( ptr2 ) ptr = ptr2; + ptr1 = strchr(array_start(&My_Connections[Idx].rbuf), '\r'); + ptr2 = strchr(array_start(&My_Connections[Idx].rbuf), '\n'); + if (ptr1 && ptr2) + ptr = ptr1 > ptr2 ? ptr2 : ptr1; + else if (ptr1) + ptr = ptr1; + else if (ptr2) + ptr = ptr2; } #endif - if( ! ptr ) + if (!ptr) break; - /* End of request found */ + /* Complete (=line terminated) request found, handle it! */ *ptr = '\0'; - len = ( ptr - (char*) array_start(&My_Connections[Idx].rbuf)) + delta; + len = ptr - (char *)array_start(&My_Connections[Idx].rbuf) + delta; - if( len > ( COMMAND_LEN - 1 )) { - /* Request must not exceed 512 chars (incl. CR+LF!), see - * RFC 2812. Disconnect Client if this happens. */ - Log( LOG_ERR, "Request too long (connection %d): %d bytes (max. %d expected)!", - Idx, array_bytes(&My_Connections[Idx].rbuf), COMMAND_LEN - 1 ); - Conn_Close( Idx, NULL, "Request too long", true ); + if (len > (COMMAND_LEN - 1)) { + /* Request must not exceed 512 chars (incl. CR+LF!), + * see RFC 2812. Disconnect Client if this happens. */ + Log(LOG_ERR, + "Request too long (connection %d): %d bytes (max. %d expected)!", + Idx, array_bytes(&My_Connections[Idx].rbuf), + COMMAND_LEN - 1); + Conn_Close(Idx, NULL, "Request too long", true); return false; } - if (len <= 2) { /* request was empty (only '\r\n') */ - array_moveleft(&My_Connections[Idx].rbuf, 1, delta); /* delta is either 1 or 2 */ + if (len <= delta) { + /* Request is empty (only '\r\n', '\r' or '\n'); + * delta is 2 ('\r\n') or 1 ('\r' or '\n'), see above */ + array_moveleft(&My_Connections[Idx].rbuf, 1, len); break; } + #ifdef ZLIB /* remember if stream is already compressed */ old_z = My_Connections[Idx].options & CONN_ZIP; #endif My_Connections[Idx].msg_in++; - if (!Parse_Request(Idx, (char*)array_start(&My_Connections[Idx].rbuf) )) + if (!Parse_Request + (Idx, (char *)array_start(&My_Connections[Idx].rbuf))) return false; result = true; array_moveleft(&My_Connections[Idx].rbuf, 1, len); LogDebug("Connection %d: %d bytes left in read buffer.", - Idx, array_bytes(&My_Connections[Idx].rbuf)); + Idx, array_bytes(&My_Connections[Idx].rbuf)); #ifdef ZLIB - if(( ! old_z ) && ( My_Connections[Idx].options & CONN_ZIP ) && - ( array_bytes(&My_Connections[Idx].rbuf) > 0 )) - { - /* The last Command activated Socket-Compression. - * Data that was read after that needs to be copied to Unzip-buf - * for decompression */ - if (!array_copy( &My_Connections[Idx].zip.rbuf, &My_Connections[Idx].rbuf )) + if ((!old_z) && (My_Connections[Idx].options & CONN_ZIP) && + (array_bytes(&My_Connections[Idx].rbuf) > 0)) { + /* The last command activated socket compression. + * Data that was read after that needs to be copied + * to the unzip buffer for decompression: */ + if (!array_copy + (&My_Connections[Idx].zip.rbuf, + &My_Connections[Idx].rbuf)) return false; array_trunc(&My_Connections[Idx].rbuf); - LogDebug("Moved already received data (%u bytes) to uncompression buffer.", - array_bytes(&My_Connections[Idx].zip.rbuf)); + LogDebug + ("Moved already received data (%u bytes) to uncompression buffer.", + array_bytes(&My_Connections[Idx].zip.rbuf)); } -#endif /* ZLIB */ +#endif } return result; } /* Handle_Buffer */ @@ -1439,7 +1462,7 @@ New_Server( int Server , ng_ipaddr_t *dest) af_dest = ng_ipaddr_af(dest); new_sock = socket(af_dest, SOCK_STREAM, 0); if (new_sock < 0) { - Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno )); + Log( LOG_CRIT, "Can't create socket (af %d) : %s!", af_dest, strerror( errno )); return; }