【网络协议-9】网络路由配置实操

Demon.Lee 2022年04月17日 2,463次浏览

本文实践环境:
Operating System: CentOS Linux release 8.4.2105
Kernel: 4.18.0-305
Architecture: x86-64

在上一篇 网络路由概述 中,笔者对路由的基本概念进行了介绍,并通过 netstat -rn 命令查看了路由表,同时对动态路由和静态路由也进行了简单的说明。 在这一篇,笔者将对网络路由的配置进行实操,并对相关内容进行梳理和总结。

路由配置实操

在进行路由实操之前,让我们先回过头,再复习一下之前文章中提及的网络流量走向图:

工作在第 3 层的路由器,会根据目的 IP 找到下一站地址,层层接力,就像生活中的快递一般,一直将数据送到指定位置。而之所以每一层的路由器都能接力,原因在于这些路由器之间会交换信息,即它们都有目的地 IP 的路由信息。

路由表查看

一张路由表既然作为引路人,其中的每一条路由规则至少需要包含三类信息:

  • 目的网络:这个网络包的最终目的地;
  • 出口设备:这个网络包从哪个网卡设备出去;
  • Next Hop 网关:网络包去往的下一个路由器地址。

除了使用 netstat -rn 查看路由表外,还可以通过 routeip route 进行路由表的配置或查看。

net-tools vs iproute2 这篇文章中,笔者对两个类库进行了对比,其中就提到 route; netstat -rip route 的功能是相对应的。

下面是笔者在 CentOS 机器上执行三条命令的结果:

➜  ~ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         10.120.74.1     0.0.0.0         UG        0 0          0 eth0
10.120.74.0     0.0.0.0         255.255.255.0   U         0 0          0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U         0 0          0 docker0
➜  ~ 
➜  ~ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         _gateway        0.0.0.0         UG    100    0        0 eth0
10.120.74.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
➜  ~ 
➜  ~ ip route
default via 10.120.74.1 dev eth0 proto dhcp metric 100 
10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
➜  ~

可以看到,netstat -rnroute 命令的输出是一致的,由于笔者在上一篇 网络路由概述 中已经对相关输出参数进行了说明,所以这里就不再赘述。

下面,我们就重点看看 ip route 命令的输出结果,结合 routenetstat -rn 命令的结果,在不查询资料的情况下,我们也能大致猜测出其内容,比如:

default via 10.120.74.1 dev eth0 proto dhcp metric 100
default 为默认网关,下一跳为 10.120.74.1,需要走 eth0 网口出去,距离为 100

再比如:

10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100
到目的地 10.120.74.0/24 网段,走 eth0 网口出去,由于没有 via,所以不需要走网关,距离也是 100

下面我们通过 man ip-route 来将相关参数一个个剖析:

  • dev: the output device name
  • proto:the routing protocol identifier of this route. 路由协议标识符,dhcp 表示这条路由是由 dhcp 协议生成的,kernel 表示路由是由操作系统内核自动配置的,static 表示管理员手动添加的路由。
  • scope: the scope of the destinations covered by the route prefix. 路由范围,取值有 host | link | global 等,host 表示本机路由,link 表示同一链路上的路由,global 表示走网关的全局路由。
  • src: the source address to prefer when sending to the destinations covered by the route prefix. 发送数据包时的源 ip 地址,可能主机上有多个网卡都能发送该包,但使用 src 指定源地址后,该包就只从对应的网卡出去[1]
  • via: the address of the nexthop router

最后一条路由中,还有一个 linkdown 属性,这个的意思是其出口的网卡(这里为 docker0)状态是 DOWN,我们通过 ip addr show docker0 来确认一下:

➜  ~ ip addr show docker0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:f2:df:7c:6e brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
➜  ~

路由表配置

根据 man ip-route 的说明,可以看到路由表管理的部分命令如下:

NAME
ip-route - routing table management

SYNOPSIS
ip [ ip-OPTIONS ] route { COMMAND | help }
ip route { show | flush } SELECTOR
ip route save SELECTOR
ip route restore
ip route get ROUTE_GET_FLAGS ADDRESS [ from ADDRESS iif STRING ] [ oif STRING ] [ mark MARK] [ tos TOS ] [ vrf NAME ] [ ipproto PROTOCOL ] [ sport NUMBER ] [ dport NUMBER ]
ip route { add | del | change | append | replace } ROUTE
ROUTE := NODE_SPEC [ INFO_SPEC ]
NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ] [ table TABLE_ID ] [ proto RTPROTO ] [ scope SCOPE ] [ metric METRIC ] [ ttl-propagate { enabled | disabled } ]
INFO_SPEC := { NH | nhid ID } OPTIONS FLAGS [ nexthop NH ] …


