背景
- 需要改变老系统的后台架构,为了在不影响系统的使用并且能拿到真实环境中的数据来进行测试,保证新系统的正确性
功能
- 从一台机器上面复制到这台机器的TCP请求流量到另一台机器,达到两台机器能拿到一样的数据,这样可以用真实的线上数据对即将上线的服务进行测试
环境
TCPCOPY版本:
- TCPcopy:V1.0.0
- Intercept:V1.0.0
架构
上图是目前TCPCOPY的架构图。实现TCPCOPY需要用到三台机器:
- Online Server:线上的机器,运行TCPCOPY程序
- Target Server:测试机,也就是需要将线上流量复制到这台机器上
- Assistant Server:辅助机,运行Intercept程序
Online Server:
Online Server上面运行着TCPCOPY程序,从上图可以看出TCPCOPY程序在IP层抓取数据包,对数据包进行相应的处理,再由IP层将数据包发到Target Server。运行TCPCOPY程序需要指定复制本机的哪个端口的数据和复制到哪台机器的哪个端口
Target Server:
Target Server上面运行需要测试的程序。由于线上的服务器会将请求回给请求的发起者(例如客户端),因此Target Server是不应该给请求的发起者回复请求,Target Server需要将返回的请求发给Assistant Server。因此需要在Target Server上面配置路由将返回客户端的请求数据发给Assistant Server,由Assistant Server上面运行的Intercept程序处理。
Assistant Server:
Assistant Server上面运行Intercept程序,由图可见,Intercept程序在数据链路层截获数据包,获取数据包的头信息,进行相应的处理,再返回给Online Server上面的TCPCOPY程序
程序下载与安装:
TCPCOPY安装:
需要root权限
cd tcpcopy-1.0.0/
./configure
make
make install
安装完后,默认目录:/usr/local/tcpcopy/
Intercept安装:
需要root权限
cd intercept-1.0.0/
./configure
make
make install
安装完后,默认目录:/usr/local/intercept
部署
假设如下机器对应IP:
- Online Server:192.168.40.156
- Assistant Server:192.168.40.157
- Target Server:192.168.40.158
1)在Oneline Server上面运行TCPCOPY
/usr/local/tcpcopy/sbin/tcpcopy -x 80-192.168.40.158:80 -s 192.168.40.157 -d
参数解释:
- -x [source-port]-[target-ip]:[target-port] 指定复制本台机器的80端口的数据到192.168.40.158机器上的80端口
- -s 指定辅助服务器的IP
- -d 后台运行
后台运行可以查看TCPCOPY的日志,看是否正常启动,目录为 : /usr/local/tcpcopy/logs/
2)在Assistant Server上面运行Intercept
/usr/local/intercept/sbin/intercept -i eth0 -F 'tcp and src port 80' -d
参数解释:
- -i 指定对哪个网卡
- -F 过滤规则
- -d 后台运行
日志目录:/usr/local/intercept/logs
注意在本台机器上面要开放36524端口,在运行TCPCOPY程序时,会去连辅助机的这个端口,这个端口是由intercept程序监听
3)在Target Sever上面写路由规则
在Target Server上面运行需要测试的程序,最重要的是写路由规则。达到的目标就是让Target Serve上的回复请求不要发给客户端,要发给辅助服务器。
注意,在写路由规则将返回请求转发到辅助服务器上时,要保持Online Server和Target Server能正常TCP握手。也就是在Online Server 给Target Server的请求,Target Server回复请求要正常回复,不要路由到辅助服务器上
根据请求的客户端IP分为两种情况:
客户端IP已知
如果客户端IP已知,例如是192.168.100.x的内网网段,则可以直接如下设置:
route add -net 192.168.100.0 netmask 255.255.255.0 gw 192.168.40.157
这是很方便的情况,只需要将会给192.168.100.0网段的数据包路由到192.168.40.157上面
客户端IP未知
在客户端未知(客户端IP来自于全国各地)时有两种情况:
1. 测试程序中不需要用到客户端IP
这种情况下也很简单,在运行TCPCOPY程序时,可以在COPY流量时顺便更改客户端发来的数据包中的源IP
/usr/local/intercept/sbin/intercept -i eth0 -F 'tcp and src port 80' -c 192.168.100.x -d
上述-c 参数将IP更改为192.168.100.x 网段的IP,这样在Target Server上面进行路由时和客户端IP已知的情况一样
route add -net 192.168.100.0 netmask 255.255.255.0 gw 192.168.40.157
2. 测试程序中需要使用客户端IP
在某些情况下,测试程序中要对客户端的IP进行解析等操作,这样就需要客户端的真实IP
一般做法如下:
要求Target Server有一张内网网卡和外网网卡,需要修改外网网卡的默认网关,使测试程序回给外网的客户端的数据包都路由到修改后的默认网关。
route del default gw 真正的网关ip地址
route add default gw 辅助服务器的ip地址
在修改外网网卡的默认网关之前一定要保证能通过其他机器ssh登录到target server,不然修改了默认网关之后ssh登不上去就惨了
例如,我想在192.168.40.111机器上面ssh登录到Target Server
route add 192.168.40.111 gw 真正的网关IP地址
因为在寻找路由时遵循最长匹配的原则,所有发往192.168.40.111的数据包都会发给真正的网关,即使在后面将默认网关更改了
还要考虑到你的Target Server上面运行的测试程序是否会和其他的机器连接,例如写数据库等,如果有,在修改默认网关之前,需要将访问这些机器的IP加到路由中显示指定,保证能正常进行连接。
将Target Server需要访问的机器考虑全了,便可以进行修改默认网关
另:
如果Target Server上的程序是用tornado写的,并且到Online Server上的请求是在前端用了nginx做了代理,则就不需要更改默认网关了,可以直接使用TCPCOPY 的 -c 参数修改数据包的IP指定一个网段的IP,这样tornado程序仍能获取到客户端的真正IP。需满足如下要求:
1. nginx做的代理,其中的配置必须要加上”X-Real-IP”:
proxy_set_header X-Real-IP $remote_addr;
2.tornado在运行时加上xheaders=True参数:
http_server = tornado.httpserver.HTTPServer(app, xheaders=True)
因为这样tornado会从http header中去取”X-Real-IP”字段的值来作为数据包的IP,而不是从IP数据包中获取(此时IP数据包中的IP已经是被TCPCOPY程序更改过了)
其他将header中的X-Real-IP当做请求的真正IP的写法都是可以达到效果,不一定是tornado。或者改程序,获取客户端IP就直接去找header中的这个字段
遇到的问题
1) 编译intercept程序时出现错误,报了 pcap.h can not found .这时需要安装libpcap-dev包
apt-get install libpcap-dev
2)TCPCOPY程序运行错误。通过查看日志,发现是辅助服务器的36524端口不能访问到,没有开通这个端口的权限。在iptable中加上对这个端口的访问
注意
1)这三台机器最好在同一网关,这样更方便
2)在决定改默认网关时要将本身Target Server上的后台程序对其他机器的访问依赖找全。以便后台程序不能正常运行
说明
目前也只是对TCPCOPY进行了简单的利用,对于其中更多网络方面的知识,Linux内核中关于网络的知识,以及更大规模的利用TCPCOPY进行测试需要进一步学习。