说说策略路由

前言

前阵子问一个老同事,我说你觉得android数据网络管理这部分知识点的核心是什么?

他说:apn管理,网络评分机制,这些是最基础最简单的,我认为的核心应该是策略路由。

问题来了,什么是策略路由呢?

基本概念

我们都熟悉路由器,它是三层设备。路由器的作用是把数据包转发,将数据包从一个网络转发到另一个网络,那么路由器是如何确定数据包的下一跳转发到哪个路由设备呢,答案是通过路由表。 路由表的两个作用:选择网卡和指定下一跳地址(网关地址–指路由器地址)。

路由表本身很简单,而基于策略的路由比传统路由在功能上更强大,使用更灵活,它不仅能够根据目的地址,而且能够根据报文大小,应用或IP源地址等属性来选择转发路径。简单说就是Linux有多张路由表,而路由策略会根据一些条件,将路由请求转向不同的路由表。比如源地址在某些范围内走路由表A,另外的数据包走路由表B,类似这样的规则是有策略路由来控制。

ip命令

Linux下,策略路由主要是通过ip命令来管理的。所以要学习策略路由,首先要熟悉ip命令,它是Linux系统中一个强大的网络管理工具,主要功能包括:

  1. 可替代ifconfig命令,通过ip工具可管理系统中的网络接口,包括配置和查看网络接口情况,使能或禁止指定的网络接口。
  2. 可替代route命令,通过ip工具设置主机路由,网络路由,网关参数等。
  3. 可替代arp命令,通过ip工具查看,修改和管理系统的ARP缓存等。

命令详解

ip的命令格式如下(可通过在命令行输入 ip -h 查询):

ip [OPTIONS] OBJECT {COMMAND | help}

对象OBJECT = {link | addr | route | rule | addrlabel | neigh | ntable | tunnel | xfrm | maddr | …}

选项OPTIONS = {-V[ersion] | -S[tatistics] | -d[etails] | -r[esolve] | -h[uman-readable] | -f[amily] …}

命令COMMAND一般是add, del, show之类的操作命令。

常用的对象取值
对象描述
link网络设备
address设备上的协议地址(IP/IPv6地址)
route路由表条目
rule路由策略数据库中的规则
neighbour邻居表
tunnelIP隧道
maddress多播地址
常用的选项取值
选项描述
-V,-Version显示指令版本信息
-s,-stats, -statistics输出详细信息
-h, -human, -human-readable输出人类可读的统计信息和后缀
-o, -oneline将每条记录输出到一行
常用的ip命令
ip命令说明
ip addr show显示网卡及配置的地址信息
ip addr add 192.168.0.123/24 dev eth0设置IP
ip link set eth0 up启用被禁用的网卡
ip link set eth0 down禁用网卡
ip route show查看路由信息
ip route add default via 192.168.0.150/24所有数据包都通过192.168.0.150来转发
ip -s link显示所有网络接口的统计信息
ip -s link ls eth0获取特定网络接口的信息
ip rule show显示路由策略信息

路由表管理

查看路由表

ip route命令用于查看并编辑计算机的IP路由表。linux可以定义1-252个路由表,linux系统维护4个路由表。在linux系统中,可以在 /etc/iproute2/rt_tables 中查看:
在这里插入图片描述

编号表名描述
0unspec系统保留表
255local本地路由表,存有本地接口地址,广播地址,NAT地址。由系统自动维护,管理员不能操作此表
254main主路由表,ip route命令若没指定表都是默认操作这个表
253default默认路由表,一般存放默认路由

安卓系统中,netd进程会创建更多的路由表,创建的逻辑和流程可以查阅代码:\netd\server\RouteController.cpp

可以通过adb命令查看文件 /data/misc/net/rt_tables,路由表如下所示:

在这里插入图片描述

显示路由信息

通过ip route show table命令,我们来查看android手机中路由信息。

1.查看main路由表

seaice:/ # ip route show table main
10.20.173.184/29 dev rmnet_data0 proto kernel scope link src 10.20.173.188

这里表示如果来源为10.20.173.188的数据包要发到10.20.173.184/29这个网段,直接通过rmnet_data0这个网络接口发出。

2.查看rmnet_data0路由表

seaice:/ # ip route show table rmnet_data0
default via 10.20.173.189 dev rmnet_data0 proto static mtu 1460
10.20.173.184/29 dev rmnet_data0 proto static scope link

