基于WinINet实现的网络库中有趣知识点收集(5) - 常见Windows应用程序面对代理服务器的不同策略

        本文旨在以精简而易懂的方式介绍应用程序与代理服务器之间的关系。虽然这个话题具有许多细节,但笔者尝试以清晰的思路引领读者轻松通读。文章首先从主流应用程序处理代理连接的常见行为入手,帮助读者建立初步认识。然后探讨原理,并点出了实现代码的关键细节。最后还会开阔视野,涉及一些相关的知识点,以期引发读者更大的兴趣和理解。

1. Windows 常见主流应用处理代理连接的行为

图1 Windows10代理设置界面

        

        图1是 Windows10 代理设置界面,我们先从最简单的代理设置【红框1】开始。假设你所在的组织为了测试管理网络的有效性,管理员给了你一个IP地址(也可能是域名)和端口号 ,并且告诉你这是一个不需要用户名和密码认证的代理服务器。接着你在 Winows10 代理设置界面填上并保存后,发现对你用各种浏览器上网(接下来将选取Edge, Chrome 和 Firefox 进行比较),用微信和QQ聊天,用腾讯会议或者 Zoom 参加网络会议似乎并没有什么影响。但是如果你不小心输错了地址或者端口,以上应用程序的行为可就大相径庭了?

图2 假设误填了错误的地址或者端口

表-1 常见应用程序对于访问代理失败的不同行为表现
应用程序结果
Edge
图3 Edge浏览器无法访问网络
Chrome
图4 Chrome浏览器无法访问网络
Firefox
图5 Firefox浏览器可以访问网络
微信
图6 微信无法访问网络
图7 微信支持手动设置代理
QQ
图8 QQ无法访问网络
图9 QQ支持更全面的手动设置代理
腾讯会议
图10 腾讯会议无法访问网络
Zoom
图11 Zoom无法访问网络
表2 解释各应用程序不同行为的原因
行为截图原因解释
图12 Edge浏览器代理设置
图13 Chrome浏览器代理设置

  • Edge 浏览器的代理设置非常简单,完全跟随操作系统的设置,所以当你在操作系统代理设置界面误填了代理信息之后,必然会影响到 Edge 对网络的访问。
  • Chrome 浏览器亦是如此。部分原因是因为 Edge 浏览器和 Chrome 浏览器的内核相似。Edge 浏览器从 Microsoft Edge 版本 79 开始转向使用 Chromium 内核,该内核与 Google Chrome 使用的 Blink 内核相同。这意味着 Edge 和 Chrome 在某些方面具有类似的特性和行为,包括代理设置的跟随操作系统设置。
图14 Firefox浏览器代理设置
  • Firefox 浏览器在 Windows 上具有独立的代理设置,它将不会自动使用操作系统的代理设置。这就是表-1中为什么唯独 Firefox 能继续打开网页的原因。
  • 对于开发人员、网络管理员或测试人员来说,独立的代理设置在调试和测试代理服务器时非常有用。用户可以在 Firefox 中设置特定的代理服务器,以便验证代理服务器的配置和行为。
  • 独立的代理设置是 Firefox 与其他浏览器之间的一个差异化亮点,并在特定用户群体中得到高度赞赏。
图15 微信的手动代理设置界面
  • 微信比较“鸡贼”,要么禁用代理跟随系统设置,要么自己手动设置代理,所以当系统代理设置有误的时候,微信倒是可以单独设置自己的代理。
图16 QQ的手动代理设置界面
  • QQ在网络设置里同样可支持单独设置代理,而且还添加了一个测试按钮,可谓相当人性化了。
至于腾讯会议和 Zoom,笔者至少没有在登录界面发现可以单独设置代理的入口。

         至此,可以发现 Windows 桌面应用程序对于代理设置大致可分为两类。一类是“躺平型”,就是完全跟随系统的代理设置。另一类是“进取型”,在跟随系统代理设置之外,还支持单独设置代理。

2. 原理和相关代码介绍

图17 代理设置界面对应的注册表项

        如图17所示,Windows10 系统的代理设置最终会被记录在注册表HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings 下具体的项目里。而应用程序本质上就是根据代码读取相应配置来创建和初始化网络连接的。

HINTERNET InternetOpen(
  _In_ LPCTSTR lpszAgent,
  _In_ DWORD   dwAccessType,
  _In_ LPCTSTR lpszProxyName,
  _In_ LPCTSTR lpszProxyBypass,
  _In_ DWORD   dwFlags
);

    InternetOpen 是 Windows 操作系统提供的一个函数,属于 WinINet API(Internet Services API)的一部分。WinINet API 允许应用程序通过标准的 Internet 协议(如 HTTP、HTTPS、FTP 等)来进行网络通信。InternetOpen 函数的作用是初始化一个应用程序与 Internet 之间的通信会话。

