网络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