最后一行表示发往这个网段10.20.173.184/29的数据包,直接通过rmnet_data0这个网络接口发出。倒数第二行表示其他数据包统一转发给10.20.173.189主机处理。

添加路由

先查看main表的内容,再添加一条路由信息,最后显示结果:

seaice:/ # ip route show table main
10.20.173.184/29 dev rmnet_data0 proto kernel scope link src 10.20.173.188

seaice:/ # ip route add 192.168.2.0/24 via 10.20.173.189 table main

seaice:/ # ip route show table main
10.20.173.184/29 dev rmnet_data0 proto kernel scope link src 10.20.173.188
192.168.2.0/24 via 10.20.173.189 dev rmnet_data0
删除路由

先查看main表的内容,然后删除一条路由信息,最后显示结果:

seaice:/ # ip route show table main
10.20.173.184/29 dev rmnet_data0 proto kernel scope link src 10.20.173.188
192.168.2.0/24 via 10.20.173.189 dev rmnet_data0

seaice:/ # ip route del 192.168.2.0/24 table main

seaice:/ # ip route show table main
10.20.173.184/29 dev rmnet_data0 proto kernel scope link src 10.20.173.188

路由策略

在linux系统中,一条路由策略主要包含三个信息:

  1. 优先级
  2. 条件
  3. 路由表

其中优先级数字越小表示优先级越高,然后是满足某个条件下,由指定的路由表来进行路由。

ip rule命令格式

Usage: ip rule [ list | add | del ] SELECTOR ACTION
    SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ][ dev STRING ] [ pref NUMBER ]
    ACTION := [ table TABLE_ID ] [ nat ADDRESS ][ prohibit | reject | unreachable ]
              [ flowid CLASSID ]
    TABLE_ID := [ local | main | default | new | NUMBER ]

参数解析如下:
From -- 源地址
To -- 目的地址(这里是选择规则时使用,查找路由表时也使用)
Tos -- IP包头的TOS(type of sevice)域
Dev -- 物理接口
Fwmark -- iptables标签

查看路由策略数据库

使用ip rule list命令,查看路由策略数据库的内容。下面是linux系统下执行命令后得到的结果,可以看到系统的三条默认规则,而这三条规则默认分别对应于local、main以及default三个路由表。

seaice@seaice-VirtualBox:~$ ip rule list
0:  from all lookup local 
32766:  from all lookup main
32767:  from all lookup default

linux系统中是按照规则的优先级顺序依次匹配。首先,系统会根据规则0在本地路由表(local)里寻找路由,如果目的地址是本地网络或广播网络,就可以找到匹配的路由;如果没有找到路由,就会匹配下一个不空的规则,这里是规则32766,那么会在主路由表里面寻找路由;如果还没有找到,则匹配规则32767,在默认路由表里面寻找;如果最后还是没找到,则路由失败。

优先级条件路由表
0from alllocal
32766from allmain
32767from alldefault

安卓系统中,netd进程会创建更多的路由策略,创建的逻辑和流程可以查阅代码:\netd\server\RouteController.cpp。通过adb命令执行ip -4 rule show,结果如下所示:

ip -4 rule list
0:      from all lookup local
10000:  from all fwmark 0xc0000/0xd0000 lookup legacy_system
11000:  from all iif lo oif dummy0 uidrange 0-0 lookup dummy0
11000:  from all iif lo oif rmnet_data2 uidrange 0-0 lookup rmnet_data2
11000:  from all iif lo oif rmnet_data0 uidrange 0-0 lookup rmnet_data0
16000:  from all fwmark 0x10063/0x1ffff iif lo lookup local_network
16000:  from all fwmark 0xd006a/0xdffff iif lo lookup rmnet_data2
16000:  from all fwmark 0x1006b/0x1ffff iif lo lookup rmnet_data0
17000:  from all iif lo oif dummy0 lookup dummy0
17000:  from all fwmark 0xc0000/0xc0000 iif lo oif rmnet_data2 lookup rmnet_data2
17000:  from all iif lo oif rmnet_data0 lookup rmnet_data0
18000:  from all fwmark 0x0/0x10000 lookup legacy_system
19000:  from all fwmark 0x0/0x10000 lookup legacy_network
20000:  from all fwmark 0x0/0x10000 lookup local_network
23000:  from all fwmark 0x6b/0x1ffff iif lo lookup rmnet_data0
29000:  from all fwmark 0x0/0xffff iif lo lookup rmnet_data0
32000:  from all unreachable

