Пример #1
0
void
dump_sockaddr(
    sockaddr_union *sa)
{
#ifdef WORKING_IPV6
    char ipstr[INET6_ADDRSTRLEN];
#else
    char ipstr[INET_ADDRSTRLEN];
#endif
    int port;

    port = SU_GET_PORT(sa);
#ifdef WORKING_IPV6
    if (SU_GET_FAMILY(sa) == AF_INET6) {
	inet_ntop(AF_INET6, &sa->sin6.sin6_addr, ipstr, sizeof(ipstr));
	dbprintf("(sockaddr_in6 *)%p = { %d, %d, %s }\n",
		 sa,
		 SU_GET_FAMILY(sa),
		 port,
		 ipstr);
    } else
#endif
    {
	inet_ntop(AF_INET, &sa->sin.sin_addr.s_addr, ipstr, sizeof(ipstr));
	dbprintf("(sockaddr_in *)%p = { %d, %d, %s }\n",
		 sa,
		 SU_GET_FAMILY(sa),
		 port,
		 ipstr);
    }
}
Пример #2
0
/*
 * Create the server end of a stream.  For bsd, this means setup a tcp
 * socket for receiving a connection.
 */
static void *
bsd_stream_server(
    void *	h)
{
    struct sec_stream *bs = NULL;
    struct sec_handle *bh = h;

    assert(bh != NULL);

    bs = g_new0(struct sec_stream, 1);
    security_streaminit(&bs->secstr, &bsd_security_driver);
    bs->socket = stream_server(SU_GET_FAMILY(&bh->udp->peer), &bs->port,
			       (size_t)STREAM_BUFSIZE, (size_t)STREAM_BUFSIZE,
			       0);
    if (bs->socket < 0) {
	security_seterror(&bh->sech,
	    _("can't create server stream: %s"), strerror(errno));
	amfree(bs->secstr.error);
	amfree(bs);
	return (NULL);
    }
    bs->fd = -1;
    bs->ev_read = NULL;
    return (bs);
}
Пример #3
0
char *
str_sockaddr(
    sockaddr_union *sa)
{
#ifdef WORKING_IPV6
    char ipstr[INET6_ADDRSTRLEN];
#else
    char ipstr[INET_ADDRSTRLEN];
#endif
    int port;

    port = SU_GET_PORT(sa);
#ifdef WORKING_IPV6
    if ( SU_GET_FAMILY(sa) == AF_INET6) {
	inet_ntop(AF_INET6, &sa->sin6.sin6_addr, ipstr, sizeof(ipstr));
    } else
#endif
    {
	inet_ntop(AF_INET, &sa->sin.sin_addr.s_addr, ipstr, sizeof(ipstr));
    }
    g_snprintf(mystr_sockaddr,sizeof(mystr_sockaddr),"%s.%d", ipstr, port);
    mystr_sockaddr[sizeof(mystr_sockaddr)-1] = '\0';

    return mystr_sockaddr;
}
Пример #4
0
gboolean
ndmp_connection_mover_connect(
	NDMPConnection *self,
	ndmp9_mover_mode mode,
	DirectTCPAddr *addrs)
{
    unsigned int naddrs, i;
    ndmp4_tcp_addr *na;

    g_assert(!self->startup_err);

    /* count addrs */
    g_assert(addrs);
    for (naddrs = 0; SU_GET_FAMILY(&addrs[naddrs]) != 0; naddrs++) ;

    /* convert addrs to an ndmp4_tcp_addr */
    na = g_new0(ndmp4_tcp_addr, naddrs);
    for (i = 0; i < naddrs; i++) {
	na[i].ip_addr = ntohl(addrs[i].sin.sin_addr.s_addr);
	na[i].port = SU_GET_PORT(&addrs[i]);
    }


    NDMP_TRANS(self, ndmp4_mover_connect)
	request->mode = mode;
	request->addr.addr_type = NDMP4_ADDR_TCP;
	request->addr.ndmp4_addr_u.tcp_addr.tcp_addr_len = naddrs;
	request->addr.ndmp4_addr_u.tcp_addr.tcp_addr_val = na;
	NDMP_CALL(self);
	NDMP_FREE();
    NDMP_END
    return TRUE;
}
Пример #5
0
int
cmp_sockaddr(
    sockaddr_union *ss1,
    sockaddr_union *ss2,
    int addr_only)
{
    sockaddr_union tmp1, tmp2;

    /* if addresses are v4mapped, "unmap" them */
    ss1 = unmap_v4mapped(ss1, &tmp1);
    ss2 = unmap_v4mapped(ss2, &tmp2);

    if (SU_GET_FAMILY(ss1) == SU_GET_FAMILY(ss2)) {
        if (addr_only) {
#ifdef WORKING_IPV6
            if(SU_GET_FAMILY(ss1) == AF_INET6)
                return memcmp(
                    &ss1->sin6.sin6_addr,
                    &ss2->sin6.sin6_addr,
                    sizeof(ss1->sin6.sin6_addr));
            else
#endif
                return memcmp(
                    &ss1->sin.sin_addr,
                    &ss2->sin.sin_addr,
                    sizeof(ss1->sin.sin_addr));
        } else {
            return memcmp(ss1, ss2, SS_LEN(ss1));
        }
    } else {
        /* compare families to give a total order */
        if (SU_GET_FAMILY(ss1) < SU_GET_FAMILY(ss2))
            return -1;
        else
            return 1;
    }
}
Пример #6
0
static sockaddr_union *
unmap_v4mapped(
    sockaddr_union *sa,
    sockaddr_union *tmp)
{
    if (SU_GET_FAMILY(sa) == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) {
	SU_INIT(tmp, AF_INET);
	SU_SET_PORT(tmp, SU_GET_PORT(sa));
	/* extract the v4 address from byte 12 of the v6 address */
	memcpy(&tmp->sin.sin_addr.s_addr,
	       &sa->sin6.sin6_addr.s6_addr[12],
	       sizeof(struct in_addr));
	return tmp;
    }

    return sa;
}
Пример #7
0
static int
do_directtcp_connect(
    XferElementGlue *self,
    DirectTCPAddr *addrs)
{
    XferElement *elt = XFER_ELEMENT(self);
    sockaddr_union addr;
    int sock;
#ifdef WORKING_IPV6
    char strsockaddr[INET6_ADDRSTRLEN + 20];
#else
    char strsockaddr[INET_ADDRSTRLEN + 20];
#endif

    if (!addrs) {
	g_debug("element-glue got no directtcp addresses to connect to!");
	if (!elt->cancelled) {
	    xfer_cancel_with_error(elt,
		"%s got no directtcp addresses to connect to",
		xfer_element_repr(elt));
	}
	goto cancel_wait;
    }

    /* set up the sockaddr -- IPv4 only */
    copy_sockaddr(&addr, addrs);

    str_sockaddr_r(&addr, strsockaddr, sizeof(strsockaddr));

    if (strncmp(strsockaddr,"255.255.255.255:", 16) == 0) {
	char  buffer[32770];
	char *s;
	int   size;
	char *data_host;
	int   data_port;

	g_debug("do_directtcp_connect making indirect data connection to %s",
		strsockaddr);
	data_port = SU_GET_PORT(&addr);
	sock = stream_client(NULL, "localhost", data_port,
                                   STREAM_BUFSIZE, 0, NULL, 0);
	if (sock < 0) {
	    xfer_cancel_with_error(elt, "stream_client(): %s", strerror(errno));
	    goto cancel_wait;
	}
	size = full_read(sock, buffer, 32768);
	if (size < 0 ) {
	    xfer_cancel_with_error(elt, "failed to read from indirecttcp: %s",
				   strerror(errno));
	    goto cancel_wait;
	}
	close(sock);
	buffer[size++] = ' ';
	buffer[size] = '\0';
	if ((s = strchr(buffer, ':')) == NULL) {
	    xfer_cancel_with_error(elt,
				   "Failed to parse indirect data stream: %s",
				   buffer);
	    goto cancel_wait;
	}
	*s++ = '\0';
	data_host = buffer;
	data_port = atoi(s);

	str_to_sockaddr(data_host, &addr);
	SU_SET_PORT(&addr, data_port);

	str_sockaddr_r(&addr, strsockaddr, sizeof(strsockaddr));
    }

    sock = socket(SU_GET_FAMILY(&addr), SOCK_STREAM, 0);

    g_debug("do_directtcp_connect making data connection to %s", strsockaddr);

    if (sock < 0) {
	xfer_cancel_with_error(elt,
	    "socket(): %s", strerror(errno));
	goto cancel_wait;
    }
    if (connect(sock, (struct sockaddr *)&addr, SS_LEN(&addr)) < 0) {
	xfer_cancel_with_error(elt,
	    "connect(): %s", strerror(errno));
	close(sock);
	goto cancel_wait;
    }

    g_debug("do_directtcp_connect: connected to %s, fd %d", strsockaddr, sock);

    return sock;

cancel_wait:
    wait_until_xfer_cancelled(elt->xfer);
    return -1;
}
Пример #8
0
static gboolean
do_directtcp_listen(
    XferElement *elt,
    int *sockp,
    DirectTCPAddr **addrsp)
{
    int sock;
    sockaddr_union data_addr;
    DirectTCPAddr *addrs;
    socklen_t len;
    struct addrinfo *res;
    struct addrinfo *res_addr;
    sockaddr_union *addr = NULL;

    if (resolve_hostname("localhost", 0, &res, NULL) != 0) {
	xfer_cancel_with_error(elt, "resolve_hostname(): %s", strerror(errno));
	return FALSE;
    }
    for (res_addr = res; res_addr != NULL; res_addr = res_addr->ai_next) {
	if (res_addr->ai_family == AF_INET) {
            addr = (sockaddr_union *)res_addr->ai_addr;
            break;
        }
    }
    if (!addr) {
        addr = (sockaddr_union *)res->ai_addr;
    }

    sock = *sockp = socket(SU_GET_FAMILY(addr), SOCK_STREAM, 0);
    if (sock < 0) {
	xfer_cancel_with_error(elt, "socket(): %s", strerror(errno));
	freeaddrinfo(res);
	return FALSE;
    }

    len = SS_LEN(addr);
    if (bind(sock, (struct sockaddr *)addr, len) != 0) {
	xfer_cancel_with_error(elt, "bind(): %s", strerror(errno));
	freeaddrinfo(res);
	close(sock);
	*sockp = -1;
	return FALSE;
    }

    if (listen(sock, 1) < 0) {
	xfer_cancel_with_error(elt, "listen(): %s", strerror(errno));
	freeaddrinfo(res);
	close(sock);
	*sockp = -1;
	return FALSE;
    }

    /* TODO: which addresses should this display? all ifaces? localhost? */
    len = sizeof(data_addr);
    if (getsockname(sock, (struct sockaddr *)&data_addr, &len) < 0)
	error("getsockname(): %s", strerror(errno));

    addrs = g_new0(DirectTCPAddr, 2);
    copy_sockaddr(&addrs[0], &data_addr);
    *addrsp = addrs;
    freeaddrinfo(res);

    return TRUE;
}
Пример #9
0
int
stream_accept(
    int server_socket,
    int timeout,
    size_t sendsize,
    size_t recvsize)
{
    time_t timeout_time;
    int connected_socket;
    int save_errno;
    in_port_t port;

    assert(server_socket >= 0);

    /* set the time we want to stop accepting */
    timeout_time = time(NULL) + timeout;

    while(1) {
	addrlen = (socklen_t_equiv)sizeof(sockaddr_union);
	connected_socket = interruptible_accept(server_socket,
				  (struct sockaddr *)&addr,
				  &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;
	}
	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 (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;
    g_debug(_("stream_accept: accept() failed: %s"),
	      strerror(save_errno));
    errno = save_errno;
    return -1;
}
Пример #10
0
static int
stream_client_internal(
    const char *hostname,
    in_port_t port,
    size_t sendsize,
    size_t recvsize,
    in_port_t *localport,
    int nonblock,
    int priv)
{
    sockaddr_union svaddr, claddr;
    int save_errno = 0;
    int client_socket = 0;
    int *portrange = NULL;
    int result;
    struct addrinfo *res, *res_addr;

    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;
    }

    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);

	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) {
	    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)
	    break;
    }

    freeaddrinfo(res);
					  
    if (client_socket > 0)
	goto out;

    g_debug(_("stream_client: Could not bind to port in range %d-%d."),
	      portrange[0], portrange[1]);

    errno = save_errno;
    return -1;

