mRemoteNG 端口扫描(Port Scan)完全指南:网段探测、协议识别与批量导入连接
2026/9/23 23:23:49 网站建设 项目流程
  • 桌面应用
  • 网络

【免费下载链接】mRemoteNG

mRemoteNG is the next generation of mRemote, open source, tabbed, multi-protocol, remote connections manager.

项目地址:https://gitcode.com/gh_mirrors/mr/mRemoteNG
点击查看免费下载

mRemoteNG 内置的Port Scan功能(位于菜单 Tools > Port Scan,当前版本由mRemoteNG.Plugins.PortScan插件承载)提供了一种类似 nmap 的轻量端口扫描能力:它按指定 IP 范围逐主机探测 mRemoteNG 所支持协议的端口是否开放,随后将命中的主机按所选协议批量导入为连接,是初始化一批服务器连接配置的高效手段。阅读本文后,你将掌握 Port Scan 的完整操作流程、每个输入参数的含义与默认值、扫描结果的解读方式,以及批量导入连接背后的实现原理与代码路径。

Port Scan 是什么

Port Scan 面向"我要管理一批新主机,但不想逐个手工创建连接"的场景。官方文档(port_scan.rst)将其描述为:

The Port Scan feature (under Tools > Port Scan) is similar to a nmap port scan. It will scan a range of IP addresses and to determine if specific mRemoteNG supported protocols are active. Hosts can then be bulk imported into mRemoteNG.

核心价值有两点:

  1. 协议探测:扫描一个 IP 地址区间,判断哪些主机开放了 mRemoteNG 支持的协议端口(SSH、Telnet、HTTP、HTTPS、Rlogin、RDP、VNC 等);
  2. 批量导入:把扫描命中的主机直接转换成 mRemoteNG 连接节点,无需手工录入。

从当前仓库的实现看,该功能分两条代码路径:

  • 现代插件实现mRemoteNG.Plugins.PortScan项目):以IToolWindowPlugin形式注册,随插件体系分发,包含PortScanPlugin.csPortScanControl.csPortScanService.csPortScanHostResult.cs
  • 主程序内的经典实现mRemoteNG/Tools/PortScanner.csScanHost.cs,配合mRemoteNG/Config/Import/PortScanImporter.csmRemoteNG/Config/Serializers/MiscSerializers/PortScanDeserializer.cs完成扫描结果到连接树的序列化导入。

下文以当前仓库插件实现为主体展开,经典实现作为原理佐证。

启动 Port Scan

菜单入口与插件注册

按文档描述,通过菜单栏Tools > Port Scan启动。在插件化架构下,这个入口由 PortScanPlugin.cs 注册:

public sealed class PortScanPlugin : IToolWindowPlugin { public string Id => "mRp.PortScan"; public string DisplayName => Resources.GetString("PortScan", "Port Scan"); public Version Version => new(1, 0, 0); public Version MinimumHostVersion => new(1, 0, 0); public ToolWindowRegistration ToolWindow => new() { ContextMenuGroup = PluginContextMenuGroup.Import, ContextMenuText = Resources.GetString("ImportPortScan", "Import from Port Scan..."), Icon = Resources.GetImage("SearchAndApps_16x") as Image, MenuText = Resources.GetString("PortScan", "Port Scan"), PanelName = "General", ShowAsDocument = true, SortOrder = 100, WindowTitle = Resources.GetString("PortScan", "Port Scan"), }; ... }

要点:

  • 插件 ID 为mRp.PortScan,版本 1.0.0;
  • 工具窗口以文档形式(ShowAsDocument = true)显示,归属面板General
  • 除了 "Port Scan" 菜单项,还在导入相关上下文菜单组(PluginContextMenuGroup.Import)注册了 "Import from Port Scan..." 快捷入口;
  • 工具窗口的实际界面由 PortScanControl.cs 提供(CreateControl()返回该控件)。

