nc: make connecting to IPv4 from IPv6-enabled hosts easier

(was requiring -s <local addr>)
This commit is contained in:
Denis Vlasenko 2007-06-05 20:08:11 +00:00
parent 6c501a71ae
commit 5c51a7ca52
3 changed files with 39 additions and 25 deletions

View File

@ -304,9 +304,12 @@ enum {
} }
) )
}; };
/* Create stream socket, and allocated suitable lsa /* Create stream socket, and allocate suitable lsa.
* (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6)) */ * (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6))
int xsocket_type(len_and_sockaddr **lsap, int sock_type); * af == AF_UNSPEC will result in trying to create IPv6, and
* if kernel doesn't support it, IPv4.
*/
int xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int af,) int sock_type);
int xsocket_stream(len_and_sockaddr **lsap); int xsocket_stream(len_and_sockaddr **lsap);
/* Create server socket bound to bindaddr:port. bindaddr can be NULL, /* Create server socket bound to bindaddr:port. bindaddr can be NULL,
* numeric IP ("N.N.N.N") or numeric IPv6 address, * numeric IP ("N.N.N.N") or numeric IPv6 address,

View File

@ -208,23 +208,31 @@ len_and_sockaddr* xdotted2sockaddr(const char *host, int port)
return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
} }
int xsocket_type(len_and_sockaddr **lsap, int sock_type) int xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int family,) int sock_type)
{ {
SKIP_FEATURE_IPV6(enum { family = AF_INET };)
len_and_sockaddr *lsa; len_and_sockaddr *lsa;
int fd; int fd;
int len = sizeof(struct sockaddr_in); int len;
int family = AF_INET;
#if ENABLE_FEATURE_IPV6 #if ENABLE_FEATURE_IPV6
fd = socket(AF_INET6, sock_type, 0); if (family == AF_UNSPEC) {
if (fd >= 0) { fd = socket(AF_INET6, sock_type, 0);
len = sizeof(struct sockaddr_in6); if (fd >= 0) {
family = AF_INET6; family = AF_INET6;
} else goto done;
#endif }
{ family = AF_INET;
fd = xsocket(AF_INET, sock_type, 0);
} }
#endif
fd = xsocket(family, sock_type, 0);
len = sizeof(struct sockaddr_in);
#if ENABLE_FEATURE_IPV6
if (family == AF_INET6) {
done:
len = sizeof(struct sockaddr_in6);
}
#endif
lsa = xzalloc(offsetof(len_and_sockaddr, sa) + len); lsa = xzalloc(offsetof(len_and_sockaddr, sa) + len);
lsa->len = len; lsa->len = len;
lsa->sa.sa_family = family; lsa->sa.sa_family = family;
@ -234,7 +242,7 @@ int xsocket_type(len_and_sockaddr **lsap, int sock_type)
int xsocket_stream(len_and_sockaddr **lsap) int xsocket_stream(len_and_sockaddr **lsap)
{ {
return xsocket_type(lsap, SOCK_STREAM); return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
} }
static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
@ -247,7 +255,7 @@ static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
/* user specified bind addr dictates family */ /* user specified bind addr dictates family */
fd = xsocket(lsa->sa.sa_family, sock_type, 0); fd = xsocket(lsa->sa.sa_family, sock_type, 0);
} else { } else {
fd = xsocket_type(&lsa, sock_type); fd = xsocket_type(&lsa, USE_FEATURE_IPV6(AF_UNSPEC,) sock_type);
set_nport(lsa, htons(port)); set_nport(lsa, htons(port));
} }
setsockopt_reuseaddr(fd); setsockopt_reuseaddr(fd);

View File

@ -751,6 +751,13 @@ int nc_main(int argc, char **argv)
/* We manage our fd's so that they are never 0,1,2 */ /* We manage our fd's so that they are never 0,1,2 */
/*bb_sanitize_stdio(); - not needed */ /*bb_sanitize_stdio(); - not needed */
if (argv[0]) {
themaddr = xhost2sockaddr(argv[0],
argv[1]
? bb_lookup_port(argv[1], o_udpmode ? "udp" : "tcp", 0)
: 0);
}
/* create & bind network socket */ /* create & bind network socket */
x = (o_udpmode ? SOCK_DGRAM : SOCK_STREAM); x = (o_udpmode ? SOCK_DGRAM : SOCK_STREAM);
if (option_mask32 & OPT_s) { /* local address */ if (option_mask32 & OPT_s) { /* local address */
@ -758,7 +765,11 @@ int nc_main(int argc, char **argv)
ouraddr = xhost2sockaddr(str_s, o_lport); ouraddr = xhost2sockaddr(str_s, o_lport);
x = xsocket(ouraddr->sa.sa_family, x, 0); x = xsocket(ouraddr->sa.sa_family, x, 0);
} else { } else {
x = xsocket_type(&ouraddr, x); /* We try IPv6, then IPv4, unless addr family is
* implicitly set by way of remote addr/port spec */
x = xsocket_type(&ouraddr,
USE_FEATURE_IPV6((themaddr ? themaddr->sa.sa_family : AF_UNSPEC),)
x);
if (o_lport) if (o_lport)
set_nport(ouraddr, htons(o_lport)); set_nport(ouraddr, htons(o_lport));
} }
@ -789,14 +800,6 @@ int nc_main(int argc, char **argv)
xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), ofd); xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), ofd);
#endif #endif
if (argv[0]) {
themaddr = xhost2sockaddr(argv[0],
argv[1]
? bb_lookup_port(argv[1], o_udpmode ? "udp" : "tcp", 0)
: 0);
///what if sa_family won't match??
}
if (o_listen) { if (o_listen) {
dolisten(); dolisten();
/* dolisten does its own connect reporting */ /* dolisten does its own connect reporting */