TYPE := [ unicast | local | broadcast | multicast | throw | unreachable | prohibit | black‐hole | nat ]
TABLE_ID := [ local| main | default | all | NUMBER ]
SCOPE := [ host | link | global | NUMBER ]
NHFLAGS := [ onlink | pervasive ]
RTPROTO := [ kernel | boot | static | NUMBER ]

由于涉及的命令以及相关参数非常多,故无法一一说明。这里,笔者以 ip route add/delete 来演示路由规则的增加和删除。

101.71.145.130 是 www.163.com 上暴露的一个公网 IP,上面展示的 3 条路由规则中,没有相关的匹配条件,所以 ping 101.71.145.130 会走默认路由。现在笔者来做一些调整,演示过程如下:

step0: 默认情况,访问正常。

➜  ~ ip route list
default via 10.120.74.1 dev eth0 proto dhcp metric 100 
10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
➜  ~ 
➜  ~ ping 101.71.145.130
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
64 bytes from 101.71.145.130: icmp_seq=1 ttl=53 time=14.4 ms
64 bytes from 101.71.145.130: icmp_seq=2 ttl=53 time=14.2 ms
64 bytes from 101.71.145.130: icmp_seq=3 ttl=53 time=14.4 ms
64 bytes from 101.71.145.130: icmp_seq=4 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=5 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=6 ttl=53 time=14.2 ms
--- 101.71.145.130 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5007ms
rtt min/avg/max/mdev = 14.201/14.286/14.383/0.154 ms
➜  ~ 

step1: 配置 101.71.145.130/32 走 eth0 出去,但不经过默认网关。

➜  ~ ip route add 101.71.145.130/32 src 10.120.74.18 dev eth0
➜  ~ 
➜  ~ ip route list                                               
default via 10.120.74.1 dev eth0 proto dhcp metric 100 
10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
101.71.145.130 dev eth0 scope link src 10.120.74.18 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
➜  ~ 
➜  ~ ping 101.71.145.130                                         
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
From 10.120.74.18 icmp_seq=1 Destination Host Unreachable
From 10.120.74.18 icmp_seq=2 Destination Host Unreachable
From 10.120.74.18 icmp_seq=3 Destination Host Unreachable
From 10.120.74.18 icmp_seq=4 Destination Host Unreachable
From 10.120.74.18 icmp_seq=5 Destination Host Unreachable
From 10.120.74.18 icmp_seq=6 Destination Host Unreachable
--- 101.71.145.130 ping statistics ---
7 packets transmitted, 0 received, +6 errors, 100% packet loss, time 6161ms
➜  ~ 

可以看到,让 101.71.145.130 走新的链路路由后,无法 ping 通了,主机不可达。

step2: 将路由改为走网关,访问恢复正常。

➜  ~ ip route replace 101.71.145.130/32 via 10.120.74.1 src 10.120.74.18 dev eth0
➜  ~ 
➜  ~ ip route list
default via 10.120.74.1 dev eth0 proto dhcp metric 100 
10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
101.71.145.130 via 10.120.74.1 dev eth0 src 10.120.74.18 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
➜  ~ 
➜  ~ ping 101.71.145.130                                                          
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
64 bytes from 101.71.145.130: icmp_seq=1 ttl=53 time=14.5 ms
64 bytes from 101.71.145.130: icmp_seq=2 ttl=53 time=14.2 ms
64 bytes from 101.71.145.130: icmp_seq=3 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=4 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=5 ttl=53 time=14.3 ms
--- 101.71.145.130 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
rtt min/avg/max/mdev = 14.236/14.313/14.484/0.090 ms
➜  ~ 

step3: 删除这条路由,访问依然正常。

