Port scanning

netcat can be used as “hacking” tool, e.g., -z option for port scanning:

  1. # nc -vz google.com 443-445
  2. Connection to google.com 443 port [tcp/https] succeeded!
  3. nc: connect to google.com port 444 (tcp) failed: Operation timed out
  4. nc: connect to google.com port 445 (tcp) failed: Operation timed out

First, build_ports parses 443-445 to generate port lists:

  1. void
  2. build_ports(char *p)
  3. {
  4. char *n;
  5. int hi, lo, cp;
  6. int x = 0;
  7. if ((n = strchr(p, '-')) != NULL) {
  8. *n = '\0';
  9. n++;
  10. /* Make sure the ports are in order: lowest->highest. */
  11. hi = strtoport(n, uflag);
  12. lo = strtoport(p, uflag);
  13. if (lo > hi) {
  14. cp = hi;
  15. hi = lo;
  16. lo = cp;
  17. }
  18. /*
  19. * Initialize portlist with a random permutation. Based on
  20. * Knuth, as in ip_randomid() in sys/netinet/ip_id.c.
  21. */
  22. if (rflag) {
  23. for (x = 0; x <= hi - lo; x++) {
  24. cp = arc4random_uniform(x + 1);
  25. portlist[x] = portlist[cp];
  26. if (asprintf(&portlist[cp], "%d", x + lo) < 0)
  27. err(1, "asprintf");
  28. }
  29. } else { /* Load ports sequentially. */
  30. for (cp = lo; cp <= hi; cp++) {
  31. if (asprintf(&portlist[x], "%d", cp) < 0)
  32. err(1, "asprintf");
  33. x++;
  34. }
  35. }
  36. } else {
  37. ......
  38. }
  39. }

The portlist array is defined as following:

  1. ......
  2. #define PORT_MAX 65535
  3. ......
  4. char *portlist[PORT_MAX+1];
  5. ......

One feature of is generating port lists randomly, not in sequence through -r option:

  1. ......
  2. if (rflag) {
  3. for (x = 0; x <= hi - lo; x++) {
  4. cp = arc4random_uniform(x + 1);
  5. portlist[x] = portlist[cp];
  6. if (asprintf(&portlist[cp], "%d", x + lo) < 0)
  7. err(1, "asprintf");
  8. }
  9. }
  10. ......

The interesting part is arc4random_uniform(), which guarantees cp is less than or equal x. So if cp == x:

  1. ......
  2. portlist[x] = portlist[cp];
  3. if (asprintf(&portlist[cp], "%d", x + lo) < 0)
  4. err(1, "asprintf");
  5. ......

portlist[x] and portlist[cp] point to same slot. Otherwise, if cp < x, put the original value of portlist[cp] to portlist[x], and generate a new value of portlist[cp].

After generating port list, try connecting the port to check whether it is open or not. For UDP service, there is a further step to test:

  1. /*
  2. * udptest()
  3. * Do a few writes to see if the UDP port is there.
  4. * Fails once PF state table is full.
  5. */
  6. int
  7. udptest(int s)
  8. {
  9. int i, ret;
  10. for (i = 0; i <= 3; i++) {
  11. if (write(s, "X", 1) == 1)
  12. ret = 1;
  13. else
  14. ret = -1;
  15. }
  16. return ret;
  17. }

Finally, getservbyport() is used to display service name:

  1. ......
  2. /* Don't look up port if -n. */
  3. if (nflag)
  4. sv = NULL;
  5. else {
  6. sv = getservbyport(
  7. ntohs(atoi(portlist[i])),
  8. uflag ? "udp" : "tcp");
  9. }
  10. fprintf(stderr,
  11. "Connection to %s %s port [%s/%s] "
  12. "succeeded!\n", host, portlist[i],
  13. uflag ? "udp" : "tcp",
  14. sv ? sv->s_name : "*");
  15. ......

BTW, nflag is set by -n option, means not do service look-up.