make Listen parameter a comma-seperated list of addresses.
authorFlorian Westphal <fw@strlen.de>
Sun, 18 May 2008 22:12:41 +0000 (00:12 +0200)
committerFlorian Westphal <fw@strlen.de>
Mon, 19 May 2008 12:27:35 +0000 (14:27 +0200)
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.

doc/sample-ngircd.conf
man/ngircd.conf.5.tmpl
src/ipaddr/ng_ipaddr.c
src/ipaddr/ng_ipaddr.h
src/ngircd/conf.c
src/ngircd/conf.h
src/ngircd/conn.c

index 9f107a83f42e524da59a604d5879509d069a3e9f..87a94d9df8be365b4de8d2597cf06ed4d316800b 100644 (file)
        # 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:
        # 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
index cff474965d7a33c4e48e0a13fb51caa8623a74c3..7c9ce3163e4f8b0b69b0cca9cecd66bf993199f7 100644 (file)
@@ -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.
index 3b0595d79719b92b13edfd0f4a5422311f1ff550..b412cc83af6e2789b03b2e34f7b74b4c962f8f1c 100644 (file)
@@ -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)
index 7894af25fbebefdb22f24adac1afe9a9dcb639b6..6490a0747a9ac0f62ff4608c8d7cbaea9e8023a5 100644 (file)
@@ -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));
index c5a621fee65d9a7f8f484c592f45ab58a4599f78..554fee4a92d12e973c8b1f94864c8360e1dff6cf 100644 (file)
@@ -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++) {
index 3bc206605e208d40b78cd02c1cab05fcb9eeb8cb..6ec5bce909010e47075b672542bb398bf071ddd8 100644 (file)
@@ -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)
index 4772fd34628b660f8f517fcb1edc30515b0c283e..7c4c8d23782cc995fc11c41baeee9041e0ae1416 100644 (file)
@@ -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;
        }