• Python 实现IP段扫描


    1. 简介

    很多童鞋都会有这样一个需求,我想要扫描特定网段并需要知道未使用和已使用的IP有哪些,甚至需要将其做统计,那这时候用Python去实现IP段扫描就会比较的轻松,当前文中我是将数据保存到mongo中,这里的代码只做参考,需要根据实际的场景进行修改!!

    2. 代码实现

    import time
    import IPy
    from concurrent.futures import ThreadPoolExecutor
    import subprocess
    from pymongo import MongoClient
    
    
    class ip_check(object):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
            # 数据库相关
            self.client = MongoClient('127.0.0.1', 27017)
            self.db = self.client['devops']
    
            # self.save_dbname = "snmp_ping_result"  # 存储历史记录
            self.store_db = 'snmp_ping'
            # 存放IP地址
            self.ip_allocated = []  # 已分配/已使用的IP
            self.ip_not_allocated = []  # 未分配/未使用的IP
            self.ip_error = []  # 访问失败或异常的IP
    
            # icmp相关(ping底层用的就是icmp协议)
            self.icmp_timeout = 5  # 超时时间
            self.icmp_count = 5  # 发送次数
    
            # 并发相关
            self.is_thread = True  # 是否多线程(建议开启,否则检测速度异常的慢)
            self.max_thread_workers = 100  # 最大线程池数
    
        def run(self):
            self.get_result()
    
        def get_result(self):
            # 存放最终返回的结果
            # result = {}
    
            # 获取网段地址
            segment = '172.16.58.0/24'
            db = self.db[self.store_db]
            # todo 从数据库中查询对应segment的数据,但是这里注意,如果不需要指定 segment 来查询的话,可以直接查询到所有IP数据,然后通过for循环的方式一个一个网段的ping
            data = db.find_one({'segment': segment})
            if data is None:
                raise Exception('网段不存在')
    
            _ips = IPy.IP(data.get('segment'))  # IPy 获取所有IP地址
    
            # todo 获取该网段已使用的IP 一般这里是从数据库中查询
            exist_ip = data.get('used_ip')
    
            # 过滤已存在的IP
            ips = [str(ip) for ip in _ips if str(ip) not in exist_ip]
    
            """并发执行ping"""
            max_workers = self.max_thread_workers if self.max_thread_workers else 20
            if self.is_thread:
                with ThreadPoolExecutor(max_workers) as executor:
                    for ip in ips:
                        executor.submit(self.send_ping, ip)
            else:
                for ip in ips:
                    self.send_ping(ip)
                    
            """统计IP数量"""
            # 只有当 总ip数量 = 已使用IP + 剩余IP + 异常IP 才能确保所有IP都被扫描到了
            if len(ips) == (len(self.ip_allocated) + len(self.ip_not_allocated) + len(self.ip_error)):
                total_ip, used_ip, available_ip, err_ip = len(ips), len(self.ip_allocated), len(self.ip_not_allocated), len(
                    self.ip_error)
    
                print("""
                     总IP:%s
                     已使用IP: %s
                     剩余IP:%s
                     故障的IP:%s
                     """ % (total_ip, used_ip, available_ip, err_ip))
    
            else:
                # todo 之后会增加日志记录或者是报异常
                ...
    
            # todo 最后需要将结果存储到数据库中
            save_result = {
                '$set': {
                    'total_ip': len(ips),
                    'used_ip': self.ip_allocated,
                    'available_ip': self.ip_not_allocated,
                    'err_ip': self.ip_error,
                }
            }
            db.update_one(data, save_result)
    
            """处理异常的IP"""
            # todo 保留,可以对异常的IP再次发起二次ping或者是其他处理
    
        def send_ping(self, ip):
            """
            发送ping命令,执行IP扫描
            :param ip: 字符串形式的IP地址,例如:'172.16.2.12'
            :return:
            """
            if ip:
                try:
                    pipe = subprocess.run(f"ping -c {self.icmp_count} -t {self.icmp_timeout} {ip} > /dev/null 2>&1",
                                          shell=True)
    
                    code = pipe.returncode  # 获取执行状态码 ping通:返回0,ping不通:返回 2(非0)
                    if code == 0:
                        self.ip_allocated.append(ip)  # 已使用的IP
                    elif code != 0 or code == 2:
                        self.ip_not_allocated.append(ip)  # 未使用的IP
    
                except Exception as e:
                    # icmp不可达的记录为异常IP
                    print(f'ip:{ip} 访问异常: {e}')
                    self.ip_error.append(ip)  # 异常IP
            else:
                # todo 之后会增加日志记录或者是报异常
                ...
    
    
    if __name__ == "__main__":
        x = ip_check()
        x.run()
    

    数据库表结构:

  • 相关阅读:
    LDAP概念及原理
    基于Kerberos+Ldap复合认证的大数据权限
    架构师需要知道的20个英文缩写
    Alluxio集群搭建并整合CDH(MR/Hive/Spark)
    编译Alluxio源码适配CDH5.16.1
    Hive全库数据迁移方案
    基于LDAP认证的大数据权限解决方案
    基于Kerberos认证的大数据权限解决方案
    普通用户fork问题 fork: retry: No child processes
    (二)数据预处理
  • 原文地址:https://www.cnblogs.com/jasonminghao/p/13288925.html
Copyright © 2020-2023  润新知