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.