aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Gao <jmgao@google.com>2018-12-10 16:57:46 -0800
committerRob Landley <rob@landley.net>2018-12-10 20:09:34 -0600
commit0e431542e98f70aeb26291c0ada7bff84851dc77 (patch)
tree455a28237307d72aa6f34000a85ba204d8762c5f
parent3c2a6d3622707d53b254b71df5b73e8a465d03b5 (diff)
downloadtoybox-0e431542e98f70aeb26291c0ada7bff84851dc77.tar.gz
nc: add IPv6 support.
-rw-r--r--lib/lib.h1
-rw-r--r--lib/net.c18
-rw-r--r--toys/net/netcat.c108
3 files changed, 75 insertions, 52 deletions
diff --git a/lib/lib.h b/lib/lib.h
index 14bb7cf6..6dc2ca2b 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -301,6 +301,7 @@ void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len);
struct addrinfo *xgetaddrinfo(char *host, char *port, int family, int socktype,
int protocol, int flags);
int xconnect(struct addrinfo *ai_arg);
+int xbind(struct addrinfo *ai_arg);
int xpoll(struct pollfd *fds, int nfds, int timeout);
int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout);
char *ntop(struct sockaddr *sa);
diff --git a/lib/net.c b/lib/net.c
index 8969306b..880ad89b 100644
--- a/lib/net.c
+++ b/lib/net.c
@@ -53,6 +53,24 @@ int xconnect(struct addrinfo *ai_arg)
return fd;
}
+int xbind(struct addrinfo *ai_arg)
+{
+ struct addrinfo *ai;
+ int fd = -1;
+
+ // Try all the returned addresses. Report errors if last entry can't connect.
+ for (ai = ai_arg; ai; ai = ai->ai_next) {
+ fd = (ai->ai_next ? socket : xsocket)(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol);
+ if (!bind(fd, ai->ai_addr, ai->ai_addrlen)) break;
+ else if (!ai->ai_next) perror_exit("connect");
+ close(fd);
+ }
+ freeaddrinfo(ai_arg);
+
+ return fd;
+}
+
int xpoll(struct pollfd *fds, int nfds, int timeout)
{
int i;
diff --git a/toys/net/netcat.c b/toys/net/netcat.c
index aa251b88..d7dd9264 100644
--- a/toys/net/netcat.c
+++ b/toys/net/netcat.c
@@ -7,14 +7,16 @@
* netcat -L zombies
USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
-USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:"USE_NETCAT_LISTEN("[!tlL][!Lw]"), TOYFLAG_BIN))
+USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46]", TOYFLAG_BIN))
config NETCAT
bool "netcat"
default y
help
- usage: netcat [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}
+ usage: netcat [-46] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}
+ -4 Force IPv4
+ -6 Force IPv6
-f Use FILENAME (ala /dev/ttyS0) instead of network
-p Local port number
-q Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet
@@ -66,35 +68,10 @@ static void set_alarm(int seconds)
alarm(seconds);
}
-// Translate x.x.x.x numeric IPv4 address, or else DNS lookup an IPv4 name.
-static void lookup_name(char *name, uint32_t *result)
-{
- struct hostent *hostbyname;
-
- hostbyname = gethostbyname(name); // getaddrinfo
- if (!hostbyname) error_exit("no host '%s'", name);
- *result = *(uint32_t *)*hostbyname->h_addr_list;
-}
-
-// Worry about a fancy lookup later.
-static unsigned short lookup_port(char *str)
-{
- struct servent *se;
- int i = atoi(str);
-
- if (i>0 && i<65536) return SWAP_BE16(i);
-
- se = getservbyname(str, "tcp");
- i = se ? se->s_port : 0;
- endservent();
-
- return i;
-}
-
void netcat_main(void)
{
- struct sockaddr_in *address = (void *)toybuf;
- int sockfd=-1, in1 = 0, in2 = 0, out1 = 1, out2 = 1;
+ int sockfd = -1, in1 = 0, in2 = 0, out1 = 1, out2 = 1;
+ int family = AF_UNSPEC;
pid_t child;
// Addjust idle and quit_delay to miliseconds or -1 for no timeout
@@ -109,30 +86,18 @@ void netcat_main(void)
(!(toys.optflags&(FLAG_l|FLAG_L)) && toys.optc!=2))
help_exit("bad argument count");
+ if (toys.optflags&FLAG_4)
+ family = AF_INET;
+ else if (toys.optflags&FLAG_6)
+ family = AF_INET6;
+
if (TT.f) in1 = out2 = xopen(TT.f, O_RDWR);
else {
// Setup socket
- sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
- setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &out1, sizeof(out1));
-
- address->sin_family = AF_INET;
- if (TT.s || TT.p) {
- address->sin_port = SWAP_BE16(TT.p);
- if (TT.s)
- lookup_name(TT.s, (uint32_t *)&(address->sin_addr));
- if (bind(sockfd, (struct sockaddr *)address, sizeof(*address)))
- perror_exit("bind");
- }
-
- // Dial out
-
if (!(toys.optflags&(FLAG_L|FLAG_l))) {
- // Figure out where to dial out to.
- lookup_name(*toys.optargs, (uint32_t *)&(address->sin_addr));
- address->sin_port = lookup_port(toys.optargs[1]);
-// TODO xconnect
- if (connect(sockfd, (struct sockaddr *)address, sizeof(*address))<0)
- perror_exit("connect");
+ struct addrinfo *addr = xgetaddrinfo(toys.optargs[0], toys.optargs[1],
+ family, SOCK_STREAM, 0, 0);
+ sockfd = xconnect(addr);
// We have a connection. Disarm timeout.
set_alarm(0);
@@ -142,12 +107,51 @@ void netcat_main(void)
pollinate(in1, in2, out1, out2, TT.W, TT.q);
} else {
// Listen for incoming connections
- socklen_t len = sizeof(*address);
+ struct sockaddr* address = (void*)toybuf;
+ socklen_t len = sizeof(struct sockaddr_storage);
+
+ if (TT.s) {
+ char* port = toybuf;
+ struct addrinfo* bind_addr;
+
+ sprintf(port, "%ld", TT.p);
+ bind_addr = xgetaddrinfo(TT.s, port, family, SOCK_STREAM, 0, 0);
+ sockfd = xbind(bind_addr);
+ } else {
+ size_t bind_addrlen;
+
+ address->sa_family = family;
+
+ if (family == AF_INET6) {
+ struct sockaddr_in6* addr_in6 = (void*)address;
+ bind_addrlen = sizeof(*addr_in6);
+ addr_in6->sin6_port = SWAP_BE16(TT.p);
+ addr_in6->sin6_addr = in6addr_any;
+ } else {
+ struct sockaddr_in* addr_in = (void*)address;
+ bind_addrlen = sizeof(*addr_in);
+ addr_in->sin_port = SWAP_BE16(TT.p);
+ addr_in->sin_addr.s_addr = INADDR_ANY;
+ }
+
+ sockfd = xsocket(family, SOCK_STREAM, 0);
+ if (bind(sockfd, address, bind_addrlen))
+ perror_exit("bind");
+ }
if (listen(sockfd, 5)) error_exit("listen");
if (!TT.p) {
- getsockname(sockfd, (struct sockaddr *)address, &len);
- printf("%d\n", SWAP_BE16(address->sin_port));
+ short port_be;
+
+ getsockname(sockfd, address, &len);
+ if (address->sa_family == AF_INET)
+ port_be = ((struct sockaddr_in*)address)->sin_port;
+ else if (address->sa_family == AF_INET6)
+ port_be = ((struct sockaddr_in6*)address)->sin6_port;
+ else
+ perror_exit("getsockname: bad family");
+
+ printf("%d\n", SWAP_BE16(port_be));
fflush(stdout);
// Return immediately if no -p and -Ll has arguments, so wrapper
// script can use port number.