参数说明:

  • lpszAgent:代理的用户代理字符串,用于标识应用程序。
  • dwAccessType:访问类型,可以是 INTERNET_OPEN_TYPE_DIRECT(直接访问互联网)、INTERNET_OPEN_TYPE_PROXY(通过代理访问互联网)、INTERNET_OPEN_TYPE_PRECONFIG(使用系统的预配置设置来确定网络连接的类型)等。
  • lpszProxyName:代理服务器的名称(如果使用代理)。
  • lpszProxyBypass:指定不使用代理的地址(如果使用代理)。
  • dwFlags:附加选项标志。

    InternetOpen 函数的调用将返回一个 HINTERNET 句柄,该句柄可以在后续的网络操作中使用。例如,您可以使用 InternetConnect 函数建立到特定服务器的连接,然后使用 HttpOpenRequest 函数来发起 HTTP 请求。

#include <wininet.h>

int main() {
    HINTERNET hInternet;

    hInternet = InternetOpen(L"MyApp", INTERNET_OPEN_TYPE_PROXY, L"proxy-server:port", NULL, 0);
    hInternet = InternetOpen(L"MyApp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    hInternet = InternetOpen(L"MyApp", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    if (hInternet) {
        // 使用 hInternet 进行网络操作,比如使用 InternetConnect、HttpOpenRequest 等函数
        // ...
        
        InternetCloseHandle(hInternet); // 关闭会话句柄
    }
    
    return 0;
}

        所以 Windows 应用程序如果使用的是 WinINet API 的话,“躺平型”程序一般会将“访问类型”dwAccessType 参数设置为 INTERNET_OPEN_TYPE_PRECONFIG,即跟随系统的代理设置。而“进取型”程序则在需要的时候会根据用户输入的代理地址和端口,将 dwAccessType 参数设置为 INTERNET_OPEN_TYPE_PROXY 来初始化通信会话。大家可以脑补一下以上各种应用程序在处理代理时大概是一个什么样的业务逻辑。

3. 总结

3.1 代理设置的其他类型

        现在让我们再来回顾和比较一下 “图1 Windows10代理设置界面” 和 “图14 Firefox浏览器代理设置” 的一些异同。如果你使用过比 Windows10 更早的一些操作系统,你会发现在过去的 Windows 版本中,也是和图14中 Firefox 一样,需要分别配置 HTTP Proxy、HTTPS Proxy 和 SOCKS Host,因为不同的协议可能需要不同的代理服务器设置。然而,Windows 10 引入了一个名为“统一设置”(Unified Settings)的功能,旨在简化代理设置,使其更加直观和用户友好。在 Windows 10 中,用户只需在“网络和互联网”设置中配置一个统一的代理服务器,而不再需要区分 HTTP、HTTPS 和 SOCKS 协议的代理设置。这个统一设置将应用于所有协议,而不再需要为每个协议分别配置。这种改变的目的是为了提供更加简化的用户体验,减少用户配置的复杂性,并使代理服务器设置更加一致和易于管理。然而,这也可能导致一些高级用户或特定需求的用户可能无法针对不同的协议进行定制化的代理设置。

        图1【红框2】部分是用来填入一些不希望应用代理的网络地址,类似与一个白名单的作用。图14 中 "No proxy for" 也是起到相同的作用。

        图1【红框3】部分 "Proxy automatically detect settings"(自动检测代理设置)是一种自动配置代理服务器的方式,它基于 Web 代理自动配置协议(Web Proxy Auto-Discovery Protocol,简称 WPAD)。通过这种方式,客户端可以自动发现本地网络中是否存在代理服务器,并获取代理服务器的配置信息。图14 中 “Auto-detect proxy settings for this network” 也是起到相同的作用。

        图1【红框4】部分 “Use setup script”(使用设置脚本),这种方式允许您为代理配置指定一个自动代理脚本(通常是 PAC 文件,Proxy Auto-Configuration)。PAC 文件是一个包含 JavaScript 代码的文件,可以在其中根据不同条件动态决定是否使用代理以及如何配置代理。客户端会定期下载并执行这个 PAC 文件,根据其中的逻辑来自动配置代理。与其类似的是图14中 “Automatic proxy configuration URL”,这种方式允许您直接指定一个包含代理配置信息的 URL。客户端会从这个 URL 下载代理配置信息并应用。与 PAC 文件不同,这种方式不涉及脚本执行,而是直接使用下载的配置信息来设置代理。当然,无论是脚本还是URL,通常都是你所在组织的网络管理员为你提供的。而且更多的时候,你并不需要手动去填写,而是在发给你的电脑上已经预先填写过并且不可更改。

        图1【红框5】部分涉及到另一个通常不太被注意到的知识点,但正是这个知识点却从另一个角度揭示了真实世界网络的复杂性。Windows 系统下代理的设置为什么不会影响到VPN连接呢?因为代理服务器是位于客户端和目标服务器之间的中间服务器,用于转发网络请求和响应,其通常工作在 OSI 模型的应用层。当你在 Windows 中设置代理服务器,实际上是告诉操作系统在发出网络请求时通过指定的代理服务器进行中转。代理服务器通常用于访问互联网资源、控制访问权限、进行网络监控等。代理设置一般只影响通过特定网络协议(例如HTTP、HTTPS)发送的流量。

        而虚拟专用网络(VPN)是一种用于建立安全连接的技术,它可以通过加密和隧道化将您的计算机连接到远程网络,就像您直接连接到本地网络一样。VPN 通常用于访问远程资源、保护您的数据传输安全、隐藏真实 IP 地址等。通过 VPN 连接,您的计算机会成为远程网络的一部分,所有通过 VPN 的流量都会通过 VPN 隧道发送,而不是通过您的本地网络。由于代理设置和 VPN 连接具有不同的作用和机制,它们通常是独立的。这就是为什么您在设置代理后,可能不会影响 VPN 连接的原因。VPN 连接将所有流量通过 VPN 隧道发送,而不会受到操作系统的代理设置的影响。这样可以确保 VPN 连接的隧道安全性和完整性,不会受到代理服务器的影响。

        例如,笔者经常在连接了 VPN 的电脑上运行 Fiddler 软件用于调试和分析网络流量,Fiddler 本质上就是在电脑本地创建了一个特殊的代理服务器,所以 VPN 的流量不会被 Fiddler 捕捉到,就是因为 VPN 在操作系统的网络协议栈底层建立了一个加密的隧道,将网络流量直接发送到 VPN 服务器,绕过了本地代理服务器。

        与 VPN 类似还有 Windows Remote Desktop Connection,即远程桌面连接。你会发现当你在一台被通过远程桌面连接的电脑上运行 Fiddler 的时候,你与远程电脑之间的网络连接也不会被 Fiddler 捕捉到。这是因为 Windows 远程桌面连接使用了一种特殊的协议(RDP 协议)来建立远程连接,该协议通常在操作系统的较低层次进行操作,以实现远程控制,使得一般的代理工具如 Fiddler 难以直接捕捉到其产生的流量。

        笔者还曾经发现即使在本机设置了代理,另一款著名的软件 TeamViewer 的连接不受影响,可能是因为 TeamViewer 使用了自己的网络通信协议和通道,而不依赖于操作系统的代理设置。TeamViewer 建立的连接可能是通过 TeamViewer 自己的服务器中转的,而不是通过操作系统的代理服务器。因此,即使设置了代理服务器,TeamViewer 仍然可以建立其自己的连接。

        所以对于这些更底层应用的网络数据,就需要使用更专门的网络抓包工具,如 Wireshark,以捕捉底层的网络数据包。