➜  ~  ip route del 101.71.145.130/32 via 10.120.74.1 src 10.120.74.18 dev eth0
➜  ~ 
➜  ~  ip route list
default via 10.120.74.1 dev eth0 proto dhcp metric 100 
10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
➜  ~ 
➜  ~  ping 101.71.145.130
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
64 bytes from 101.71.145.130: icmp_seq=1 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=2 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=3 ttl=53 time=14.4 ms
64 bytes from 101.71.145.130: icmp_seq=4 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=5 ttl=53 time=14.2 ms
64 bytes from 101.71.145.130: icmp_seq=6 ttl=53 time=14.4 ms
--- 101.71.145.130 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5007ms
rtt min/avg/max/mdev = 14.234/14.318/14.384/0.085 ms
➜  ~ 

再探路由表

路由表,它是一张或多张表,那这个表怎么体现呢?认真查阅 man ip-route 的话,可以看到有一个 [table TABLE_ID] 选项,而 TABLE_ID 的取值有:

TABLE_ID := [ local| main | default | all | NUMBER ]

笔者这里先猜测:前面 4 个是字符串,all 代表所有,local、main 和 default 分别代表 3 张表,最后一个 NUMBER 是这些表对应的数字标识,笔者通过 ip route list table xxx 来看看它们返回的区别:

➜  ~ ip route list table local
broadcast 10.120.74.0 dev eth0 proto kernel scope link src 10.120.74.18 
local 10.120.74.18 dev eth0 proto kernel scope host src 10.120.74.18 
broadcast 10.120.74.255 dev eth0 proto kernel scope link src 10.120.74.18 
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1 
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1 
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1 
broadcast 172.17.0.0 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
local 172.17.0.1 dev docker0 proto kernel scope host src 172.17.0.1 
broadcast 172.17.255.255 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
➜  ~ 
➜  ~ ip route list table main
default via 10.120.74.1 dev eth0 proto dhcp metric 100 
10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
➜  ~ 
➜  ~ ip route list table default
Error: ipv4: FIB table does not exist.
Dump terminated
➜  ~ 
➜  ~ ip route list table all    
default via 10.120.74.1 dev eth0 proto dhcp metric 100 
10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
broadcast 10.120.74.0 dev eth0 table local proto kernel scope link src 10.120.74.18 
local 10.120.74.18 dev eth0 table local proto kernel scope host src 10.120.74.18 
broadcast 10.120.74.255 dev eth0 table local proto kernel scope link src 10.120.74.18 
broadcast 127.0.0.0 dev lo table local proto kernel scope link src 127.0.0.1 
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1 
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1 
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1 
broadcast 172.17.0.0 dev docker0 table local proto kernel scope link src 172.17.0.1 linkdown 
local 172.17.0.1 dev docker0 table local proto kernel scope host src 172.17.0.1 
broadcast 172.17.255.255 dev docker0 table local proto kernel scope link src 172.17.0.1 linkdown 
::1 dev lo proto kernel metric 256 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
local ::1 dev lo table local proto kernel metric 0 pref medium
local fe80::5054:99ff:fe2f:37b1 dev eth0 table local proto kernel metric 0 pref medium
ff00::/8 dev eth0 table local metric 256 pref medium
➜  ~

接着看 man ip-route 中的描述,来详细了解一下:

Route tables: Linux-2.x can pack routes into several routing tables
identified by a number in the range from 1 to 2^32-1 or by name from the file /etc/iproute2/rt_tables.
By default all normal routes are inserted into the main table (ID 254) and the kernel only uses this table when calculating routes. Values (0, 253, 254, and 255) are reserved for built-in use.

Actually, one other table always exists, which is invisible but even more important.
It is the local table (ID 255). This table consists of routes for local and broadcast addresses.
The kernel maintains this table automatically and the administrator usually need not modify it or even look at it.

The multiple routing tables enter the game when policy routing is used.

