Python 制作快速端口扫描器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26174743/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:10:59  来源:igfitidea点击:

Making a Fast Port Scanner

pythonsocketsportport-scanning

提问by Shane

So I'm making a port scanner in python...

所以我正在用python制作一个端口扫描器......

import socket
ip = "External IP"
s = socket.socket(2, 1) #socket.AF_INET, socket.SOCK_STREAM

def porttry(ip, port):
    try:
        s.connect((ip, port))
        return True
    except:
        return None

for port in range(0, 10000):
    value = porttry(ip, port)
    if value == None:
        print("Port not opened on %d" % port)
    else:
        print("Port opened on %d" % port)
        break
raw_input()

But this is too slow, I want to somehow be able to some how close or break code after a period of time of not returning anything.

但这太慢了,我希望在一段时间不返回任何内容后能够以某种方式接近或破坏代码。

采纳答案by Billy T

In addition to setting socket timeout, you can also apply multi-threading technique to turbo boost the process. It will be, at best, N times faster when you have N ports to scan.

除了设置套接字超时之外,您还可以应用多线程技术来加速进程。当您有 N 个端口要扫描时,它最多会快 N 倍。

# This script runs on Python 3
import socket, threading


def TCP_connect(ip, port_number, delay, output):
    TCPsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    TCPsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    TCPsock.settimeout(delay)
    try:
        TCPsock.connect((ip, port_number))
        output[port_number] = 'Listening'
    except:
        output[port_number] = ''



def scan_ports(host_ip, delay):

    threads = []        # To run TCP_connect concurrently
    output = {}         # For printing purposes

    # Spawning threads to scan ports
    for i in range(10000):
        t = threading.Thread(target=TCP_connect, args=(host_ip, i, delay, output))
        threads.append(t)

    # Starting threads
    for i in range(10000):
        threads[i].start()

    # Locking the main thread until all threads complete
    for i in range(10000):
        threads[i].join()

    # Printing listening ports from small to large
    for i in range(10000):
        if output[i] == 'Listening':
            print(str(i) + ': ' + output[i])



def main():
    host_ip = input("Enter host IP: ")
    delay = int(input("How many seconds the socket is going to wait until timeout: "))   
    scan_ports(host_ip, delay)

if __name__ == "__main__":
    main()

回答by Lukasz Ciesluk

I think that this one snippet could help you : http://www.coderholic.com/python-port-scanner/

我认为这个片段可以帮助你:http: //www.coderholic.com/python-port-scanner/

回答by Dataman

Consider setting a timeout instead of a for loop by using socket.setdefaulttimeout(timeout).

考虑使用 设置超时而不是 for 循环socket.setdefaulttimeout(timeout)

回答by Muhammad Suleman

socket.setdefaulttimeout(0.5) This will make the program faster!

socket.setdefaulttimeout(0.5) 这将使程序更快!

回答by Nisarg

socket.setdefualttimeout (time)

socket.setdefualttimeout(时间)

is used to keep trying to connect with port for perticular time...when you send request and there is timeout set for 2 seconds so it will try to connect with port for 2 seconds....if there will be no response from that port in 2 seconds....it will be count as a dead port

用于在特定时间内继续尝试与端口连接...当您发送请求并且超时设置为 2 秒时,它会尝试与端口连接 2 秒....如果没有响应2 秒内的端口......它将被视为死端口

回答by Ricky Wilson

This should be a bit faster.

这应该快一点。

#-*-coding:utf8;-*-
#qpy:3
#qpy:console

import socket
import os

# This is used to set a default timeout on socket
# objects.
DEFAULT_TIMEOUT = 0.5

# This is used for checking if a call to socket.connect_ex
# was successful.
SUCCESS = 0

def check_port(*host_port, timeout=DEFAULT_TIMEOUT):
    ''' Try to connect to a specified host on a specified port.
    If the connection takes longer then the TIMEOUT we set we assume
    the host is down. If the connection is a success we can safely assume
    the host is up and listing on port x. If the connection fails for any
    other reason we assume the host is down and the port is closed.'''

    # Create and configure the socket.
    sock = socket.socket()
    sock.settimeout(timeout)

    # the?SO_REUSEADDR?flag tells the kernel to reuse a local 
    # socket in?TIME_WAIT?state, without waiting for its natural
    # timeout to expire.
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    # Like?connect(address), but return an error indicator instead
    # of raising an exception for errors returned by the C-level?connect()?
    # call (other problems, such as “host not found,” can still raise exceptions). 
    # The error indicator is?0?if the operation succeeded, otherwise the value of 
    # the?errnovariable. This is useful to support, for example, asynchronous connects.
    connected = sock.connect_ex(host_port) is SUCCESS

    # Mark the socket closed. 
    # The underlying system resource (e.g. a file descriptor)
    # is also closed when all file objects from?makefile()?are closed.
    # Once that happens, all future operations on the socket object will fail. 
    # The remote end will receive no more data (after queued data is flushed).
    sock.close()

    # return True if port is open or False if port is closed.
    return connected


con = check_port('www.google.com', 83)
print(con)

回答by Gysi Rrjolli

here is a quick and simple port scanner, it scans 100000 ports in 180 sec:

这是一个快速简单的端口扫描器,它在 180 秒内扫描 100000 个端口:

import threading
import socket

target = 'pythonprogramming.net'
#ip = socket.gethostbyname(target)

def portscan(port):

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(0.5)# 

    try:
        con = s.connect((target,port))

        print('Port :',port,"is open.")

        con.close()
    except: 
        pass
