【转】 使用 Bash 编写的 TCP 端口扫描器

我突然有一个用 Bash 来编写 TCP 端口扫描器的想法。Bash 支持可读写的特殊文件 /dev/tcp/host/port ,往这个文件写内容可以让 bash 打开一个 TCP 连接到 host:port ,如果写文件成功则表示此端口是打开的,否则说明该端口没有打开。

因此我们先简单的写一个测试脚本:

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

该脚本将扫描 google.com 服务器端口,从 1 到 65535。当然,如果端口没打开的话是没法工作的,bash 花了 2 分钟时间意识到这点。

为了解决这个问题我们需要一些类似 alarm(2) 的方法来中断 bash,而 bash 没有内置的 alarm 函数,因此我们用 Perl 语言写了一个:

01 alarm() {
02   perl -e '
03     eval {
04       $SIG{ALRM} = sub die };
05       alarm shift;
06       system(@ARGV);
07     };
08     if ($@) { exit 1 }
09   "$@";
10 }

这个 alarm 函数需要两个参数:alarm 调用的秒数和要执行的代码,如果执行的代码没有在指定的时间内执行完毕则该函数调用失败。

有了这个 alarm 函数,我们就可以修改上面的代码如下:

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

这个终于可以运行了,当扫描到某个端口是关闭的, bash 将在 1 秒后执行下一个端口的扫描。

然后我们将这些代码封装到一个 scan 函数中:

01 scan() {
02   if [[ -z $1 || -z $2 ]]; then
03     echo "Usage: $0 <host> <port, ports, or port-range>"
04     return
05   fi
06
07   local host=$1
08   local ports=()
09   case $2 in
10     *-*)
11       IFS=- read start end <<< "$2"
12       for ((port=start; port <= end; port++)); do
13         ports+=($port)
14       done
15       ;;
16     *,*)
17       IFS=, read -ra ports <<< "$2"
18       ;;
19     *)
20       ports+=($2)
21       ;;
22   esac
23
24
25   for port in "${ports[@]}"do
26     alarm 1 "echo >/dev/tcp/$host/$port &&
27       echo \"port $port is open\"" ||
28       echo "port $port is closed"
29   done
30 }

这样就可以在 shell 中使用 scan 函数,需要的参数包括要扫描的主机地址、端口列表(可以时端口组合和端口范围,或者是某个特定端口)

下面是扫描 google.com 服务器的 78 - 82 端口:


1 $ scan google.com 78-82
2 port 78 is closed
3 port 79 is closed
4 port 80 is open
5 port 81 is closed
6 port 82 is closed

如果你想测试 UDP 端口,只需要将前面提及的 /dev/tcp 改为 /dev/udp/

原文:http://www.oschina.net/question/12_67215

猜你喜欢

转载自cloudmail.iteye.com/blog/1670273