Sponsor

2012/08/29

TCP Port Scanner in Bash - good coders code, great reuse

TCP Port Scanner in Bash - good coders code, great reuse


TCP Port Scanner in Bash

Posted: 28 Aug 2012 06:02 AM PDT


I just had this quick idea to write a tcp port scanner in bash. Bash supports the special /dev/tcp/host/port file that you can read/write. Writing to this special file makes bash open a tcp connection to host:port. If writing to the port succeeds, the port is open, else the port is closed.

So at first I wrote this quick script:

for port in {1..65535}; do    echo >/dev/tcp/google.com/$port &&      echo "port $port is open" ||      echo "port $port is closed"  done  

This loops over ports 1-65535 and tries to open google.com:$port. However this doesn't work that well because if the port is closed, it takes bash like 2 minutes to realize that.

To solve this I needed something like alarm(2) to interrupt bash. Bash doesn't have a built-in alarm function, so I had to write my own using Perl:

alarm() {    perl -e '      eval {        $SIG{ALRM} = sub { die };        alarm shift;        system(@ARGV);      };      if ($@) { exit 1 }    ' "$@";  }  

This alarm function takes two args: seconds for the alarm call, and the code to execute. If the code doesn't execute in the given time, the function fails.

Once I had this, I could take my earlier code and just call it through alarm:

for port in {1..65535}; do    alarm 1 "echo >/dev/tcp/google.com/$port &&      echo \"port $port is open\"" ||      echo "port $port is closed"  done  

This is working! Now if bash freezes because of a closed port, the alarm 1 will kill the probe in 1 second, and the script will move to the next port.

I went ahead and turned this into a proper scan function:

scan() {    if [[ -z $1 || -z $2 ]]; then      echo "Usage: $0 <host> <port, ports, and/or port-range>"      return    fi      host=$1    ports=()    case $2 in      *-*)        IFS=- read start end <<< "$2"        for ((port=start; port <= end; port++)); do          ports+=($port)        done        ;;      *,*)        IFS=, read -ra ports <<< "$2"        ;;      *)        ports+=($2)        ;;    esac        for port in "${ports[@]}"; do      alarm 1 "echo >/dev/tcp/$host/$port &&        echo \"port $port is open\"" ||        echo "port $port is closed"    done  }  

You can run the scan function from your shell. It takes two arguments: the host to scan, and a list of ports to scan (such as 22,80,443), or a range of ports to scan (such as 1-1024), or an individual port to scan (such as 80).

Here is what happens when I run scan google.com 78-82:

  $ scan google.com 78-82   port 78 is closed  port 79 is closed  port 80 is open  port 81 is closed  port 82 is closed  

Similarly you can write an udp port scanner. Just replace /dev/tcp/ with /dev/udp/.

No comments:

Post a Comment

Keep a civil tongue.

Label Cloud

Technology (1464) News (793) Military (646) Microsoft (542) Business (487) Software (394) Developer (382) Music (360) Books (357) Audio (316) Government (308) Security (300) Love (262) Apple (242) Storage (236) Dungeons and Dragons (228) Funny (209) Google (194) Cooking (187) Yahoo (186) Mobile (179) Adobe (177) Wishlist (159) AMD (155) Education (151) Drugs (145) Astrology (139) Local (137) Art (134) Investing (127) Shopping (124) Hardware (120) Movies (119) Sports (109) Neatorama (94) Blogger (93) Christian (67) Mozilla (61) Dictionary (59) Science (59) Entertainment (50) Jewelry (50) Pharmacy (50) Weather (48) Video Games (44) Television (36) VoIP (25) meta (23) Holidays (14)

Popular Posts (Last 7 Days)