引子
之前我写过一个 Socks5 代理 demo, 但是其并不能实现全局流量转发, 有些不支持 socks5 转发的软件就不能使用这种方式, 碰巧有个不可明说的项目需要做到这一点, 于是就针对全局流量转发做了一点研究, 首先提到流量转发, 可能是游戏打得比较多, 第一印象是网游加速器, 而目前的网游加速器大部分都有几个模式, 问了某个带佬后, 大致明白这几个模式分别是虚拟网卡 (Tun/Tap),Lsp,WFP 等方式, 而传统 HTTP 代理, 则会用到 Proxifier. 下面分别对这几种方式进行说明:
HTTP 代理(Proxifier)
HTTP 代理比较特殊, 因为很多浏览器插件(就像我使用的 SwitchyOmega) 或者浏览器本身就支持 Socks5, 但是对普通用户来说, 你不能奢望他们使用的浏览器恰好支持, 况且即使支持, 也不一定能指望他们会设置.
一般浏览器的代理选项默认会选择系统代理 (IE 代理), 这代理 模式虽然没说, 但是查阅还是可以知道只支持 HTTP 代理, 而我们要做的就是把 Socks5 转成 HTTP.
一般业内使用的是 Proxifier 比较多, 比如出名的 SS/SSR 之类.
Proxifier 有两种版本, 一个是需要安装的, 一个是不需要安装的 Portable Version, 两种原理是不一样的.Portable Version 使用的是 hook 技术, 使用 SetWindowsHookEx 将 dll 注入到目标进程, 然后该 dll 来 hook WinSock 相关的函数; 安装版的是用的 LSP(Layered Service Provider)技术, 这个技术已经被微软给废弃了, 因为不安全
因为 Proxifier 启动时可以通过赋给启动参数 - c 来让其调用配置文件, 所以在这个文件中对其进行配置, 比如, 在我这个项目中, 将 SSR 流量转发为 HTTP 代理的方式如下:
ConfFullPath = $"{Environment.CurrentDirectory}\\{ConfName}";
string ConfStr = new StringBuilder().
AppendN($"listen-address {LocalAddress}:{Socks5LocalPort}").
AppendN("toggle 0").
AppendN("show-on-task-bar 0").
AppendN("activity-animation 0").
AppendN($"forward-socks5 / {LocalAddress}:{SSRLocalPort} .").
AppendN("max-client-connections 4096").
Append("hide-console").
ToString();
if (File.Exists(ConfFullPath)) { File.Delete(ConfFullPath); }
using (FileStream ConfFile = File.OpenWrite($"{Environment.CurrentDirectory}\\{ConfName}"))
{
ConfFile.Write(ConfStr.ToBytes(), 0, ConfStr.ToBytes().Length);
}
Instance = new Process
{
StartInfo =
{
FileName = Path.GetFullPath("Privoxy.exe"),
WorkingDirectory = Environment.CurrentDirectory,
Arguments = $"-c {ConfName}",
CreateNoWindow = true,
UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Hidden
}
};
由此对 Instance 进行 Start 操作后 Privoxy 就会将参数的{LocalAddress}:{SSRLocalPort}
转发到对应的{LocalAddress}:{Socks5LocalPort}
.
Tun/Tap(虚拟网卡)
这个技术貌似是从 Openvpn 发展过来的,, 因为其 Tap-Windows 可以剥离出来使用, 所以但是很快被应用到其它场景之上, 很多强大的项目都是基于此, 例如 SSTAP 和相对比较新的 Netch, 使用它的话需要提前安装虚拟网卡, 也有 Tun2Socks 这种项目对其整个驱动进行封装, 方便调用.Netch 中是首先将虚拟网卡权重调到最高, 而我项目中, 则是用的路由表的方式, 首先将系统网卡的跃点修改到 150, 然后将代理服务器的走系统网卡, 再添加一条路由表将 Tun 网卡跃点修改为 20(只要 Tun 网卡跃点比系统网卡低就行). 代码如下:
public Tun2(string ServerHost)
{
_savedServer = ServerHost;
Instance = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = Path.GetFileName("tun2socks.exe"),
Arguments = $"-proxyType socks -proxyServer {LocalAddress}:{SSRLocalPort} -tunAddr 10.0.20.2 -tunGw 10.0.20.1 -tunMask 255.255.255.0 -tunDns 223.5.5.5,8.8.8.8 --fakeDns",
CreateNoWindow = false,
/*RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,*/
WindowStyle = ProcessWindowStyle.Hidden
}
};
Configure();
//修改跃点
bool t = ChangeRoute("0.0.0.0", 0, AdpGateway.ToString(), AdpIndex, 150);
//添加路由
bool b = CreateRoute(_serverAddresses[0].ToString(), 32, AdpGateway.ToString(), AdpIndex, 20);
Console.WriteLine(b);
}
public override void Start()
{
Instance.Start();
bool c = CreateRoute("0.0.0.0", 0, "10.0.20.1", TunTapIndex, 50);
Console.WriteLine(c);
}
WFP(Windows Filtering Platform -- Windows 筛选平台)
这个模式是由 Microsoft 在废弃上文中说到的 Lsp 技术中后开发的:
WFP 维基百科
Windows 筛选平台(Windows Filtering Platform,缩写 WFP;也译 Windows 过滤平台)是微软操作系统中的一套系统服务和应用程序接口,于 2006 年至 2007 年在 Windows Vista 中首次引入。它允许应用程序绑定到包处理环节,过滤下一代 TCP/IP 协议栈的流水线。它提供集成通信等功能,管理员可以将其配置为在每个应用程序的基础上调用处理逻辑。微软预期 WFP 将被防火墙及其他数据包处理或连接监控组件使用,如杀毒软件和家长控制软件。另外,WFP 也被用于实现网络地址转换(NAT)和存储 IPSec 策略配置。
不过这个东西太复杂了, 还得写内核驱动, 好在有开源项目对这个进行了封装, 可以直接调用接口
WinDivert 2.2: Windows Packet Divert
这个项目很强大, 可以拦截任意的网络封包并进行修改或者转发.
除此之外, 还有相对商业化, 闭源且收费的
Network filtering toolkit
比起 WinDivert, 它在多平台和多语言上都有相应的组件. 但和 Tun2 一样, 它也需要事先安装驱动.
值得一提的是,Netch 的 WFP 模式用的驱动就是 Windivert 的 Demo 版本驱动, 所以有 1000000 个连接的限制——虽然可以通过卸载重装实现清零操作.
由于对此研究不够, 所以并没有引用在自己项目中. 具体运用可以参考 Netch.