现在来对其中的某些策略路由进行解析

10000:  from all fwmark 0xc0000/0xd0000 lookup legacy_system

优先级为10000的策略表示,所有的数据包(from all), 其iptables的mark和0xd0000按位与后,所得结果为0xc0000的数据包(fwmark 0xc0000/0xd0000),使用legacy_system路由表进行路由查找(lookup legacy_system)。

11000:  from all iif lo oif rmnet_data0 uidrange 0-0 lookup rmnet_data0

优先级为11000的策略表示,所有是的数据包(from all),如果是从lo回环接口输入(iif lo),从rmnet_data0接口输出(oif rmnet_data0),其uid为0(uidrange 0-0)即系统用户,使用rmnet_data0路由表进行路由查找。lo接口的作用是,假如一个本地进程向另一个本地进程发送数据,那么将会使用lo接口,此时如果在rmnet_data0接口上抓包是无法抓到的,但是在lo接口上能够抓到。

29000:  from all fwmark 0x0/0xffff iif lo lookup rmnet_data0

优先级为29000的策略表示,所有的数据包,其iptables的mark和0xffff按位与后,所得结果为0x0,且是从lo回环接口输入的数据包,使用rmnet_data0路由表。在不主动设置数据包的mark时,数据包的mark就是0,所以在不设置mark的时候,数据包通常会满足这条路由策略。

添加路由策略

在添加策略前时,要确认好条件,优先级,路由表ID,再执行添加规则的操作。条件是用来判断哪些数据包符合这条策略,可以用来匹配的字段包括数据包的源地址,目的地址,TOS,fwmark, dev等等。那么下面我们来演示一下。

根据数据包的源地址来决定参考那个路由表。下面两个命令指出,如果数据包的来源IP是109.131.7.10, 就参考路由表10;如果来源端的IP是109.131.8.0/24网段的IP,就参考路由20。

root@seaice-VirtualBox:/home/seaice# ip rule add from 109.131.7.10 table 10
root@seaice-VirtualBox:/home/seaice# ip rule add from 109.131.8.0/24 table 20
root@seaice-VirtualBox:/home/seaice# ip rule list
0:	from all lookup local
32764:	from 109.131.8.0/24 lookup 20
32765:	from 109.131.7.10 lookup 10
32766:	from all lookup main
32767:	from all lookup default

可以发现,在添加规则时,如果没有特别设置优先级别,那么,优先级别默认会从32766开始递减,如32765、32764……,如果我们需要特别设置优先级别,可以在ip rule add命令的最后加上prio XXX参数。

根据数据包目的地址与上面类似。

root@seaice-VirtualBox:/home/seaice# ip rule add to 109.131.9.0/24 table 30
root@seaice-VirtualBox:/home/seaice# ip rule add to 109.131.10.10 table 40

根据fwmark作为匹配条件时,需要和iptables打标签配合使用。比如我们想把发出去的http数据包去寻找特定的路由表寻找路由,假设路由表是50。那么我们可以先把http的数据包mark值设为1,再通过路由策略判断fwmark的值,去寻找指定的路由表。

seaice# iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 1
seaice# ip rule add fwmark 1 table 50

最后,我们还可以使用数据包输入的接口来作为判断依据,如下所示,我们希望凡是由enp0s3接口送入的数据包都去查找路由表55进行路由。

root@seaice-VirtualBox:/# ip rule add dev enp0s3 table 55

删除路由策略

ip命令提供删除规则的命令很灵活,可以使用优先级,条件,路由表其中一个值来删除规则。先看上面添加规则后,目前的路由策略信息,如下所示:

root@seaice-VirtualBox:/# ip rule list
0:	from all lookup local
32760:	from all iif enp0s3 lookup 55
32761:	from all fwmark 0x1 lookup 50
32762:	from all to 109.131.10.10 lookup 40
32763:	from all to 109.131.9.0/24 lookup 30
32764:	from 109.131.8.0/24 lookup 20
32765:	from 109.131.7.10 lookup 10
32766:	from all lookup main
32767:	from all lookup default

我们根据上面所说的删除命令,执行过程如下所示

