Python端口扫描

简介

实现简易的端口扫描器:
使用Python的socket编程,去实现与指定ip端口进行TCP连接;
使用sys模块,实现命令交互;
使用多线程,加快扫描速度。

扫描原理

尝试与每一个指定的端口进行TCP“三次握手”通信,如果成功建立连接,则证明端口开放,否则认为端口关闭。三次握手过程如下:
在这里插入图片描述

实现代码
import socket
import threading
import queue
import sys

class DHPScan:
    #无聊做了个logo
    logo = '''
____  _    _ ____   ____ 
|  _ \| |  | |  _ \ /  __| ____  ___ _____
| | \ | |__| | |_\ |  \__ /  __|/ _ |  _  |
| |_/ /  __  |  __/ \__  |  |__| |_|| | | |
|____/|_|  |_|_|   |____/ \____|\___|_| |_|
        '''
    help = '''
usage  : python dhpscan.py [-i ip] [-p port|beginPort-endPort] [-t threadNum]
example: python dhpscan.py -i 127.0.0.1 -p 443
         python dhpscan.py -i 127.0.0.1 -p 443 -t 10
         python dhpscan.py -i 127.0.0.1 -p 1-1000 -t 10
        '''
    class scanThread(threading.Thread):
        def __init__(self, ip, portQueue):
            threading.Thread.__init__(self)
            self.ip = ip
            self.portQueue = portQueue
        # 重写run方法
        def run(self):
            while True:
                if self.portQueue.empty():#队列空就结束
                    break
                port = self.portQueue.get()#从队列中取出
                try:
                    tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    tcp.settimeout(0.5)#如果设置太小,检测不精确,设置太大,检测太慢
                    result = tcp.connect_ex((self.ip, port))  # 效率比connect高,成功时返回0,失败时返回错误码
                    if result == 0:
                        print('%d\tOPENED' % port)
                except:
                    print('ERROR:ip or port ERROR')
                finally:
                    tcp.close()

    #获取端口队列
    def getPort(self,arg):
        if '-' in arg:
            num = arg.split('-', 1)
            for i in range(int(num[0]), int(num[1]) + 1):
                portQueue.put(i)#将端口i加入到队列中
        else:
            portQueue.put(int(arg))
    #创建线程
    def createThread(self,num,scanip,scanport):
        for i in range(num):
            threads.append(scan.scanThread(scanip,scanport))

if __name__ == '__main__':
    scan = DHPScan()
    print(scan.logo,scan.help)
    threadNum = 5 #默认5个线程
    ip = '127.0.0.1'
    threads = []#线程列表
    portQueue = queue.Queue()#待检测端口队列,会在《Python常用操作》一文中更新用法
    argvs = sys.argv#用于实现交互
    if len(argvs) == 7 and argvs[5] == '-t' and argvs[3] == '-p' and argvs[1] == '-i':
        ip = argvs[2]
        threadNum = int(argvs[6])
        scan.getPort(argvs[4])
    elif len(argvs) == 5 and argvs[3] == '-p' and argvs[1] == '-i':
        ip = argvs[2]
        scan.getPort(argvs[4])
    else:
        print('ERROR:Please input correct command according to usage')
    scan.createThread(threadNum,ip,portQueue)
    print('Scaning...')
    for t in threads:#启动线程
        t.start()
    for t in threads:#阻塞线程,等待线程结束
        t.join()
    print('Scan Over')
测试结果

测试一下
在这里插入图片描述

总结
  1. 一开始不知道队列的get方法,使用get方法获取数据后,该数据便不在队列中,相当于提取出来了;
  2. 使用队列,将待检测的端口put进队列中,可以配合多线程去调用检测,感觉以后会经常用到;
  3. socket中connect()和connect_ex()的区别:
    connect()的连接失败是抛出异常,而connect_ex()是返回错误码而不是抛异常;
参考文章

Python常用操作

更新

修改线程中重写的run方法,使用recv()方法,使得能够获取端口的服务信息

def run(self):
    while True:
        if self.portQueue.empty():
            break
        port = self.portQueue.get()
        try:
            tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            tcp.settimeout(0.5)#如果设置太小,检测不精确,设置太大,检测太慢
            result = tcp.connect_ex((self.ip, port))  # 效率比connect高,成功时返回0,失败时返回错误码
            try:
                server = tcp.recv(1024).decode().strip()
            except:
                server = 'unknow'
            if result == 0:
                print('%d\topened\t\t%s' %(port,server))
        except:
            print('ERROR:ip or port ERROR')
        finally:
            tcp.close()

测试原来的ip
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值