From 82d32ffb28262b302fb435739e4c81bd3c1a1b85 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 23 Nov 2007 16:26:03 +0000 Subject: [PATCH] bind ListenAddress for outgoing connections ngircd would always use INADDR_ANY for outgoing connections; which might not be desirable. Added new [Server] option "Bind" to set source ip. --- doc/sample-ngircd.conf | 6 +++- man/ngircd.conf.5.tmpl | 6 +++- src/ngircd/conf.c | 11 ++++++- src/ngircd/conf.h | 3 +- src/ngircd/conn.c | 73 ++++++++++++++++++++++++++++-------------- src/tool/tool.c | 25 ++++++++++++++- src/tool/tool.h | 6 ++-- 7 files changed, 98 insertions(+), 32 deletions(-) diff --git a/doc/sample-ngircd.conf b/doc/sample-ngircd.conf index 924f0595..973c6803 100644 --- a/doc/sample-ngircd.conf +++ b/doc/sample-ngircd.conf @@ -1,4 +1,4 @@ -# $Id: sample-ngircd.conf,v 1.42 2007/11/21 12:16:35 alex Exp $ +# $Id: sample-ngircd.conf,v 1.43 2007/11/23 16:26:03 fw Exp $ # # This is a sample configuration file for the ngIRCd, which must be adepted @@ -154,6 +154,10 @@ # this server should establish the connection). ;Host = connect-to-host.the.net + # IP address to use as _source_ address for the connection. if unspecified, + # ngircd will let the operating system pick an address. + ;Bind = 10.0.0.1 + # Port of the server to which the ngIRCd should connect. If you # assign no port the ngIRCd waits for incoming connections. ;Port = 6667 diff --git a/man/ngircd.conf.5.tmpl b/man/ngircd.conf.5.tmpl index 457a162c..3a6b7d56 100644 --- a/man/ngircd.conf.5.tmpl +++ b/man/ngircd.conf.5.tmpl @@ -1,5 +1,5 @@ .\" -.\" $Id: ngircd.conf.5.tmpl,v 1.6 2007/11/21 12:16:36 alex Exp $ +.\" $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" .SH NAME @@ -212,6 +212,10 @@ IRC name of the server \fBHost\fR Internet host name 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. diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index c55aaf53..7ca5567d 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: conf.c,v 1.102 2007/11/21 12:16:36 alex Exp $"; +static char UNUSED id[] = "$Id: conf.c,v 1.103 2007/11/23 16:26:04 fw Exp $"; #include "imp.h" #include @@ -937,6 +937,14 @@ Handle_SERVER( int Line, char *Var, char *Arg ) Config_Error_TooLong( Line, Var ); return; } + if (strcasecmp(Var, "Bind") == 0) { + if (ngt_IPStrToBin(Arg, &New_Server.bind_addr)) + return; + + Config_Error(LOG_ERR, "%s, line %d (section \"Server\"): Can't parse IP address \"%s\"", + NGIRCd_ConfFile, Line, Arg); + return; + } if( strcasecmp( Var, "MyPassword" ) == 0 ) { /* Password of this server which is sent to the peer */ if (*Arg == ':') { @@ -1205,6 +1213,7 @@ Init_Server_Struct( CONF_SERVER *Server ) Resolve_Init(&Server->res_stat); Server->conn_id = NONE; + Server->bind_addr.s_addr = htonl(INADDR_ANY); } /* Init_Server_Struct */ diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 371f94db..9e152266 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: conf.h,v 1.45 2007/11/21 12:16:36 alex Exp $ + * $Id: conf.h,v 1.46 2007/11/23 16:26:04 fw Exp $ * * Configuration management (header) */ @@ -43,6 +43,7 @@ typedef struct _Conf_Server RES_STAT res_stat; /* Status of the resolver */ int flags; /* Flags */ CONN_ID conn_id; /* ID of server connection or NONE */ + struct in_addr bind_addr; /* source address to use for outgoing connections */ } CONF_SERVER; typedef struct _Conf_Channel diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 95ed3088..07c80783 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -17,7 +17,7 @@ #include "portab.h" #include "io.h" -static char UNUSED id[] = "$Id: conn.c,v 1.214 2007/11/18 15:05:35 alex Exp $"; +static char UNUSED id[] = "$Id: conn.c,v 1.215 2007/11/23 16:26:04 fw Exp $"; #include "imp.h" #include @@ -333,6 +333,42 @@ Conn_ExitListeners( void ) } /* Conn_ExitListeners */ +static void +InitSinaddr(struct sockaddr_in *addr, UINT16 Port) +{ + struct in_addr inaddr; + + memset(addr, 0, sizeof(*addr)); + memset( &inaddr, 0, sizeof(inaddr)); + + addr->sin_family = AF_INET; + addr->sin_port = htons(Port); + inaddr.s_addr = htonl(INADDR_ANY); + addr->sin_addr = inaddr; +} + + +static bool +InitSinaddrListenAddr(struct sockaddr_in *addr, UINT16 Port) +{ + struct in_addr inaddr; + + InitSinaddr(addr, Port); + + if (!Conf_ListenAddress[0]) + return true; + + if (!ngt_IPStrToBin(Conf_ListenAddress, &inaddr)) { + Log( LOG_CRIT, "Can't bind to %s:%u: can't convert ip address \"%s\"", + Conf_ListenAddress, Port, Conf_ListenAddress); + return false; + } + + addr->sin_addr = inaddr; + return true; +} + + /* return new listening port file descriptor or -1 on failure */ static int NewListener( const UINT16 Port ) @@ -340,33 +376,15 @@ NewListener( const UINT16 Port ) /* Create new listening socket on specified port */ struct sockaddr_in addr; - struct in_addr inaddr; int sock; #ifdef ZEROCONF char name[CLIENT_ID_LEN], *info; #endif - /* Server-"Listen"-Socket initialisieren */ - memset( &addr, 0, sizeof( addr )); - memset( &inaddr, 0, sizeof( inaddr )); + InitSinaddrListenAddr(&addr, Port); + addr.sin_family = AF_INET; addr.sin_port = htons( Port ); - if( Conf_ListenAddress[0] ) - { -#ifdef HAVE_INET_ATON - if( inet_aton( Conf_ListenAddress, &inaddr ) == 0 ) -#else - inaddr.s_addr = inet_addr( Conf_ListenAddress ); - if( inaddr.s_addr == (unsigned)-1 ) -#endif - { - Log( LOG_CRIT, "Can't listen on %s:%u: can't convert ip address %s!", - Conf_ListenAddress, Port, Conf_ListenAddress ); - return -1; - } - } - else inaddr.s_addr = htonl( INADDR_ANY ); - addr.sin_addr = inaddr; sock = socket( PF_INET, SOCK_STREAM, 0); if( sock < 0 ) { @@ -1358,7 +1376,7 @@ static void New_Server( int Server ) { /* Establish new server link */ - + struct sockaddr_in local_addr; struct sockaddr_in new_addr; struct in_addr inaddr; int res, new_sock; @@ -1382,11 +1400,12 @@ New_Server( int Server ) return; } - memset( &new_addr, 0, sizeof( new_addr )); + memset(&new_addr, 0, sizeof( new_addr )); new_addr.sin_family = AF_INET; new_addr.sin_addr = inaddr; new_addr.sin_port = htons( Conf_Server[Server].port ); + new_sock = socket( PF_INET, SOCK_STREAM, 0 ); if ( new_sock < 0 ) { Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno )); @@ -1395,6 +1414,12 @@ New_Server( int Server ) if( ! Init_Socket( new_sock )) return; + /* if we fail to bind, just continue and let connect() pick a source address */ + InitSinaddr(&local_addr, 0); + local_addr.sin_addr = Conf_Server[Server].bind_addr; + if (bind(new_sock, (struct sockaddr *)&local_addr, (socklen_t)sizeof(local_addr))) + Log(LOG_WARNING, "Can't bind socket to %s!", Conf_ListenAddress, strerror( errno )); + res = connect(new_sock, (struct sockaddr *)&new_addr, (socklen_t)sizeof(new_addr)); if(( res != 0 ) && ( errno != EINPROGRESS )) { @@ -1402,7 +1427,7 @@ New_Server( int Server ) close( new_sock ); return; } - + if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)new_sock)) { Log(LOG_ALERT, "Cannot allocate memory for server connection (socket %d)", diff --git a/src/tool/tool.c b/src/tool/tool.c index 01d892fd..dc238451 100644 --- a/src/tool/tool.c +++ b/src/tool/tool.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: tool.c,v 1.6 2006/04/09 12:53:07 alex Exp $"; +static char UNUSED id[] = "$Id: tool.c,v 1.7 2007/11/23 16:26:05 fw Exp $"; #include "imp.h" #include @@ -22,6 +22,11 @@ static char UNUSED id[] = "$Id: tool.c,v 1.6 2006/04/09 12:53:07 alex Exp $"; #include #include +#include +#ifdef HAVE_ARPA_INET_H +# include +#endif + #include "exp.h" #include "tool.h" @@ -105,4 +110,22 @@ ngt_TrimLastChr( char *String, const char Chr) } /* ngt_TrimLastChr */ +GLOBAL bool +ngt_IPStrToBin(const char *ip_str, struct in_addr *inaddr) +{ + /* AF is always AF_INET for now */ +#ifdef HAVE_INET_ATON + if (inet_aton(ip_str, inaddr) == 0) + return false; +#else + inaddr->s_addr = inet_addr(ip_str); + if (inaddr->s_addr == (unsigned)-1) + return false; +#endif + return true; +} + + + + /* -eof- */ diff --git a/src/tool/tool.h b/src/tool/tool.h index 5b386e59..bdd846f7 100644 --- a/src/tool/tool.h +++ b/src/tool/tool.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: tool.h,v 1.3 2005/03/19 18:43:53 fw Exp $ + * $Id: tool.h,v 1.4 2007/11/23 16:26:05 fw Exp $ * * Tool functions (Header) */ @@ -16,7 +16,7 @@ #ifndef __tool_h__ #define __tool_h__ - +#include "portab.h" GLOBAL void ngt_TrimLastChr PARAMS((char *String, const char Chr )); @@ -24,7 +24,7 @@ GLOBAL void ngt_TrimStr PARAMS((char *String )); GLOBAL char *ngt_LowerStr PARAMS((char *String )); - +GLOBAL bool ngt_IPStrToBin PARAMS((const char *ip_str, struct in_addr *inaddr)); #endif -- 2.39.2