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); } }
/* * 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); }
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; }
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; }
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; } }
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; }
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; }
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; }
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; }
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; }
/* 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; }
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; }