I sent some patches to add these a year ago, and the people requesting
the functionality probably just hit the same point in their
development cycle where they're wanting this again :-)
From 0f431a44804920a693e8832dbc784b70f227318a Mon Sep 17 00:00:00 2001
From: Josh Gao <jm...@google.com>
Date: Mon, 10 Dec 2018 16:57:46 -0800
Subject: [PATCH 1/2] nc: add IPv6 support.

---
 lib/lib.h         |   1 +
 lib/net.c         |  18 ++++++++
 toys/net/netcat.c | 108 ++++++++++++++++++++++++----------------------
 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.
-- 
2.20.0.rc2.403.gdbc3b29805-goog

From 05c7a873b637aef7e2ec29cb36de35b81aebbd5f Mon Sep 17 00:00:00 2001
From: Josh Gao <jm...@google.com>
Date: Mon, 10 Dec 2018 17:04:21 -0800
Subject: [PATCH 2/2] nc: add UDP support.

---
 toys/net/netcat.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/toys/net/netcat.c b/toys/net/netcat.c
index d7dd9264..761d1f2a 100644
--- a/toys/net/netcat.c
+++ b/toys/net/netcat.c
@@ -7,7 +7,7 @@
  * 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:46"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46]", TOYFLAG_BIN))
+USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46u"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46]", TOYFLAG_BIN))
 
 config NETCAT
   bool "netcat"
@@ -21,6 +21,7 @@ config NETCAT
     -p	Local port number
     -q	Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet
     -s	Local source address
+    -u	Use UDP
     -w	SECONDS timeout to establish connection
     -W	SECONDS timeout for more data on an idle connection
 
@@ -72,6 +73,7 @@ void netcat_main(void)
 {
   int sockfd = -1, in1 = 0, in2 = 0, out1 = 1, out2 = 1;
   int family = AF_UNSPEC;
+  int type = SOCK_STREAM;
   pid_t child;
 
   // Addjust idle and quit_delay to miliseconds or -1 for no timeout
@@ -91,12 +93,15 @@ void netcat_main(void)
   else if (toys.optflags&FLAG_6)
     family = AF_INET6;
 
+  if (toys.optflags&FLAG_u)
+    type = SOCK_DGRAM;
+
   if (TT.f) in1 = out2 = xopen(TT.f, O_RDWR);
   else {
     // Setup socket
     if (!(toys.optflags&(FLAG_L|FLAG_l))) {
       struct addrinfo *addr = xgetaddrinfo(toys.optargs[0], toys.optargs[1],
-                                           family, SOCK_STREAM, 0, 0);
+                                           family, type, 0, 0);
       sockfd = xconnect(addr);
 
       // We have a connection. Disarm timeout.
@@ -115,7 +120,7 @@ void netcat_main(void)
         struct addrinfo* bind_addr;
 
         sprintf(port, "%ld", TT.p);
-        bind_addr = xgetaddrinfo(TT.s, port, family, SOCK_STREAM, 0, 0);
+        bind_addr = xgetaddrinfo(TT.s, port, family, type, 0, 0);
         sockfd = xbind(bind_addr);
       } else {
         size_t bind_addrlen;
@@ -134,7 +139,7 @@ void netcat_main(void)
           addr_in->sin_addr.s_addr = INADDR_ANY;
         }
 
-        sockfd = xsocket(family, SOCK_STREAM, 0);
+        sockfd = xsocket(family, type, 0);
         if (bind(sockfd, address, bind_addrlen))
           perror_exit("bind");
       }
-- 
2.20.0.rc2.403.gdbc3b29805-goog

_______________________________________________
Toybox mailing list
Toybox@lists.landley.net
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to