From: Guilhem Moulin <guilhem@debian.org>
Date: Mon, 22 Oct 2018 04:15:52 +0200
Subject: destination port list

---
 nc.1     |   26 ++++++++++++++++---
 netcat.c |   86 ++++++++++++++++++++++++++++++++-------------------------------
 2 files changed, 68 insertions(+), 44 deletions(-)

--- a/nc.1
+++ b/nc.1
@@ -414,15 +414,35 @@ The
 flag can be used to tell
 .Nm
 to report open ports,
-rather than initiate a connection.
+rather than initiate a connection. Usually it's useful to turn on verbose
+output to stderr by use this option in conjunction with
+.Fl v
+option.
+.Pp
 For example:
 .Bd -literal -offset indent
-$ nc -z host.example.com 20-30
+$ nc \-zv host.example.com 20-30
 Connection to host.example.com 22 port [tcp/ssh] succeeded!
 Connection to host.example.com 25 port [tcp/smtp] succeeded!
 .Ed
 .Pp
-The port range was specified to limit the search to ports 20 \- 30.
+The port range was specified to limit the search to ports 20 \- 30, and is
+scanned by increasing order (unless the
+.Fl r
+flag is set).
+.Pp
+You can also specify a list of ports to scan, for example:
+.Bd -literal -offset indent
+$ nc \-zv host.example.com http 20 22-23
+nc: connect to host.example.com 80 (tcp) failed: Connection refused
+nc: connect to host.example.com 20 (tcp) failed: Connection refused
+Connection to host.example.com port [tcp/ssh] succeeded!
+nc: connect to host.example.com 23 (tcp) failed: Connection refused
+.Ed
+.Pp
+The ports are scanned by the order you given (unless the
+.Fl r
+flag is set).
 .Pp
 Alternatively, it might be useful to know which server software
 is running, and which versions.
--- a/netcat.c
+++ b/netcat.c
@@ -191,7 +191,7 @@ int minttl = -1;
 
 void	atelnet(int, unsigned char *, unsigned int);
 int	strtoport(char *portstr, int udp);
-void	build_ports(char *);
+void	build_ports(char **);
 void	help(void) __attribute__((noreturn));
 int	local_listen(const char *, const char *, struct addrinfo);
 # if defined(TLS)
@@ -242,7 +242,7 @@ int
 main(int argc, char *argv[])
 {
 	int ch, s = -1, ret, socksv;
-	char *host, *uport;
+	char *host, **uport;
 	struct addrinfo hints;
 	struct servent *sv;
 	socklen_t len;
@@ -526,11 +526,11 @@ main(int argc, char *argv[])
 	} else if (argv[0] && !argv[1]) {
 		if (!lflag)
 			usage(1);
-		uport = argv[0];
+		uport = &argv[0];
 		host = NULL;
 	} else if (argv[0] && argv[1]) {
 		host = argv[0];
-		uport = argv[1];
+		uport = &argv[1];
 	} else
 		usage(1);
 
@@ -718,7 +718,7 @@ main(int argc, char *argv[])
 			else
 				s = unix_listen(host);
 		} else
-			s = local_listen(host, uport, hints);
+			s = local_listen(host, *uport, hints);
 		if (s < 0)
 			err(1, NULL);
 
@@ -1786,57 +1786,61 @@ strtoport(char *portstr, int udp)
  * that we should try to connect to.
  */
 void
-build_ports(char *p)
+build_ports(char **p)
 {
 	struct servent *sv;
 	char *n;
 	int hi, lo, cp;
 	int x = 0;
+	int i;
 
 	char *proto = proto_name(uflag, dccpflag);
-	sv = getservbyname(p, proto);
-	if (sv) {
-		if (asprintf(&portlist[0], "%d", ntohs(sv->s_port)) < 0)
-			err(1, "asprintf");
-	} else if (isdigit((unsigned char)*p) && (n = strchr(p, '-')) != NULL) {
-		*n = '\0';
-		n++;
-
-		/* Make sure the ports are in order: lowest->highest. */
-		hi = strtoport(n, uflag);
-		lo = strtoport(p, uflag);
-		if (lo > hi) {
-			cp = hi;
-			hi = lo;
-			lo = cp;
-		}
-
-		/*
-		 * Initialize portlist with a random permutation.  Based on
-		 * Knuth, as in ip_randomid() in sys/netinet/ip_id.c.
-		 */
-		if (rflag) {
-			for (x = 0; x <= hi - lo; x++) {
-				cp = arc4random_uniform(x + 1);
-				portlist[x] = portlist[cp];
-				if (asprintf(&portlist[cp], "%d", x + lo) == -1)
-					err(1, "asprintf");
+	for (i = 0; p[i] != NULL; i++) {
+		sv = getservbyname(p[i], proto);
+		if (sv) {
+			if (asprintf(&portlist[x], "%d", ntohs(sv->s_port)) < 0)
+				err(1, "asprintf");
+			x++;
+		} else if (isdigit((unsigned char)*p[i]) && (n = strchr(p[i], '-')) != NULL) {
+			*n = '\0';
+			n++;
+
+			/* Make sure the ports are in order: lowest->highest. */
+			hi = strtoport(n, uflag);
+			lo = strtoport(p[i], uflag);
+			if (lo > hi) {
+				cp = hi;
+				hi = lo;
+				lo = cp;
 			}
-		} else { /* Load ports sequentially. */
+
+			/* Load ports sequentially. */
 			for (cp = lo; cp <= hi; cp++) {
 				if (asprintf(&portlist[x], "%d", cp) == -1)
 					err(1, "asprintf");
 				x++;
 			}
+		} else {
+			hi = strtoport(p[i], uflag);
+			if (asprintf(&portlist[x], "%d", hi) < 0)
+				err(1, "asprintf");
+			x++;
 		}
-	} else {
-		char *tmp;
+	}
 
-		hi = strtoport(p, uflag);
-		if (asprintf(&tmp, "%d", hi) != -1)
-			portlist[0] = tmp;
-		else
-			err(1, NULL);
+	/*
+	 * Initialize portlist with a random permutation using
+	 * Fisher–Yates shuffle.
+	 */
+	if (rflag) {
+		for (i = x-1; i > 0; i--) {
+			cp = arc4random_uniform(i+1);
+			if (cp != i) {
+				n = portlist[i];
+				portlist[i] = portlist[cp];
+				portlist[cp] = n;
+			}
+		}
 	}
 }
 
