You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

网络Windows主机探测及主机名获取报错问题求助

解决你的Windows主机探测问题

我来帮你逐个解决遇到的几个问题:

1. 所有文件记录的主机名相同的问题

你代码里用的gethostname()是获取当前运行脚本的本机主机名,不是目标IP对应的主机名,这就是为什么所有文件里的名字都一模一样。你需要用gethostbyaddr(adr)来获取目标IP的主机名(不过你已经尝试了,但遇到了报错,我们后面解决这个问题)。

2. Socket导入方式的问题

当你用import socket时,需要通过模块名来调用里面的类和函数,比如socket.socket(AF_INET, SOCK_STREAM)而不是直接写socket(...);而from socket import *是把socket模块的所有内容导入到全局命名空间,所以可以直接用socket()。为了避免命名冲突,建议用import socket的方式,修改后的is_up函数应该是这样:

import socket

def is_up(adr):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(0.01)
    if not s.connect_ex((adr, 135)):
        s.close()
        return True
    else:
        s.close()
        return False

(顺便把返回值从1/0改成True/False,更符合Python的布尔值使用习惯)

3. gethostbyaddr报错[Errno 11004]的问题

这个错误是反向DNS解析失败导致的,常见原因有:

  • 目标Windows主机没有在DNS服务器上注册反向记录
  • 网络中的DNS服务器无法解析该IP对应的主机名
  • 目标主机的防火墙阻止了反向DNS查询请求
  • 虽然目标主机135端口开放(你的is_up检测的是135,这是Windows的RPC端口),但主机没有正确配置DNS

解决方法:

方法一:捕获异常,解析失败时显示默认值

我们可以先捕获解析失败的异常,给一个默认名称,比如:

try:
    hostname = socket.gethostbyaddr(adr)[0]
except socket.herror:
    hostname = "Unknown Hostname"

方法二:用SMB协议获取主机名(更可靠的Windows专属方式)

对于Windows主机,通过SMB协议获取主机名会比反向DNS更可靠,不过需要额外安装impacket库(执行pip install impacket即可),示例代码片段:

from impacket.smbconnection import SMBConnection

def get_windows_hostname(adr):
    try:
        smb_conn = SMBConnection(adr, adr)
        smb_conn.login('', '')  # 匿名登录,大部分Windows主机允许
        hostname = smb_conn.getServerName()
        smb_conn.logoff()
        return hostname
    except Exception as e:
        return f"Unknown ({str(e)})"

这个方法不需要依赖DNS,直接通过SMB协议获取主机名,成功率更高。

修改后的完整代码

结合上面的所有修复,这里是可以正常工作的完整代码:

import socket

ipa = '192.168.1.'

def is_up(adr):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(0.01)
    result = s.connect_ex((adr, 135))
    s.close()
    return result == 0

def get_hostname(adr):
    try:
        return socket.gethostbyaddr(adr)[0]
    except socket.herror:
        # 如果反向DNS失败,尝试用SMB(需要安装impacket)
        # 不需要的话可以直接注释掉下面的try-except块,保留返回"Unknown Hostname"
        try:
            from impacket.smbconnection import SMBConnection
            smb_conn = SMBConnection(adr, adr)
            smb_conn.login('', '')
            hostname = smb_conn.getServerName()
            smb_conn.logoff()
            return hostname
        except Exception as e:
            return f"Unknown Hostname ({str(e)})"

def main():
    for i in range(1, 256):
        adr = ipa + str(i)
        if is_up(adr):
            hostname = get_hostname(adr)
            # 使用with语句自动管理文件,避免资源泄漏
            with open(f"Machine {i}.txt", "w+") as f:
                f.write(f"Name: {hostname}\t- {adr}\n")
            print(f"在线主机: {adr} - {hostname}")

if __name__ == "__main__":
    main()

额外提示

  • 135端口可能被部分Windows主机的防火墙阻止,你可以尝试用ICMP ping来检测主机是否在线(需要管理员权限),或者用445端口(SMB)来检测,成功率可能更高。
  • 后续记录已安装应用的话,对于Windows主机,可以用WMI或者PsExec工具,不过需要目标主机开启WMI服务,并且你有对应的访问权限。

内容的提问来源于stack exchange,提问作者fread

火山引擎 最新活动