从这段内容中,可以得到以下信息:

  • 路由表名可以用字符串或数字表示,数字范围:1 ~ 2^32-1。

  • 路由表名称可以从 /etc/iproute2/rt_tables 中查看,笔者查看如下。可以看到,/etc/iproute2 目录下除了 rt_tables,还有多个其他配置参数。

    [root@i-mluwuwl1]/etc/iproute2# pwd              
    /etc/iproute2
    [root@i-mluwuwl1]/etc/iproute2# 
    [root@i-mluwuwl1]/etc/iproute2# ls -l
    total 36
    -rw-r--r--. 1 root root  85 Oct 16 01:08 bpf_pinning
    -rw-r--r--. 1 root root  81 Oct 16 01:08 ematch_map
    -rw-r--r--. 1 root root  31 Oct 16 01:08 group
    -rw-r--r--. 1 root root 262 Oct 16 01:08 nl_protos
    -rw-r--r--. 1 root root 735 Oct 16 01:08 rt_dsfield
    -rw-r--r--  1 root root 210 Oct 16 01:08 rt_protos
    -rw-r--r--. 1 root root 112 Oct 16 01:08 rt_realms
    -rw-r--r--. 1 root root  92 Oct 16 01:08 rt_scopes
    -rw-r--r--. 1 root root  87 Oct 16 01:08 rt_tables
    [root@i-mluwuwl1]/etc/iproute2# 
    [root@i-mluwuwl1]/etc/iproute2# cat rt_tables 
    #
    # reserved values
    #
    255     local
    254     main
    253     default
    0       unspec
    #
    # local
    #
    #1      inr.ruhep
    [root@i-mluwuwl1]/etc/iproute2#
    
  • 内置的路由表有 4 个:local、main、default 和 unspec,对应的数字分别为 255、254、253 和 0,笔者用数字进行了实践,如下所示。从结果上来看,table=0 其实就是查询所有。

    ➜  ~ ip route list table 254
    default via 10.120.74.1 dev eth0 proto dhcp metric 100 
    10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
    172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
    ➜  ~ 
    ➜  ~ ip route list table 0  
    default via 10.120.74.1 dev eth0 proto dhcp metric 100 
    10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
    172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
    broadcast 10.120.74.0 dev eth0 table local proto kernel scope link src 10.120.74.18 
    local 10.120.74.18 dev eth0 table local proto kernel scope host src 10.120.74.18 
    broadcast 10.120.74.255 dev eth0 table local proto kernel scope link src 10.120.74.18 
    broadcast 127.0.0.0 dev lo table local proto kernel scope link src 127.0.0.1 
    local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1 
    local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1 
    broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1 
    broadcast 172.17.0.0 dev docker0 table local proto kernel scope link src 172.17.0.1 linkdown 
    local 172.17.0.1 dev docker0 table local proto kernel scope host src 172.17.0.1 
    broadcast 172.17.255.255 dev docker0 table local proto kernel scope link src 172.17.0.1 linkdown 
    ::1 dev lo proto kernel metric 256 pref medium
    fe80::/64 dev eth0 proto kernel metric 256 pref medium
    local ::1 dev lo table local proto kernel metric 0 pref medium
    local fe80::5054:99ff:fe2f:37b1 dev eth0 table local proto kernel metric 0 pref medium
    ff00::/8 dev eth0 table local metric 256 pref medium
    ➜  ~ 
    
  • 默认情况下,ip route list 查看的是 main table,而配置一条新路由时,默认插入的也是 main table(如果不指定 table 参数)。

  • local table (ID 255) 是不可见的,但很重要。其由内核自动维护,管理员无需关注,表中内容由本地地址和广播地址的路由组成。

  • default table (ID 253) 默认为空,这也是为啥上面查询时出现了错误提示。

    The default table is empty. It is reserved for some post-processing if no previous default rules selected the packet.

补充:除了 ip route list 可以查看路由外,ip route show 也是可以的,笔者这里就不再赘述了。

注意上面描述中最后一句话,当使用路由策略时,路由表会被用到。

The multiple routing tables enter the game when policy routing is used.

那么,什么是路由策略呢?

路由策略

通过 man ip-rule 可以了解到相关信息:

ip-rule - routing policy database management
ip rule manipulates rules in the routing policy database control the route selection algorithm.

Classic routing algorithms used in the Internet make routing decisions based only on the destination address of packets (and in theory, but not in practice, on the TOS field).

In some circumstances we want to route packets differently depending not only on destination addresses, but also on other packet fields: source address, IP protocol, transport protocol ports or even packet payload. This task is called ‘policy routing’.

在上面的路由表实操中,其实是根据 IP 地址来配置路由的。但在真实的复杂网络环境中,在此基础上还可以根据多个参数来配置路由,比如源 IP 地址、入口设备(数据包从哪个网卡进入)、传输协议端口、TOS(Type Of Service)等,这就是策略路由。如此一来,就能将不同来源的数据包走不同的路由。

配置路由策略,就得用到 ip rule 命令,通过 ip rule show 可以查看当前已经有的规则:

➜  ~  ip rule show
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default
➜  ~ 

