2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Author: James da Silva, Systems Design and Analysis Group
25 * Computer Science Department
26 * University of Maryland at College Park
29 * $Id: stream.c,v 1.39 2006/08/24 01:57:15 paddy_s Exp $
31 * functions for managing stream sockets
38 #include "security-util.h"
39 #include "sockaddr-util.h"
42 static void try_socksize(int sock, int which, size_t size);
43 static int stream_client_internal(const char *hostname, in_port_t port,
44 size_t sendsize, size_t recvsize, in_port_t *localport,
45 int nonblock, int priv);
55 int server_socket, retries;
57 #if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
61 sockaddr_union server;
64 socklen_t_equiv socklen;
67 *portp = USHRT_MAX; /* in case we error exit */
69 socket_family = AF_NATIVE;
71 socket_family = family;
73 g_debug("stream_server opening socket with family %d (requested family was %d)", socket_family, family);
74 server_socket = socket(socket_family, SOCK_STREAM, 0);
77 /* if that address family actually isn't supported, just try AF_INET */
78 if (server_socket == -1 && errno == EAFNOSUPPORT) {
79 g_debug("stream_server retrying socket with AF_INET");
80 socket_family = AF_INET;
81 server_socket = socket(AF_INET, SOCK_STREAM, 0);
84 if (server_socket == -1) {
86 g_debug(_("stream_server: socket() failed: %s"),
87 strerror(save_errno));
91 if(server_socket < 0 || server_socket >= (int)FD_SETSIZE) {
92 aclose(server_socket);
93 errno = EMFILE; /* out of range */
95 g_debug(_("stream_server: socket out of range: %d"),
101 SU_INIT(&server, socket_family);
102 SU_SET_INADDR_ANY(&server);
105 r = setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
106 (void *)&on, (socklen_t_equiv)sizeof(on));
108 g_debug(_("stream_server: setsockopt(SO_REUSEADDR) failed: %s"),
113 try_socksize(server_socket, SO_SNDBUF, sendsize);
114 try_socksize(server_socket, SO_RCVBUF, recvsize);
117 * If a port range was specified, we try to get a port in that
118 * range first. Next, we try to get a reserved port. If that
119 * fails, we just go for any port.
121 * In all cases, not to use port that's assigned to other services.
123 * It is up to the caller to make sure we have the proper permissions
124 * to get the desired port, and to make sure we return a port that
125 * is within the range it requires.
127 for (retries = 0; ; retries++) {
129 portrange = getconf_intrange(CNF_RESERVED_TCP_PORT);
131 portrange = getconf_intrange(CNF_UNRESERVED_TCP_PORT);
134 if (portrange[0] != 0 && portrange[1] != 0) {
135 if (bind_portrange(server_socket, &server, (in_port_t)portrange[0],
136 (in_port_t)portrange[1], "tcp") == 0)
138 g_debug(_("stream_server: Could not bind to port in range: %d - %d."),
139 portrange[0], portrange[1]);
141 socklen = SS_LEN(&server);
142 if (bind(server_socket, (struct sockaddr *)&server, socklen) == 0)
144 g_debug(_("stream_server: Could not bind to any port: %s"),
148 if (retries >= BIND_CYCLE_RETRIES)
151 g_debug(_("stream_server: Retrying entire range after 10 second delay."));
157 g_debug(_("stream_server: bind(in6addr_any) failed: %s"),
158 strerror(save_errno));
159 aclose(server_socket);
164 listen(server_socket, 1);
166 /* find out what port was actually used */
168 len = SIZEOF(server);
169 if(getsockname(server_socket, (struct sockaddr *)&server, &len) == -1) {
171 g_debug(_("stream_server: getsockname() failed: %s"),
172 strerror(save_errno));
173 aclose(server_socket);
179 r = setsockopt(server_socket, SOL_SOCKET, SO_KEEPALIVE,
180 (void *)&on, (socklen_t_equiv)sizeof(on));
183 g_debug(_("stream_server: setsockopt(SO_KEEPALIVE) failed: %s"),
184 strerror(save_errno));
185 aclose(server_socket);
191 *portp = SU_GET_PORT(&server);
192 g_debug(_("stream_server: waiting for connection: %s"),
193 str_sockaddr(&server));
194 return server_socket;
198 stream_client_internal(
199 const char *hostname,
203 in_port_t *localport,
207 sockaddr_union svaddr, claddr;
209 int client_socket = 0;
210 int *portrange = NULL;
212 struct addrinfo *res, *res_addr;
214 result = resolve_hostname(hostname, SOCK_STREAM, &res, NULL);
216 g_debug(_("resolve_hostname(%s): %s"), hostname, gai_strerror(result));
217 errno = EHOSTUNREACH;
221 g_debug(_("resolve_hostname(%s): no results"), hostname);
222 errno = EHOSTUNREACH;
226 for (res_addr = res; res_addr != NULL; res_addr = res_addr->ai_next) {
227 /* copy the first (preferred) address we found */
228 copy_sockaddr(&svaddr, (sockaddr_union *)res_addr->ai_addr);
229 SU_SET_PORT(&svaddr, port);
231 SU_INIT(&claddr, SU_GET_FAMILY(&svaddr));
232 SU_SET_INADDR_ANY(&claddr);
235 * If a privileged port range was requested, we try to get a port in
236 * that range first and fail if it is not available. Next, we try
237 * to get a port in the range built in when Amanda was configured.
238 * If that fails, we just go for any port.
240 * It is up to the caller to make sure we have the proper permissions
241 * to get the desired port, and to make sure we return a port that
242 * is within the range it requires.
245 portrange = getconf_intrange(CNF_RESERVED_TCP_PORT);
247 portrange = getconf_intrange(CNF_UNRESERVED_TCP_PORT);
249 client_socket = connect_portrange(&claddr, (in_port_t)portrange[0],
250 (in_port_t)portrange[1],
251 "tcp", &svaddr, nonblock);
253 if (client_socket > 0)
259 if (client_socket > 0)
262 g_debug(_("stream_client: Could not bind to port in range %d-%d."),
263 portrange[0], portrange[1]);
269 try_socksize(client_socket, SO_SNDBUF, sendsize);
270 try_socksize(client_socket, SO_RCVBUF, recvsize);
271 if (localport != NULL)
272 *localport = SU_GET_PORT(&claddr);
273 return client_socket;
277 stream_client_privileged(
278 const char *hostname,
282 in_port_t *localport,
285 return stream_client_internal(hostname,
296 const char *hostname,
300 in_port_t *localport,
303 return stream_client_internal(hostname,
312 /* don't care about these values */
313 static sockaddr_union addr;
314 static socklen_t_equiv addrlen;
317 stream_accept_prolong(
321 return time(NULL) <= *tp;
332 int connected_socket;
336 assert(server_socket >= 0);
338 /* set the time we want to stop accepting */
339 timeout_time = time(NULL) + timeout;
342 addrlen = (socklen_t_equiv)sizeof(sockaddr_union);
343 connected_socket = interruptible_accept(server_socket,
344 (struct sockaddr *)&addr,
345 &addrlen, stream_accept_prolong,
347 if(connected_socket < 0) {
349 g_debug(plural(_("stream_accept: timeout after %d second"),
350 _("stream_accept: timeout after %d seconds"),
358 g_debug(_("stream_accept: connection from %s"),
359 str_sockaddr(&addr));
361 * Make certain we got an inet connection and that it is not
362 * from port 20 (a favorite unauthorized entry tool).
364 if (SU_GET_FAMILY(&addr) == AF_INET
366 || SU_GET_FAMILY(&addr) == AF_INET6
369 port = SU_GET_PORT(&addr);
370 if (port != (in_port_t)20) {
371 try_socksize(connected_socket, SO_SNDBUF, sendsize);
372 try_socksize(connected_socket, SO_RCVBUF, recvsize);
373 return connected_socket;
375 g_debug(_("remote port is %u: ignored"),
380 g_debug(_("family is %d instead of %d(AF_INET)"
381 " or %d(AF_INET6): ignored"),
382 SU_GET_FAMILY(&addr),
385 g_debug(_("family is %d instead of %d(AF_INET)"
387 SU_GET_FAMILY(&addr),
391 aclose(connected_socket);
395 g_debug(_("stream_accept: accept() failed: %s"),
396 strerror(save_errno));
415 /* keep trying, get as big a buffer as possible */
416 while((isize > 1024) &&
417 (setsockopt(sock, SOL_SOCKET,
418 which, (void *) &isize, (socklen_t_equiv)sizeof(isize)) < 0)) {
422 g_debug(_("try_socksize: %s buffer size is %d"),
423 (which == SO_SNDBUF) ? _("send") : _("receive"),
426 g_debug(_("try_socksize: could not allocate %s buffer of %zu"),
427 (which == SO_SNDBUF) ? _("send") : _("receive"),