1 #!/usr/bin/env python
2 # -*- coding: utf_8 -*-
3 # Date: 2015年10月23日
4 # Author:蔚蓝行
5 # 博客 http://www.cnblogs.com/duanv/
6
7 from IPy import IP
8 import threading
9 import nmap
10 import time
11 import sys
12 import subprocess
13 from xml.dom import minidom
14
15 def usage():
16     print 'The script requires root privileges!'
17     print 'example:python scan.py 192.168.0.1/24'
18
19 #生成xml文件的模板函数
20 def addResult(newresult):
21     global doc
22     global scan_result
23
24     ip = doc.createElement("ip")
25     ip.setAttribute("address", newresult["address"])
26
27     osclass = doc.createElement("osclass")
28     osclass.appendChild(doc.createTextNode(newresult["osclass"]))
29     ip.appendChild(osclass)
30
31     port = doc.createElement("port")
32
33     tcp = doc.createElement("tcp")
34     tcp.appendChild(doc.createTextNode(newresult["tcp"]))
35     port.appendChild(tcp)
36
37     udp = doc.createElement("udp")
38     udp.appendChild(doc.createTextNode(newresult["udp"]))
39     port.appendChild(udp)
40
41     ip.appendChild(port)
42     scan_result.appendChild(ip)
43
44 #扫描函数,调用nmap库
45 def ip_scan(ip):
46     global nm
47     #这里调用系统ping命令来判断主机存活
48     p = subprocess.Popen("ping -c 1 -t 1 "+ip,stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
49     out = p.stdout.read()
50     #如过没有丢包则主机存活,对是否丢包的判断是抓取系统回显内容,测试用的是‘MAC OS X’系统,抓取内容为‘100.0% packet loss’
51     if '100.0% packet loss' not in out:
52         try:
53             #调用nmap扫描主机操作系统,同时进行SYN扫描和UDP扫描探测开放的端口
54             nm.scan(ip,arguments='-O -sS -sU -F')
55             sr={'address':ip,'osclass':str(nm[ip]['osclass'])[1:-1],'tcp':str(nm[ip].all_tcp())[1:-1],'udp':str(nm[ip].all_udp())[1:-1]}
56             addResult(sr)
57         except:
58             pass
59
60 #循环,遍历未扫描的IP
61 def loop():
62     global mutex
63     global ipx
64
65     while 1:
66         #线程锁,扫描一个IP将IPX列表中的该IP移除
67         mutex.acquire()
68         #如果列表中没有IP,则跳出循环结束该线程
69         if len(ipx)<=0:
70             mutex.release()
71             break
72         ip=ipx[0]
73         ipx.remove(ipx[0])
74         mutex.release()
75         #调用扫描函数
76         ip_scan(str(ip))
77
78 #创建线程的函数,默认创建40个
79 def creat_threads():
80     threads=[]
81     for i in range(40):
82         threads.append(threading.Thread(target=loop,))
83     for t in threads:
84         t.start()
85     for t in threads:
86         t.join()
87
88
89 def start():
90     #mutex:线程锁
91     global mutex
92     #ipx:存储要扫描的IP地址段列表
93     global ipx
94     #nm:nmap模块扫描对象
95     global nm
96     #doc:xml文档对象
97     global doc
98     #scan_result:xml文档的根元素
99     global scan_result
100
101     if '-h' == sys.argv[1]:
102         usage()
103         exit()
104     else:
105         #获取命令行输入的要扫描的IP段
106         ip=sys.argv[1]
107         #xml文档一些对象的初始化
108         doc = minidom.Document()
109         doc.appendChild(doc.createComment("scan_result xml."))
110         scan_result = doc.createElement("scan_result")
111         doc.appendChild(scan_result)
112
113         #初始化参数
114         ipx=[]
115         nm=nmap.PortScanner()
116         mutex=threading.Lock()
117
118         #调用IPy模块的IP函数,将IP地址段的每个IP存入列表
119         ipp=IP(ip, make_net=True)
120         for x in ipp:
121             ipx.append(x)
122         #去掉首尾代表子网和全部主机的IP
123         ipx=ipx[1:-1]
124
125         print("please wait...")
126         #计算时间
127         time_start=time.time()
128         #创建线程
129         creat_threads()
130
131         time_end=time.time()
132         t=time_end-time_start
133         print '*'*48
134         print ' Time:'+str(t)+'s'
135         print 'Scan results have been saved to scan_result.xml. '
136         print '*'*48
137
138         #xml文件操作
139         f = file("scan_result.xml","w")
140         f.write(doc.toprettyxml(indent = " ", newl = " ", encoding = "utf-8"))
141         f.close()
142
143 if __name__=='__main__':
144     start()