您的位置:首页 > 编程语言 > Python开发

Python构造简单端口扫描程序

2018-01-03 09:37 676 查看
#-*- coding: UTF-8 -*-
import optparse
from socket import *
from threading import *

#由于线程同步导致扫描不同端口输出的次序会乱掉,因此设置一个信号量Semaphore,用来在输出时锁定线程,保证端口扫描输出依次打印
screenLock = Semaphore(value = 1)  #定义一个信号量用于锁定线程

#用于连接指定的地址以及指定端口,建立连接发送信息,看是否有返回信息以确定端口是否开放
def connScan(tgtHost, tgtPort):
try:
'''
int socket(int domain, int type, int protocol);
#参数domain用于设置网络通信的域       AF_INET,PF_INET  IPv4 Internet协议
#参数type用于设置套接字通信的类型     SOCK_STREAM:Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输
#参数protocol用于制定某个协议的特定类型
'''
connSkt = socket(AF_INET, SOCK_STREAM) #建立一个流式套接字
'''
int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
connect函数通常用于客户端建立tcp连接。
参数sockfd:标识一个套接字。
参数serv_addr:套接字s想要连接的主机地址和端口号。
参数addrlen:name缓冲区的长度。
返回值:成功则返回0,失败返回-1,错误原因存于errno中。
'''
connSkt.connect((tgtHost, tgtPort)) #连接指定的地址和端口
'''
int send( SOCKET s,const char* buf,int len,int flags);
客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。
第一个参数指定发送端套接字描述符;
第二个参数指明一个存放应用程序要发送数据的缓冲区;
第三个参数指明实际要发送的数据的字节数;
第四个参数一般置0。
'''
connSkt.send('ViolentPython\r\n') #发送消息
'''
int recv(SOCKET s,char* buf,int len,int flags);
不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。
第一个参数指定接收端套接字描述符;
第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
第三个参数指明buf的长度;
第四个参数一般置0。
'''
results = connSkt.recv(100) #若端口开放,记录返回的消息
'''
【信号量】用于控制对某资源访问的同一时间的并发量
semaphore.acquire(),没信号量可用时,将进行阻塞等
【如何释放】semaphore.release()
'''
screenLock.acquire() #Lock锁定线程
print ('[+]%d/tcp open'% tgtPort)
print ('[+] ' + str(results))
except:
screenLock.acquire()
print ('[-] %d/tcp closed'% tgtPort)
finally:
screenLock.release()  #释放控制信号量
connSkt.close()  #关闭 Socket 连接并释放所有关联的资源

#获取主机名,打印,调用connScan()进行扫描
def portScan(tgtHost,tgtPorts):
try:
tgtIP = gethostbyname(tgtHost)  #返回的是 主机名 的IPv4 的地址格式
except:
print ("[-] Cannot resolve '%s': Unknown host" %tgtHost)
return
try:
tgtName = gethostbyaddr(tgtIP)   #根据IP地址反向查找主机名称
print ('\n[+] Scan Results for:' + tgtName[0])
except:
print ('\n[+] Scan Results for:' +tgtIP)
setdefaulttimeout(1) #时间戳,通过socket模块的setdefaulttimeout函数来控制超时时间
for tgtPort in tgtPorts:
'''
Thread是线程类,构造方法: Thread(group=None, target=None, name=None, args=(), kwargs={})
group: 线程组,目前还没有实现,库引用中提示必须是None;
   target: 要执行的方法;
   name: 线程名;
   args/kwargs: 要传入方法的参数。
'''
t = Thread(target = connScan, args=(tgtHost, int(tgtPort))) #创建线程,调用connScan()
t.start()   #启动线程

def main():
'''
MSG_USAGE = "myprog[ -f <filename>][-s <xyz>] arg1[,arg2..]"
optParser = OptionParser(MSG_USAGE)
构造一个OptionParser的对象optParse,传入的值MSG_USAGE可被调用打印命令时显示出来
'''
parser = optparse.OptionParser("usage%prog"+"-H <target host> -p <target port>")
'''
调用OptionParser.add_option()添加选项
add_option()参数说明:
action:存储方式,分为三种store、store_false、store_true
type:类型
dest:存储的变量
default:默认值
help:帮助信息
'''
parser.add_option('-H', dest = 'tgtHost', type = 'string', help = 'specify target host')
parser.add_option('-p', dest = 'tgtPort', type = 'string', help = 'specify target port[s] separated by comma')
'''
调用OptionParser.parse_args()剖析并返回一个directory和一个list
options为是一个directory,它的内容fakeArgs为“参数/值 ”的键值对。
args 是一个list,它的内容是parser除去options后,剩余的输入内容。
'''
(options,args) = parser.parse_args()
tgtHost = options.tgtHost #获取主机名
tgtPorts = str(options.tgtPort).split(',')  #获取端口列表,端口间用逗号分隔
if(tgtHost == None) | (tgtPorts[0] == None):
print (parser.usage)
exit(0)
portScan(tgtHost, tgtPorts)

if __name__ == '__main__':
main()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: