kernel网络之策略路由

转载自https://blog.csdn.net/u012758088/article/details/76255543

早期在管理Linux系统的网络时,常使用ifconfig及route之类的命令,不过如果你准备开始使用Linux强大的基于策略的路由机制,那么,就请不要使用这类工具了,因为这类工具根本无法用于功能强大的基于策略的路由机制,取而代之的工具是iproute。iproute这个软件在RedHat系列的Linux系统中是默认安装的,因此,你通常可以找到这个工具。如果真因为某些原因找不到这个软件,只要在使用Fedora或CentOS Linux时,在联网的情况下,用yum install iproute命令即可顺利安装;或者也可以使用ip -V命令来检查iproute软件是否已经安装,再次请注意,-V参数为大写的英语字母:

[root@localhost /]# ip -V
ip utility, iproute2-ss091226

一、管理策略数据库

在Linux下,基于策略路由的策略数据库是由ip命令来管理的,下面讨论“管理”的几个方面:
1、查看策略数据库
要查看策略数据库的内容,可以使用ip rule show命令,或者可以使用ip rule ls。如下是命令执行后所得到的输出结果,在这些数据中,可以看到系统的三条默认规则,而这三条规则默认分别对应于local、main及default三个路由表。

[root@localhost /]# ip rule show
0: from all lookup local
32766: from all lookup main
32767: from all lookup default

2、添加规则
在添加规则时,必须先确定好“条件”、“优先级别”及“路由表ID”,此后才可以执行添加规则的操作。
a. 条件
条件是用来决定哪类数据包可以符合这项规则,而可用来匹配的字段为Source IP、Destination IP、Type of Service、fwmark及dev等,这些字段的使用方式如下:
Source IP
根据来源端IP来决定数据包参考哪个路由表发送出去。以下两个示例分别指出,如果数据包的来源端IP是192.168.1.10,就参考路由表10;如果来源端IP为192.168.2.0/24网段的IP,就参考路由表20。

ip rule add from 192.168.1.10 table 10
ip rule add from 192.168.2.0/24 table 20

Destination IP
根据目的端IP来决定数据包参考哪个路由表发送出去。以下两个示例分别指出,如果数据包的目的端IP是168.95.1.1,就参考路由表10;如果目的端IP是168.95.0.0/24网段的IP,就参考路由表20。

ip rule add to 168.95.1.1 table 10
ip rule add to 168.96.0.0/24 table 20

fwmark(firewall mark)
将fwmark作为匹配条件时,必须搭配Netfilter一起使用, 这看起来很麻烦, 却是最灵活的匹配条件。如图10-8所示,某公司对外有三条ADSL,我们希望所有HT T P 协议经由第一条ADS L ,SMTP及POP3经由第二条ADSL,其余流量则经由第三条ADSL。可以使用如下的命令组合来达到这样的目的:

image.png

iptables -t mangle -A FORWARD -i eth3 -p tcp --dport 80 -j MARK --set-mark 1
iptables -t mangle -A FORWARD -i eth3 -p tcp --dport 25 -j MARK --set-mark 2
iptables -t mangle -A FORWARD -i eth3 -p tcp --dport 110 -j MARK --set-mark 2
iptables -t mangle -A FORWARD -i eth3 -j MARK --set-mark 3
ip rule add fwmark 1 table 1
ip rule add fwmark 2 table 2
ip rule add fwmark 3 table 3

首先使用Netfilter的managle机制针对特定的数据包设置MARK值,在此将HTTP数据包的MARK值设置为1,SMTP及POP3数据包的MARK值设置为2,其余数据包则设置MARK值为3。接着,再根据fwmark条件来判断数据包的MARK值,如果MARK值为1,则参考路由表1将数据包送出;MAKR值为2时,则参考路由表2将数据包送出;最后,MARK值为3的数据包则参考路由表3送出。

以上示例只是一个概念而已,如果真要完整体现出这个示例的所有功能,还需要注意许多细节,稍后将使用详细的示例讲解这部分内容,在此只要首先了解fwmark与Netfilter结合使用的概念即可。

dev
最后,还可以使用数据包输入的接口来作为判断依据,如图10-9所示,我们希望凡是由eth2接口送入的数据包都由eth0接口转发出去,由eth3接口送入的数据包都由eth1接口转发出去。以下命令组合将能满足我们的要求:

ip rule add dev eth2 table 1
ip rule add dev eth3 table 3
image.png

b. 优先级别
前面介绍了规则中“条件”的使用方式,接下来要讨论的是优先级别。优先级别用数字来表示,其范围可由0~4亿多,堪称天文数字,我们实际上不可能在一台PC上设置如此庞大的路由机制。

[root@localhost ~]# ip rule show
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
[root@localhost ~]#
[root@localhost ~]# ip rule add from 192.168.1.0/24 table 1
[root@localhost ~]# ip rule add from 192.168.2.0/24 table 2
[root@localhost ~]#
[root@localhost ~]# ip rule show
0: from all lookup local
32764: from 192.168.2.0/24 lookup 2
32765: from 192.168.1.0/24 lookup 1
32766: from all lookup main
32767: from all lookup default

如以上示例,我们执行ip rule show命令所显示内容的第一个字段就是优先级别,数字越小,代表优先级别越高,也代表这条规则可以排得越靠前,如此数据包在进行条件匹配时,就会越早匹配到这条规则,从输出的数据中,默认优先级别0、32766及32767已被占用,因此,在添加规则时,如果没有特别设置优先级别,那么,优先级别默认会从32766开始递减,如32765、32764……,如果我们需要特别设置优先级别,可以在ip rule add命令的最后加上prio XXX参数。如下例所示:

[root@localhost ~]# ip rule show
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
[root@localhost ~]#
[root@localhost ~]# ip rule add from 192.168.1.0/24 table 1 prio 10
[root@localhost ~]# ip rule add from 192.168.2.0/24 table 2 prio 20
[root@localhost ~]#
[root@localhost ~]# ip rule show
0: from all lookup local
10: from 192.168.1.0/24 lookup 1
20: from 192.168.2.0/24 lookup 2
32766: from all lookup main
32767: from all lookup default

c. 路由表ID
在Linux的基于策略的路由中,路由表用ID来表示,但如有必要,还可以用ID与名称对照表将ID转换成名称。

3、删除规则
ip命令提供的删除规则的方式十分灵活,例如,要删除下列第2条规则,可以分别使用“优先级别”、“条件”及“路由表”当中任何一个唯一的值来设置所需删除的规则,如下:

ip rule del prio 10
ip rule del from 192.168.1.0/24
ip rule del table 1
ip rule del from 192.168.1.0/24 table 1 prio 10
[root@localhost ~]# ip rule show
0: from all lookup local
10: from 192.168.1.0/24 lookup 1
20: from 192.168.2.0/24 lookup 2
32766: from all lookup main
32767: from all lookup default

二、路由表管理
由于route -n命令已经完全不适合在基于策略的路由使用,因此,route命令仅能操作一个特定的路由表,但在基于策略的路由中,会同时存在多个路由表,请放弃这个路由管理工具,取而代之的依然是ip命令。接下来将讨论如何使用ip命令来管理路由表。

1、查看路由表内容
在查看路由表之前,首先使用ip rule show命令来查看目前使用了哪些路由表,接着,再使用ip route show [table id | name]命令来查看路由表的内容。例如,可以使用ip route show table main来查看路由表main的内容,如果省略路由表名称(如ip route show),会默认地查看路由表main的内容。

[root@localhost /]# ip rule show
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
[root@localhost /]#
[root@localhost /]# ip route show table main
10.10.15.0/25 dev eth0 proto kernel scope link src 10.10.15.46
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.10
default via 10.10.15.1 dev eth0

在默认情况下,系统有三个路由表,这三个路由表的功能如下:
local:路由表local包含本机路由及广播信息。例如,在本机上执行ssh 127.0.0.1时,就会参考这份路由表的内容,在正常情况下,只要配置好网卡的网络设置,就会自动生成local路由表的内容,我们应该也不必修改其内容。

main:使用传统命令route -n所看到的路由表就是main的内容。Linux系统在默认情况下使用这份路由表的内容来传输数据包,因此,其内容极为重要,在正常情况下,只要配置好网卡的网络设置,就会自动生成main路由表的内容。

default:最后是default路由表,这个路由表在默认情况下内容为空;除非有特别的要求,否则保持其内容为空即可。

在此使用路由表main的内容进行解释,以下是路由表main的内容,因为在主机上有eth0及eth1两块网卡,且为其设置的IP分别是10.10.15.46/25及192.168.1.10/24,因此,路由表内的第一行即是告诉系统,如果有数据包要送到10.10.15.0/25这个网段,就直接将数据包由eth0接口送出即可,而本机临近这个网段的IP是10.10.15.46,第二行则是设置到192.168.1.0/24的路由,其含义与第一行完全相同;以上这两行是只要将计算机网卡上的IP设置好,并在网络服务重启之后,默认就会生成的路由,无需特别的设置。最后一行则指:如果数据包不是送往10.10.15.0/25及192.168.1.0/24网段,那么数据包将统一转发给10.10.15.1主机去处理,而10.10.15.1就是我们在网络配置中所设置的“默认网关”。

10.10.15.0/25 dev eth0 proto kernel scope link src 10.10.15.46
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.10
default via 10.10.15.1 dev eth0

2、添加路由
添加路由在此还是一样采用ip命令而不是route命令,下例首先使用ip route show.命令显示路由表main的内容,接着再使用ip route add命令将所需的路由添加到路由表main中.,最后再次使用ip route show命令将路由表main的内容打印出来,此时就可以在路由表main之中看到刚才添加的路由了。

[root@localhost /]# ip route show table main
10.10.15.0/25 dev eth0 proto kernel scope link src 10.10.15.46
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.10
default via 10.10.15.1 dev eth0
[root@localhost /]#
[root@localhost /]# ip route add 192.168.2.0/24 via 10.10.15.50 table main
[root@localhost /]#
[root@localhost /]# ip route show table main
10.10.15.0/25 dev eth0 proto kernel scope link src 10.10.15.46
192.168.2.0/24 via 10.10.15.50 dev eth0
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.10
default via 10.10.15.1 dev eth0

如果要添加的路由并未出现在现有的路由表中,又该如何处理呢?在此请先有一个概念,单纯添加路由表并无意义,因为新增出来的路由表,系统默认是不会去使用的,如果要将路由添加到main以外的路由表,只有先添加“规则”才能确定新的路由表名称(Table ID),有了新的路由表之后,才会把路由添加到新的路由表中。

我们使用下列示例来说明这个过程。首先使用ip rule show.来查询RPDB的当前状态,可以看到目前只有三条默认规则,接着,再使用ip rule add命令来添加一条规则.,此时系统内就多了一个有用的路由表,其路由表ID为10,我们可以立即使用ip route show命令来查看这个新的路由表.,其内容默认为空,接着可以在这个新路由表中添加路由,在此使用ip route add命令来添加路由,我们决定凡是来自于192.168.2.0/24网段的数据包,都从eth1接口将数据包送离本机,因此,必须完整编写eth1接口的路由。首先将临近eth1接口的路由填入.,告诉系统本机与192.168.1.0/24网段的通信都通过eth1接口来处理,接着填入这个路由表的默认路由.,最后使用ip route show命令显示路由表10的内容。

[root@localhost ~]# ip rule show
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
[root@localhost ~]#
[root@localhost ~]# ip rule add from 192.168.2.0/24 table 10
[root@localhost ~]#
[root@localhost ~]# ip route show table 10
[root@localhost ~]#
[root@localhost ~]# ip route add 192.168.1.0/24 dev eth1 table 10
[root@localhost ~]# ip route add default via 192.168.1.254 table 10
[root@localhost ~]#
[root@localhost ~]# ip route show table 10
192.168.1.0/24 dev eth1 scope link
default via 192.168.1.254 dev eth1

3、删除路由
可以使用ip命令来方便地删除路由,我们使用以下示例来说明如何删除路由。首先将路由表10的内容显示出来.,可以看到路由表10中当前有两条路由,接着使用ip route del命令删除默认路由.,在此别忘了指定我们所要删除的是路由表10,否则默认会删除路由表main的默认路由,接着再使用ip route show 命令查看路由表10.,此时路由表10的默认路由已经不存在了,再次使用ip route del命令删除192.168.122.0/24的路由.,最后可以看到路由表10中已经没有任何路由了。

[root@localhost ~]# ip route show table 10
192.168.1.0/24 dev virbr0 scope link
default via 192.168.1.254 dev eth1
[root@localhost ~]#
[root@localhost ~]# ip route del default table 10
[root@localhost ~]#
[root@localhost ~]# ip route show table 10
192.168.1.0/24 dev virbr0 scope link
[root@localhost ~]#
[root@localhost ~]# ip route del 192.168.1.0/24 table 10
[root@localhost ~]#
[root@localhost ~]# ip route show table 10
[root@localhost ~]#

三. 源码分析
参考 https://blog.csdn.net/lickylin/article/details/38884841

如果编译内核时,配置了CONFIG_IP_MULTIPLE_TABLES选项,说明支持策略路由,否则就是普通路由。这两种路由模式分别定义了路由查找函数fib_lookup。

现在默认都会打开策略路由,所以主要分析策略路由流程,而且策略路由也包含了普通路由查找。

策略路由fib_default_rules_init初始化时,会调用fib_default_rule_add添加三个默认rule: local,main和default,分别指向三个对应的路由表。添加rule时,第二个参数pref是优先级的意思,值越小优先级越高。所以local rule的优先级最高,不管有没有其他策略路由,都会先匹配local rule。

static int fib_default_rules_init(struct fib_rules_ops *ops)
{
    int err;

    err = fib_default_rule_add(ops, 0, RT_TABLE_LOCAL, 0);
    if (err < 0)
        return err;
    err = fib_default_rule_add(ops, 0x7FFE, RT_TABLE_MAIN, 0);
    if (err < 0)
        return err;
    err = fib_default_rule_add(ops, 0x7FFF, RT_TABLE_DEFAULT, 0);
    if (err < 0)
        return err;
    return 0;
}

添加默认rule时,参数只有优先级和table id,将被添加到rules_list链表中,初始化完后,rules_list链表只有这三个rule,以后添加rule时,根据优先级插入到指定的位置。

int fib_default_rule_add(struct fib_rules_ops *ops,
             u32 pref, u32 table, u32 flags)
{
    struct fib_rule *r;

    r = kzalloc(ops->rule_size, GFP_KERNEL);
    if (r == NULL)
        return -ENOMEM;

    atomic_set(&r->refcnt, 1);
    r->action = FR_ACT_TO_TBL;
    r->pref = pref;
    r->table = table;
    r->flags = flags;
    r->fr_net = hold_net(ops->fro_net);

    r->suppress_prefixlen = -1;
    r->suppress_ifgroup = -1;

    /* The lock is not required here, the list in unreacheable
     * at the moment this function is called */
    list_add_tail(&r->list, &ops->rules_list);
    return 0;
}

如果没有添加过策略规则(net->ipve.fib_has_custom_rules为false),则直接查找三个默认路由表。如果添加过策略路由,则会调用__fib_lookup匹配策略,如果匹配成功则执行策略的action,包括

enum {
    FR_ACT_UNSPEC,
    FR_ACT_TO_TBL,      /* Pass to fixed table */
    FR_ACT_GOTO,        /* Jump to another rule */
    FR_ACT_NOP,     /* No operation */
    FR_ACT_RES3,
    FR_ACT_RES4,
    FR_ACT_BLACKHOLE,   /* Drop without notification */
    FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
    FR_ACT_PROHIBIT,    /* Drop with EACCES */
    __FR_ACT_MAX,
};

在查找路由表时,如果指定了策略路由,则先查找策略路由

ip_rcv_finish->ip_route_input_slow->fib_lookup

static inline int fib_lookup(struct net *net, struct flowi4 *flp,
                 struct fib_result *res)
{
    if (!net->ipv4.fib_has_custom_rules) {
        res->tclassid = 0;
        if (net->ipv4.fib_local &&
            !fib_table_lookup(net->ipv4.fib_local, flp, res,
                      FIB_LOOKUP_NOREF))
            return 0;
        if (net->ipv4.fib_main &&
            !fib_table_lookup(net->ipv4.fib_main, flp, res,
                      FIB_LOOKUP_NOREF))
            return 0;
        if (net->ipv4.fib_default &&
            !fib_table_lookup(net->ipv4.fib_default, flp, res,
                      FIB_LOOKUP_NOREF))
            return 0;
        return -ENETUNREACH;
    }
    return __fib_lookup(net, flp, res);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342