out:
    try_socksize(client_socket, SO_SNDBUF, sendsize);
    try_socksize(client_socket, SO_RCVBUF, recvsize);
    if (localport != NULL)
	*localport = SU_GET_PORT(&claddr);
    return client_socket;
}
Пример #11
0
/* return >0: this is the connected socket */
int
connect_port(
    sockaddr_union *addrp,
    in_port_t  		port,
    char *		proto,
    sockaddr_union *svaddr,
    int			nonblock)
{
    int			save_errno;
    struct servent *	servPort;
    socklen_t_equiv	len;
    socklen_t_equiv	socklen;
    int			s;

    servPort = getservbyport((int)htons(port), proto);
    if (servPort != NULL && !strstr(servPort->s_name, AMANDA_SERVICE_NAME)) {
	dbprintf(_("connect_port: Skip port %d: owned by %s.\n"),
		  port, servPort->s_name);
	errno = EBUSY;
	return -1;
    }

    if ((s = make_socket(SU_GET_FAMILY(addrp))) == -1) return -2;

    SU_SET_PORT(addrp, port);
    socklen = SS_LEN(addrp);
    if (bind(s, (struct sockaddr *)addrp, socklen) != 0) {
	save_errno = errno;
	aclose(s);
	if(servPort == NULL) {
	    dbprintf(_("connect_port: Try  port %d: available - %s\n"),
		     port, strerror(errno));
	} else {
	    dbprintf(_("connect_port: Try  port %d: owned by %s - %s\n"),
		     port, servPort->s_name, strerror(errno));
	}
	if (save_errno != EADDRINUSE) {
	    errno = save_errno;
	    return -2;
	}

	errno = save_errno;
	return -1;
    }
    if(servPort == NULL) {
	dbprintf(_("connect_port: Try  port %d: available - Success\n"), port);
    } else {
	dbprintf(_("connect_port: Try  port %d: owned by %s - Success\n"),
		  port, servPort->s_name);
    }

    /* find out what port was actually used */

    len = sizeof(*addrp);
    if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
	save_errno = errno;
	dbprintf(_("connect_port: getsockname() failed: %s\n"),
		  strerror(save_errno));
	aclose(s);
	errno = save_errno;
	return -1;
    }

    if (nonblock) {
	int r = fcntl(s, F_GETFL, 0);
	if (r < 0) {
	    save_errno = errno;
	    g_debug("Can't fcntl(F_GETFL): %s", strerror(errno));
	    aclose(s);
	    errno = save_errno;
	    return -1;
	}
	r = fcntl(s, F_SETFL, r|O_NONBLOCK);
	if (r < 0) {
	    save_errno = errno;
	    g_debug("Can't fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
	    errno = save_errno;
	    aclose(s);
	    return -1;
	}
    }
    if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {
	save_errno = errno;
	dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),
		  str_sockaddr(addrp),
		  strerror(save_errno));
	dbprintf(_("connect_portrange: connect to %s failed: %s\n"),
		  str_sockaddr(svaddr),
		  strerror(save_errno));
	aclose(s);
	errno = save_errno;
	if (save_errno == ECONNREFUSED ||
	    save_errno == EHOSTUNREACH ||
	    save_errno == ENETUNREACH ||
	    save_errno == ETIMEDOUT)  {
	    return -2	;
	}
	return -1;
    }

    dbprintf(_("connected to %s\n"),
              str_sockaddr(svaddr));
    dbprintf(_("our side is %s\n"),
              str_sockaddr(addrp));
    return s;
}
Пример #12
0
int
dgram_send_addr(
    sockaddr_union	*addr,
    dgram_t *		dgram)
{
    int s, rc;
    int socket_opened;
    int save_errno;
    int max_wait;
    int wait_count;
#if defined(USE_REUSEADDR)
    const int on = 1;
    int r;
#endif

    dbprintf(_("dgram_send_addr(addr=%p, dgram=%p)\n"),
	      addr, dgram);
    dump_sockaddr(addr);
    dbprintf(_("dgram_send_addr: %p->socket = %d\n"),
	      dgram, dgram->socket);
    if(dgram->socket != -1) {
	s = dgram->socket;
	socket_opened = 0;
    } else {
	int sndbufsize = MAX_DGRAM;

	g_debug("dgram_send_addr: setting up a socket with family %d", SU_GET_FAMILY(addr));
	if((s = socket(SU_GET_FAMILY(addr), SOCK_DGRAM, 0)) == -1) {
	    save_errno = errno;
	    dbprintf(_("dgram_send_addr: socket() failed: %s\n"),
		      strerror(save_errno));
	    errno = save_errno;
	    return -1;
	}
	socket_opened = 1;
#ifdef USE_REUSEADDR
	r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
		(void *)&on, (socklen_t_equiv)sizeof(on));
	if (r < 0) {
	    dbprintf(_("dgram_send_addr: setsockopt(SO_REUSEADDR) failed: %s\n"),
		      strerror(errno));
	}
#endif

	/* try setting the buffer size (= maximum allowable UDP packet size) */
	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
		       (void *) &sndbufsize, sizeof(sndbufsize)) < 0) {
	   dbprintf("dgram_send_addr: could not set udp send buffer to %d: %s (ignored)\n",
		     sndbufsize, strerror(errno));
	}
    }

    if(s < 0 || s >= (int)FD_SETSIZE) {
	dbprintf(_("dgram_send_addr: socket out of range: %d\n"), s);
	errno = EMFILE;				/* out of range */
	rc = -1;
    } else {
	max_wait = 300 / 5;				/* five minutes */
	wait_count = 0;
	rc = 0;
	while(sendto(s,
		 dgram->data,
		 dgram->len,
		 0, 
		 (struct sockaddr *)addr,
		 SS_LEN(addr)) == -1) {
#ifdef ECONNREFUSED
	    if(errno == ECONNREFUSED && wait_count++ < max_wait) {
		sleep(5);
		dbprintf(_("dgram_send_addr: sendto(%s): retry %d after ECONNREFUSED\n"),
		      str_sockaddr(addr),
		      wait_count);
		continue;
	    }
#endif
#ifdef EAGAIN
	    if(errno == EAGAIN && wait_count++ < max_wait) {
		sleep(5);
		dbprintf(_("dgram_send_addr: sendto(%s): retry %d after EAGAIN\n"),
		      str_sockaddr(addr),
		      wait_count);
		continue;
	    }
#endif
	    save_errno = errno;
	    dbprintf(_("dgram_send_addr: sendto(%s) failed: %s \n"),
		  str_sockaddr(addr),
		  strerror(save_errno));
	    errno = save_errno;
	    rc = -1;
	    break;
	}
    }

    if(socket_opened) {
	save_errno = errno;
	if(close(s) == -1) {
	    dbprintf(_("dgram_send_addr: close(%s): failed: %s\n"),
		      str_sockaddr(addr),
		      strerror(errno));
	    /*
	     * Calling function should not care that the close failed.
	     * It does care about the send results though.
	     */
	}
	errno = save_errno;
    }

    return rc;
}