by fanxiushu 2020-10-13 转载或引用请注明原始作者

开始之前,我们先来理解标题是什么意思。
这里所说的局域网内的所有设备通过代理上网,并不是在每台设备上安装某个代理软件然后再通过代理服务端来上网。
而是所有这些设备的网关IP设置到某个主机上,这样所有设备的网络数据都会转发到这个主机上。
而这个主机的软件再通过代理服务端转发所有这些设备的网络数据。
这个主机与NAT路由器很像,但是又与NAT路由器有不同:
一般的NAT路由器是外网网卡直接把局域网内所有设备的网络数据发送出去,通常需要两块网卡,一块外网侧,一块内网侧。
而这个作为代理的主机,则是把局域网内的所有设备的网络数据全部转发到另外一个作为代理的服务端机器上面,
然后这个代理服务端的机器才是作为真正实现NAT路由器转发网络数据。
通常这个代理主机并不需要两块以上的网卡,只需要能与代理服务端正常连接通讯就可以了。

这么解释可能也不大容易理解,因此最好以实例来说明。
我们以游戏加速为例,
假设我们在公司的或者家庭的局域网内,有一款很不错的Xbox或PS4游戏机,
但是奈何游戏的服务端网络通讯非常糟糕,游戏服务器在国外或者距离我们的城市太过遥远,数据响应很糟糕。
于是我们想到了使用游戏加速程序,加速程序的代理服务端机器在我们城市的机房中,速度自然很快,
同时代理服务端机器通过专线连接到真正的游戏服务器,速度自然也很快。
于是我们再在客户端安装游戏加速的客户端软件,这样就能顺利加速了。但是这里有个问题:
Xbox,PS4这些是专用的游戏机,不像PC那样可以随意安装游戏加速软件。
因此,该如何实现游戏机的游戏加速呢?
无法在Xbox或PS4上安装游戏加速程序,那就直接在网络路由器上打主意。我们把游戏机的网关IP直接设置到我们的代理主机上,
这样游戏机的所有网络请求全都转发到我们的代理主机上了,代理主机上的软件再把数据包转发到代理服务器上,
于是直接通过我们的代理主机就能实现Xbox,PS4等游戏机游戏加速了。
而且只要是在同一个局域网内,不管是什么网络设备(不管是手机,其他嵌入式设备,还是其他PC),只要设置他们的网关IP为代理主机。
所有的网络通讯都会自动转发到代理主机上。
这样大家都省事,也用不着在所有这些设备上专门安装游戏加速程序了。
不过这种做法也有个坏处:因为设置网关IP,是全局性的,所有程序的网络通讯都会走代理,这无疑增加了代理服务器的压力。
而且有些程序并不需要通过代理加速。

一般的游戏加速程序,或者V-P-N程序,都是在本机上安装相应的代理客户端软件,
然后把本机的应用程序的网络请求数据包转发到代理服务端上,从而实现网络数据加速的目的。
游戏加速程序的实现原理其实和一般的V-P-N程序原理基本一样。
中国境内对V-P-N限制比较严格,因此须遵守中国相关法律。
本文描述的内容,也比较容易迁移到普通V-P-N程序的实现上。
但是就比如菜刀是用来切菜的,如果非要用来行凶,谁也拦不住。

我们在实现游戏加速程序的时候,为了尽量避免被防火墙拦截,通常并不使用一些标准的代理协议,
比如IPSec,IKEV2, L2TP等,因为这些协议非常容易被防火墙识别,并且拦截。
因此,通常都是自定义的网络通讯协议,并且常常会封装到HTTPS/HTTP,FTP,DNS等这些防火墙不能拦截的协议中。

要封装实现自定义的通讯协议,拦截和处理IP数据包是最通用的做法。
我们知道TCP/IP有四层协议:
1,应用层,
2,TCP,UDP,ICMP等传输层
3,IP网际层
4,链路层
这里重点关注第三层:IP层。其实我们在其他层也能实现代理加速。
比如windows平台的LSP,就是在应用层拦截数据。再比如SOCKS5也是应用层代理协议。
但是应用层和传输层对网络数据的处理,都会存在一定得局限性。
链路层会牵涉到与网卡硬件相关的信息,比如MAC地址等。
只有在IP层,各种网络通讯数据都被打散成一个一个的IP数据包,且与具体的硬件无关。

