Bash中并行迭代IP地址

时间:2014-08-20 08:21:40

标签: linux bash curl gnu-parallel

我正在处理一个大型的private / 8网络,需要枚举所有正在侦听端口443并在HTTP HEADER响应中声明的特定版本的Web服务器。

首先,我考虑使用连接扫描运行nmap并通过输出文件grep自己,但结果发现许多误报在nmap声明端口被“过滤”的同时它实际上是“开放的”(使用连接扫描:nmap -sT -sV -Pn -n -oA foo 10.0.0.0/8 -p 443)。

所以现在我想用bash和curl编写脚本 - 伪代码就像:

for each IP in 10.0.0.0/8  
do:  
    curl --head https://{IP}:443 | grep -iE "(Server\:\ Target)" > {IP}_info.txt;  
done  

由于我不熟悉bash,我不确定如何正确编写脚本 - 我必须:

  • 遍历所有IP
  • 确保只有X威胁并行运行
  • 理想情况下将输出切换为仅在一个文件中记下匹配主机的IP
  • 理想情况下,确保只记下匹配的服务器版本

高度赞赏任何建议或指向方向。

2 个答案:

答案 0 :(得分:8)

小规模 - 迭代

对于较小的 IP地址范围,可能会建议像这样迭代:

for ip in 192.168.1.{1..10}; do ...

similar question所述。


大规模 - 平行!

鉴于您的问题涉及巨大 IP地址范围,您应该考虑采用不同的方法。

请求以使用gnu parallel

使用gnu parallel在bash中并行迭代大量IP地址需要将逻辑拆分为多个文件(对于要使用的并行命令)。

ip2int

#!/bin/bash

set -e

function ip_to_int()
{
  local IP="$1"
  local A=$(echo $IP | cut -d. -f1)
  local B=$(echo $IP | cut -d. -f2)
  local C=$(echo $IP | cut -d. -f3)
  local D=$(echo $IP | cut -d. -f4)
  local INT

  INT=$(expr 256 "*" 256 "*" 256 "*" $A)
  INT=$(expr 256 "*" 256 "*" $B + $INT)
  INT=$(expr 256 "*" $C + $INT)
  INT=$(expr $D + $INT)

  echo $INT
}

function int_to_ip()
{
  local INT="$1"

  local D=$(expr $INT % 256)
  local C=$(expr '(' $INT - $D ')' / 256 % 256)
  local B=$(expr '(' $INT - $C - $D ')' / 65536 % 256)
  local A=$(expr '(' $INT - $B - $C - $D ')' / 16777216 % 256)

  echo "$A.$B.$C.$D"
}



scan_ip

#!/bin/bash

set -e

source ip2int

if [[ $# -ne 1 ]]; then
    echo "Usage: $(basename "$0") ip_address_number"
    exit 1
fi

CONNECT_TIMEOUT=2 # in seconds
IP_ADDRESS="$(int_to_ip ${1})"

set +e
data=$(curl --head -vs -m ${CONNECT_TIMEOUT} https://${IP_ADDRESS}:443 2>&1)
exit_code="$?"
data=$(echo -e "${data}" | grep "Server: ")
     # wasn't sure what are you looking for in your servers
set -e

if [[ ${exit_code} -eq 0 ]]; then
    if [[ -n "${data}" ]]; then
        echo "${IP_ADDRESS} - ${data}"
    else
        echo "${IP_ADDRESS} - Got empty data for server!"
    fi
else
    echo "${IP_ADDRESS} - no server."
fi



scan_range

#!/bin/bash

set -e

source ip2int

START_ADDRESS="10.0.0.0"
NUM_OF_ADDRESSES="16777216" # 256 * 256 * 256

start_address_num=$(ip_to_int ${START_ADDRESS})
end_address_num=$(( start_address_num + NUM_OF_ADDRESSES ))

seq ${start_address_num} ${end_address_num} | parallel -P0 ./scan_ip

# This parallel call does the same as this:
#
# for ip_num in $(seq ${start_address_num} ${end_address_num}); do
#     ./scan_ip ${ip_num}
# done
#
# only a LOT faster!


迭代方法的改进:

  

根据@skrskrskr的说法,naive for循环的运行时间(对于256 * 256 * 256地址估计需要200天)被改善为

答案 1 :(得分:2)

更短的:

mycurl() {
    curl --head https://${1}:443 | grep -iE "(Server\:\ Target)" > ${1}_info.txt;  
}
export -f mycurl
parallel -j0 --tag mycurl {1}.{2}.{3}.{4} ::: {10..10} ::: {0..255} ::: {0..255} ::: {0..255}

使用--tag而不是许多_info.txt文件略有不同:

parallel -j0 --tag curl --head https://{1}.{2}.{3}.{4}:443 ::: {10..10} ::: {0..255} ::: {0..255} ::: {0..255} | grep -iE "(Server\:\ Target)" > info.txt

扇出并行运行超过500个:

parallel echo {1}.{2}.{3}.{4} ::: {10..10} ::: {0..255} ::: {0..255} ::: {0..255} | \
  parallel -j100 --pipe -N1000 --load 100% --delay 1 parallel -j250 --tag -I ,,,, curl --head https://,,,,:443 | grep -iE "(Server\:\ Target)" > info.txt

这将产生多达100 * 250个作业,但会尝试找到任何CPU没有空闲时间的最佳作业数。在我的8核系统7500上。确保你有足够的RAM来运行最大潜力(在这种情况下为25000)。