结合官方手册,我们知道这是系统默认的 3 条规则:

  • 第 1 列的数字为优先级,值越小优先级越高。
  • 3 条规则分别对应 3 张路由表,分别为 local,main 和 default。

下面笔者就依据官方手册,进行简单的实操配置,比如针对从 10.120.74.18 发出的包,目的地为 101.71.145.130 包走单独的 tabel 10。

step0: 将 rule 的 type 类型定义为 unreachable

➜  ~ echo 10 testing >> /etc/iproute2/rt_tables
➜  ~ 
➜  ~ ip rule add from 10.120.74.18 to 101.71.145.130 type unreachable table testing
➜  ~ 
➜  ~ ip rule list
0:      from all lookup local
32765:  from 10.120.74.18 to 101.71.145.130 lookup testing unreachable
32766:  from all lookup main
32767:  from all lookup default
➜  ~ 
➜  ~ ping 101.71.145.130
connect: Network is unreachable
➜  ~ 

关于这个规则类型,在官方手册中有如下定义:

The RPDB may contain rules of the following types:

  • unicast - the rule prescribes to return the route found in the routing table referenced by the rule.
  • blackhole - the rule prescribes to silently drop the packet.
  • unreachable - the rule prescribes to generate a ‘Network is unreachable’ error.
  • prohibit - the rule prescribes to generate ‘Communication is administratively prohibited’ error.
  • nat - the rule prescribes to translate the source address of the IP packet into some other value.

step1: 将 rule 的 type 类型调整为 blackhole,观察其与上面的区别

➜  ~ ip rule del from 10.120.74.18 to 101.71.145.130 type unreachable table testing
➜  ~ 
➜  ~ ip rule add from 10.120.74.18 to 101.71.145.130 type blackhole table testing
➜  ~ 
➜  ~ ip rule list
0:      from all lookup local
32765:  from 10.120.74.18 to 101.71.145.130 lookup testing blackhole
32766:  from all lookup main
32767:  from all lookup default
➜  ~ 
➜  ~ ping 101.71.145.130
connect: Invalid argument
➜  ~ 

step2: 将 rule 的 type 类型调整为默认值 unicast,观察其与上面的区别

➜  ~ ip rule del from 10.120.74.18 to 101.71.145.130 type blackhole table testing
➜  ~ 
➜  ~ ip rule add from 10.120.74.18 to 101.71.145.130 type unicast table testing
➜  ~ 
➜  ~ ip rule list
0:      from all lookup local
32765:  from 10.120.74.18 to 101.71.145.130 lookup testing
32766:  from all lookup main
32767:  from all lookup default
➜  ~ 
➜  ~ ping 101.71.145.130
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
64 bytes from 101.71.145.130: icmp_seq=1 ttl=53 time=14.2 ms
64 bytes from 101.71.145.130: icmp_seq=2 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=3 ttl=53 time=14.4 ms
64 bytes from 101.71.145.130: icmp_seq=4 ttl=53 time=14.2 ms
--- 101.71.145.130 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 14.214/14.269/14.354/0.156 ms
➜  ~ 

step3: 给 table 10 中添加路由规则,默认走 10.120.74.1 网关出去

➜  ~ ip route list table 10
Error: ipv4: FIB table does not exist.
Dump terminated
➜  ~ 
➜  ~ ip route add default via 10.120.74.1 dev eth0 table testing
➜  ~ 
➜  ~ ip route list table 10
default via 10.120.74.1 dev eth0 
➜  ~ 
➜  ~ ping 101.71.145.130
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
64 bytes from 101.71.145.130: icmp_seq=1 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=2 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=3 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=4 ttl=53 time=14.4 ms
64 bytes from 101.71.145.130: icmp_seq=5 ttl=53 time=14.2 ms
--- 101.71.145.130 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
rtt min/avg/max/mdev = 14.235/14.280/14.357/0.114 ms
➜  ~ 

step4: 修改 table 10 中路由规则

