Python 使用外部工具、subprocess.Popen和线程进行多端口扫描

Python 使用外部工具、subprocess.Popen和线程进行多端口扫描,python,subprocess,python-2.4,Python,Subprocess,Python 2.4,我正在使用端口扫描程序扫描我的子网。不幸的是,端口扫描程序一次只能扫描一台主机的一个端口。此外,对于无法访问的主机,扫描仪还有1秒的超时时间。扫描器(作为一个外部程序)必须从subprocess.Popen()运行,并且为了加快速度,我可以在前面的一些探测器等待答复时发送多个探测器,我使用线程。使用大量线程进行完整的/24子网扫描时会出现问题。一些实际打开的端口显示为关闭。我怀疑不知怎么的,输出被弄乱了。请注意,如果一次扫描较少的主机或一台主机,则不会发生这种情况 以下代码是我尝试创建一个线程池

我正在使用端口扫描程序扫描我的子网。不幸的是,端口扫描程序一次只能扫描一台主机的一个端口。此外,对于无法访问的主机,扫描仪还有1秒的超时时间。扫描器(作为一个外部程序)必须从subprocess.Popen()运行,并且为了加快速度,我可以在前面的一些探测器等待答复时发送多个探测器,我使用线程。使用大量线程进行完整的/24子网扫描时会出现问题。一些实际打开的端口显示为关闭。我怀疑不知怎么的,输出被弄乱了。请注意,如果一次扫描较少的主机或一台主机,则不会发生这种情况

以下代码是我尝试创建一个线程池的代码,该线程池采用IP地址并对定义的端口运行“顺序”端口扫描。扫描完所有指定端口后,它将从列表中选择下一个IP

        while True:
            if not thread_queue.empty():
                try:
                    hst = ip_iter.next()
                except StopIteration:
                    break
                m=thread_queue.get()
                l=ThreadWork(self,hst,m)
                l.start()
        while open_threads != 0:
            pass      
此片段在其中设置线程队列

        thread_list = [x for x in range(num_threads)]
        for t in thread_list:
            thread_queue.put(str(t))
        ip_iter=iter(self.final_target)
在ThreadWork函数中,我保留了一个打开线程的选项卡(因为thread_queue.empty被证明是不可靠的,所以我不得不使用这种粗糙的方法)

对SinFpRes的调用为一个IP创建一个结果对象,并仅为该IP启动端口的顺序扫描。 每个端口的实际扫描如图所示

        com_string = '/usr/local/sinfp/bin/sinfp.pl '+self.options+' -ai '+str(self.ip)+' -p '+str(p)
        args = shlex.split(com_string) 
        self.result=subprocess.Popen(args,stdout=subprocess.PIPE).communicate()[0]
        self.parse(p)
然后,解析函数使用self.result中存储的结果来存储该端口的输出。所有端口的集合构成IP的扫描结果

使用10个线程调用此代码可以提供准确的o/p(与nmap输出相比)。在给定15个线程时,偶尔会丢失一个打开的端口。在给定20个线程时,会丢失更多打开的端口。在给定50个线程时,许多端口丢失

作为第一个计时器,这个代码非常复杂。向清教徒道歉

p.p.S.-即使是线程端口扫描,对于几乎不扫描20个端口的整个C类子网也需要15分钟。我想知道是否应该将这段代码移到另一种语言,并使用Python只解析结果。谁能给我推荐一种语言吗? 注意-我正在探索S.Lott所示的Shell选项,但在将其转储到文件中之前需要手动处理。

为什么不试试

(回答:不,他们将有自己的管道)

使用外壳

 for h in host1 host2 host3
 do
     scan $h >$h.scan &
 done
 cat *.scan >all.scan
这将同时扫描所有主机的整个列表,每个主机都在一个单独的进程中。没有线程


每次扫描将生成一个
.scan
文件。然后,您可以将所有
.scan
文件压缩成一个庞大的
all.scan
文件,以便进一步处理或执行任何操作。

使用Perl而不是Python。程序(SinFP)是用Perl编写的,您可以根据需要修改代码。

为什么要让线程运行进程?操作系统可以为您运行多个这样的进程,而无需编写大量线程。1。为什么不使用现有的解决方案,例如
nmap
?2.异步解决方案(如基于)可能比线程(快速扫描255*64k端口)3更合适
close_fds=True
如果您不在Windows上,则不会有任何影响。4.问题可能不在
子流程
中,但在扫描仪中,请尝试使用GNU
并行
运行它,并查看错误是否仍然存在。这是来自该项目的python脚本,实际上它设想使用多个扫描仪。所以我已经使用了nmap作为工具之一。它很好用。对于“第二种意见”,我使用了扫描仪“sinfp”。顺便说一句,对于10个线程,输出也不会混淆。但随着线程数量的增加,o/p开始变得更加模糊。对于50个线程,一些活动主机也会被丢弃。@RedBaron:为什么还要乱处理线程呢?为什么不使用简单的操作系统进程?@S.Lott:既然我是python的新手,你能举个例子吗?我试过了。实际上,我尝试使用一个文件对象作为标准输出。不同线程的文件名不同。它似乎工作得很好。但是对于大量的线程,对我来说,输出似乎是混淆的,因为程序偏离了正常的行为。如果您使用一个文件对象进行标准输出,那么很明显,输出将混淆。不然怎么可能呢?如果每个进程使用一个文件对象,那么它显然不会混淆。这就是管道标志所做的,您将获得进程标准输出流的句柄。每个标准输出流一个句柄。文件对象针对每个线程的不同文件。所以我不认为他们会搞混。随着线程数的增加,输出开始混淆。我不清楚:它们是不同的文件吗?如果是的话,我看不出输出会如何混淆。是的,他们是。。。。而且产出确实参差不齐。更准确地说,我扫描了整个子网中的一些已知端口,并将每个端口和每个IP的结果存储在不同的文件中。此结果以文本字符串的形式显示端口是否已关闭,如果未关闭,则显示操作系统匹配。它适用于10个螺纹或20个带锁螺纹(如上所示)。但是如果我使用20或50个线程,一些开放端口文件也会显示与g个封闭端口相关的文本。很明显,该工具或popen本身都不是线程安全的。使用subprocess.PIPE作为标准输出也会导致相同的行为。如何在不混合输出(文本字符串)的情况下检索它们?@RedBaron:使用shell。这很直截了当。将每个输出收集到单独的文件中,然后使用
cat
合并这些文件。请仔细阅读Linux操作系统。所有这些都在“shell简介”一书中有很好的记录。@S.洛特:这对我来说还不够。我想我还是坚持使用python吧,因为这个程序只适用于有限数量的线程。我最初的问题是为什么大量线程的输出会变得混乱。在使用线程时使用Popen生成进程是否有可能受到限制。@RedBaron:“这不足以满足我的要求。”?以什么方式?这很好用。“你能具体说明一下这有什么问题吗?”RedBaron:“顺便说一句,Shell是一个快速而非我的产品
 for h in host1 host2 host3
 do
     scan $h >$h.scan &
 done
 cat *.scan >all.scan