From: Florian Westphal Date: Sun, 18 May 2008 22:12:41 +0000 (+0200) Subject: make Listen parameter a comma-seperated list of addresses. X-Git-Tag: rel-13-rc1~106 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=commitdiff_plain;h=4ed2cb1a0248130f476ff9afd4fd4ed887fee376 make Listen parameter a comma-seperated list of addresses. this also obsoletes ListenIPv4 and ListenIPv6 options. If Listen is unset, it is treated as Listen="::,0.0.0.0". Note: ListenIPv4 and ListenIPv6 options are still recognized, but ngircd will print a warning if they are used in the config file. Also, some plattforms require that ai_socktype is set in the getaddrinfo() hints structure. --- diff --git a/doc/sample-ngircd.conf b/doc/sample-ngircd.conf index 9f107a83..87a94d9d 100644 --- a/doc/sample-ngircd.conf +++ b/doc/sample-ngircd.conf @@ -40,9 +40,11 @@ # one port, separated with ",". (Default: 6667) ;Ports = 6667, 6668, 6669 - # IP address on which the server should listen. (Default: empty, - # so the server listens on all IP addresses of the system) - ;Listen = 1.2.3.4 + # comma seperated list of IP addresses on which the server should + # listen. Default values are: + # "0.0.0.0" or (if compiled with IPv6 support) "::,0.0.0.0" + # so the server listens on all IP addresses of the system by default. + ;Listen = 127.0.0.1,192.168.0.1 # Text file with the "message of the day" (MOTD). This message will # be shown to all users connecting to the server: @@ -103,11 +105,6 @@ # Don't do any DNS lookups when a client connects to the server. ;NoDNS = no - # allow both ipv4 and ipv6 clients to connect by opening both - # ipv4 and ipv6 sockets - ;ListenIPv6 = yes - ;ListenIPv4 = yes - # try to connect to other irc servers using ipv4 and ipv6, if possible ;ConnectIPv6 = yes ;ConnectIPv4 = yes diff --git a/man/ngircd.conf.5.tmpl b/man/ngircd.conf.5.tmpl index cff47496..7c9ce316 100644 --- a/man/ngircd.conf.5.tmpl +++ b/man/ngircd.conf.5.tmpl @@ -73,8 +73,10 @@ Ports on which the server should listen. There may be more than one port, separated with ','. Default: 6667. .TP \fBListen\fR -The IP address on which the server should listen. Default is empty, so -the server listens on all configured IP addresses and interfaces. +A comma seperated list of IP address on which the server should listen. +If unset, the defaults value is "0.0.0.0", or, if ngircd was compiled +with IPv6 support, "::,0.0.0.0", so the server listens on all configured +IP addresses and interfaces by default. .TP \fBMotdFile\fR Text file with the "message of the day" (MOTD). This message will be shown @@ -160,15 +162,6 @@ If you configure ngircd to connect to other servers, ngircd may still perform a DNS lookup if required. Default: No. .TP -\fBListenIPv4\fR -Set this to no if you do not want ngircd to accept clients using the standard internet protocol, ipv4. -This allows use of ngircd in ipv6-only setups. -Default: Yes. -.TP -\fBListenIPv6\fR -Set this to no if you do not want ngircd to accept clients using the new internet protocol, ipv6. -Default: Yes. -.TP \fBConnectIPv4\fR Set this to no if you do not want ngircd to connect to other irc servers using ipv4. This allows use of ngircd in ipv6-only setups. diff --git a/src/ipaddr/ng_ipaddr.c b/src/ipaddr/ng_ipaddr.c index 3b0595d7..b412cc83 100644 --- a/src/ipaddr/ng_ipaddr.c +++ b/src/ipaddr/ng_ipaddr.c @@ -24,18 +24,19 @@ ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, UINT16 port) int ret; char portstr[64]; struct addrinfo *res0; - struct addrinfo hints = { -#ifndef WANT_IPV6 /* only accept v4 addresses */ - .ai_family = AF_INET, -#endif - .ai_flags = AI_NUMERICHOST - }; + struct addrinfo hints; + + assert(ip_str); - if (ip_str == NULL) - hints.ai_flags |= AI_PASSIVE; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + + /* some getaddrinfo implementations require that ai_socktype is set. */ + hints.ai_socktype = SOCK_STREAM; /* silly, but ngircd stores UINT16 in server config, not string */ snprintf(portstr, sizeof(portstr), "%u", (unsigned int) port); + ret = getaddrinfo(ip_str, portstr, &hints, &res0); assert(ret == 0); if (ret != 0) @@ -49,8 +50,7 @@ ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, UINT16 port) freeaddrinfo(res0); return ret == 0; #else /* HAVE_GETADDRINFO */ - if (ip_str == NULL) - ip_str = "0.0.0.0"; + assert(ip_str); addr->sin4.sin_family = AF_INET; # ifdef HAVE_INET_ATON if (inet_aton(ip_str, &addr->sin4.sin_addr) == 0) diff --git a/src/ipaddr/ng_ipaddr.h b/src/ipaddr/ng_ipaddr.h index 7894af25..6490a074 100644 --- a/src/ipaddr/ng_ipaddr.h +++ b/src/ipaddr/ng_ipaddr.h @@ -84,7 +84,6 @@ ng_ipaddr_getport(const ng_ipaddr_t *a) * init a ng_ipaddr_t object. * @param addr: pointer to ng_ipaddr_t to initialize. * @param ip_str: ip address in dotted-decimal (ipv4) or hexadecimal (ipv6) notation - * if ip_str is NULL it is treated as 0.0.0.0/[::] * @param port: transport layer port number to use. */ GLOBAL bool ng_ipaddr_init PARAMS((ng_ipaddr_t *addr, const char *ip_str, UINT16 port)); diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index c5a621fe..554fee4a 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -56,6 +56,18 @@ static CONF_SERVER New_Server; static int New_Server_Idx; +#ifdef WANT_IPV6 +/* + * these options appeared in ngircd 0.12; they are here + * for backwards compatibility. They should be removed + * in the future. Instead of setting these options, + * the "Listen" option should be set accordingly. + */ +static bool Conf_ListenIPv6; +static bool Conf_ListenIPv4; +#endif + + static void Set_Defaults PARAMS(( bool InitServers )); static bool Read_Config PARAMS(( bool ngircd_starting )); static void Validate_Config PARAMS(( bool TestOnly, bool Rehash )); @@ -199,8 +211,7 @@ Conf_Test( void ) fputs(" Ports = ", stdout); ports_puts(&Conf_ListenPorts); - - printf( " Listen = %s\n", Conf_ListenAddress ); + printf(" Listen = %s\n", Conf_ListenAddress); pwd = getpwuid( Conf_UID ); if( pwd ) printf( " ServerUID = %s\n", pwd->pw_name ); else printf( " ServerUID = %ld\n", (long)Conf_UID ); @@ -216,8 +227,11 @@ Conf_Test( void ) printf( " NoDNS = %s\n", yesno_to_str(Conf_NoDNS)); #ifdef WANT_IPV6 - printf(" ListenIPv6 = %s\n", yesno_to_str(Conf_ListenIPv6)); - printf(" ListenIPv4 = %s\n", yesno_to_str(Conf_ListenIPv4)); + /* both are deprecated, only mention them if their default value changed. */ + if (!Conf_ListenIPv6) + puts(" ListenIPv6 = no"); + if (!Conf_ListenIPv4) + puts(" ListenIPv4 = no"); printf(" ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6)); printf(" ConnectIPv6 = %s\n", yesno_to_str(Conf_ConnectIPv4)); #endif @@ -448,8 +462,8 @@ Set_Defaults( bool InitServers ) strlcpy( Conf_PidFile, PID_FILE, sizeof( Conf_PidFile )); - strcpy( Conf_ListenAddress, "" ); - + free(Conf_ListenAddress); + Conf_ListenAddress = NULL; Conf_UID = Conf_GID = 0; Conf_PingTimeout = 120; @@ -650,6 +664,23 @@ Read_Config( bool ngircd_starting ) exit( 1 ); } } + + if (!Conf_ListenAddress) { + /* no Listen addresses configured, use default */ +#ifdef WANT_IPV6 + /* Conf_ListenIPv6/4 should no longer be used */ + if (Conf_ListenIPv6 && Conf_ListenIPv4) + Conf_ListenAddress = strdup_warn("::,0.0.0.0"); + else if (Conf_ListenIPv6) + Conf_ListenAddress = strdup_warn("::"); + else +#endif + Conf_ListenAddress = strdup_warn("0.0.0.0"); + } + if (!Conf_ListenAddress) { + Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME); + exit(1); + } return true; } /* Read_Config */ @@ -840,17 +871,25 @@ Handle_GLOBAL( int Line, char *Var, char *Arg ) } #ifdef WANT_IPV6 /* the default setting for all the WANT_IPV6 special options is 'true' */ - if( strcasecmp( Var, "ListenIPv6" ) == 0 ) { - /* listen on ipv6 sockets, if available? */ + if (strcasecmp(Var, "ListenIPv6") == 0) { /* DEPRECATED, option appeared in 0.12.0 */ + /* + * listen on ipv6 sockets, if available? + * Deprecated use "Listen = 0.0.0.0" (or, rather, do not list "::") + */ Conf_ListenIPv6 = Check_ArgIsTrue( Arg ); + Config_Error(LOG_WARNING, "%s, line %d: %s=%s is deprecated, %sinclude '::' in \"Listen =\" option instead", + NGIRCd_ConfFile, Line, Var, yesno_to_str(Conf_ListenIPv6), Conf_ListenIPv6 ? " ":"do not "); return; } - if( strcasecmp( Var, "ListenIPv4" ) == 0 ) { + if (strcasecmp(Var, "ListenIPv4") == 0) { /* DEPRECATED, option appeared in 0.12.0 */ /* * listen on ipv4 sockets, if available? - * this allows "ipv6-only" setups. + * this allows "ipv6-only" setups + * Deprecated use "Listen = ::" (or, rather, do not list "0.0.0.0") */ Conf_ListenIPv4 = Check_ArgIsTrue( Arg ); + Config_Error(LOG_WARNING, "%s, line %d: %s=%s is deprecated, %sinclude '0.0.0.0' in \"Listen =\" option instead", + NGIRCd_ConfFile, Line, Var, yesno_to_str(Conf_ListenIPv4), Conf_ListenIPv4 ? " ":"do not "); return; } if( strcasecmp( Var, "ConnectIPv6" ) == 0 ) { @@ -911,14 +950,24 @@ Handle_GLOBAL( int Line, char *Var, char *Arg ) if( strcasecmp( Var, "Listen" ) == 0 ) { /* IP-Address to bind sockets */ - len = strlcpy( Conf_ListenAddress, Arg, sizeof( Conf_ListenAddress )); - if (len >= sizeof( Conf_ListenAddress )) - Config_Error_TooLong( Line, Var ); + if (Conf_ListenAddress) { + Config_Error(LOG_ERR, "Multiple Listen= options, ignoring: %s", Arg); + return; + } + Conf_ListenAddress = strdup_warn(Arg); + /* + * if allocation fails, we're in trouble: + * we cannot ignore the error -- otherwise ngircd + * would listen on all interfaces. + */ + if (!Conf_ListenAddress) { + Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME); + exit(1); + } return; } - - Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!", - NGIRCd_ConfFile, Line, Var ); + Config_Error(LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!", + NGIRCd_ConfFile, Line, Var); } /* Handle_GLOBAL */ @@ -1186,16 +1235,6 @@ Validate_Config(bool Configtest, bool Rehash) "No administrative information configured but required by RFC!"); } -#ifdef WANT_IPV6 - if (!Conf_ListenIPv4 && !Conf_ListenIPv6) - Config_Error(LOG_ALERT, - "Both \"ListenIPv4\" and \"ListenIPv6\" are set to 'no'; no network protocol available!"); - - if (!Conf_ConnectIPv4 && !Conf_ConnectIPv6) - Config_Error(LOG_ALERT, - "Both \"ConnectIPv4\" and \"ConnectIPv6\" are set to 'no'; ngircd will fail to connect to other irc servers"); -#endif - #ifdef DEBUG servers = servers_once = 0; for (i = 0; i < MAX_SERVERS; i++) { diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 3bc20660..6ec5bce9 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -86,7 +86,7 @@ GLOBAL char Conf_MotdPhrase[LINE_LEN]; GLOBAL array Conf_ListenPorts; /* Address to which the socket should be bound or empty (=all) */ -GLOBAL char Conf_ListenAddress[16]; +GLOBAL char *Conf_ListenAddress; /* User and group ID the server should run with */ GLOBAL uid_t Conf_UID; @@ -124,12 +124,6 @@ GLOBAL bool Conf_OperCanMode; /* Disable all DNS functions? */ GLOBAL bool Conf_NoDNS; -/* listen for incoming ipv6 connections if OS supports it (default: yes)? */ -GLOBAL bool Conf_ListenIPv6; - -/* listen for incoming ipv4 connections if OS supports it (default: yes)? */ -GLOBAL bool Conf_ListenIPv4; - /* * try to connect to remote systems using the ipv6 protocol, * if they have an ipv6 address? (default yes) diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 4772fd34..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,25 +401,24 @@ 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)) @@ -438,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 */ @@ -1461,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; }