r = 1 
for x in range(1,100): 

    t = threading.Thread(target=portscan,kwargs={'port':r}) 

    r += 1     
    t.start() 

回答by Noctis Skytower

The following port scanner has a few constants defined at the top that you can modify as needed:

以下端口扫描器在顶部定义了一些常量,您可以根据需要进行修改:

  • PURPOSE -- help message for the command line
  • PORTS -- range of ports you would like scanned
  • POOL_SIZE -- number of processes to scan with
  • TIMEOUT -- how long to wait for server connection
  • 目的——命令行的帮助信息
  • PORTS -- 您要扫描的端口范围
  • POOL_SIZE -- 要扫描的进程数
  • TIMEOUT -- 等待服务器连接的时间

Feel free to adapt this according to your requirements. Maybe add some command line arguments?

随意根据您的要求进行调整。也许添加一些命令行参数?

#! /usr/bin/env python3
import argparse
import collections
import itertools
import multiprocessing
import operator
import socket

PURPOSE = 'Scan for open ports on a computer.'
PORTS = range(1 << 16)
POOL_SIZE = 1 << 8
TIMEOUT = 0.01


def main():
    """Get computer to scan, connect with process pool, and show open ports."""
    parser = argparse.ArgumentParser(description=PURPOSE)
    parser.add_argument('host', type=str, help='computer you want to scan')
    host = parser.parse_args().host
    with multiprocessing.Pool(POOL_SIZE, socket.setdefaulttimeout, [TIMEOUT]) \
            as pool:
        results = pool.imap_unordered(test, ((host, port) for port in PORTS))
        servers = filter(operator.itemgetter(0), results)
        numbers = map(operator.itemgetter(1), servers)
        ordered = sorted(numbers)
    print(f'Ports open on {host}:', *format_ports(ordered), sep='\n    ')


field_names = 'family', 'socket_type', 'protocol', 'canon_name', 'address'
AddressInfo = collections.namedtuple('AddressInfo', field_names)
del field_names


def test(address):
    """Try connecting to the server and return whether or not it succeeded."""
    host, port = address
    for info in itertools.starmap(AddressInfo, socket.getaddrinfo(host, port)):
        try:
            probe = socket.socket(info.family, info.socket_type, info.protocol)
        except OSError:
            pass
        else:
            try:
                probe.connect(info.address)
            except OSError:
                pass
            else:
                probe.shutdown(socket.SHUT_RDWR)
                return True, port
            finally:
                probe.close()
    return False, port


def format_ports(ports):
    """Convert port numbers into strings and show all associated services."""
    if ports:
        for port in ports:
            try:
                service = socket.getservbyport(port)
            except OSError:
                service = '?'
            yield f'{port:<5} = {service}'
    else:
        yield 'None'


if __name__ == '__main__':
    main()

回答by Alex

One can use threading.Thread and threading.Condition to synchronize port check and spawning new threads.

可以使用 threading.Thread 和 threading.Condition 来同步端口检查和生成新线程。

Script example usage:

脚本示例用法:

python port_scan.py google.com 70 90
Checking 70 - 80
Checking 80 - 84
Checking 84 - 90
Found active port 80
Checking 90 - 91
Checking 91 - 94
All threads started ...

port_scan.py:

port_scan.py:

# import pdb
import socket, threading
from traceback import print_exc


class AllThreadsStarted(Exception): pass


class IPv4PortScanner(object):
    def __init__(self, domain, timeout=2.0, port_range=(1024, 65535), threadcount=10):
        self.domain               = domain
        self.timeout              = timeout
        self.port_range           = port_range
        self.threadcount          = threadcount
        self._lock                = threading.Lock()
        self._condition           = threading.Condition(self._lock)
        self._ports_active        = []
        self._ports_being_checked = []

        self._next_port = self.port_range[0]

    def check_port_(self, port):
        "If connects then port is active"
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.settimeout(self.timeout)
        try:
            sock.connect((self.domain, port))
            with self._lock:
                self._ports_active.append(port)
            print ("Found active port {}".format(port))
            sock.close()
        except socket.timeout, ex:
            return
        except:
            print_exc()
            # pdb.set_trace()

    def check_port(self, port):
        "updates self._ports_being_checked list on exit of this method"
        try:
            self.check_port_(port)
        finally:
            self._condition.acquire()
            self._ports_being_checked.remove(port)
            self._condition.notifyAll()
            self._condition.release()

    def start_another_thread(self):
        if self._next_port > self.port_range[1]:
            raise AllThreadsStarted()
        port             = self._next_port
        self._next_port += 1
        t = threading.Thread(target=self.check_port, args=(port,))
        # update books
        with self._lock:
            self._ports_being_checked.append(port)
        t.start()

    def run(self):
        try:
            while True:
                self._condition.acquire()
                while len(self._ports_being_checked) >= self.threadcount:
                    # we wait for some threads to complete the task
                    self._condition.wait()
                slots_available = self.threadcount - len(self._ports_being_checked)
                self._condition.release()
                print ("Checking {} - {}".format(self._next_port, self._next_port+slots_available))
                for i in xrange(slots_available):
                    self.start_another_thread()
        except AllThreadsStarted, ex:
            print ("All threads started ...")
        except:
            print_exc()


if __name__ == "__main__":
    import sys
    domain  = sys.argv[1]
    port_s  = int(sys.argv[2])
    port_e  = int(sys.argv[3])
    scanner = IPv4PortScanner(domain=domain, port_range=(port_s, port_e))
    scanner.run()