背景介绍

目前互联网业界主流的服务器开发系统主要包括linux和windows两款操作系统,很多网络服务商需要获取客户端的真实IP和Port,特别是IP地址,对业务策略进行制定,优化;同时客户端的IP和Port信息作为基本的统计数据,对线上业务运营的监控和评估具有非常重要的意义。大部分情况下,服务器端可以通过网络API直接获取连接的网络信息,但是针对服务器前侧添加了代理的网络框架来说,就无法直接通过网络API来获取了。而TOA通过扩展TCP首部的可选字段,可以很好的将客户的真实的IP和Port信息传递到服务器端。因此需要一种手段可以在服务器侧来解析TOA字段,linux系统下的获取在业界有比较成熟的方法获取,但是windows系统下至今没有一种成熟的方案去获取。

目前Linux下获取TOA的方法比较成熟,有专门的TOA系统补丁,主要原理是在网络协议栈层面添加钩子函数,解析出TOA信息后替换存放网络信息的结构体的对端IP和Port字段,这样直接通过网络系统API的调用方式,例如getpeername,来获取客户端网络地址信息。但是在windows系统下没有相似的补丁,系统无法识别TOA字段,无法直接通过系统API来解析或者获取TOA信息。

基本原理

TOA存在于数据包TCP首部的可选域中,因此在windows系统上利用winpcap对网卡进行监控捕获业务流,并利用程序对业务流进行解析获取到TOA值并缓存起来,同时对应用层提供API来进行访问。

该方案的核心功能点主要包括以下几个方面。

1. 业务数据流捕获与过滤

利用winpcap对对外提供服务的网卡进行监控,可以获取该网卡上的所有数据流,但网卡工作在数据链路层,捕获到数据包括真实的业务数据和其他非相关的数据,需要进一步通过设置过滤规则获取到真实的数据流。

我们知道TCP的连接建立需要进行三次握手,目前大部分中间代理通常会在转发SYN包时打上TOA信息,还有部分中间代理会在每个转发包上都携带TOA信息。因此只需要设置成过滤SYN包即可。

同时,考虑到TCP连接的生命周期,还需要对FIN包和RST包进行过滤。

过滤的具体规则如下(该规则采用winpcap的规则语法进行描述):

( tcp[13] & 0x7 != 0 ) and host x.x.x.x and ( tcp port y1 or tcp port y2…) or ( tcp portrange z1-z2 or… )

其中:

tcp[13] & 0x7 != 0 表示对SYN,FIN,RST进行过滤

host x.x.x.x 表示针对服务器对外提供服务的IP进行过滤

tcp port和 tcp portrange表示针对服务器对外提供服务的一个或多个Port和Port段进行过滤。

2. TOA解析及缓存

目标数据包被捕获后,winpcap会触发一个回调函数对该数据包进行处理,在回调处理函数里根据IP/TCP的首部格式进行解析,可以拿到真实的客户端IP和Port信息。

一般应用层请求真实客户端信息的操作是一个异步操作,因此需要对解析出来的真实网络信息进行缓存。

缓存机制涉及以下两个方面:

1)缓存映射表

以数据包的源IP和Port为key建立hashmap,存储的值为解析出来的真实IP和Port。

2)缓存生命周期

    1. 当收到SYN包时,解析TOA获取真实IP和Port,根据包头源IP和Port生成key,存储到hashmap中,同时记录当前的时间戳,仍然以源IP和Port为key存入到老化表中。
    1. 当收到FIN包或者RST包时,说明该连接已经失效,端口号可能被回收使用到其他连接上去, 因此需要使旧的TOA信息失效,根据解析出包头源IP和Port生成key,从hashmap中删除对应的键值对。
    1. 启动缓冲定时器,主要目的做一层保护,防止资源残留,定时扫描老化表,计算各个key的缓冲时间,超时后,无论是否收到FIN或者RST,主动从hashmap删除键值对。

3. TOA获取

应用层根据TCP建立或者通信时获取到的源IP和Port为key,向hashmap进行查询获取到真实客户端IP和Port信息。

系统框架

该框架包括以下几个部分:

旁路线程:

由上层应用程序创建并初始化,用于启动网卡监控服务,过滤目标数据流以及TOA解析。

TOA映射表:

以TCP源IP和Port为key,TOA解析出来的信息为value所建立的hashmap,主要用于存储和查询TOA信息。

缓冲定时器:

由旁路线程创建,周期性扫描老化表,计算缓冲时间,淘汰老化的键值对,防止资源泄露。

具体步骤如下:

  1. 应用层根据本机网卡信息及对外服务的IP和Port信息,创建TOA旁路线程,启动网卡监听服务,设定数据流过滤规则,初始化TOA映射表和老化表,设定老化时间并启动缓冲定时器。
  2. 客户端发起TCP连接建立,TOA旁路线程数据流,捕获SYN数据包,触发回调函数对SYN包进行处理。
  3. 回调函数解析TCP首部,获取源IP和Port以及TOA信息。以源IP和Port生成hash key,存入TOA映射表中,同时获取当前时戳,存入老化表。
  4. 应用层完成TCP连接建立,获取连接对端的IP和Port,生成key,查询TOA映射表,完成TOA信息的获取。
  5. 当客户端或者服务器终止连接时,TOA旁路线程捕获到FIN或者RST数据包,触发回调函数进行处理。
  6. 回调函数获取源IP和Port,生成key,从TOA映射表删除对应键值对。

缓冲定时器达到定时时间,触发定时处理函数,遍历老化表,计算缓冲时间,当超过设定的老化时间,从老化表和TOA映射表中清除对应的键值对。

总结

在实现上可以以lib或dll的方式提供,在业务服务程序中进行调用和管理。另外也可以以独立的后台服务存在,通过网络通信的方式与需要获取TOA信息的业务服务进行交互。该方法实现简单,方便管理和维护,与linux不同,不需要对底层协议栈进行深度改造,对系统没有依赖性。同时可以实现与业务程序的隔离,不影响正常业务的运行。

文章来源于腾讯云开发者社区,点击查看原文