3.2 产品研发阶段如何对待代理测试

  • 明确测试范围:确定需要测试的代理设置和情景。例如,是否涉及不同类型的代理(HTTP、HTTPS、SOCKS等)?是否需要测试绕过规则?是否需要验证代理的安全性和隐私保护?

  • 设置代理环境:在测试环境中设置不同的代理服务器,包括各种类型的代理和绕过规则。确保代理服务器能够模拟真实世界中的各种网络情况。笔者在本文中只举例了最简单的无需认证的代理连接,以及 Fiddler 所模拟的本地代理调试环境。在真实的企业级代理环境中,种类繁多。尽可能利用真实的代理环境进行端到端的测试能够取得最好的效果。然而,在实际情况下,很难获得客户提供代理环境供调试使用。因此,在代码中添加详细的日志输出变得尤为重要。至少,一旦客户提交日志,工程师能够快速定位问题,并提供修复方案。这样能够极大地缩短故障排查时间,确保问题得到及时解决。

  • 编写测试用例:针对不同的代理设置,编写测试用例来验证应用程序在这些设置下的行为。测试用例应涵盖代理的启用、禁用、更改以及绕过规则等方面。

  • 代理配置验证:通过编程或手动方式,在应用程序中配置不同的代理设置。这可以涉及修改应用程序的代理配置文件、通过 API 进行代理设置,或者使用开发者工具进行配置。

  • 错误处理测试:测试应用程序在代理设置发生错误或异常情况下的表现。例如,如果代理服务器不可用或配置错误,应用程序是否能够正确处理?

  • 性能测试:在代理设置下进行性能测试,确保代理不会影响应用程序的性能和响应时间。

  • 记录结果:记录每个测试用例的结果,包括在不同代理设置下的成功和失败情况。标记问题并记录详细信息,以便后续解决。

  • 修复和优化:根据测试结果,修复和优化应用程序,确保它在各种代理设置下正常运行。

  • 定期回归测试:随着应用程序的开发和变更,定期进行代理测试,以确保代理相关的功能持续正常工作。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值