界面组成

打开后,界面自上而下由三块区域组成(对应 PortScanControl.cs 中的TableLayoutPanel布局):

  1. 扫描参数输入区:First IP / Last IP / First Port / Last Port / "Default protocol ports only" 复选框 / Timeout(秒);
  2. 结果表格区:逐行展示每个主机的探测结果;
  3. 导入操作区:协议下拉框(Protocol to import)+ Import 按钮。

扫描参数详解

IP 范围:First IP 与 Last IP

输入扫描区间的起始 IP 与结束 IP,两个地址都会被IPAddress.TryParse校验,解析失败会提示 "Cannot start port scan."(见ScanButtonOnClick)。需要注意:

  • 仅支持 IPv4:地址展开逻辑在 PortScanService.cs 中,若地址族不是InterNetwork会抛出NotSupportedException("Only IPv4 ranges are supported.")
  • 顺序无关:内部会对起止地址取min/max后按数值顺序展开,无论你输入的顺序如何;
  • 区间大小决定扫描量ExpandAddresses会把起止 IP 转成 uint32 逐一遍历,例如192.168.1.1~192.168.1.254就是 254 个主机,每个主机还要依次做 Ping 与端口探测,区间越大耗时越长(文档原话:"Wait. Possibly a long time.")。

端口范围:First Port 与 Last Port

  • 输入框为NumericUpDown,取值范围1 ~ 65535
  • 插件默认值为22(First Port)与 5900(Last Port),即默认覆盖 SSH 到 VNC 的常用端口区间;
  • 代码对端口列表的构造逻辑(BuildPortList):取min(first, last)max(first, last)逐端口枚举;如果起始端口为 0,则退化为只扫描结束端口(start == 0start = end)。

文档提示(tip):"If you leave this at the default of 0 & 0, the test will be for the default protocol ports that mRemoteNG supports."(如果保持默认的 0 & 0,将只测试 mRemoteNG 支持的默认协议端口。)经典版 PortScanner.cs 中的行为与此一致:checkDefaultPortsOnly为真时只扫描 7 个默认协议端口。在插件版界面中,这一逻辑由"Default protocol ports only" 复选框显式承担——勾选后忽略端口输入框,只探测默认协议端口列表。

默认协议端口表

无论经典实现(PortScanner构造函数中内联的端口数组,端口取值来自 ScanHost.cs 中各协议默认端口)还是插件实现(PortScanService.cs 中的DefaultPorts),默认端口完全一致:

端口协议说明
22SSH来自ProtocolSSH1.Defaults.Port
23Telnet来自ProtocolTelnet.Defaults.Port
80HTTP来自ProtocolHTTP.Defaults.Port
443HTTPS来自ProtocolHTTPS.Defaults.Port
513Rlogin来自ProtocolRlogin.Defaults.Port
3389RDP来自RdpProtocol.Defaults.Port
5900VNC来自ProtocolVNC.Defaults.Port

当你勾选 "Default protocol ports only" 时,扫描范围就固定为这 7 个端口,扫描速度会显著加快。

Timeout(秒)

  • 取值范围1 ~ 60 秒,默认5 秒
  • 在插件实现中,界面值会被乘以 1000 转换为毫秒,同时用于Ping 超时TCP 连接超时Task.WhenAny(connectTask, timeoutTask),见 PortScanService.cs);
  • 经典版 PortScanner.cs 的构造函数默认timeoutInMilliseconds = 5000,同样默认 5 秒。

扫描流程:从点击 Scan 到结果就绪

