X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Fstream.c;h=9f93cceb8ac76fe404b30edb47f676980b659844;hb=b116e9366c7b2ea2c2eb53b0a13df4090e176235;hp=8ec116f6eebdf34907b0637740c50737ebd3ca86;hpb=34197d9f46a5f4e944378cbb65fca32ee0eec7b9;p=debian%2Famanda diff --git a/common-src/stream.c b/common-src/stream.c index 8ec116f..9f93cce 100644 --- a/common-src/stream.c +++ b/common-src/stream.c @@ -25,7 +25,7 @@ * University of Maryland at College Park */ /* - * $Id: stream.c,v 1.39.2.1 2006/12/12 14:56:38 martinea Exp $ + * $Id: stream.c,v 1.39 2006/08/24 01:57:15 paddy_s Exp $ * * functions for managing stream sockets */ @@ -33,6 +33,9 @@ #include "dgram.h" #include "stream.h" #include "util.h" +#include "conffile.h" +#include "security-util.h" +#include "sockaddr-util.h" /* local functions */ static void try_socksize(int sock, int which, size_t size); @@ -42,26 +45,45 @@ static int stream_client_internal(const char *hostname, in_port_t port, int stream_server( + int family, in_port_t *portp, size_t sendsize, size_t recvsize, int priv) { int server_socket, retries; - socklen_t len; + socklen_t_equiv len; #if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR) const int on = 1; int r; #endif - struct sockaddr_in server; + sockaddr_union server; int save_errno; + int *portrange; + socklen_t_equiv socklen; + int socket_family; *portp = USHRT_MAX; /* in case we error exit */ - if((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + if (family == -1) { + socket_family = AF_NATIVE; + } else { + socket_family = family; + } + g_debug("stream_server opening socket with family %d (requested family was %d)", socket_family, family); + server_socket = socket(socket_family, SOCK_STREAM, 0); + +#ifdef WORKING_IPV6 + /* if that address family actually isn't supported, just try AF_INET */ + if (server_socket == -1 && errno == EAFNOSUPPORT) { + g_debug("stream_server retrying socket with AF_INET"); + socket_family = AF_INET; + server_socket = socket(AF_INET, SOCK_STREAM, 0); + } +#endif + if (server_socket == -1) { save_errno = errno; - dbprintf(("%s: stream_server: socket() failed: %s\n", - debug_prefix(NULL), - strerror(save_errno))); + g_debug(_("stream_server: socket() failed: %s"), + strerror(save_errno)); errno = save_errno; return -1; } @@ -69,23 +91,21 @@ stream_server( aclose(server_socket); errno = EMFILE; /* out of range */ save_errno = errno; - dbprintf(("%s: stream_server: socket out of range: %d\n", - debug_prefix(NULL), - server_socket)); + g_debug(_("stream_server: socket out of range: %d"), + server_socket); errno = save_errno; return -1; } - memset(&server, 0, SIZEOF(server)); - server.sin_family = (sa_family_t)AF_INET; - server.sin_addr.s_addr = INADDR_ANY; + + SU_INIT(&server, socket_family); + SU_SET_INADDR_ANY(&server); #ifdef USE_REUSEADDR r = setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, - (void *)&on, (socklen_t)sizeof(on)); + (void *)&on, (socklen_t_equiv)sizeof(on)); if (r < 0) { - dbprintf(("%s: stream_server: setsockopt(SO_REUSEADDR) failed: %s\n", - debug_prefix(NULL), - strerror(errno))); + g_debug(_("stream_server: setsockopt(SO_REUSEADDR) failed: %s"), + strerror(errno)); } #endif @@ -104,40 +124,37 @@ stream_server( * is within the range it requires. */ for (retries = 0; ; retries++) { -#ifdef TCPPORTRANGE - if (bind_portrange(server_socket, &server, TCPPORTRANGE, "tcp") == 0) - goto out; - dbprintf(("%s: stream_server: Could not bind to port in range: %d - %d.\n", - debug_prefix(NULL), TCPPORTRANGE)); -#endif + if (priv) { + portrange = getconf_intrange(CNF_RESERVED_TCP_PORT); + } else { + portrange = getconf_intrange(CNF_UNRESERVED_TCP_PORT); + } - if(priv) { - if (bind_portrange(server_socket, &server, - (in_port_t)512, (in_port_t)(IPPORT_RESERVED - 1), "tcp") == 0) + if (portrange[0] != 0 && portrange[1] != 0) { + if (bind_portrange(server_socket, &server, (in_port_t)portrange[0], + (in_port_t)portrange[1], "tcp") == 0) goto out; - dbprintf(("%s: stream_server: Could not bind to port in range 512 - %d.\n", - debug_prefix(NULL), IPPORT_RESERVED - 1)); + g_debug(_("stream_server: Could not bind to port in range: %d - %d."), + portrange[0], portrange[1]); + } else { + socklen = SS_LEN(&server); + if (bind(server_socket, (struct sockaddr *)&server, socklen) == 0) + goto out; + g_debug(_("stream_server: Could not bind to any port: %s"), + strerror(errno)); } - server.sin_port = INADDR_ANY; - if (bind(server_socket, (struct sockaddr *)&server, (socklen_t)sizeof(server)) == 0) - goto out; - dbprintf(("%s: stream_server: Could not bind to any port: %s\n", - debug_prefix(NULL), strerror(errno))); - if (retries >= BIND_CYCLE_RETRIES) break; - dbprintf(("%s: stream_server: Retrying entire range after 10 second delay.\n", - debug_prefix(NULL))); + g_debug(_("stream_server: Retrying entire range after 10 second delay.")); sleep(15); } save_errno = errno; - dbprintf(("%s: stream_server: bind(INADDR_ANY) failed: %s\n", - debug_prefix(NULL), - strerror(save_errno))); + g_debug(_("stream_server: bind(in6addr_any) failed: %s"), + strerror(save_errno)); aclose(server_socket); errno = save_errno; return -1; @@ -150,9 +167,8 @@ out: len = SIZEOF(server); if(getsockname(server_socket, (struct sockaddr *)&server, &len) == -1) { save_errno = errno; - dbprintf(("%s: stream_server: getsockname() failed: %s\n", - debug_prefix(NULL), - strerror(save_errno))); + g_debug(_("stream_server: getsockname() failed: %s"), + strerror(save_errno)); aclose(server_socket); errno = save_errno; return -1; @@ -160,23 +176,20 @@ out: #ifdef SO_KEEPALIVE r = setsockopt(server_socket, SOL_SOCKET, SO_KEEPALIVE, - (void *)&on, (socklen_t)sizeof(on)); + (void *)&on, (socklen_t_equiv)sizeof(on)); if(r == -1) { save_errno = errno; - dbprintf(("%s: stream_server: setsockopt(SO_KEEPALIVE) failed: %s\n", - debug_prefix(NULL), - strerror(save_errno))); + g_debug(_("stream_server: setsockopt(SO_KEEPALIVE) failed: %s"), + strerror(save_errno)); aclose(server_socket); errno = save_errno; return -1; } #endif - *portp = (in_port_t)ntohs(server.sin_port); - dbprintf(("%s: stream_server: waiting for connection: %s.%d\n", - debug_prefix_time(NULL), - inet_ntoa(server.sin_addr), - *portp)); + *portp = SU_GET_PORT(&server); + g_debug(_("stream_server: waiting for connection: %s"), + str_sockaddr(&server)); return server_socket; } @@ -190,88 +203,67 @@ stream_client_internal( int nonblock, int priv) { - struct sockaddr_in svaddr, claddr; - struct hostent *hostp; - int save_errno; + sockaddr_union svaddr, claddr; + int save_errno = 0; char *f; - int client_socket; + int client_socket = 0; + int *portrange = NULL; + int result; + struct addrinfo *res, *res_addr; f = priv ? "stream_client_privileged" : "stream_client"; - if((hostp = gethostbyname(hostname)) == NULL) { - save_errno = EHOSTUNREACH; - dbprintf(("%s: %s: gethostbyname(%s) failed\n", - debug_prefix(NULL), - f, - hostname)); - errno = save_errno; + result = resolve_hostname(hostname, SOCK_STREAM, &res, NULL); + if(result != 0) { + g_debug(_("resolve_hostname(%s): %s"), hostname, gai_strerror(result)); + errno = EHOSTUNREACH; + return -1; + } + if(!res) { + g_debug(_("resolve_hostname(%s): no results"), hostname); + errno = EHOSTUNREACH; return -1; } - memset(&svaddr, 0, SIZEOF(svaddr)); - svaddr.sin_family = (sa_family_t)AF_INET; - svaddr.sin_port = (in_port_t)htons(port); - memcpy(&svaddr.sin_addr, hostp->h_addr, (size_t)hostp->h_length); - + for (res_addr = res; res_addr != NULL; res_addr = res_addr->ai_next) { + /* copy the first (preferred) address we found */ + copy_sockaddr(&svaddr, (sockaddr_union *)res_addr->ai_addr); + SU_SET_PORT(&svaddr, port); - memset(&claddr, 0, SIZEOF(claddr)); - claddr.sin_family = (sa_family_t)AF_INET; - claddr.sin_addr.s_addr = INADDR_ANY; + SU_INIT(&claddr, SU_GET_FAMILY(&svaddr)); + SU_SET_INADDR_ANY(&claddr); - /* - * If a privileged port range was requested, we try to get a port in - * that range first and fail if it is not available. Next, we try - * to get a port in the range built in when Amanda was configured. - * If that fails, we just go for any port. - * - * It is up to the caller to make sure we have the proper permissions - * to get the desired port, and to make sure we return a port that - * is within the range it requires. - */ - if (priv) { -#ifdef LOW_TCPPORTRANGE - client_socket = connect_portrange(&claddr, LOW_TCPPORTRANGE, - "tcp", &svaddr, nonblock); -#else - client_socket = connect_portrange(&claddr, (socklen_t)512, - (socklen_t)(IPPORT_RESERVED - 1), - "tcp", &svaddr, nonblock); -#endif - + /* + * If a privileged port range was requested, we try to get a port in + * that range first and fail if it is not available. Next, we try + * to get a port in the range built in when Amanda was configured. + * If that fails, we just go for any port. + * + * It is up to the caller to make sure we have the proper permissions + * to get the desired port, and to make sure we return a port that + * is within the range it requires. + */ + if (priv) { + portrange = getconf_intrange(CNF_RESERVED_TCP_PORT); + } else { + portrange = getconf_intrange(CNF_UNRESERVED_TCP_PORT); + } + client_socket = connect_portrange(&claddr, (in_port_t)portrange[0], + (in_port_t)portrange[1], + "tcp", &svaddr, nonblock); + save_errno = errno; if (client_socket > 0) - goto out; - -#ifdef LOW_TCPPORTRANGE - dbprintf(( - "%s: stream_client: Could not bind to port in range %d-%d.\n", - debug_prefix(NULL), LOW_TCPPORTRANGE)); -#else - dbprintf(( - "%s: stream_client: Could not bind to port in range 512-%d.\n", - debug_prefix(NULL), IPPORT_RESERVED - 1)); -#endif + break; } -#ifdef TCPPORTRANGE - client_socket = connect_portrange(&claddr, TCPPORTRANGE, - "tcp", &svaddr, nonblock); - if(client_socket > 0) + freeaddrinfo(res); + + if (client_socket > 0) goto out; - dbprintf(("%s: stream_client: Could not bind to port in range %d - %d.\n", - debug_prefix(NULL), TCPPORTRANGE)); -#endif + g_debug(_("stream_client: Could not bind to port in range %d-%d."), + portrange[0], portrange[1]); - client_socket = connect_portrange(&claddr, (socklen_t)(IPPORT_RESERVED+1), - (socklen_t)(65535), - "tcp", &svaddr, nonblock); - - if(client_socket > 0) - goto out; - - save_errno = errno; - dbprintf(("%s: stream_client: Could not bind to any port: %s\n", - debug_prefix(NULL), strerror(save_errno))); errno = save_errno; return -1; @@ -279,7 +271,7 @@ out: try_socksize(client_socket, SO_SNDBUF, sendsize); try_socksize(client_socket, SO_RCVBUF, recvsize); if (localport != NULL) - *localport = (in_port_t)ntohs(claddr.sin_port); + *localport = SU_GET_PORT(&claddr); return client_socket; } @@ -320,8 +312,16 @@ stream_client( } /* don't care about these values */ -static struct sockaddr_in addr; -static socklen_t addrlen; +static sockaddr_union addr; +static socklen_t_equiv addrlen; + +static gboolean +stream_accept_prolong( + gpointer data) +{ + time_t *tp = data; + return time(NULL) <= *tp; +} int stream_accept( @@ -330,95 +330,72 @@ stream_accept( size_t sendsize, size_t recvsize) { - SELECT_ARG_TYPE readset; - struct timeval tv; - int nfound, connected_socket; + time_t timeout_time; + int connected_socket; int save_errno; - int ntries = 0; + in_port_t port; assert(server_socket >= 0); - do { - ntries++; - memset(&tv, 0, SIZEOF(tv)); - tv.tv_sec = timeout; - memset(&readset, 0, SIZEOF(readset)); - FD_ZERO(&readset); - FD_SET(server_socket, &readset); - nfound = select(server_socket+1, &readset, NULL, NULL, &tv); - if(nfound <= 0 || !FD_ISSET(server_socket, &readset)) { - save_errno = errno; - if(nfound < 0) { - dbprintf(("%s: stream_accept: select() failed: %s\n", - debug_prefix_time(NULL), - strerror(save_errno))); - } else if(nfound == 0) { - dbprintf(("%s: stream_accept: timeout after %d second%s\n", - debug_prefix_time(NULL), - timeout, - (timeout == 1) ? "" : "s")); - errno = ENOENT; /* ??? */ - return -1; - } else if (!FD_ISSET(server_socket, &readset)) { - int i; - - for(i = 0; i < server_socket + 1; i++) { - if(FD_ISSET(i, &readset)) { - dbprintf(("%s: stream_accept: got fd %d instead of %d\n", - debug_prefix_time(NULL), - i, - server_socket)); - } - } - save_errno = EBADF; - } - if (ntries > 5) { - errno = save_errno; - return -1; - } - } - } while (nfound <= 0); + /* set the time we want to stop accepting */ + timeout_time = time(NULL) + timeout; while(1) { - addrlen = (socklen_t)sizeof(struct sockaddr); - connected_socket = accept(server_socket, + addrlen = (socklen_t_equiv)sizeof(sockaddr_union); + connected_socket = interruptible_accept(server_socket, (struct sockaddr *)&addr, - &addrlen); + &addrlen, stream_accept_prolong, + &timeout_time); if(connected_socket < 0) { + if (errno == 0) { + g_debug(plural(_("stream_accept: timeout after %d second"), + _("stream_accept: timeout after %d seconds"), + timeout), + timeout); + errno = ETIMEDOUT; + return -1; + } break; } - dbprintf(("%s: stream_accept: connection from %s.%d\n", - debug_prefix_time(NULL), - inet_ntoa(addr.sin_addr), - ntohs(addr.sin_port))); + g_debug(_("stream_accept: connection from %s"), + str_sockaddr(&addr)); /* * Make certain we got an inet connection and that it is not * from port 20 (a favorite unauthorized entry tool). */ - if((addr.sin_family == (sa_family_t)AF_INET) - && (ntohs(addr.sin_port) != (in_port_t)20)) { - try_socksize(connected_socket, SO_SNDBUF, sendsize); - try_socksize(connected_socket, SO_RCVBUF, recvsize); - return connected_socket; - } - if(addr.sin_family != (sa_family_t)AF_INET) { - dbprintf(("%s: family is %d instead of %d(AF_INET): ignored\n", - debug_prefix_time(NULL), - addr.sin_family, - AF_INET)); - } - if(ntohs(addr.sin_port) == 20) { - dbprintf(("%s: remote port is %d: ignored\n", - debug_prefix_time(NULL), - ntohs(addr.sin_port))); + if (SU_GET_FAMILY(&addr) == AF_INET +#ifdef WORKING_IPV6 + || SU_GET_FAMILY(&addr) == AF_INET6 +#endif + ){ + port = SU_GET_PORT(&addr); + if (port != (in_port_t)20) { + try_socksize(connected_socket, SO_SNDBUF, sendsize); + try_socksize(connected_socket, SO_RCVBUF, recvsize); + return connected_socket; + } else { + g_debug(_("remote port is %u: ignored"), + (unsigned int)port); + } + } else { +#ifdef WORKING_IPV6 + g_debug(_("family is %d instead of %d(AF_INET)" + " or %d(AF_INET6): ignored"), + SU_GET_FAMILY(&addr), + AF_INET, AF_INET6); +#else + g_debug(_("family is %d instead of %d(AF_INET)" + ": ignored"), + SU_GET_FAMILY(&addr), + AF_INET); +#endif } aclose(connected_socket); } save_errno = errno; - dbprintf(("%s: stream_accept: accept() failed: %s\n", - debug_prefix_time(NULL), - strerror(save_errno))); + g_debug(_("stream_accept: accept() failed: %s"), + strerror(save_errno)); errno = save_errno; return -1; } @@ -430,26 +407,26 @@ try_socksize( size_t size) { size_t origsize; + int isize; if (size == 0) return; origsize = size; + isize = size; /* keep trying, get as big a buffer as possible */ - while((size > 1024) && + while((isize > 1024) && (setsockopt(sock, SOL_SOCKET, - which, (void *) &size, (socklen_t)sizeof(int)) < 0)) { - size -= 1024; + which, (void *) &isize, (socklen_t_equiv)sizeof(isize)) < 0)) { + isize -= 1024; } - if(size > 1024) { - dbprintf(("%s: try_socksize: %s buffer size is %zu\n", - debug_prefix(NULL), - (which == SO_SNDBUF) ? "send" : "receive", - size)); + if(isize > 1024) { + g_debug(_("try_socksize: %s buffer size is %d"), + (which == SO_SNDBUF) ? _("send") : _("receive"), + isize); } else { - dbprintf(("%s: try_socksize: could not allocate %s buffer of %zu\n", - debug_prefix(NULL), - (which == SO_SNDBUF) ? "send" : "receive", - origsize)); + g_debug(_("try_socksize: could not allocate %s buffer of %zu"), + (which == SO_SNDBUF) ? _("send") : _("receive"), + origsize); } }