ngIRCd: Patch to upgrade ngIRCd 0.12.0 to version 0.12.1. ChangeLog | 14 ++++++ NEWS | 9 ++++ configure.in | 2 +- contrib/Debian/changelog | 10 +++- contrib/ngircd.spec | 2 +- doc/sample-ngircd.conf | 13 ++--- man/ngircd.8.tmpl | 6 +- man/ngircd.conf.5.tmpl | 65 +++++++++++++------------- src/ipaddr/ng_ipaddr.c | 20 ++++---- src/ipaddr/ng_ipaddr.h | 1 - src/ngircd/conf.c | 115 ++++++++++++++++++++++++++++++++------------- src/ngircd/conf.h | 8 +--- src/ngircd/conn.c | 116 ++++++++++++++++++++++++++-------------------- src/ngircd/ngircd.c | 37 ++++++++------ src/ngircd/parse.c | 30 ++++++++++-- 15 files changed, 277 insertions(+), 171 deletions(-) diff --git a/ChangeLog b/ChangeLog index 09ad689..18cadd7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,20 @@ -- ChangeLog -- +ngIRCd 0.12.1 (2008-07-09) + + - Allow mixed line terminations (CR+LF/CR/LF) in non-RFC-compliant mode + - Don't allow stray \r or \n in command parameters + - --configtest: return non-zero exit code if there are errors + - Update ngIRCd manual pages + - Add option aliases -V (for --version) and -h (for --help). + - Fix 'no-ipv6' compile error. + - 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. + ngIRCd 0.12.0 (2008-05-13) - Fix Bug: 85: "WHO #SecretChannel" that user is not a member of now returns diff --git a/NEWS b/NEWS index 47def92..7607aef 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,15 @@ -- NEWS -- +ngIRCd 0.12.1 (2008-07-09) + + - Add option aliases -V (for --version) and -h (for --help). + - 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. + ngIRCd 0.12.0 (2008-05-13) ngIRCd 0.12.0-pre2 (2008-04-29) diff --git a/configure.in b/configure.in index 0d1fe7f..f7a321f 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ # -- Initialisation -- AC_PREREQ(2.50) -AC_INIT(ngircd, 0.12.0) +AC_INIT(ngircd, 0.12.1) AC_CONFIG_SRCDIR(src/ngircd/ngircd.c) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE(1.6) diff --git a/contrib/Debian/changelog b/contrib/Debian/changelog index 9895de7..a1647c4 100644 --- a/contrib/Debian/changelog +++ b/contrib/Debian/changelog @@ -1,4 +1,10 @@ -ngircd (0.12.0-0ab0-pre3) unstable; urgency=low +ngircd (0.12.1-0ab1) unstable; urgency=low + + * New "upstream" release ngIRCd 0.12.1. + + -- Alexander Barton Wed, 9 Jul 2008 11:27:00 +0200 + +ngircd (0.12.0-0ab1) unstable; urgency=low * New "upstream" release ngIRCd 0.12.0. @@ -6,7 +12,7 @@ ngircd (0.12.0-0ab0-pre3) unstable; urgency=low ngircd (0.12.0-0ab0-pre2) unstable; urgency=low - * Second prereloease of upcoming new "upstrem" release 0.12.0-pre1. + * Second prerelease of upcoming new "upstrem" release 0.12.0-pre1. -- Alexander Barton Tue, 29 Apr 2008 23:06:14 +0200 diff --git a/contrib/ngircd.spec b/contrib/ngircd.spec index 2a98612..f18f13a 100644 --- a/contrib/ngircd.spec +++ b/contrib/ngircd.spec @@ -1,5 +1,5 @@ %define name ngircd -%define version 0.12.0 +%define version 0.12.1 %define release 1 %define prefix %{_prefix} diff --git a/doc/sample-ngircd.conf b/doc/sample-ngircd.conf index 9f107a8..87a94d9 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.8.tmpl b/man/ngircd.8.tmpl index f16025e..692c188 100644 --- a/man/ngircd.8.tmpl +++ b/man/ngircd.8.tmpl @@ -1,7 +1,7 @@ .\" .\" $Id: ngircd.8.tmpl,v 1.2 2007/11/15 01:03:29 fw Exp $ .\" -.TH ngircd 8 "August 2005" ngircd "ngIRCd Manual" +.TH ngircd 8 "May 2008" ngircd "ngIRCd Manual" .SH NAME ngIRCd \- the next generation IRC daemon .SH SYNOPSIS @@ -50,10 +50,10 @@ CONNECT later on as IRC Operator to link this ngIRCd to other servers. \fB\-t\fR, \fB\-\-configtest\fR Read, validate and display the configuration; then exit. .TP -\fB\-\-version\fR +\fB\-V\fR, \fB\-\-version\fR Output version information and exit. .TP -\fB\-\-help\fR +\fB\-h\fR, \fB\-\-help\fR Display a brief help text and exit. .SH FILES .I :ETCDIR:/ngircd.conf diff --git a/man/ngircd.conf.5.tmpl b/man/ngircd.conf.5.tmpl index cd5922a..7c9ce31 100644 --- a/man/ngircd.conf.5.tmpl +++ b/man/ngircd.conf.5.tmpl @@ -1,7 +1,7 @@ .\" .\" $Id: ngircd.conf.5.tmpl,v 1.7 2007/11/23 16:26:03 fw Exp $ .\" -.TH ngircd.conf 5 "August 2005" ngircd "ngIRCd Manual" +.TH ngircd.conf 5 "May 2008" ngircd "ngIRCd Manual" .SH NAME ngircd.conf \- configuration file of ngIRCd .SH SYNOPSIS @@ -26,19 +26,20 @@ Sections contain parameters of the form .RE .PP Empty lines and any line beginning with a semicolon (';') or a hash ('#') -character is treated as a comment and will be ignored. +character are treated as a comment and will be ignored. Leading and trailing +whitespaces are trimmed before any processing takes place. .PP -The file format is line-based - that means, each newline-terminated line -represents either a comment, a section name or a parameter. +The file format is line-based - that means, each non-empty newline-terminated +line represents either a comment, a section name, or a parameter. .PP Section and parameter names are not case sensitive. .SH "SECTION OVERVIEW" The file can contain blocks of four types: [Global], [Operator], [Server], and [Channel]. .PP -In the +The main configuration of the server is stored in the .I [Global] -section, there is the main configuration like the server name and the +section, like the server name, administrative information and the ports on which the server should be listening. IRC operators of this server are defined in .I [Operator] @@ -57,7 +58,7 @@ section is used to define the server main configuration, like the server name and the ports on which the server should be listening. .TP \fBName\fR -Server name in the IRC network +Server name in the IRC network, must contain at least one dot ("."). .TP \fBInfo\fR Info text of the server. This will be shown by WHOIS and LINKS requests for @@ -72,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 @@ -81,7 +84,8 @@ to all users connecting to the server. .TP \fBMotdPhrase\fR A simple Phrase (<256 chars) if you don't want to use a MOTD file. -If it is set no MotdFile will be read at all. +If it is set no MotdFile will be read at all which can be handy if the +daemon should run inside a chroot directory. .TP \fBServerUID\fR User ID under which the server should run; you can use the name of the user @@ -158,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. @@ -212,31 +207,34 @@ Example: nick!ident@*.example.com Other servers are configured in .I [Server] sections. If you configure a port for the connection, then this ngIRCd -tries to connect to to the other server on the given port; if not, it waits -for the other server to connect. +tries to connect to to the other server on the given port (active); +if not, it waits for the other server to connect (passive). .PP -The ngIRCd allows "server groups": You can assign an "ID" to every server -with which you want this ngIRCd to link. If a server of a group won't -answer, the ngIRCd tries to connect to the next server in the given group. -But ngIRCd never tries to connect to two servers with the same group ID. +ngIRCd supports "server groups": You can assign an "ID" to every server +with which you want this ngIRCd to link, and the daemon ensures that at +any given time only one direct link exists to servers with the same ID. +So if a server of a group won't answer, ngIRCd tries to connect to the next +server in the given group (="with the same ID"), but never tries to connect +to more than one server of this group simultaneously. .PP There may be more than one .I [Server] block. .TP \fBName\fR -IRC name of the server +IRC name of the remote server. .TP \fBHost\fR -Internet host name of the peer +Internet host name (or IP address) of the peer. .TP \fBBind\fR IP address to use as source IP for the outgoing connection. Default ist to let the operating system decide. .TP \fBPort\fR -Port of the server to which the ngIRCd should connect. If you assign no port -the ngIRCd waits for incoming connections. +Port of the remote server to which ngIRCd should connect (active). +If no port is assigned to a configured server, the daemon only waits for +incoming connections (passive). .TP \fBMyPassword\fR Own password for this connection. This password has to be configured as @@ -248,6 +246,7 @@ Foreign password for this connection. This password has to be configured as .TP \fBGroup\fR Group of this server (optional). +.TP \fBPassive\fR Disable automatic connection even if port value is specified. Default: false. You can use the IRC Operator command CONNECT later on to create the link. @@ -265,19 +264,19 @@ There may be more than one block. .TP \fBName\fR -Name of the channel +Name of the channel, including channel prefix ("#"). .TP \fBTopic\fR -Topic for this channel +Topic for this channel. .TP \fBModes\fR Initial channel modes. .TP \fBKey\fR -Sets initial channel key (only relevant if mode k is set) +Sets initial channel key (only relevant if mode k is set). .TP \fBMaxUsers\fR -Set maximum user limit for this channel (only relevant if mode l is set) +Set maximum user limit for this channel (only relevant if mode l is set). .SH HINTS It's wise to use "ngircd --configtest" to validate the configuration file after changing it. See diff --git a/src/ipaddr/ng_ipaddr.c b/src/ipaddr/ng_ipaddr.c index 3b0595d..b412cc8 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 3bc075e..9c45d2f 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 c5a621f..5d4c695 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -56,9 +56,21 @@ 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 )); +static bool Validate_Config PARAMS(( bool TestOnly, bool Rehash )); static void Handle_GLOBAL PARAMS(( int Line, char *Var, char *Arg )); static void Handle_OPERATOR PARAMS(( int Line, char *Var, char *Arg )); @@ -170,11 +182,14 @@ Conf_Test( void ) struct group *grp; unsigned int i; char *topic; + bool config_valid; Use_Log = false; - Read_Config( true ); - Validate_Config(true, false); + if (! Read_Config(true)) + return 1; + + config_valid = Validate_Config(true, false); /* If stdin and stdout ("you can read our nice message and we can * read in your keypress") are valid tty's, wait for a key: */ @@ -199,8 +214,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 +230,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 @@ -265,7 +282,7 @@ Conf_Test( void ) printf( " Topic = %s\n\n", topic ? topic : ""); } - return 0; + return (config_valid ? 0 : 1); } /* Conf_Test */ @@ -448,8 +465,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; @@ -466,10 +483,11 @@ Set_Defaults( bool InitServers ) Conf_OperServerMode = false; Conf_ConnectIPv4 = true; - Conf_ListenIPv4 = true; Conf_ConnectIPv6 = true; +#ifdef WANT_IPV6 + Conf_ListenIPv4 = true; Conf_ListenIPv6 = true; - +#endif Conf_MaxConnections = 0; Conf_MaxConnectionsIP = 5; Conf_MaxJoins = 10; @@ -650,6 +668,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 +875,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 +954,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 */ @@ -1114,7 +1167,7 @@ Handle_CHANNEL( int Line, char *Var, char *Arg ) } /* Handle_CHANNEL */ -static void +static bool Validate_Config(bool Configtest, bool Rehash) { /* Validate configuration settings. */ @@ -1122,6 +1175,7 @@ Validate_Config(bool Configtest, bool Rehash) #ifdef DEBUG int i, servers, servers_once; #endif + bool config_valid = true; char *ptr; /* Validate configured server name, see RFC 2812 section 2.3.1 */ @@ -1140,6 +1194,7 @@ Validate_Config(bool Configtest, bool Rehash) if (!Conf_ServerName[0]) { /* No server name configured! */ + config_valid = false; Config_Error(LOG_ALERT, "No (valid) server name configured in \"%s\" (section 'Global': 'Name')!", NGIRCd_ConfFile); @@ -1153,6 +1208,7 @@ Validate_Config(bool Configtest, bool Rehash) if (Conf_ServerName[0] && !strchr(Conf_ServerName, '.')) { /* No dot in server name! */ + config_valid = false; Config_Error(LOG_ALERT, "Invalid server name configured in \"%s\" (section 'Global': 'Name'): Dot missing!", NGIRCd_ConfFile); @@ -1167,6 +1223,7 @@ Validate_Config(bool Configtest, bool Rehash) #ifdef STRICT_RFC if (!Conf_ServerAdminMail[0]) { /* No administrative contact configured! */ + config_valid = false; Config_Error(LOG_ALERT, "No administrator email address configured in \"%s\" ('AdminEMail')!", NGIRCd_ConfFile); @@ -1186,16 +1243,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++) { @@ -1209,6 +1256,8 @@ Validate_Config(bool Configtest, bool Rehash) "Configuration: Operators=%d, Servers=%d[%d], Channels=%d", Conf_Oper_Count, servers, servers_once, Conf_Channel_Count); #endif + + return config_valid; } /* Validate_Config */ diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 3bc2066..6ec5bce 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 df65fc0..7efc5b8 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 */ @@ -1226,7 +1227,7 @@ 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; + char *ptr1, *ptr2, *first_eol; #endif char *ptr; size_t len, delta; @@ -1254,19 +1255,32 @@ Handle_Buffer( CONN_ID Idx ) return false; /* A Complete Request end with CR+LF, see RFC 2812. */ + 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' ); + /* Check for non-RFC-compliant request (only CR or LF)? + * Unfortunately, there are quite a few clients out there + * that do this -- e. g. mIRC, BitchX, and Trillian :-( */ + ptr1 = strchr(array_start(&My_Connections[Idx].rbuf), '\r'); + ptr2 = strchr(array_start(&My_Connections[Idx].rbuf), '\n'); + if (ptr) { + /* Check if there is a single CR or LF _before_ the + * corerct CR+LF line terminator: */ + first_eol = ptr1 < ptr2 ? ptr1 : ptr2; + if (first_eol < ptr) { + /* Single CR or LF before CR+LF found */ + ptr = first_eol; + delta = 1; + } + } else if (ptr1 || ptr2) { + /* No CR+LF terminated command found, but single + * CR or LF found ... */ + if (ptr1 && ptr2) + ptr = ptr1 < ptr2 ? ptr1 : ptr2; + else + ptr = ptr1 ? ptr1 : ptr2; delta = 1; - if( ptr1 && ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1; - else if( ptr1 ) ptr = ptr1; - else if( ptr2 ) ptr = ptr2; } #endif @@ -1441,7 +1455,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; } diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c index 626b8b2..45487bc 100644 --- a/src/ngircd/ngircd.c +++ b/src/ngircd/ngircd.c @@ -166,14 +166,12 @@ main( int argc, const char *argv[] ) { ok = false; #ifdef DEBUG - if( argv[i][n] == 'd' ) - { + if (argv[i][n] == 'd') { NGIRCd_Debug = true; ok = true; } #endif - if( argv[i][n] == 'f' ) - { + if (argv[i][n] == 'f') { if(( ! argv[i][n + 1] ) && ( i + 1 < argc )) { /* Ok, next character is a blank */ @@ -185,31 +183,38 @@ main( int argc, const char *argv[] ) ok = true; } } - if( argv[i][n] == 'n' ) - { + + if (argv[i][n] == 'h') { + Show_Version(); + puts(""); Show_Help(); puts(""); + exit(1); + } + + if (argv[i][n] == 'n') { NGIRCd_NoDaemon = true; ok = true; } - if( argv[i][n] == 'p' ) - { + if (argv[i][n] == 'p') { NGIRCd_Passive = true; ok = true; } #ifdef SNIFFER - if( argv[i][n] == 's' ) - { + if (argv[i][n] == 's') { NGIRCd_Sniffer = true; ok = true; } #endif - if( argv[i][n] == 't' ) - { + if (argv[i][n] == 't') { configtest = true; ok = true; } - if( ! ok ) - { + if (argv[i][n] == 'V') { + Show_Version(); + exit(1); + } + + if (! ok) { printf( "%s: invalid option \"-%c\"!\n", PACKAGE_NAME, argv[i][n] ); printf( "Try \"%s --help\" for more information.\n", PACKAGE_NAME ); exit( 1 ); @@ -577,8 +582,8 @@ Show_Help( void ) puts( " -s, --sniffer enable network sniffer and display all IRC traffic" ); #endif puts( " -t, --configtest read, validate and display configuration; then exit" ); - puts( " --version output version information and exit" ); - puts( " --help display this help and exit" ); + puts( " -V, --version output version information and exit" ); + puts( " -h, --help display this help and exit" ); } /* Show_Help */ diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index 5cfeaaa..409231a 100644 --- a/src/ngircd/parse.c +++ b/src/ngircd/parse.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de) + * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -9,11 +9,8 @@ * Please read the file COPYING, README and AUTHORS for more information. */ - #include "portab.h" -static char UNUSED id[] = "$Id: parse.c,v 1.72 2008/02/17 13:26:42 alex Exp $"; - /** * @file * IRC command parser and validator. @@ -338,12 +335,35 @@ Validate_Command( UNUSED CONN_ID Idx, UNUSED REQUEST *Req, bool *Closed ) static bool -Validate_Args( UNUSED CONN_ID Idx, UNUSED REQUEST *Req, bool *Closed ) +Validate_Args(CONN_ID Idx, REQUEST *Req, bool *Closed) { +#ifdef STRICT_RFC + int i; +#endif + assert( Idx >= 0 ); assert( Req != NULL ); *Closed = false; +#ifdef STRICT_RFC + /* CR and LF are never allowed in command parameters. + * But since we do accept lines terminated only with CR or LF in + * "non-RFC-compliant mode" (besides the correct CR+LF combination), + * this check can only trigger in "strict RFC" mode; therefore we + * optimize it away otherwise ... */ + for (i = 0; i < Req->argc; i++) { + if (strchr(Req->argv[i], '\r') || strchr(Req->argv[i], '\n')) { + Log(LOG_ERR, + "Invalid character(s) in parameter (connection %d, command %s)!?", + Idx, Req->command); + if (!Conn_WriteStr(Idx, + "ERROR :Invalid character(s) in parameter!")) + *Closed = true; + return false; + } + } +#endif + return true; } /* Validate_Args */