前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >移动/PC客户端流量拦截与转发

移动/PC客户端流量拦截与转发

原创
作者头像
doudouhe
发布2021-12-01 17:01:19
4.9K3
发布2021-12-01 17:01:19
举报
文章被收录于专栏:SDP零信任SDP零信任

各种VPN客户端实现都离不开流量拦截与转发,那么各个客户端如何拦截流量,以及转发给指定的安全通道就成为了各个客户端所面临的重要问题。首先看下图:

虚拟网卡拦截流量原理
虚拟网卡拦截流量原理

启动VPN一般流程为建立虚拟网卡,配置虚拟网卡IP、MTU、修改路由表,配置系统DNS,之后操作虚拟网卡文件描述符,拦截用户指定的流量进行转发。

先说移动端:

//////////////////////////////////Android//////////////////////////////////////

Android 客户端流量拦截,主要依赖VpnService类服务拦截流量,其本质是建立了一个虚拟网卡”/dev/tun“文件,可在启动网卡建立连接前设置路由表,分包规则等。

Intent intent = VpnService.prepare(this);

StartActivityForResult(intent,0) //启动VPN申请权限

VpnService.Builder builder = new VpnService.Builder();

builder.addAddress(VPN_ADDRESS, 32);//vpn网卡的ip builder.addRoute(VPN_ROUTE, ROUTE_PREFIX);//设置路由规则

builder.setMtu(15000);//数据超过多少之后分包

vpnInterface = builder.setSession(app_name).setConfigureIntent(pendingIntent).establish();

FileDescriptor vpnFileDescriptor=vpnInterface.getFileDescriptor(); //获取文件描述符

拿到设备的文件描述符之后,就可以读取网卡拦截到的所有流量

//////////////////////////////////IOS/////////////////////////////////////

IOS 客户端流量拦截,Apple提供了 NetworkExtension 框架,让开发者可以在iOS、Mac os中进行VPN开发。iOS中的VPN开发分为 个人VPN 和 非个人VPN 开发。个人VPN开发比较简单,可以直接使用系统提供的IPSec、IKEv2协议来进行VPN连接。而在iOS9之后,Apple开放了新的api,可以让开发者开发自己的私密协议的VPN。

个人VPN主要依赖 NEVPNManager 类来进行开发,NEVPNManager 用于创建和管理VPN配置并控制最终的VPN隧道连接。参考地址:https://developer.apple.com/reference/networkextension/nevpnmanager 。

然而我们在实际的开发中往往需要开发安全程度更高的私密协议的VPN,以满足客户需求,这就需要用到NetworkExtension框架的另外一个类 NEPacketTunnelProvider,利用该类建立虚拟网卡拦截流量。

NEPacketTunnelProvider,是真正的 vpn 核心代码。项目中 PacketTunnelProvider 是其子类,并且以下两个方法必须实现。

/////////////////////////////////开启隧道//////////////////////////////////////////////////

- (void)startTunnelWithOptions:(NSDictionary<NSString *,NSObject *> *)options completionHandler:(void (^)(NSError * _Nullable))completionHandler {

    [self addObserver:self

           forKeyPath:@"defaultPath"

              options:0

              context:NULL];

    if (!_tmfPacketTunnel) {

        _tmfPacketTunnel = [[TMFPacketTunnel alloc] initWithData:self];

    }

    NETunnelProviderProtocol *protocol = (NETunnelProviderProtocol*) self.protocolConfiguration;

    [_tmfPacketTunnel startTunnelWithOptions:protocol completionHandler:completionHandler];

}

/////////////////////////////////停止隧道//////////////////////////////////////////////////

- (void)stopTunnelWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler {

    // NEProviderStopReasonUserInitiated:用户主动断开或切换了别的VPN

    // NEProviderStopReasonSuperceded:被其他VPN抢占

    if (_tmfPacketTunnel) {

        [_tmfPacketTunnel stopTunnelWithReason:reason completionHandler:completionHandler];

    }

}

这一步就只做了一件事情: 将配置信息传给系统, 也就是调用setTunnelNetworkSettings方法, 完成建立 VPN 的过程.

   [_tunnelProvider setTunnelNetworkSettings:settings completionHandler:^(NSError * _Nullable error) {

        if (error) {

            if (completionHandler) {

                completionHandler(error);

            }

        } else {

            if (completionHandler) {

                completionHandler(nil);

            }

        }

    }];

官方已经说了, 通过packetFlow来收发系统/app 与服务器进行的通讯数据包.理论上, 只要 VPN 一建立就需要监听往返的数据包了

代码语言:javascript
复制
/// Make the initial readPacketsWithCompletionHandler call.
func startHandlingPackets() {
    packetFlow.readPackets { inPackets, inProtocols in
        self.handlePackets(inPackets, protocols: inProtocols)
    }
}
代码语言:javascript
复制
// 读数据包进行解析
self.packetFlow.readPackets { inPackets, inProtocols in
     self.handlePackets(inPackets, protocols: inProtocols)
}
代码语言:javascript
复制
// 将从服务端接收到的数据包写入虚拟网卡
override func sendPackets(_ packets: [Data], protocols: [NSNumber]) {
    packetFlow.writePackets(packets, withProtocols: protocols)
}

IOS本地读到数据包后想怎么处理就怎么处理,随后可以连接TCP,建立相关通道进行转发之类。

代码语言:javascript
复制
let tunFd = self.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int32;

同样拿到虚拟网卡描述符也很重要,可以自定义读取tunFd

PC 端与移动端的最大不同再于建立虚拟网卡,移动端有专门的API给用户创建虚拟网卡,修改路由表,然而PC端创建虚拟网卡,修改路由表,要靠自己编写代码实现,稍微复杂一点。

Windows主要用到命令有:

netsh、route、ipconfig等,具体使用方法可以自行查阅。

Linux主要用到命令有:

ifconfig、route等其它相关系统调用

MAC主要用到有:

系统调用:syscall.AF_SYSTEM、syscall.AF_IOCTL、syscall.AF_CONNECT等

命令行:route、ifconfig、networksetup等

然而无论是移动端还是PC端都能获取其虚拟网卡的文件描述符,因此底层流量拦截库可以统一实现。

下图为TCP状态机

虚拟网卡拦截的数据包均为IPV4包,被TCP解析后如果是Syn包,且是白名单拦截目标,则建立TCP加密连接,之后向服务端发送HTTP-Connect协议建立VPN通道。

当网关返回TCP数据给TCP状态机时,TCP状态机将TCP回复包重新组装为IPV4包,写入虚拟网卡,虚拟网卡转回给用户APP 请求。

服务端必须支持http-connect协议,如果是nginx打包编译时必须添加http-connect模块。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
VPN 连接
VPN 连接(VPN Connections)是一种基于网络隧道技术,实现本地数据中心与腾讯云上资源连通的传输服务,它能帮您在 Internet 上快速构建一条安全、可靠的加密通道。VPN 连接具有配置简单,云端配置实时生效、可靠性高等特点,其网关可用性达到 99.95%,保证稳定、持续的业务连接,帮您轻松实现异地容灾、混合云部署等复杂业务场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档