X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Fstream.c;h=b7925e9a8b697504eb6f91d694fc3f6e3ca62a82;hb=d3b2175e084f88c8736ad7073eacbf4670147aec;hp=8ec116f6eebdf34907b0637740c50737ebd3ca86;hpb=34197d9f46a5f4e944378cbb65fca32ee0eec7b9;p=debian%2Famanda diff --git a/common-src/stream.c b/common-src/stream.c index 8ec116f..b7925e9 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,8 @@ #include "dgram.h" #include "stream.h" #include "util.h" +#include "conffile.h" +#include "security-util.h" /* local functions */ static void try_socksize(int sock, int which, size_t size); @@ -53,14 +55,26 @@ stream_server( const int on = 1; int r; #endif - struct sockaddr_in server; + struct sockaddr_storage server; int save_errno; + int *portrange; + socklen_t socklen; + int socket_family; *portp = USHRT_MAX; /* in case we error exit */ - if((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + socket_family = AF_NATIVE; + server_socket = socket(AF_NATIVE, SOCK_STREAM, 0); +#ifdef WORKING_IPV6 + /* if that address family actually isn't supported, just try AF_INET */ + if (server_socket == -1 && errno == EAFNOSUPPORT) { + 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), + debug_prefix_time(NULL), strerror(save_errno))); errno = save_errno; return -1; @@ -70,21 +84,21 @@ stream_server( errno = EMFILE; /* out of range */ save_errno = errno; dbprintf(("%s: stream_server: socket out of range: %d\n", - debug_prefix(NULL), + debug_prefix_time(NULL), 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; + + SS_INIT(&server, socket_family); + SS_SET_INADDR_ANY(&server); #ifdef USE_REUSEADDR r = setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&on, (socklen_t)sizeof(on)); if (r < 0) { dbprintf(("%s: stream_server: setsockopt(SO_REUSEADDR) failed: %s\n", - debug_prefix(NULL), + debug_prefix_time(NULL), strerror(errno))); } #endif @@ -104,39 +118,38 @@ 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)); + dbprintf(("%s: stream_server: Could not bind to port in range: %d - %d.\n", + debug_prefix_time(NULL), portrange[0], portrange[1])); + } else { + socklen = SS_LEN(&server); + if (bind(server_socket, (struct sockaddr *)&server, socklen) == 0) + goto out; + dbprintf(("%s: stream_server: Could not bind to any port: %s\n", + debug_prefix_time(NULL), 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))); + debug_prefix_time(NULL))); sleep(15); } save_errno = errno; - dbprintf(("%s: stream_server: bind(INADDR_ANY) failed: %s\n", - debug_prefix(NULL), + dbprintf(("%s: stream_server: bind(in6addr_any) failed: %s\n", + debug_prefix_time(NULL), strerror(save_errno))); aclose(server_socket); errno = save_errno; @@ -151,7 +164,7 @@ out: if(getsockname(server_socket, (struct sockaddr *)&server, &len) == -1) { save_errno = errno; dbprintf(("%s: stream_server: getsockname() failed: %s\n", - debug_prefix(NULL), + debug_prefix_time(NULL), strerror(save_errno))); aclose(server_socket); errno = save_errno; @@ -164,7 +177,7 @@ out: if(r == -1) { save_errno = errno; dbprintf(("%s: stream_server: setsockopt(SO_KEEPALIVE) failed: %s\n", - debug_prefix(NULL), + debug_prefix_time(NULL), strerror(save_errno))); aclose(server_socket); errno = save_errno; @@ -172,11 +185,10 @@ out: } #endif - *portp = (in_port_t)ntohs(server.sin_port); - dbprintf(("%s: stream_server: waiting for connection: %s.%d\n", + *portp = SS_GET_PORT(&server); + dbprintf(("%s: stream_server: waiting for connection: %s\n", debug_prefix_time(NULL), - inet_ntoa(server.sin_addr), - *portp)); + str_sockaddr(&server))); return server_socket; } @@ -190,33 +202,49 @@ stream_client_internal( int nonblock, int priv) { - struct sockaddr_in svaddr, claddr; - struct hostent *hostp; + struct sockaddr_storage svaddr, claddr; int save_errno; char *f; int client_socket; + int *portrange; + int result; + struct addrinfo hints; + struct addrinfo *res = NULL; 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; +#ifdef WORKING_IPV6 + hints.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ALL; + hints.ai_family = (sa_family_t)AF_UNSPEC; +#else + hints.ai_flags = AI_CANONNAME; + hints.ai_family = (sa_family_t)AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + result = getaddrinfo(hostname, NULL, &hints, &res); +#ifdef WORKING_IPV6 + if(result != 0) { + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_UNSPEC; + result = getaddrinfo(hostname, NULL, &hints, &res); + } +#endif + if(result != 0) { + dbprintf(("getaddrinfo: %s\n", gai_strerror(result))); 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); - + memcpy(&svaddr, res->ai_addr, (size_t)res->ai_addrlen); + freeaddrinfo(res); + SS_SET_PORT(&svaddr, port); - memset(&claddr, 0, SIZEOF(claddr)); - claddr.sin_family = (sa_family_t)AF_INET; - claddr.sin_addr.s_addr = INADDR_ANY; + SS_INIT(&claddr, svaddr.ss_family); + SS_SET_INADDR_ANY(&claddr); /* * If a privileged port range was requested, we try to get a port in @@ -229,49 +257,21 @@ stream_client_internal( * 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 (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 + portrange = getconf_intrange(CNF_RESERVED_TCP_PORT); + } else { + portrange = getconf_intrange(CNF_UNRESERVED_TCP_PORT); } - -#ifdef TCPPORTRANGE - client_socket = connect_portrange(&claddr, TCPPORTRANGE, + client_socket = connect_portrange(&claddr, (in_port_t)portrange[0], + (in_port_t)portrange[1], "tcp", &svaddr, nonblock); - if(client_socket > 0) + save_errno = errno; + + 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 - - client_socket = connect_portrange(&claddr, (socklen_t)(IPPORT_RESERVED+1), - (socklen_t)(65535), - "tcp", &svaddr, nonblock); - - if(client_socket > 0) - goto out; + dbprintf(("%s: stream_client: Could not bind to port in range %d-%d.\n", + debug_prefix_time(NULL), portrange[0], portrange[1])); - 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 +279,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 = SS_GET_PORT(&claddr); return client_socket; } @@ -320,7 +320,7 @@ stream_client( } /* don't care about these values */ -static struct sockaddr_in addr; +static struct sockaddr_storage addr; static socklen_t addrlen; int @@ -335,6 +335,7 @@ stream_accept( int nfound, connected_socket; int save_errno; int ntries = 0; + in_port_t port; assert(server_socket >= 0); @@ -380,37 +381,48 @@ stream_accept( } while (nfound <= 0); while(1) { - addrlen = (socklen_t)sizeof(struct sockaddr); + addrlen = (socklen_t)sizeof(struct sockaddr_storage); connected_socket = accept(server_socket, (struct sockaddr *)&addr, &addrlen); if(connected_socket < 0) { break; } - dbprintf(("%s: stream_accept: connection from %s.%d\n", + dbprintf(("%s: stream_accept: connection from %s\n", debug_prefix_time(NULL), - inet_ntoa(addr.sin_addr), - ntohs(addr.sin_port))); + 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", + if (addr.ss_family == (sa_family_t)AF_INET +#ifdef WORKING_IPV6 + || addr.ss_family == (sa_family_t)AF_INET6 +#endif + ){ + port = SS_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 { + dbprintf(("%s: remote port is %u: ignored\n", + debug_prefix_time(NULL), (unsigned int)port)); + } + } else { +#ifdef WORKING_IPV6 + dbprintf(("%s: family is %d instead of %d(AF_INET)" + " or %d(AF_INET6): 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", + addr.ss_family, + AF_INET, AF_INET6)); +#else + dbprintf(("%s: family is %d instead of %d(AF_INET)" + ": ignored\n", debug_prefix_time(NULL), - ntohs(addr.sin_port))); + addr.ss_family, + AF_INET)); +#endif } aclose(connected_socket); } @@ -430,25 +442,27 @@ 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)sizeof(isize)) < 0)) { + isize -= 1024; } - if(size > 1024) { - dbprintf(("%s: try_socksize: %s buffer size is %zu\n", - debug_prefix(NULL), + if(isize > 1024) { + dbprintf(("%s: try_socksize: %s buffer size is %d\n", + debug_prefix_time(NULL), (which == SO_SNDBUF) ? "send" : "receive", - size)); + isize)); } else { - dbprintf(("%s: try_socksize: could not allocate %s buffer of %zu\n", - debug_prefix(NULL), + dbprintf(("%s: try_socksize: could not allocate %s buffer of " SIZE_T_FMT "\n", + debug_prefix_time(NULL), (which == SO_SNDBUF) ? "send" : "receive", origsize)); }