如何拦截和处理操作系统中各个应用程序的网络IP数据包,各个操作系统有不同的做法,
通常都会牵涉到底层的驱动处理。除非是像iOS或Android专门提供了相关的应用层组件来拦截IP数据包。
windows中,使用WFP驱动来拦截处理IP数据包,
当然使用NDIS协议驱动或NDISFilter驱动也能处理IP数据包,
不过NDIS驱动是工作在链路层中,因此NDIS驱动中我们还得多进行一步操作,去掉链路层的信息。
在linux系统中,我们可以在应用层直接使用 PF_PACKET协议,
通过socket直接获取链路层数据包,然后再过滤掉链路层信息,留下IP数据包。
也可以在linux内核层,实现netfilter驱动拦截处理IP数据包。
反正方法很多,都能截获和处理IP数据包。

iOS和Android系统中,系统在应用层提供了专门的组件来截获和处理IP数据包。
如果没有专门的组件,我们也无法在iOS或Android系统中拦截处理IP数据包。
因为iOS和Android本身的限制,我们无法直接操作系统驱动层。
Android使用VpnService组件,来获取到某个app的IP数据包,然后我们的代理加速App程序中截获到IP数据包,
再封装一下发送到代理服务器上,代理服务器回复对应数据,然后我们的代理加速App程序再解封成IP数据包,
再通过VpnService传递给Android内核,Android内核再让这个IP数据包进入正常的IP通讯栈。
iOS系统中对应的组件则是 NEAppProxyProvider 和 NEPacketTunnelProvider,具体使用可查阅apple开发文档:
https://developer.apple.com/documentation/networkextension/app_proxy_provider
https://developer.apple.com/documentation/networkextension/packet_tunnel_provider

其实iOS和Android中对IP数据包的截获和处理大致都差不多,
当某个app程序的IP数据包进入真实网卡时候,如果确定需要拦截这个IP数据包,则会被转发到一个虚拟网卡中,
虚拟网卡驱动再把这个Ip数据包发送到应用层,
于是应用层的组件(Android的是VpnService,iOS对应的是 NEPacketTunnelProvider)就会接收到这个IP数据包,
于是我们的VPN的App程序再把数据包封装转发到代理服务器上。
接着从代理服务器接收到IP数据包,通过Android的VpnService 或iOS的NEPacketTunnelProvider组件把他发送到虚拟网卡中。
于是虚拟网卡把这个IP数据包投递到正常IP通讯栈中进行正常的传输处理。
这个是不是与我在讲述 WFP驱动的时候,把IP数据包转发到应用层来处理的做法很像!异曲同工之妙。
不同的是windows中我们必须非常麻烦的自己处理整套流程,iOS和Android都是帮我们封装好了的。
https://blog.csdn.net/fanxiushu/article/details/78221340  Windows7以上使用WFP驱动框架实现IP数据包截取(一)
https://blog.csdn.net/fanxiushu/article/details/78347137  Windows7以上使用WFP驱动框架实现IP数据包截取(二)

那如何实现主机代理,让局域网内的设备都能通过这个主机代理上网呢?
这个主机可以是windows系统,可以是linux系统,也可以是嵌入式linux(比如openwrt等路由器)。
但是排除iOS和Android系统,因为这两个系统并没有提供应用层组件来接收来自局域网的IP网络数据,
由于手机系统的限制(除非是特殊定制机器或root了的机器),我们也无法深入到iOS和Android的驱动层去拦截IP数据包。

正如上面描述的,linux系统中可以使用PF_PACKET的socket来获取IP数据包,也可以使用netfilter在驱动层获取IP数据包。
windows系统可以使用WFP驱动,或者NDIS驱动来获取IP数据包。
在这里也并不需要拦截IP数据包,所谓拦截,就是不再继续把IP数据包朝上层传输。
只需要获取到从局域网其他设备发来的IP数据包就可以,不用关心和担心是否这个IP数据包是否会再次被传递到上层会造成其他影响。
因此这里才可以直接使用NDIS协议驱动。
这个与实现NAT有点不同,NAT的外侧网卡必须做到拦截处理IP数据包,
否则会被上层通讯协议栈发个RESET什么的数据包来扰乱NAT处理流程。
当然使用NDISfilter驱动拦截不必要的IP数据包继续上传会更好,因为这样可以节省资源占用。
毕竟使用NDIS驱动需要过滤链路层信息,因此这里还是建议使用WFP驱动,同时WFP驱动也能做到拦截,不继续传递。
使用WFP驱动,也能同时一起处理本机的应用程序的代理加速。

如下连接:
https://blog.csdn.net/fanxiushu/article/details/87958656  NDIS协议驱动应用之(另类的NAT路由程序开发)
与本文需要实现的主机代理有点类同,但是上面链接里边实现的把局域网的IP数据包转成外网一侧的socket通讯,却是要复杂。
复杂在转化,尤其是对TCP的处理,我记得当时是实现了一个非常简单TCP的超时重传和组包的算法,
在局域网通讯良好的情况下,还能使用。但是在局域网丢包严重,无线信号差等情况下,TCP传输就会时常断线。
这主要是对TCP组包算法处理得太简单的原因。
好在本文我们只需要关心IP数据包如何传输就行了,不需要关心复杂的TCP组包算法。

