Commit Diff


commit - 818a206a4261f3d4153b0ab5c2025d77002290f5
commit + 4ed2cb1a0248130f476ff9afd4fd4ed887fee376
blob - 9f107a83f42e524da59a604d5879509d069a3e9f
blob + 87a94d9df8be365b4de8d2597cf06ed4d316800b
--- doc/sample-ngircd.conf
+++ 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
blob - cff474965d7a33c4e48e0a13fb51caa8623a74c3
blob + 7c9ce3163e4f8b0b69b0cca9cecd66bf993199f7
--- man/ngircd.conf.5.tmpl
+++ man/ngircd.conf.5.tmpl
@@ -73,8 +73,10 @@ Ports on which the server should listen. There may be 
 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, n
 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.
blob - 3b0595d79719b92b13edfd0f4a5422311f1ff550
blob + b412cc83af6e2789b03b2e34f7b74b4c962f8f1c
--- src/ipaddr/ng_ipaddr.c
+++ src/ipaddr/ng_ipaddr.c
@@ -24,18 +24,19 @@ ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, 
 	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;
 
-	if (ip_str == NULL)
-		hints.ai_flags |= AI_PASSIVE;
+	assert(ip_str);
 
+	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, 
 	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)
blob - 7894af25fbebefdb22f24adac1afe9a9dcb639b6
blob + 6490a0747a9ac0f62ff4608c8d7cbaea9e8023a5
--- src/ipaddr/ng_ipaddr.h
+++ 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));
blob - c5a621fee65d9a7f8f484c592f45ab58a4599f78
blob + 554fee4a92d12e973c8b1f94864c8360e1dff6cf
--- src/ngircd/conf.c
+++ src/ngircd/conf.c
@@ -54,6 +54,18 @@ static char UNUSED id[] = "$Id: conf.c,v 1.105 2008/03
 static bool Use_Log = true;
 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 ));
@@ -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;
@@ -649,7 +663,24 @@ Read_Config( bool ngircd_starting )
 							(unsigned int) defaultport, strerror(errno));
 			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 */
 
 
@@ -1185,16 +1234,6 @@ Validate_Config(bool Configtest, bool Rehash)
 		Config_Error(LOG_WARNING,
 			     "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;
blob - 3bc206605e208d40b78cd02c1cab05fcb9eeb8cb
blob + 6ec5bce909010e47075b672542bb398bf071ddd8
--- src/ngircd/conf.h
+++ 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)
blob - 4772fd34628b660f8f517fcb1edc30515b0c283e
blob + 7c4c8d23782cc995fc11c41baeee9041e0ae1416
--- src/ngircd/conn.c
+++ 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
 
 	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
 		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,24 +401,23 @@ 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);
 
@@ -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;
 	}