Python獲取網路中的存活主機以及哪些主機是Linux

昀溪發表於2019-01-24

這個指令碼用於掃描網路中的存活主機,通常在CMDB中自動獲取主機的時候用到。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
執行這個指令碼的主機要安裝下面兩個模組
pip3 install python-nmap 這個Python模組依賴作業系統的nmap
確保作業系統安裝了nmap  yum -y install nmap   # for centos
主要功能:掃描網段獲取存活主機以及主機是否為Linux。不是Linux的被標記為Unknown,這些主機會包括交換機、路由器、Windows等。
"""
import sys
from functools import partial

import nmap
import telnetlib
import asyncio


def timer(tagName):
    import time
    def wapper(func):
        def aa(self, *args, **kwargs):
            start = time.time()
            data = func(self, *args, **kwargs)
            end = time.time()
            consume = end - start
            if consume > 60:
                min, sec = divmod(consume, 60)
                print("%s 執行耗時:%s 分 %s 秒。" % (tagName, str(min), str(sec)))
            else:
                print("%s 執行耗時:%s 秒。" % (tagName, str(consume)))
            return data
        return aa

    return wapper


class ScanHost(object):

    def __init__(self):
        self._hostsinfor = []

    @timer(tagName="掃描")
    def scan(self, hosts='127.0.0.1', ports=None):
        """
        掃描主機
        :param hosts:  可以是IP也可以是網段,例如 192.168.100.10、192.168.100.0/24
        :param ports:  可以寫埠也可以寫埠範圍,例如22、22-33,預設是None也就是所有埠
        :return: [{'IP': '127.0.0.1', 'Status': 'up', 'OSType': 'Linux'}, {}, {}]
        """
        hostlist = self._scanner(hosts, ports)
        loop = asyncio.get_event_loop()
        taskList = []
        for hostdic in hostlist:
            taskList.append(loop.create_task(self._isLinux(hostdic["IP"],)))

        for task in taskList:
            task.add_done_callback(partial(self._callback))

        loop.run_until_complete(asyncio.wait(taskList))
        return self._hostsinfor

    def _callback(self, future):
        res = future.result()
        self._hostsinfor.append(res)

    async def _isLinux(self, host, port='22'):
        """
        判斷目標主機是否是Linux,這是透過telnet遠端登入SSH埠號後根據輸出內容來判斷的
        所以需要遠端主機開啟SSH服務
        :param host:
        :param port:
        :return: True|False
        """
        try:
            tm = telnetlib.Telnet(host=host, port=port, timeout=5)
            # 讀取的內容通常是這樣的 b'SSH-2.0-OpenSSH_5.3\r\n'  位元組,所以只需要判斷是否含有OpenSSH就知道是否是Linux
            # 因為預設Windows上面沒有OpenSSH服務,雖然你可以單獨安裝通常來講沒必要。
            b_content = tm.read_until(b'\n', timeout=5)
            str_content = str(b_content.decode(encoding='utf-8')).strip()
            # 判斷是否包含OpenSSH字元,這裡統一用大寫比較
            if "OPENSSH" in str_content.upper():
                return {"IP": host, 'Status': 'up', "OSType": "Linux"}
            else:
                return {"IP": host, 'Status': 'up', "OSType": "Unknown"}
        except (ConnectionRefusedError, TimeoutError) as err:
            return {"IP": host, 'Status': 'up', "OSType": "Unknown"}
        except Exception as err:
            print("Error occurd in class ScanHost function _isLinux")
            print("Error message: ", err)

    def _scanner(self, hosts, ports=None):
        """
        探測某一主機是否存活或者探測給定網段記憶體活的主機
        :param hosts:  可以是IP也可以是網段,例如 192.168.100.10、192.168.100.0/24
        :param ports:  可以寫埠也可以寫埠範圍,例如22、22-33
        :return:  [{'IP': '127.0.0.1', 'Status': 'up'}, {}, {}]
        """
        data = []
        try:
            nm = nmap.PortScanner()
            """
            -n 不顯示主機名,不進行IP到主機名的反向解析
            -sP 使用ICMP協議探測
            -PE 顯示哪些埠號開啟
            -sP -PE 使用IMCP和TCP來探測,結果不顯示埠號
            """
            nm.scan(hosts=hosts, ports=ports, arguments='-sP -PE ')
            # 這裡獲取的只是返回的有效IP
            hosts_list = nm.all_hosts()

            for host in hosts_list:
                # 透過nmap例項獲取主機的資訊
                # print(nm[host])
                data.append({"IP": host, "Status": nm[host]["status"]["state"]})
            return data
        except Exception as err:
            print("Error occurd in class ScanHost function _scanner")
            print("Error message: ", err)


def main():
    sh = ScanHost()
    print(sh.scan(hosts="172.16.48.0/24"))


if __name__ == "__main__":
    try:
        main()
    finally:
        sys.exit()

 

判斷是否是Linux主機的原理是這樣的

由於Linux主機通常預設都會開啟ssh服務而且預設埠是22,所以telnet上去會出現紅色箭頭指向的內容。

擴充套件內容,當有了這些Linux主機後就可以遠端執行dmidecode命令來獲取更相信的伺服器硬體方面的資訊。這個功能在我的部落格中也有。

相關文章