root@seaice-VirtualBox:/# ip rule del prio 32760
root@seaice-VirtualBox:/# ip rule del fwmark 1
root@seaice-VirtualBox:/# ip rule del table 40
root@seaice-VirtualBox:/# ip rule del table 30
root@seaice-VirtualBox:/# ip rule del from 109.131.8.0/24
root@seaice-VirtualBox:/# ip rule del prio 32765

root@seaice-VirtualBox:/# ip rule list
0:	from all lookup local
32766:	from all lookup main
32767:	from all lookup default

创建新路由表

单纯添加路由表并没有意义,因为新增出来的路由表,系统默认是不会去使用的。如果要添加到main以外的路由表,只有先添加规则才能确定新的路由表名称(table id),有了新的路由表之后,才会把路由添加到新的路由表中。

ip rule add from 192.168.2.0/24 table 10
ip route add 192.168.1.0/24 dev eth1 table 10
ip route add default via 192.168.1.254 table 10
ip route show table 10

注意!不要混淆路由表(route)和规则(rule):ip rule规则指向路由表,多个规则可以引用一个路由表,而且某些路由表可以没有策略指向它。如果系统管理员删除了指向某个路由表的所有规则,这个表就没有用了,但是仍然存在,直到里面的所有路由都被删除,它才会消失。

fwmark的定义

Android 通过多个路由表 + fwmark的形式,来设置整体路由策略,确定网络请求通过哪块网卡发出。 在多网卡的情况下,包括数据网络、wifi网络、以太网网络,网络管理程序可以进行灵活的配置,指定数据从哪个网络发出。另一方面在vpn网络下,也能方便实现vpn代理,配置哪些应用通过vpn网络进行数据代理。

fwmark是用于实现策略路由的,mark的意思是给数据流量打标记,这样路由规则就可以根据mark值做一些更细粒度的路由策略。 fwmark分两部分,包括匹配值/掩码。 路由策略只关心掩码位为1的位。 Android 使用的fwmark为21位,查阅代码netd/include/Fwmark.h,定义如下:

union Fwmark {
    uint32_t intValue;
    struct {
        unsigned netId          : 16; //低16位,网络ID。
        bool explicitlySelected :  1; //是否显示指定使用该网络
        bool protectedFromVpn   :  1; //是否受 vpn 保护
        Permission permission   :  2; //该数据包所属的应用权限
        bool uidBillingDone     :  1;
    };
    constexpr Fwmark() : intValue(0) {}

    static inline uint32_t getUidBillingMask() {
        Fwmark m;
        m.uidBillingDone = true;
        return m.intValue;
    }
};

static const unsigned FWMARK_NET_ID_MASK = 0xffff;  //net id
};

权限的定义如下:

enum Permission {
    PERMISSION_NONE     = 0x0,
    PERMISSION_NETWORK  = 0x1,
    PERMISSION_SYSTEM   = 0x3,
}

根据上面fwmark的定义,我们分析下面这条路由规则

10000: from all fwmark 0xc0000/0xd0000 lookup leagcy_system

0xc0000 = 1100 0000 0000 0000 0000,
表示拥有系统权限没有明确指定网络的数据包要查 leagcy_system 路由表。

一个案例

iptables网关服务器三块网卡:eth0(网通ip:10.0.0.1)、eth1(电信ip:20.0.0.1);eth2:网关192.168.10.1(内网用户的网关)。

要求:公司内网要求192.168.10.1—100以内的ip使用 10.0.0.1 网关上网(网通),其他IP使用 20.0.0.1 (电信)上网;

iptables网关服务器配置如下:

ip route add default gw 20.0.0.1
ip route add table 10 via 10.0.0.1 dev eth0
#eth0 是10.0.0.1所在的网卡,10是路由表的编号
ip rule add fwmark 10 table 10
#fwmark 10 是标记,table 10 是路由表10。 标记了 10 的数据使用table10 路由表
iptables -A PREROUTING -t mangle -i eth2 -s 192.168.10.1 - 192.168.10.100 -j MARK --set-mark 10

因为mangle的处理是优先于nat 和fiter表的,所以相应数据包到达之后先打上标记,之后再通过ip rule规则。对应的数据包使用相应的路由表进行路由,最后读取路由表信息,将数据包送出网关。

参考

Linux prerouting和postrouting的区别
Android&Linux策略路由
Linux系列—策略路由、ip rule、ip route
IPROUTE2 Utility Suite Howto
Linux ip 命令详解
IP命令详解
路由知识之ip route 命令中的疑惑

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值