【问题标题】:Parallel Iterating IP Addresses in Bash在 Bash 中并行迭代 IP 地址
【发布时间】:2014-08-20 08:21:39
【问题描述】:

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

首先我想通过连接扫描运行nmap,并通过输出文件对自己进行grep,但这结果会引发许多误报,其中nmap声明一个端口要“过滤”,而实际上它是“ open”(使用的连接扫描: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
  • 最好确保只记下匹配的服务器版本

非常感谢任何建议或指向方向。

【问题讨论】:

    标签: linux bash curl gnu-parallel


    【解决方案1】:

    小规模 - 迭代

    对于较小的 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 的说法,朴素的 for 循环的运行时间(估计 256*256*256 的地址需要 200 天)已改进到 不到一天

    【讨论】:

    • 谢谢你,这真的让我走了。非常感激!!!我把它剪掉了,稍微修改了一下,然后通过seq 16777216 | parallel -P0 ./myscript.sh > output.txt 运行它我的机器能够并行运行超过 500 个作业,现在运行速度非常快!使用 for 循环运行脚本的估计运行时间约为 200 天。有了相似之处,我现在的运行时间不到一天。完美!
    • 维持 500 和 2 秒的顶部(对于超时)意味着 67,108 秒,即 18.6 小时。在超时之前回答的服务器越多,所需的时间就越少。这还没有考虑到并行在 500 个 中不起作用,但在一个结束后运行一个作业。
    • @ArnonZilca 没错,但是如果这台机器可以不费吹灰之力地维持 30000 个工作,那么这项任务将从花一整天到午休。
    • 没有另外说。尽管他确实写道,他的机器可以运行略超过 500 个工作。
    【解决方案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)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-16
      • 2022-12-02
      • 2017-10-05
      • 1970-01-01
      • 1970-01-01
      • 2014-01-07
      相关资源
      最近更新 更多