2002-02-18 16:25:19 +00:00
/*
net_socket . c - - Handle various kinds of sockets .
2006-04-26 13:52:58 +00:00
Copyright ( C ) 1998 - 2005 Ivo Timmermans ,
2014-02-07 19:38:48 +00:00
2000 - 2014 Guus Sliepen < guus @ tinc - vpn . org >
2009-09-25 19:14:56 +00:00
2006 Scott Lamb < slamb @ slamb . org >
2009-09-24 21:29:46 +00:00
2009 Florian Forster < octo @ verplant . org >
2002-02-18 16:25:19 +00:00
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
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2009-09-24 22:01:00 +00:00
You should have received a copy of the GNU General Public License along
with this program ; if not , write to the Free Software Foundation , Inc . ,
51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
2002-02-18 16:25:19 +00:00
*/
2003-07-17 15:06:27 +00:00
# include "system.h"
2002-02-18 16:25:19 +00:00
# include "conf.h"
# include "connection.h"
2013-01-17 17:12:55 +00:00
# include "control_common.h"
2012-10-09 11:28:09 +00:00
# include "list.h"
2003-07-17 15:06:27 +00:00
# include "logger.h"
2002-02-18 16:25:19 +00:00
# include "meta.h"
2013-01-17 15:39:02 +00:00
# include "names.h"
2002-02-18 16:25:19 +00:00
# include "net.h"
# include "netutl.h"
# include "protocol.h"
2003-07-17 15:06:27 +00:00
# include "utils.h"
# include "xalloc.h"
2002-04-18 20:09:05 +00:00
2006-01-13 11:21:59 +00:00
/* Needed on Mac OS/X */
# ifndef SOL_TCP
# define SOL_TCP IPPROTO_TCP
# endif
2003-06-11 19:27:35 +00:00
int addressfamily = AF_UNSPEC ;
2002-02-18 16:25:19 +00:00
int maxtimeout = 900 ;
int seconds_till_retry = 5 ;
2010-11-13 18:05:49 +00:00
int udp_rcvbuf = 0 ;
int udp_sndbuf = 0 ;
2013-07-11 21:38:38 +00:00
int max_connection_burst = 100 ;
2002-02-18 16:25:19 +00:00
2002-03-18 22:47:20 +00:00
listen_socket_t listen_socket [ MAXSOCKETS ] ;
2002-06-13 16:12:40 +00:00
int listen_sockets ;
2013-01-17 17:12:55 +00:00
# ifndef HAVE_MINGW
io_t unix_socket ;
# endif
2009-01-20 12:12:41 +00:00
list_t * outgoing_list = NULL ;
2002-02-26 23:26:41 +00:00
2002-02-18 16:25:19 +00:00
/* Setup sockets */
2007-05-18 10:00:00 +00:00
static void configure_tcp ( connection_t * c ) {
2006-01-13 11:21:59 +00:00
int option ;
# ifdef O_NONBLOCK
2006-01-19 17:13:18 +00:00
int flags = fcntl ( c - > socket , F_GETFL ) ;
2006-01-13 11:21:59 +00:00
2006-01-19 17:13:18 +00:00
if ( fcntl ( c - > socket , F_SETFL , flags | O_NONBLOCK ) < 0 ) {
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " fcntl for %s: %s " , c - > hostname , strerror ( errno ) ) ;
2006-01-13 11:21:59 +00:00
}
2007-05-17 19:15:48 +00:00
# elif defined(WIN32)
unsigned long arg = 1 ;
if ( ioctlsocket ( c - > socket , FIONBIO , & arg ) ! = 0 ) {
2012-10-14 17:21:13 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " ioctlsocket for %s: %s " , c - > hostname , sockstrerror ( sockerrno ) ) ;
2007-05-17 19:15:48 +00:00
}
2006-01-13 11:21:59 +00:00
# endif
# if defined(SOL_TCP) && defined(TCP_NODELAY)
option = 1 ;
2010-11-12 15:15:29 +00:00
setsockopt ( c - > socket , SOL_TCP , TCP_NODELAY , ( void * ) & option , sizeof option ) ;
2006-01-13 11:21:59 +00:00
# endif
# if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
option = IPTOS_LOWDELAY ;
2010-11-12 15:15:29 +00:00
setsockopt ( c - > socket , SOL_IP , IP_TOS , ( void * ) & option , sizeof option ) ;
2006-01-13 11:21:59 +00:00
# endif
}
2009-09-24 22:14:03 +00:00
static bool bind_to_interface ( int sd ) {
2009-05-27 12:20:24 +00:00
char * iface ;
# if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
struct ifreq ifr ;
int status ;
# endif /* defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) */
if ( ! get_config_string ( lookup_config ( config_tree , " BindToInterface " ) , & iface ) )
return true ;
# if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
memset ( & ifr , 0 , sizeof ( ifr ) ) ;
strncpy ( ifr . ifr_ifrn . ifrn_name , iface , IFNAMSIZ ) ;
ifr . ifr_ifrn . ifrn_name [ IFNAMSIZ - 1 ] = 0 ;
2010-05-01 13:39:59 +00:00
status = setsockopt ( sd , SOL_SOCKET , SO_BINDTODEVICE , ( void * ) & ifr , sizeof ( ifr ) ) ;
2009-05-27 12:20:24 +00:00
if ( status ) {
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Can't bind to interface %s: %s " , iface ,
2014-06-26 19:42:40 +00:00
sockstrerror ( sockerrno ) ) ;
2009-05-27 12:20:24 +00:00
return false ;
}
# else /* if !defined(SOL_SOCKET) || !defined(SO_BINDTODEVICE) */
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_WARNING , " %s not supported on this platform " , " BindToInterface " ) ;
2009-05-27 12:20:24 +00:00
# endif
return true ;
2009-09-24 22:14:03 +00:00
}
2009-05-27 12:20:24 +00:00
2013-08-18 21:55:40 +00:00
static bool bind_to_address ( connection_t * c ) {
int s = - 1 ;
2014-01-20 20:19:13 +00:00
for ( int i = 0 ; i < listen_sockets & & listen_socket [ i ] . bindto ; i + + ) {
2013-08-18 21:55:40 +00:00
if ( listen_socket [ i ] . sa . sa . sa_family ! = c - > address . sa . sa_family )
continue ;
if ( s > = 0 )
return false ;
s = i ;
}
if ( s < 0 )
return false ;
sockaddr_t sa = listen_socket [ s ] . sa ;
if ( sa . sa . sa_family = = AF_INET )
sa . in . sin_port = 0 ;
else if ( sa . sa . sa_family = = AF_INET6 )
sa . in6 . sin6_port = 0 ;
if ( bind ( c - > socket , & sa . sa , SALEN ( sa . sa ) ) ) {
2014-06-26 19:42:40 +00:00
logger ( DEBUG_CONNECTIONS , LOG_WARNING , " Can't bind outgoing socket: %s " , sockstrerror ( sockerrno ) ) ;
2013-08-18 21:55:40 +00:00
return false ;
}
return true ;
}
2009-09-24 22:14:03 +00:00
int setup_listen_socket ( const sockaddr_t * sa ) {
2003-12-20 19:47:53 +00:00
int nfd ;
2002-09-09 21:25:28 +00:00
char * addrstr ;
int option ;
2003-07-18 13:45:06 +00:00
char * iface ;
2002-09-09 19:40:12 +00:00
2002-09-09 21:25:28 +00:00
nfd = socket ( sa - > sa . sa_family , SOCK_STREAM , IPPROTO_TCP ) ;
2002-02-18 16:25:19 +00:00
2002-09-09 21:25:28 +00:00
if ( nfd < 0 ) {
2012-02-26 17:37:36 +00:00
logger ( DEBUG_STATUS , LOG_ERR , " Creating metasocket failed: %s " , sockstrerror ( sockerrno ) ) ;
2002-09-09 21:25:28 +00:00
return - 1 ;
}
2012-02-17 15:13:38 +00:00
# ifdef FD_CLOEXEC
fcntl ( nfd , F_SETFD , FD_CLOEXEC ) ;
# endif
2002-09-09 21:25:28 +00:00
/* Optimize TCP settings */
2002-02-18 16:25:19 +00:00
2002-09-09 21:25:28 +00:00
option = 1 ;
2010-11-12 15:15:29 +00:00
setsockopt ( nfd , SOL_SOCKET , SO_REUSEADDR , ( void * ) & option , sizeof option ) ;
2002-03-01 15:14:29 +00:00
2008-12-11 20:49:14 +00:00
# if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
if ( sa - > sa . sa_family = = AF_INET6 )
2010-05-01 13:39:59 +00:00
setsockopt ( nfd , SOL_IPV6 , IPV6_V6ONLY , ( void * ) & option , sizeof option ) ;
2008-12-11 20:49:14 +00:00
# endif
2002-09-09 21:25:28 +00:00
if ( get_config_string
2003-07-18 13:45:06 +00:00
( lookup_config ( config_tree , " BindToInterface " ) , & iface ) ) {
2002-03-01 15:14:29 +00:00
# if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
2003-12-20 19:47:53 +00:00
struct ifreq ifr ;
2008-12-11 15:56:18 +00:00
memset ( & ifr , 0 , sizeof ifr ) ;
2003-07-18 13:45:06 +00:00
strncpy ( ifr . ifr_ifrn . ifrn_name , iface , IFNAMSIZ ) ;
2002-09-09 21:25:28 +00:00
2010-11-12 15:15:29 +00:00
if ( setsockopt ( nfd , SOL_SOCKET , SO_BINDTODEVICE , ( void * ) & ifr , sizeof ifr ) ) {
2003-07-29 22:59:01 +00:00
closesocket ( nfd ) ;
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Can't bind to interface %s: %s " , iface ,
2014-06-26 19:42:40 +00:00
sockstrerror ( sockerrno ) ) ;
2002-09-09 21:25:28 +00:00
return - 1 ;
}
2002-03-01 15:14:29 +00:00
# else
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_WARNING , " %s not supported on this platform " , " BindToInterface " ) ;
2002-02-18 16:25:19 +00:00
# endif
2002-09-09 21:25:28 +00:00
}
if ( bind ( nfd , & sa - > sa , SALEN ( sa - > sa ) ) ) {
2003-07-29 22:59:01 +00:00
closesocket ( nfd ) ;
2002-09-09 21:25:28 +00:00
addrstr = sockaddr2hostname ( sa ) ;
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Can't bind to %s/tcp: %s " , addrstr , sockstrerror ( sockerrno ) ) ;
2002-09-09 21:25:28 +00:00
free ( addrstr ) ;
return - 1 ;
}
if ( listen ( nfd , 3 ) ) {
2003-07-29 22:59:01 +00:00
closesocket ( nfd ) ;
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " System call `%s' failed: %s " , " listen " , sockstrerror ( sockerrno ) ) ;
2002-09-09 21:25:28 +00:00
return - 1 ;
}
return nfd ;
2002-02-18 16:25:19 +00:00
}
2007-05-18 10:00:00 +00:00
int setup_vpn_in_socket ( const sockaddr_t * sa ) {
2003-12-20 19:47:53 +00:00
int nfd ;
2002-09-09 21:25:28 +00:00
char * addrstr ;
int option ;
nfd = socket ( sa - > sa . sa_family , SOCK_DGRAM , IPPROTO_UDP ) ;
if ( nfd < 0 ) {
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Creating UDP socket failed: %s " , sockstrerror ( sockerrno ) ) ;
2002-09-09 21:25:28 +00:00
return - 1 ;
}
2012-02-17 15:13:38 +00:00
# ifdef FD_CLOEXEC
fcntl ( nfd , F_SETFD , FD_CLOEXEC ) ;
# endif
2003-07-28 22:06:09 +00:00
# ifdef O_NONBLOCK
2003-12-20 19:47:53 +00:00
{
int flags = fcntl ( nfd , F_GETFL ) ;
if ( fcntl ( nfd , F_SETFL , flags | O_NONBLOCK ) < 0 ) {
closesocket ( nfd ) ;
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " System call `%s' failed: %s " , " fcntl " ,
2003-12-20 19:47:53 +00:00
strerror ( errno ) ) ;
return - 1 ;
}
2002-09-09 21:25:28 +00:00
}
2007-05-17 19:15:48 +00:00
# elif defined(WIN32)
{
unsigned long arg = 1 ;
if ( ioctlsocket ( nfd , FIONBIO , & arg ) ! = 0 ) {
closesocket ( nfd ) ;
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Call to `%s' failed: %s " , " ioctlsocket " , sockstrerror ( sockerrno ) ) ;
2007-05-17 19:15:48 +00:00
return - 1 ;
}
}
2003-07-28 22:06:09 +00:00
# endif
2002-09-09 21:25:28 +00:00
option = 1 ;
2010-11-12 15:15:29 +00:00
setsockopt ( nfd , SOL_SOCKET , SO_REUSEADDR , ( void * ) & option , sizeof option ) ;
2012-02-23 12:26:01 +00:00
setsockopt ( nfd , SOL_SOCKET , SO_BROADCAST , ( void * ) & option , sizeof option ) ;
2002-03-01 15:14:29 +00:00
2010-11-13 18:05:49 +00:00
if ( udp_rcvbuf & & setsockopt ( nfd , SOL_SOCKET , SO_RCVBUF , ( void * ) & udp_rcvbuf , sizeof ( udp_rcvbuf ) ) )
2014-06-26 19:42:40 +00:00
logger ( DEBUG_ALWAYS , LOG_WARNING , " Can't set UDP SO_RCVBUF to %i: %s " , udp_rcvbuf , sockstrerror ( sockerrno ) ) ;
2010-11-13 18:05:49 +00:00
if ( udp_sndbuf & & setsockopt ( nfd , SOL_SOCKET , SO_SNDBUF , ( void * ) & udp_sndbuf , sizeof ( udp_sndbuf ) ) )
2014-06-26 19:42:40 +00:00
logger ( DEBUG_ALWAYS , LOG_WARNING , " Can't set UDP SO_SNDBUF to %i: %s " , udp_sndbuf , sockstrerror ( sockerrno ) ) ;
2010-11-13 18:05:49 +00:00
2010-02-02 21:22:27 +00:00
# if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
2008-12-11 20:49:14 +00:00
if ( sa - > sa . sa_family = = AF_INET6 )
2010-05-01 13:39:59 +00:00
setsockopt ( nfd , IPPROTO_IPV6 , IPV6_V6ONLY , ( void * ) & option , sizeof option ) ;
2010-02-02 21:22:27 +00:00
# endif
# if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT)
# define IP_DONTFRAGMENT IP_DONTFRAG
2008-12-11 20:49:14 +00:00
# endif
2003-12-20 19:47:53 +00:00
# if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
2009-03-09 12:48:54 +00:00
if ( myself - > options & OPTION_PMTU_DISCOVERY ) {
option = IP_PMTUDISC_DO ;
2010-05-01 13:39:59 +00:00
setsockopt ( nfd , SOL_IP , IP_MTU_DISCOVER , ( void * ) & option , sizeof ( option ) ) ;
2003-12-20 21:09:33 +00:00
}
2009-10-24 20:32:35 +00:00
# elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT)
if ( myself - > options & OPTION_PMTU_DISCOVERY ) {
option = 1 ;
2010-05-01 13:39:59 +00:00
setsockopt ( nfd , IPPROTO_IP , IP_DONTFRAGMENT , ( void * ) & option , sizeof ( option ) ) ;
2009-10-24 20:32:35 +00:00
}
2003-12-20 21:09:33 +00:00
# endif
# if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
2009-03-09 12:48:54 +00:00
if ( myself - > options & OPTION_PMTU_DISCOVERY ) {
option = IPV6_PMTUDISC_DO ;
2010-05-01 13:39:59 +00:00
setsockopt ( nfd , SOL_IPV6 , IPV6_MTU_DISCOVER , ( void * ) & option , sizeof ( option ) ) ;
2003-12-20 19:47:53 +00:00
}
2010-02-02 21:22:27 +00:00
# elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG)
if ( myself - > options & OPTION_PMTU_DISCOVERY ) {
option = 1 ;
2010-05-01 13:39:59 +00:00
setsockopt ( nfd , IPPROTO_IPV6 , IPV6_DONTFRAG , ( void * ) & option , sizeof ( option ) ) ;
2010-02-02 21:22:27 +00:00
}
2003-12-20 19:47:53 +00:00
# endif
2002-09-09 21:25:28 +00:00
2009-05-27 12:20:24 +00:00
if ( ! bind_to_interface ( nfd ) ) {
closesocket ( nfd ) ;
return - 1 ;
2002-03-01 11:18:34 +00:00
}
2002-02-18 16:25:19 +00:00
2002-09-09 21:25:28 +00:00
if ( bind ( nfd , & sa - > sa , SALEN ( sa - > sa ) ) ) {
2003-07-29 22:59:01 +00:00
closesocket ( nfd ) ;
2002-09-09 21:25:28 +00:00
addrstr = sockaddr2hostname ( sa ) ;
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Can't bind to %s/udp: %s " , addrstr , sockstrerror ( sockerrno ) ) ;
2002-09-09 21:25:28 +00:00
free ( addrstr ) ;
return - 1 ;
}
return nfd ;
2009-05-27 12:20:24 +00:00
} /* int setup_vpn_in_socket */
2002-02-18 16:25:19 +00:00
2012-11-29 11:28:23 +00:00
static void retry_outgoing_handler ( void * data ) {
2007-05-19 13:34:32 +00:00
setup_outgoing_connection ( data ) ;
2007-05-17 22:09:55 +00:00
}
2002-09-09 21:25:28 +00:00
2007-05-17 22:09:55 +00:00
void retry_outgoing ( outgoing_t * outgoing ) {
2002-09-09 21:25:28 +00:00
outgoing - > timeout + = 5 ;
if ( outgoing - > timeout > maxtimeout )
outgoing - > timeout = maxtimeout ;
2012-11-29 11:28:23 +00:00
timeout_add ( & outgoing - > ev , retry_outgoing_handler , outgoing , & ( struct timeval ) { outgoing - > timeout , rand ( ) % 100000 } ) ;
2002-09-09 21:25:28 +00:00
2012-11-29 11:28:23 +00:00
logger ( DEBUG_CONNECTIONS , LOG_NOTICE , " Trying to re-establish outgoing connection in %d seconds " , outgoing - > timeout ) ;
2002-02-18 16:25:19 +00:00
}
2007-05-18 10:00:00 +00:00
void finish_connecting ( connection_t * c ) {
2012-02-26 17:37:36 +00:00
logger ( DEBUG_CONNECTIONS , LOG_INFO , " Connected to %s (%s) " , c - > name , c - > hostname ) ;
2002-02-18 16:25:19 +00:00
2013-03-08 13:11:15 +00:00
c - > last_ping_time = now . tv_sec ;
2007-05-17 23:04:02 +00:00
c - > status . connecting = false ;
2002-02-18 16:25:19 +00:00
2002-09-09 21:25:28 +00:00
send_id ( c ) ;
2002-02-18 16:25:19 +00:00
}
2012-04-19 13:18:31 +00:00
static void do_outgoing_pipe ( connection_t * c , char * command ) {
# ifndef HAVE_MINGW
int fd [ 2 ] ;
if ( socketpair ( AF_UNIX , SOCK_STREAM , 0 , fd ) ) {
2014-06-26 19:42:40 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Could not create socketpair: %s " , sockstrerror ( sockerrno ) ) ;
2012-04-19 13:18:31 +00:00
return ;
}
if ( fork ( ) ) {
c - > socket = fd [ 0 ] ;
close ( fd [ 1 ] ) ;
2012-06-26 11:24:20 +00:00
logger ( DEBUG_CONNECTIONS , LOG_DEBUG , " Using proxy %s " , command ) ;
2012-04-19 13:18:31 +00:00
return ;
}
close ( 0 ) ;
close ( 1 ) ;
close ( fd [ 0 ] ) ;
dup2 ( fd [ 1 ] , 0 ) ;
dup2 ( fd [ 1 ] , 1 ) ;
close ( fd [ 1 ] ) ;
// Other filedescriptors should be closed automatically by CLOEXEC
char * host = NULL ;
char * port = NULL ;
sockaddr2str ( & c - > address , & host , & port ) ;
setenv ( " REMOTEADDRESS " , host , true ) ;
setenv ( " REMOTEPORT " , port , true ) ;
setenv ( " NODE " , c - > name , true ) ;
setenv ( " NAME " , myself - > name , true ) ;
if ( netname )
setenv ( " NETNAME " , netname , true ) ;
int result = system ( command ) ;
if ( result < 0 )
2012-09-04 12:21:50 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Could not execute %s: %s " , command , strerror ( errno ) ) ;
2012-04-19 13:18:31 +00:00
else if ( result )
2012-06-26 11:24:20 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " %s exited with non-zero status %d " , command , result ) ;
2012-04-19 13:18:31 +00:00
exit ( result ) ;
# else
2012-06-26 11:24:20 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Proxy type exec not supported on this platform! " ) ;
2012-06-25 13:00:24 +00:00
return ;
2012-04-19 13:18:31 +00:00
# endif
}
2012-11-29 11:28:23 +00:00
static void handle_meta_write ( connection_t * c ) {
2013-03-01 16:15:26 +00:00
if ( c - > outbuf . len < = c - > outbuf . offset )
return ;
2012-10-07 19:02:40 +00:00
ssize_t outlen = send ( c - > socket , c - > outbuf . data + c - > outbuf . offset , c - > outbuf . len - c - > outbuf . offset , 0 ) ;
if ( outlen < = 0 ) {
2014-06-26 19:42:40 +00:00
if ( ! sockerrno | | sockerrno = = EPIPE ) {
2012-10-07 19:02:40 +00:00
logger ( DEBUG_CONNECTIONS , LOG_NOTICE , " Connection closed by %s (%s) " , c - > name , c - > hostname ) ;
} else if ( sockwouldblock ( sockerrno ) ) {
logger ( DEBUG_CONNECTIONS , LOG_DEBUG , " Sending %d bytes to %s (%s) would block " , c - > outbuf . len - c - > outbuf . offset , c - > name , c - > hostname ) ;
return ;
} else {
2014-06-26 19:42:40 +00:00
logger ( DEBUG_CONNECTIONS , LOG_ERR , " Could not send %d bytes of data to %s (%s): %s " , c - > outbuf . len - c - > outbuf . offset , c - > name , c - > hostname , sockstrerror ( sockerrno ) ) ;
2012-10-07 19:02:40 +00:00
}
terminate_connection ( c , c - > status . active ) ;
return ;
}
buffer_read ( & c - > outbuf , outlen ) ;
2012-11-29 11:28:23 +00:00
if ( ! c - > outbuf . len )
io_set ( & c - > io , IO_READ ) ;
2012-10-07 19:02:40 +00:00
}
2012-11-29 11:28:23 +00:00
static void handle_meta_io ( void * data , int flags ) {
2013-02-06 14:12:53 +00:00
connection_t * c = data ;
if ( c - > status . connecting ) {
2014-06-27 18:33:31 +00:00
/* The event loop does not protect against spurious events. Verify that we are actually connected. */
if ( connect ( c - > socket , & c - > address . sa , sizeof ( c - > address ) ) = = 0 )
logger ( DEBUG_CONNECTIONS , LOG_DEBUG , " Error while connecting to %s (%s): redundant connect() unexpectedly succeeded " , c - > name , c - > hostname ) ;
else if ( ! sockisconn ( sockerrno ) ) {
if ( ! sockalready ( sockerrno ) ) {
logger ( DEBUG_CONNECTIONS , LOG_DEBUG , " Error while checking connection status for %s (%s): %s " , c - > name , c - > hostname , sockstrerror ( sockerrno ) ) ;
terminate_connection ( c , false ) ;
}
return ;
}
2013-02-06 14:12:53 +00:00
c - > status . connecting = false ;
int result ;
socklen_t len = sizeof result ;
2013-02-20 13:39:24 +00:00
getsockopt ( c - > socket , SOL_SOCKET , SO_ERROR , ( void * ) & result , & len ) ;
2013-02-06 14:12:53 +00:00
if ( ! result )
finish_connecting ( c ) ;
else {
logger ( DEBUG_CONNECTIONS , LOG_DEBUG , " Error while connecting to %s (%s): %s " , c - > name , c - > hostname , sockstrerror ( result ) ) ;
terminate_connection ( c , false ) ;
return ;
}
}
2012-11-29 11:28:23 +00:00
if ( flags & IO_WRITE )
2013-02-06 14:12:53 +00:00
handle_meta_write ( c ) ;
2012-11-29 11:28:23 +00:00
else
2013-02-06 14:12:53 +00:00
handle_meta_connection_data ( c ) ;
2012-11-29 11:28:23 +00:00
}
2012-10-07 19:02:40 +00:00
bool do_outgoing_connection ( outgoing_t * outgoing ) {
2009-12-23 18:49:38 +00:00
char * address , * port , * space ;
2012-06-25 17:01:51 +00:00
struct addrinfo * proxyai = NULL ;
2006-08-08 13:44:19 +00:00
int result ;
2002-02-18 16:25:19 +00:00
2002-09-09 21:25:28 +00:00
begin :
2012-10-07 19:02:40 +00:00
if ( ! outgoing - > ai ) {
if ( ! outgoing - > cfg ) {
logger ( DEBUG_CONNECTIONS , LOG_ERR , " Could not set up a meta connection to %s " , outgoing - > name ) ;
retry_outgoing ( outgoing ) ;
2011-05-29 19:53:21 +00:00
return false ;
2002-09-09 21:25:28 +00:00
}
2012-10-07 19:02:40 +00:00
get_config_string ( outgoing - > cfg , & address ) ;
2002-09-09 21:25:28 +00:00
2009-12-23 18:49:38 +00:00
space = strchr ( address , ' ' ) ;
if ( space ) {
port = xstrdup ( space + 1 ) ;
* space = 0 ;
} else {
2012-10-07 19:02:40 +00:00
if ( ! get_config_string ( lookup_config ( outgoing - > config_tree , " Port " ) , & port ) )
2009-12-23 18:49:38 +00:00
port = xstrdup ( " 655 " ) ;
}
2002-09-09 21:25:28 +00:00
2012-10-07 19:02:40 +00:00
outgoing - > ai = str2addrinfo ( address , port , SOCK_STREAM ) ;
2002-09-09 21:25:28 +00:00
free ( address ) ;
free ( port ) ;
2012-10-07 19:02:40 +00:00
outgoing - > aip = outgoing - > ai ;
outgoing - > cfg = lookup_config_next ( outgoing - > config_tree , outgoing - > cfg ) ;
2002-09-09 21:25:28 +00:00
}
2002-02-18 16:25:19 +00:00
2012-10-07 19:02:40 +00:00
if ( ! outgoing - > aip ) {
if ( outgoing - > ai )
freeaddrinfo ( outgoing - > ai ) ;
outgoing - > ai = NULL ;
2002-09-09 21:25:28 +00:00
goto begin ;
}
2002-02-18 16:25:19 +00:00
2012-10-07 19:02:40 +00:00
connection_t * c = new_connection ( ) ;
c - > outgoing = outgoing ;
2002-02-18 16:25:19 +00:00
2012-10-07 19:02:40 +00:00
memcpy ( & c - > address , outgoing - > aip - > ai_addr , outgoing - > aip - > ai_addrlen ) ;
outgoing - > aip = outgoing - > aip - > ai_next ;
2002-02-18 16:25:19 +00:00
2002-09-09 21:25:28 +00:00
c - > hostname = sockaddr2hostname ( & c - > address ) ;
2002-02-18 16:25:19 +00:00
2012-10-07 19:02:40 +00:00
logger ( DEBUG_CONNECTIONS , LOG_INFO , " Trying to connect to %s (%s) " , outgoing - > name , c - > hostname ) ;
2002-02-18 16:25:19 +00:00
2012-04-18 21:19:40 +00:00
if ( ! proxytype ) {
c - > socket = socket ( c - > address . sa . sa_family , SOCK_STREAM , IPPROTO_TCP ) ;
2012-04-19 13:18:31 +00:00
configure_tcp ( c ) ;
2012-06-25 13:00:24 +00:00
} else if ( proxytype = = PROXY_EXEC ) {
2012-04-19 13:18:31 +00:00
do_outgoing_pipe ( c , proxyhost ) ;
2012-06-25 13:00:24 +00:00
} else {
2012-04-18 21:19:40 +00:00
proxyai = str2addrinfo ( proxyhost , proxyport , SOCK_STREAM ) ;
2012-10-07 19:02:40 +00:00
if ( ! proxyai ) {
free_connection ( c ) ;
2012-04-18 21:19:40 +00:00
goto begin ;
2012-10-07 19:02:40 +00:00
}
2012-06-26 11:24:20 +00:00
logger ( DEBUG_CONNECTIONS , LOG_INFO , " Using proxy at %s port %s " , proxyhost , proxyport ) ;
2012-04-18 21:19:40 +00:00
c - > socket = socket ( proxyai - > ai_family , SOCK_STREAM , IPPROTO_TCP ) ;
2013-02-07 13:22:28 +00:00
configure_tcp ( c ) ;
2012-04-18 21:19:40 +00:00
}
2012-02-17 15:13:38 +00:00
2002-09-09 21:25:28 +00:00
if ( c - > socket = = - 1 ) {
2012-02-26 17:37:36 +00:00
logger ( DEBUG_CONNECTIONS , LOG_ERR , " Creating socket for %s failed: %s " , c - > hostname , sockstrerror ( sockerrno ) ) ;
2012-10-07 19:02:40 +00:00
free_connection ( c ) ;
2002-09-09 21:25:28 +00:00
goto begin ;
}
2002-02-18 16:25:19 +00:00
2012-04-18 21:19:40 +00:00
# ifdef FD_CLOEXEC
fcntl ( c - > socket , F_SETFD , FD_CLOEXEC ) ;
2008-12-11 20:49:14 +00:00
# endif
2012-04-19 13:18:31 +00:00
if ( proxytype ! = PROXY_EXEC ) {
2008-12-22 19:40:40 +00:00
# if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
2012-04-19 13:18:31 +00:00
int option = 1 ;
if ( c - > address . sa . sa_family = = AF_INET6 )
setsockopt ( c - > socket , SOL_IPV6 , IPV6_V6ONLY , ( void * ) & option , sizeof option ) ;
2008-12-22 19:40:40 +00:00
# endif
2002-02-18 16:25:19 +00:00
2012-04-19 13:18:31 +00:00
bind_to_interface ( c - > socket ) ;
2013-08-18 21:55:40 +00:00
bind_to_address ( c ) ;
2012-04-19 13:18:31 +00:00
}
2002-02-18 16:25:19 +00:00
2002-09-09 21:25:28 +00:00
/* Connect */
2002-02-18 16:25:19 +00:00
2012-04-18 21:19:40 +00:00
if ( ! proxytype ) {
result = connect ( c - > socket , & c - > address . sa , SALEN ( c - > address . sa ) ) ;
2012-04-19 13:18:31 +00:00
} else if ( proxytype = = PROXY_EXEC ) {
result = 0 ;
2012-04-18 21:19:40 +00:00
} else {
result = connect ( c - > socket , proxyai - > ai_addr , proxyai - > ai_addrlen ) ;
freeaddrinfo ( proxyai ) ;
}
2002-02-18 16:25:19 +00:00
2012-10-07 19:02:40 +00:00
if ( result = = - 1 & & ! sockinprogress ( sockerrno ) ) {
logger ( DEBUG_CONNECTIONS , LOG_ERR , " Could not connect to %s (%s): %s " , outgoing - > name , c - > hostname , sockstrerror ( sockerrno ) ) ;
free_connection ( c ) ;
2002-09-09 21:25:28 +00:00
goto begin ;
}
2002-02-18 16:25:19 +00:00
2012-10-07 19:02:40 +00:00
/* Now that there is a working socket, fill in the rest and register this connection. */
2002-02-18 16:25:19 +00:00
2012-10-07 19:02:40 +00:00
c - > status . connecting = true ;
c - > name = xstrdup ( outgoing - > name ) ;
c - > outcipher = myself - > connection - > outcipher ;
c - > outdigest = myself - > connection - > outdigest ;
c - > outmaclength = myself - > connection - > outmaclength ;
c - > outcompression = myself - > connection - > outcompression ;
2013-03-08 13:11:15 +00:00
c - > last_ping_time = now . tv_sec ;
2011-05-14 17:20:56 +00:00
2012-10-07 19:02:40 +00:00
connection_add ( c ) ;
2012-10-07 09:45:54 +00:00
2013-02-06 14:12:53 +00:00
io_add ( & c - > io , handle_meta_io , c , c - > socket , IO_READ | IO_WRITE ) ;
2011-05-14 17:20:56 +00:00
2012-10-07 19:02:40 +00:00
return true ;
2007-05-19 22:23:02 +00:00
}
2014-01-30 16:10:30 +00:00
// Find edges pointing to this node, and use them to build a list of unique, known addresses.
static struct addrinfo * get_known_addresses ( node_t * n ) {
struct addrinfo * ai = NULL ;
for splay_each ( edge_t , e , n - > edge_tree ) {
if ( ! e - > reverse )
continue ;
bool found = false ;
for ( struct addrinfo * aip = ai ; aip ; aip = aip - > ai_next ) {
if ( ! sockaddrcmp ( & e - > reverse - > address , ( sockaddr_t * ) aip - > ai_addr ) ) {
found = true ;
break ;
}
}
if ( found )
continue ;
struct addrinfo * nai = xzalloc ( sizeof * nai ) ;
if ( ai )
ai - > ai_next = nai ;
ai = nai ;
ai - > ai_family = e - > reverse - > address . sa . sa_family ;
ai - > ai_socktype = SOCK_STREAM ;
ai - > ai_protocol = IPPROTO_TCP ;
ai - > ai_addrlen = SALEN ( e - > reverse - > address . sa ) ;
ai - > ai_addr = xmalloc ( ai - > ai_addrlen ) ;
memcpy ( ai - > ai_addr , & e - > reverse - > address , ai - > ai_addrlen ) ;
}
return ai ;
}
2007-05-18 10:00:00 +00:00
void setup_outgoing_connection ( outgoing_t * outgoing ) {
2012-11-29 11:28:23 +00:00
timeout_del ( & outgoing - > ev ) ;
2009-10-20 20:14:47 +00:00
2012-10-07 19:02:40 +00:00
node_t * n = lookup_node ( outgoing - > name ) ;
2002-09-09 21:25:28 +00:00
2012-10-07 19:02:40 +00:00
if ( n & & n - > connection ) {
logger ( DEBUG_CONNECTIONS , LOG_INFO , " Already connected to %s " , outgoing - > name ) ;
2002-09-09 21:25:28 +00:00
2012-10-07 19:02:40 +00:00
n - > connection - > outgoing = outgoing ;
return ;
}
2002-09-09 21:25:28 +00:00
2012-10-07 19:02:40 +00:00
init_configuration ( & outgoing - > config_tree ) ;
read_host_config ( outgoing - > config_tree , outgoing - > name ) ;
outgoing - > cfg = lookup_config ( outgoing - > config_tree , " Address " ) ;
2002-09-09 21:25:28 +00:00
if ( ! outgoing - > cfg ) {
2014-01-30 16:10:30 +00:00
if ( n )
outgoing - > aip = outgoing - > ai = get_known_addresses ( n ) ;
if ( ! outgoing - > ai ) {
logger ( DEBUG_ALWAYS , LOG_ERR , " No address known for %s " , outgoing - > name ) ;
return ;
}
2002-09-09 21:25:28 +00:00
}
2012-10-07 19:02:40 +00:00
do_outgoing_connection ( outgoing ) ;
2002-02-18 16:25:19 +00:00
}
/*
accept a new tcp connect and create a
new connection
*/
2012-11-29 11:28:23 +00:00
void handle_new_meta_connection ( void * data , int flags ) {
listen_socket_t * l = data ;
2002-09-09 21:25:28 +00:00
connection_t * c ;
sockaddr_t sa ;
2006-03-19 13:06:21 +00:00
int fd ;
2008-12-11 15:56:18 +00:00
socklen_t len = sizeof sa ;
2002-09-09 21:25:28 +00:00
2012-11-29 11:28:23 +00:00
fd = accept ( l - > tcp . fd , & sa . sa , & len ) ;
2002-09-09 21:25:28 +00:00
if ( fd < 0 ) {
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR , " Accepting a new connection failed: %s " , sockstrerror ( sockerrno ) ) ;
2007-05-17 20:20:10 +00:00
return ;
2002-09-09 21:25:28 +00:00
}
sockaddrunmap ( & sa ) ;
2013-07-11 21:38:38 +00:00
// Check if we get many connections from the same host
static sockaddr_t prev_sa ;
static int tarpit = - 1 ;
if ( tarpit > = 0 ) {
closesocket ( tarpit ) ;
tarpit = - 1 ;
}
2013-09-01 22:11:04 +00:00
if ( ! sockaddrcmp_noport ( & sa , & prev_sa ) ) {
static int samehost_burst ;
static int samehost_burst_time ;
if ( now . tv_sec - samehost_burst_time > samehost_burst )
samehost_burst = 0 ;
else
samehost_burst - = now . tv_sec - samehost_burst_time ;
samehost_burst_time = now . tv_sec ;
samehost_burst + + ;
if ( samehost_burst > max_connection_burst ) {
tarpit = fd ;
return ;
}
2013-07-11 21:38:38 +00:00
}
memcpy ( & prev_sa , & sa , sizeof sa ) ;
// Check if we get many connections from different hosts
static int connection_burst ;
static int connection_burst_time ;
if ( now . tv_sec - connection_burst_time > connection_burst )
connection_burst = 0 ;
else
connection_burst - = now . tv_sec - connection_burst_time ;
connection_burst_time = now . tv_sec ;
connection_burst + + ;
if ( connection_burst > = max_connection_burst ) {
connection_burst = max_connection_burst ;
tarpit = fd ;
return ;
}
// Accept the new connection
2002-09-09 21:25:28 +00:00
c = new_connection ( ) ;
2007-05-17 19:15:48 +00:00
c - > name = xstrdup ( " <unknown> " ) ;
2002-09-09 21:25:28 +00:00
c - > outcipher = myself - > connection - > outcipher ;
c - > outdigest = myself - > connection - > outdigest ;
c - > outmaclength = myself - > connection - > outmaclength ;
c - > outcompression = myself - > connection - > outcompression ;
c - > address = sa ;
c - > hostname = sockaddr2hostname ( & sa ) ;
c - > socket = fd ;
2013-03-08 13:11:15 +00:00
c - > last_ping_time = now . tv_sec ;
2002-09-09 21:25:28 +00:00
2012-02-26 17:37:36 +00:00
logger ( DEBUG_CONNECTIONS , LOG_NOTICE , " Connection from %s " , c - > hostname ) ;
2002-09-09 21:25:28 +00:00
2012-11-29 11:28:23 +00:00
io_add ( & c - > io , handle_meta_io , c , c - > socket , IO_READ ) ;
2012-10-10 15:17:49 +00:00
2006-01-13 11:21:59 +00:00
configure_tcp ( c ) ;
2004-11-10 21:56:31 +00:00
2002-09-09 21:25:28 +00:00
connection_add ( c ) ;
c - > allow_request = ID ;
send_id ( c ) ;
2002-02-18 16:25:19 +00:00
}
2013-01-17 17:12:55 +00:00
# ifndef HAVE_MINGW
/*
accept a new UNIX socket connection
*/
void handle_new_unix_connection ( void * data , int flags ) {
io_t * io = data ;
connection_t * c ;
sockaddr_t sa ;
int fd ;
socklen_t len = sizeof sa ;
fd = accept ( io - > fd , & sa . sa , & len ) ;
if ( fd < 0 ) {
logger ( DEBUG_ALWAYS , LOG_ERR , " Accepting a new connection failed: %s " , sockstrerror ( sockerrno ) ) ;
return ;
}
sockaddrunmap ( & sa ) ;
c = new_connection ( ) ;
c - > name = xstrdup ( " <control> " ) ;
c - > address = sa ;
c - > hostname = xstrdup ( " localhost port unix " ) ;
c - > socket = fd ;
2013-03-08 13:11:15 +00:00
c - > last_ping_time = now . tv_sec ;
2013-01-17 17:12:55 +00:00
logger ( DEBUG_CONNECTIONS , LOG_NOTICE , " Connection from %s " , c - > hostname ) ;
io_add ( & c - > io , handle_meta_io , c , c - > socket , IO_READ ) ;
connection_add ( c ) ;
c - > allow_request = ID ;
send_id ( c ) ;
}
# endif
2011-05-28 01:56:06 +00:00
static void free_outgoing ( outgoing_t * outgoing ) {
2012-11-29 11:28:23 +00:00
timeout_del ( & outgoing - > ev ) ;
2012-09-28 15:05:01 +00:00
2009-01-20 12:12:41 +00:00
if ( outgoing - > ai )
freeaddrinfo ( outgoing - > ai ) ;
2012-10-09 14:27:28 +00:00
if ( outgoing - > config_tree )
exit_configuration ( & outgoing - > config_tree ) ;
2009-01-20 12:12:41 +00:00
if ( outgoing - > name )
free ( outgoing - > name ) ;
free ( outgoing ) ;
}
2009-09-24 22:14:03 +00:00
void try_outgoing_connections ( void ) {
2012-09-28 15:05:01 +00:00
/* If there is no outgoing list yet, create one. Otherwise, mark all outgoings as deleted. */
if ( ! outgoing_list ) {
outgoing_list = list_alloc ( ( list_action_t ) free_outgoing ) ;
} else {
2012-10-07 22:35:38 +00:00
for list_each ( outgoing_t , outgoing , outgoing_list )
2012-09-28 15:05:01 +00:00
outgoing - > timeout = - 1 ;
}
/* Make sure there is one outgoing_t in the list for each ConnectTo. */
2012-10-07 22:35:38 +00:00
for ( config_t * cfg = lookup_config ( config_tree , " ConnectTo " ) ; cfg ; cfg = lookup_config_next ( config_tree , cfg ) ) {
char * name ;
2002-09-09 21:25:28 +00:00
get_config_string ( cfg , & name ) ;
2003-07-22 20:55:21 +00:00
if ( ! check_id ( name ) ) {
2012-02-26 17:37:36 +00:00
logger ( DEBUG_ALWAYS , LOG_ERR ,
2009-09-24 22:54:07 +00:00
" Invalid name for outgoing connection in %s line %d " ,
2002-09-09 21:25:28 +00:00
cfg - > file , cfg - > line ) ;
free ( name ) ;
continue ;
}
2012-09-28 15:05:01 +00:00
bool found = false ;
2012-10-07 22:35:38 +00:00
for list_each ( outgoing_t , outgoing , outgoing_list ) {
2012-09-28 15:05:01 +00:00
if ( ! strcmp ( outgoing - > name , name ) ) {
found = true ;
outgoing - > timeout = 0 ;
break ;
}
}
if ( ! found ) {
2013-05-01 15:31:33 +00:00
outgoing_t * outgoing = xzalloc ( sizeof * outgoing ) ;
2012-09-28 15:05:01 +00:00
outgoing - > name = name ;
list_insert_tail ( outgoing_list , outgoing ) ;
setup_outgoing_connection ( outgoing ) ;
}
}
/* Terminate any connections whose outgoing_t is to be deleted. */
2012-10-07 22:35:38 +00:00
for list_each ( connection_t , c , connection_list ) {
2012-09-28 15:05:01 +00:00
if ( c - > outgoing & & c - > outgoing - > timeout = = - 1 ) {
c - > outgoing = NULL ;
2012-10-07 19:02:40 +00:00
logger ( DEBUG_CONNECTIONS , LOG_INFO , " No more outgoing connection to %s " , c - > name ) ;
2012-09-28 15:05:01 +00:00
terminate_connection ( c , c - > status . active ) ;
}
}
/* Delete outgoing_ts for which there is no ConnectTo. */
2012-10-07 22:35:38 +00:00
for list_each ( outgoing_t , outgoing , outgoing_list )
2012-09-28 15:05:01 +00:00
if ( outgoing - > timeout = = - 1 )
2012-10-07 19:59:53 +00:00
list_delete_node ( outgoing_list , node ) ;
2002-02-18 16:25:19 +00:00
}