summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ipaddr/ng_ipaddr.c20
-rw-r--r--src/ipaddr/ng_ipaddr.h1
-rw-r--r--src/ngircd/conf.c91
-rw-r--r--src/ngircd/conf.h8
-rw-r--r--src/ngircd/conn.c83
5 files changed, 118 insertions, 85 deletions
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;
 	}