Linux应用流量和管理流量分离实战
=======================
本文主要介绍在Linux下使用高级路由功能,实现应用流量和管理流量分离。
## 场景简介
当这个网络设备作为转发设备使用时,设备会从NIC0,NIC1进行收包,在网络设备上进行处理,处理完之后,通过**默认路由**,再次回到应用业务网。但是应用业务网络流量比较大,不适合做ssh登录管理使用,而且业务网和应用网一般最好是隔离的。
因此我们使用服务器的千兆口MGT-NIC作为ssh登录管理口,链接到管理交换网。但是ssh到此台设备的IP地址可能是公司内任意网段,而且这个网段可能随时增加,因此去管理交换网的流量也需要一条**默认路由**指向管理交换网。
这样问题就来了,一台Linux服务器如何两个不同的默认网关,并且管理业务和应用业务完全正常呢?
## 网络服务器被动访问
#### 知识点
Linux其实有好几张路由表。默认我们通过命令**ip route list**看到的知识main域的路由表,其实linux默认有三张路由表,可通过**ip rule**查看,Linux在慢转的情况下,会去遍历如下所有域的路由(包括后续我们自己添加的域),直到第一个匹配为止,全部不匹配则丢包。分别如下:
优先级0:优先级最高的local域路由
优先级32766:优先级倒数第二的main域
优先级32767:优先级最低的default域
可通过命令
ip route list table [table name or table id]
example:
ip rule list table local
ip rule list table 0
正常情况下,通过ip route 命令添加的路由信息是放在main域的,因此我们把应用业务网的默认路由放在main域,通过如下命令添加:
ip route add default nexthop via 1.1.1.1 dev nic0 weight 10 nexthop via 1.1.1.5 dev nic1 weight 10
这样就会形成两条等价:
default
nexthop via 1.1.1.1 dev nic0 weight 10
nexthop via 1.1.1.5 dev nic1 weight 10
**此时如果还在main域添加默认路由是添加不上的。**
此时问题就来了:
如果公司内任意IP访问192.168.1.10这个地址,并且Client IP的网段不在此服务器的明细路由中,这样回包路由就会走到main域的default路由,此时回包会送到应用业务网中,导致管理流量异常,无法管理此服务器。当然是可以在服务器上添加管理交换网的明细路由,但是管理交换网网段随时可能增加,此时需要人工去维护服务器上的管理网路由表,比较麻烦。
#### 问题解决方案
此时基于源IP的策略路由登场,我们可以配置基于源IP的策略路由:
ip rule add pri 32765 from 192.168.1.10 table 8
ip rule查看路由域如下:
0: from all lookup local
32765: from 192.168.1.10 lookup 8
32766: from all lookup main
32767: from all lookup default
此命令的含义:
添加一个规则,优先级为32765,如果源IP是192.168.1.10则去匹配table 8域中的路由。
又因为这条规则优先级高于main域,所以如果报文的源IP是192.168.1.10的则会去table 8域中查找路由。
随后在table 8域中添加一条默认路由:
ip route add default via 192.168.1.1 dev mgt-nic table 8
查看路由表:
ip route list table 8
default via 192.168.1.1 dev mgt-nic
此时公司内部任意网段都可以ssh到此服务器进行管理了,流程大致如下:
1. client tcp 访问192.168.1.10
2. 服务器肯定以192.168.1.10为源IP返回给Client
3. 此时匹配了基于源IP的策略路由,并且去查找table 8域中的路由表
4. 在table 8域中有一条default路由,是从mgt-nic发出的,因此可以正常回到client处
## 服务器主动访问
当服务器要主动访问应用网中的其他业务,比如DNS,NTP,HTTP API,salt主动注册等业务时,如果只配置上一节提供的路由,则会出现问题的。**注意:此时主动访问的网段还是不在main域的明细路由中**
#### 知识点
首先要知道Linux主动请求时,如何选择发包的源IP。我们在写Linux Socket程序是,通常会指定目的IP,很少会指定源IP,**那么Linux是如何确定发包的源IP的呢?**
发包时,Linux会根据目的IP查找路由表(Linux只会匹配local、main、default这三个域),匹配了路由表,那么源IP则是这条路由表的出接口的IP,如果路由条目指定src,则使用指定的src作为源IP。查找源IP时不会去找table 8域的路由,因此进入main域查找。
最终目的IP会匹配到main域default路由,main域default路由的设备IP为1.1.1.1,1.1.1.5,则以1.1.1.1或1.1.1.5作为原IP,这样就不会匹配table 8域的默认路由,最终数据包会从nic0或nic1进入应用业务网,导致流量无法走入管理交换网。
#### 问题解决方案
在main域的default路由上指定src,这样主动请求时,匹配到main域的default路由,则会使用我们指定的src作为原IP,而不是设备接口地址,配置如下:
ip route add default src 192.168.1.10 nexthop via 1.1.1.1 dev nic0 weight 10 nexthop via 1.1.1.5 dev nic1 weight 10
ip route list显示如下:
default src 192.168.1.10
nexthop via 1.1.1.1 dev nic0 weight 10
nexthop via 1.1.1.5 dev nic1 weight 10
此时发包流程如下:
1. Linux socket发包,根据目的IP查找路由,最后匹配main域default路由
2. 将main域default路由上指定的src 192.168.1.10作为源IP
3. 发包时则会匹配基于源IP的策略路由规则
4. 然后查找table 8,table 8中有去管理网的默认路由
5. 此时流量能正常进入应用网
**注意:在测试过程中,发现只有TCP能以源IP192.168.1.10从管理网出去,但是UDP和ICMP是以192.168.1.10为源IP从应用业务网出去了,这是大问题**
## 服务器主动访问--udp/ICMP选路异常
我们虽然在main域的default路由上指定了发包源IP,但是udp和ICMP使用的是快转,**在查找发包源IP的时候,直接选择main域的default路由的出接口作为发包接口,不会去再次查找路由表。**
#### 知识点
tcp在发包时,获取源IP之后,发包时还会去路由表查找出接口的,走的是慢转。但是udp和icmp走的是快转,发包时不会再查找。因此我们如何强制UDP和ICMP也走慢转呢?
#### 解决方案
Linux iptable mangle中可以给报文打MARK,打了mark之后,报文发包时会找所有域的路由表,并且匹配相应规则的mark号,然后查找相应的路由表。
首先在OUTPUT Hook点上给报文打MARK:
/sbin/iptables -F -t mangle #清空mangle规则
/sbin/iptables -A OUTPUT -t mangle -p udp -j MARK --set-mark 1 #本地发出的udp报文打上mark1标记
/sbin/iptables -A OUTPUT -t mangle -p tcp -j MARK --set-mark 1 #本地发出的tcp报文打上mark1标记
/sbin/iptables -A OUTPUT -t mangle -p icmp -j MARK --set-mark 1 #本地发出的icmp报文打上mark1标记
service iptables save #保存规则到/etc/sysconfig/iptables中
chkconfig iptables on #设置开机启动
配置策略路由规则:
源IP为192.168.1.10并且打上了mark1的报文去table 8域查找路由:
/sbin/ip rule add pri 32764 from 192.168.1.10 fwmark 1 table 8
此时发包流程如下:
1. 从本地发出的报文,经过OUTPUT Hook点的报文,如果是UDP,TCP,ICMP的,全部打上mark1标签,并且走慢转
2. 在查找路由表时,匹配 from 192.168.1.10 fwmark 1
3. 查找table 8域中的路由表
4. table 8域中有去管理网的默认路由
5. 流量正确进入管理网
## 网络系统停运时,会删除main域default路由
服务器上正常运行的是网络转发系统会在main域添加default路由,并将src改成管理口IP,但是在网络系统停运后,会将main域的default路由删除,此时报文则无法找到default路由,并且主动访问时找不到源IP,从而导致发包异常。
#### 解决方案
在路由表中还有一个default域,我们可以在default域中添加一条去管理网的默认路由,这样即使main域中的default路由删除了,在发包时,也会去查找default域的路由的。因此可以解决main域default删除的问题。
命令如下:
ip route add default via 192.168.1.10 dev mgt-nic table default
查看命令:
ip route list table default
## 完成配置命令
配置应用业务网默认路由,并且将src指定为管理口IP:
ip route add default src 192.168.1.10 nexthop via 1.1.1.1 dev nic0 weight 10 nexthop via 1.1.1.5 dev nic1 weight 10
配置基于源IP的策略路由:
ip rule add pri 32765 from 192.168.1.10 table 8
配置table 8域的默认路由:
ip route add default via 192.168.1.1 dev mgt-nic table 8
iptables给OUTPUT Hook点打mark:
/sbin/iptables -F -t mangle #清空mangle规则
/sbin/iptables -A OUTPUT -t mangle -p udp -j MARK --set-mark 1 #本地发出的udp报文打上mark1标记
/sbin/iptables -A OUTPUT -t mangle -p tcp -j MARK --set-mark 1 #本地发出的tcp报文打上mark1标记
/sbin/iptables -A OUTPUT -t mangle -p icmp -j MARK --set-mark 1 #本地发出的icmp报文打上mark1标记
配置策略路由基于源IP,并且打mark1标记的报文进行策略:
/sbin/ip rule add pri 32764 from 192.168.1.10 fwmark 1 table 8
最终配置default域默认路由:
ip route add default via 192.168.1.10 dev mgt-nic table default