➜  ~ ip route del default via 10.120.74.1 dev eth0 table testing
➜  ~ 
➜  ~ ip route add default dev docker0 table 10
➜  ~ 
➜  ~ ip route list table 10
default dev docker0 scope link linkdown
➜  ~ 
➜  ~ ping 101.71.145.130
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
--- 101.71.145.130 ping statistics ---
34 packets transmitted, 0 received, 100% packet loss, time 33809ms
➜  ~ 
➜  ~ ip route del default dev docker0 table 10
➜  ~ 
➜  ~ ping 101.71.145.130
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
64 bytes from 101.71.145.130: icmp_seq=1 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=2 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=3 ttl=53 time=14.4 ms
64 bytes from 101.71.145.130: icmp_seq=4 ttl=53 time=14.4 ms
64 bytes from 101.71.145.130: icmp_seq=5 ttl=53 time=14.2 ms
64 bytes from 101.71.145.130: icmp_seq=6 ttl=53 time=14.3 ms
--- 101.71.145.130 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5007ms
rtt min/avg/max/mdev = 14.228/14.309/14.379/0.054 ms
➜  ~ 

可以看到,添加新的规则后,ping 101.71.145.130 没有响应,将新规则删除后,又可以 ping 通了。

step5: 继续修改 table 10 中路由规则,将前文一开始的路由规则添加进来

➜  ~ ip route add 101.71.145.130/32 src 10.120.74.18 dev eth0 table 10
➜  ~ 
➜  ~ ip route list table 10
101.71.145.130 dev eth0 scope link src 10.120.74.18
➜  ~ 
➜  ~ ping 101.71.145.130
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
64 bytes from 101.71.145.130: icmp_seq=1 ttl=53 time=14.5 ms
64 bytes from 101.71.145.130: icmp_seq=2 ttl=53 time=14.5 ms
64 bytes from 101.71.145.130: icmp_seq=3 ttl=53 time=14.3 ms
64 bytes from 101.71.145.130: icmp_seq=4 ttl=53 time=14.4 ms
--- 101.71.145.130 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 14.318/14.422/14.487/0.106 ms
➜  ~ 
➜  ~ ip route add 101.71.145.130/32 src 10.120.74.18 dev eth0
➜  ~ 
➜  ~ ip route list
default via 10.120.74.1 dev eth0 proto dhcp metric 100 
10.120.74.0/24 dev eth0 proto kernel scope link src 10.120.74.18 metric 100 
101.71.145.130 dev eth0 scope link src 10.120.74.18 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
➜  ~ 
➜  ~ ping 101.71.145.130
PING 101.71.145.130 (101.71.145.130) 56(84) bytes of data.
From 10.120.74.18 icmp_seq=1 Destination Host Unreachable
From 10.120.74.18 icmp_seq=2 Destination Host Unreachable
From 10.120.74.18 icmp_seq=3 Destination Host Unreachable
--- 101.71.145.130 ping statistics ---
4 packets transmitted, 0 received, +3 errors, 100% packet loss, time 3058ms
➜  ~ 

可以看到,table 10 中添加该规则之后,仍然可以 ping 通 101.71.145.130,继续把该规则加入到 table main 中,就 ping 不通了。

笔者这里还不甚理解,猜测ip rule list 返回的多条记录逐个匹配,虽然前面 table 10 中匹配到了,但并没有拦截住,所以继续匹配 table main。

最后再额外补充一下,上面各类操作,都只是当前生效,如果操作系统重启,这些配置就会被重置掉。笔者结合 stackexchange 论坛[2]和 Redhat 官方文档[3],在当前 centOS 8 上的永久配置如下,供参考:

➜  ~ echo 10 testing >> /etc/iproute2/rt_tables
➜  ~ 
➜  ~ echo "ip rule add from 10.120.74.18 to 101.71.145.130 type unicast table 10" >> /etc/rc.local
➜  ~ 
➜  ~ chmod u+x /etc/rc.local
➜  ~ 
➜  ~ touch /etc/sysconfig/network-scripts/route-eth0
➜  ~ echo "101.71.145.130/32 src 10.120.74.18 dev eth0 table 10" >> /etc/sysconfig/network-scripts/route-eth0
➜  ~ 

在谈网络路由时,除了 ip route 命令外,还有一个 iptables 命令也使用的十分频繁,那二者有什么关系呢?针对这一块的内容,笔者将在后续的内容中继续梳理和分享,敬请期待。

参考资料


  1. https://serverfault.com/questions/451601/ip-route-show-src-field ↩︎

  2. https://unix.stackexchange.com/questions/365380/how-to-persist-ip-rule-and-route-whenever-server-rebooted ↩︎

  3. https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/networking_guide/sec-configuring_static_routes_in_ifcfg_files ↩︎