完整执行路径如下(对应ScanButtonOnClickPortScanService.ScanAsync):

  1. 校验参数:解析起止 IP,失败则通过_pluginContext.Messages.Warning提示 "Cannot start port scan.";
  2. 重置状态:清空结果绑定列表、进度条归零,扫描按钮文字变为"Stop"(再次点击即取消扫描);
  3. 展开地址与端口ExpandAddresses生成 IP 列表,BuildPortList生成端口列表;
  4. 逐主机探测ScanHostAsync):
    • 先发送ICMP PingPing.SendPingAsync,超时即上文的 Timeout)判断主机是否存活;
    • Ping 失败 → 该主机所有端口记为关闭,协议标记全部为 false(经典实现中对应SetAllProtocols(false)ClosedPorts.AddRange(_ports));
    • Ping 成功 → 先做DNS 反向解析Dns.GetHostEntryAsync)拿到主机名,再对每个端口做TCP 连接测试TcpClient.ConnectAsync),连接成功即为开放端口;
  5. 实时刷新:每扫完一台主机,通过AddScannedHost回调把结果追加进表格并推进进度条(进度条总数为主机数);
  6. 完成通知:全部主机扫描完毕后,通过消息系统提示 "Port scan complete.";中途点击 Stop 则抛出OperationCanceledException,提示 "Port Scan cancelled."。

单端口探测的判定核心(PortScanService.cs):

private static async Task<bool> IsPortOpenAsync(IPAddress address, int port, int timeoutInMilliseconds, CancellationToken cancellationToken) { try { using TcpClient client = new(); Task connectTask = client.ConnectAsync(address, port); Task timeoutTask = Task.Delay(timeoutInMilliseconds, cancellationToken); Task completedTask = await Task.WhenAny(connectTask, timeoutTask); if (completedTask != connectTask) return false; // 超时未连上 await connectTask; return client.Connected; // 成功建立 TCP 连接 } catch { return false; } }

协议标记的端口判定

每个主机会根据端口探测结果打上对应协议标记(PortScanService.cs):

端口置位属性
22Ssh
23Telnet
80Http
443Https
513Rlogin
3389Rdp
5900Vnc

非默认端口即使开放,也只会出现在 Open Ports 列表里,不会影响协议标记位。

结果表格解读

扫描结果由 PortScanHostResult.cs 承载,表格列定义在ConfigureGridColumns中:

含义取值
Hostname / IP主机显示名优先显示 DNS 反解出的主机名,解析失败则显示 IP
SSH / Telnet / HTTP / HTTPS / Rlogin / RDP / VNC各协议端口是否开放Yes / No
Open Ports开放的端口列表逗号分隔,如22, 3389
Closed Ports关闭的端口列表逗号分隔

几个值得注意的细节:

  • 结果表格只读(ReadOnly = true)、支持整行多选MultiSelect+FullRowSelect),方便一次选中多台主机导入;
  • "Open Ports" 与 "Closed Ports" 列宽 160px,协议列宽 60px;
  • 经典实现 ScanHost.cs 中同样提供了OpenPortsNameClosedPortsNameHostIPorName等展示属性,还实现了ToString()输出各协议标记的汇总字符串。

批量导入扫描结果

操作方式

扫描完成后,按文档步骤操作:

  1. 在结果表格中选中需要导入的主机行(可多选);
  2. 在底部Protocol to import下拉框中选择目标协议(SSH、Telnet、HTTP、HTTPS、Rlogin、RDP、VNC、ARD);
  3. 点击Import

导入时的核心逻辑(ImportButtonOnClick):

  • 只导入勾选协议对应的端口确实开放的主机:SupportsProtocol会把所选协议 ID 映射到主机的协议标记上,例如选择 SSH 只导入host.Ssh == true的主机;注意ARD 协议复用 VNC 标记PluginProtocolIds.Ard => host.Vnc);
  • 生成PluginConnectionRequest列表:Hostname取主机显示名(优先主机名),NameHostNameWithoutDomain(主机名的第一段,如server1.domain.comserver1,若反解失败则直接用 IP);
  • 通过_pluginContext.Connections.ImportConnections(requests)把请求交给插件上下文执行导入;
  • 未选择任何主机或所选主机均不支持该协议时,会给出相应警告("No scan results are selected for import." / "The selected hosts do not expose the chosen protocol.")。