我们可以直接在驱动内部处理数据包,然后再驱动内部封装成某个协议格式的数据包,
然后再在驱动里把数据包发送到代理服务器上。也就是整个过程,都可以在驱动内部完成。
但是这种做法对于要封装成复杂的通讯格式非常不利,比如我们想把IP数据包封装成 HTTPS,那就得在驱动里实现SSL加密算法。
我不清楚各个系统的驱动内核是否都提供了SSL接口函数,但是为了通用性,最好的办法是把OpenSSL移植到驱动中,
这。。。我可没移植过。
于是把IP数据包发送到应用层,然后再来进行各种封包,可能会更好。
但是正如以前的文章中阐述关于如何把windows中的虚拟网卡驱动,NDIS驱动等数据包发送到应用层来处理,都有一个问题:效率。
如果处理不好,效率会很低。效率低的时候,整个的传输带宽可能还不及千兆网卡的25%。
但是我们做游戏加速器,也并不是为了把传输数据包占满整个网卡带宽。
也就是根据具体情况来选择不同的做法,
为了能做各种协议格式的封装,同时对海量传输数据没啥要求,采用传输到应用层也是一个不错的选择。

首先抓取数据包,
正如在文章 “NDIS协议驱动应用之(另类的NAT路由程序开发)” 中描述的那样,
不管是linux系统,还是windows系统的NDIS还是WFP驱动,
我们经过漫长的各种处理之后,在应用层最终形成一个简单而又适用的专门截取IP数据包的接口函数集合:

void* iplayer_open (  .... /*可能的其他参数*/
                                     void (*recv_ip_packet_callback)(char* ip_packet_data, int data_len, void* param),
                                     void* param);
     void  iplayer_close (void* handle);
     int     iplayer_write (void* handle, char* ip_packet_data, int datalen);

iplayer_open是打开对应的驱动,返回void*类型的 handle,提供给下面两个函数使用。
recv_ip_packet_callback是接收到IP数据包的回调函数,已经滤除了发给本机的IP数据包,
剩下的就是局域网内其他设备发给本机进行中转传输的IP数据包。
iplayer_close关闭驱动。
iplayer_write是从代理服务器接收到回复的IP数据包之后,传输给驱动的接口函数。

其实做到了这一步,我们在代理主机客户端做的工作基本完成了一大半,剩下的就是如何封装成功各种协议,然后发给代理服务器了。
比如下面的伪代码,在回调函数中:
static void recv_ip_packet_callback(char* ip_packet_data, int data_len, void* param)
{
       void* https = pack_https_packet(ip_packet_data, data_len); ///封装成 https协议
       post_proxy_server(https); 发送到代理服务器
}
然后开启一个线程,接收服务端的数据:
void* thread(void*)
{
      while(1){
             void* https = recv_proxy(); ///从代理服务器接收封装成https的数据包
              unpack_ip_packet(https, ip_packet, &data_len ); 把https解封成IP数据包
             iplayer_write(handle, ip_packet, data_len);      IP数据包写到驱动中。
      }
}

以上,客户端就完成了,然后就是如何处理代理服务器端的事情了。
其实代理服务器端也并不是十分复杂,这里采用linux作为代理服务器端,因为linux系统有现成虚拟网卡驱动和现成NAT路由程序。
用不着再我们再去开发这两样东西。
首先在linux中创建好 tap虚拟网卡驱动,然后通过iptables命令设置 NAT路由,当然tap虚拟网卡是内网一侧,linux上真实网卡是外网一侧。
然后就是开发一个应用层程序,接收代理客户端发来的封装成https的数据包,再解封成IP数据包,然后发送给tap虚拟网卡驱动。
接下来的事情就全都是linux内核处理的事情,接着就是等待tap虚拟网卡的回应的IP数据包,然后再封装成https发给代理客户端。
于是整个过程就如此跑通了,原理够简单吧。

所以说本文描述的内容比起 “NDIS协议驱动应用之(另类的NAT路由程序开发)” 只会更为简单。