底层:如何变成连接节点

主程序侧的导入链路由 PortScanImporter.cs 与 PortScanDeserializer.cs 构成:

  1. PortScanImporter持有目标ProtocolType,调用PortScanDeserializer.Deserialize(hosts)
  2. 反序列化器为每个符合条件的主机创建ConnectionInfo
ConnectionInfo newConnectionInfo = new() { Name = host.HostNameWithoutDomain, // 显示名:主机名第一段或 IP Hostname = host.HostName, // 主机名(含域)或 IP Protocol = finalProtocol }; newConnectionInfo.SetDefaultPort(); // 自动补齐该协议的默认端口
  1. 生成的连接节点被添加到当前选中的目标容器(连接树文件夹)下,完成批量导入。

其中协议映射在PortScanDeserializer.ImportScannedHost的 switch 中:SSH2 ↔host.Ssh、Telnet ↔host.Telnet、HTTP ↔host.Http、HTTPS ↔host.Https、Rlogin ↔host.Rlogin、RDP ↔host.Rdp、VNC/ARD ↔host.Vnc,其余协议类型一律跳过(protocolValid = false)。

测试验证

仓库自带的单元测试 PortScanDeserializerTests.cs 验证了导入行为:给定ScanHost("10.20.30.40")HostName = "server1.domain.com"Ssh = true,以ProtocolType.SSH2反序列化后断言:

  • 导入连接的Name等于server1DisplayNameImported);
  • Hostname等于server1.domain.comHostNameImported);
  • Protocol等于SSH2ProtocolImported)。

这三个断言精确对应了"批量导入"的产物形态:主机名精简为显示名、完整主机名作为连接地址、协议按探测结果落定

使用建议与已知限制

综合文档与源码,实操中需要注意:

  • 扫描耗时可观:扫描是逐主机串行执行的(Ping → DNS 反解 → 逐端口 TCP 探测),主机数与端口数越多耗时越长,文档也明确提示 "Wait. Possibly a long time."。若只需确认协议端口,建议勾选 "Default protocol ports only" 并保持合理超时;
  • 随时可停止:扫描期间 Scan 按钮变为 Stop,点击即取消(插件实现通过CancellationTokenSource取消,经典实现通过Ping.SendAsyncCancel取消),取消后已扫描的主机结果会保留在表格中;
  • 仅 IPv4:地址展开只支持InterNetwork(IPv4)地址族,IPv6 范围会直接报错;
  • 依赖网络环境:Ping 与 TCP 探测都会受到防火墙策略影响——主机禁 Ping 会被判为"不可达",从而跳过端口探测并全部标记为关闭;扫描机与目标机之间的访问控制(ACL)会直接影响结果的准确性;
  • 协议端口映射固定:只有探测到默认协议端口(22/23/80/443/513/3389/5900)才会点亮对应协议标记;自定义端口即使开放也只计入 Open Ports 列;
  • 导入即建连接:导入会直接在当前连接树容器下创建连接节点并调用SetDefaultPort()补齐端口,之后可按需修改各连接的详细配置。

相关资源

  • 功能文档:port_scan.rst
  • 导入导出相关说明:import_export.rst
  • 插件实现:PortScanPlugin.cs、PortScanControl.cs、PortScanService.cs、PortScanHostResult.cs
  • 主程序经典实现:PortScanner.cs、ScanHost.cs
  • 导入链路:PortScanImporter.cs、PortScanDeserializer.cs
  • 测试用例:PortScanDeserializerTests.cs
  • 桌面应用
  • 网络

【免费下载链接】mRemoteNG

mRemoteNG is the next generation of mRemote, open source, tabbed, multi-protocol, remote connections manager.

项目地址:https://gitcode.com/gh_mirrors/mr/mRemoteNG
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询