基于WFP等网络驱动实现局域网内所有设备通过代理上网相关推荐

  1. 基于WFP的windows驱动对TCP数据的抓取,修改以及注意事项

    基于WFP的windows驱动对TCP数据的抓取及修改 前言 目的 主要问题 步骤 一. WFP过滤TCP报文 WFP过滤层 二. 追加OPTIONS数据 TCP/IP数据报文格式 如何追加TCP头部 ...

  2. 移动设备如何上传文件到服务器上,局域网内移动设备快传文件

    原标题:局域网内移动设备快传文件 家里的移动设备越来越多,手机.平板等各式各样,而这些设备所使用的平台也各不相同,诸如Android.iOS.Windows等应有尽有.虽然每个平台都有着自己传输文件的 ...

  3. squid反向代理作为web前端内容缓存器及局域网内客户机通过代理服务器上网

    反向代理服务器有两种传输模式: 1.同步模式:(如:squid)用户发起请求,请求立即被转到后端的服务器,于是在浏览器和后端服务器之间就建立了一个连接,在请求完成前这个连接是一直存在的. 2.异步模式 ...

  4. android关闭或开启移动网络数据(关闭后,设备不可以上网,但可以打电话和发短信)...

    //android关闭或开启移动网络数据(关闭后,设备不可以上网,但可以打电话和发短信) public void setMobileDataEnabled(boolean enabled) { Con ...

  5. 台式计算机无法访问网络,台式机关机导致局域网内LAN设备无法连接网络

    本帖最后由 星空约翰 于 2019-1-15 00:28 编辑 2018.1.14更新: 测试了几天,似乎找错方向了,经历了绑定全部设备MAC,GEN10多次重装系统.重刷BIOS,不停更换GEN10 ...

  6. 【网络】如何扫描局域网内所有设备的ip和mac地址

    原文:https://www.jianshu.com/p/b2e68a5b88f2 cmd 输入: for /L %i IN (1,1,254) DO ping -w 2 -n 1 192.168.0 ...

  7. android 局域网 发现,局域网内android设备发现及通讯

    最近一个项目需要实现在局域网内android手机操控另一个没有显示屏的android设备(音箱),具体实现就是手机端向音箱端发送命令字符串,音箱端通过解析命令字符串来完成操作,而手机端也要实时显示音箱 ...

  8. 局域网内PC通过笔记本共享上网

    现实:PC.笔记本都通过网线接在局域网内,局域网无法上网:笔记本有无线网卡,可连WIFI上网. 现在想让PC通过笔记本来共享上网. 步骤: 1.笔记本开启DHCP.方法是开启"服务" ...

  9. 使用Spacedesk实现局域网内任意设备作为电脑拓展屏

    不管你是在做学术研究还是努力工作,看论文或者多个文档的时候都会觉得多个显示屏非常的舒适.但是如果只是偶尔才会有这样的需求,再买一台显示器显然不经济划算,在人手几乎三件套(手机.平板.电脑)的情况,如何 ...

最新文章

  1. 独家 | 一文带你上手卷积神经网络实战(附数据集学习资料)
  2. Agan的IT博客开张啦
  3. midi api java_Java声音api – 扫描MIDI设备
  4. 【Treap】[BZOJ 3224]Tyvj 1728 普通平衡树
  5. 周志華《機器學習》圖4.4和图4.9繪制(轉載+增加熵顯示功能)
  6. 12c oracle 修改内存_关于Oracle数据库12c 新特性总结
  7. windows 安装openssh服务端_Git神器| SourceTree安装使用教程
  8. 【Java进阶营】JAVA多线程基础学习二:synchronized
  9. HibernateAnnotation入门实例
  10. (七)lucene之中文检索和高亮显示以及摘要
  11. python必备入门代码-学习Python必备的八大知识板块,学好这些你就算入门啦~
  12. 5G组网-SANSA
  13. 汉语为主体的计算机网络环境,读书笔记 | 鲁川:汉语语法的意合网络 | 从网络到表层序列的生成...
  14. 台式计算机无线网经常掉线,台式机无线上网经常断网怎么办呢
  15. 网站视频链接自动提取下载
  16. 微信小程序获取手机号码(仅前端部分
  17. 华为OD机试 - 最短耗时(C++) | 附带编码思路 【2023】
  18. 微信网页授权获取用户昵称中文乱码
  19. sql compact 转mysql_如何将数据导入到 SQL Server Compact Edition 数据库中(五)
  20. 3D建模 UG8.0 32位安装过程

热门文章

  1. 画论81 戴熙《习苦斋题画》
  2. HP服务器Smart Storage Administrator 配置阵列
  3. 2019年全美数学建模竞赛(B题,重心法选址+类蚁群算法路径规划)
  4. Ubuntu和Windows10双系统下Ubuntu连不上网的解决
  5. C语言实现跨年烟花(烟花易冷)
  6. python练习5:输入三个整数 x,y,z,请把这三个数由小到大输出。
  7. java求职英文简历范本2篇_java开发英文简历范文.doc
  8. Swift 基础 UIFont, 字体, 斜体, 字体库的使用(源码)
  9. 使用第三方平台短信接口实现发送验证码
  10. 数据分析 - Basis Point(bp)