全部博文(1144)
分类: LINUX
2006-04-26 14:24:23
在讨论了命令语法以后,下面是一些上面命令的示例。 |
例 1:拒绝访问Internet |
假设有一个防火墙连接本地局域网和Internet,你希望禁止局域网的一个子网访问Internet。当然这可以通过Linux数据报过滤防火墙来实现。但是下面我们将介绍另外一种实现方法。首先我们来假设有如下的网络配置: |
内部网络地址 192.168.0.0/16 |
被拒绝访问的子网 192.168.2.0/24 |
当前主路由表(Routing Table Main,表254): |
root@netmonster# ip route list table 254 |
default via 192.168.254.254 dev eth0 proto static |
下面将针对该子网创建一条策略路由规则: |
ip rule add from 192.168.2.0/24 priority 5000 prohibit |
现在任何从192.168.2.0/24子网发送来的数据报将得到一个类型为3,代码为13的ICMP消息,同时该数据报将被丢弃。 |
应该注意的是,在运行任何这些命令都需要发送“ip route flush cache"命令来刷新路由缓冲,否则命令在一段时间以后才会生效,这段时间的长短依赖于路由表结构的大小和负载。 |
将上面的例子需要的命令放在一起就如下所示: |
ip rule del priority 5000 |
ip rule add from 192.168.2.0/24 priority 5000 prohibit |
ip route flush cache |
这个命令流通过首先删除5000号规则来确保当前系统没有该规则然后再添加新的5000号规则。如果系统本来不存在5000号的规则则会返回一个错误信息。然后添加5000号规则并通过清空运行时的路由缓存来重置RPDB,则新规则将马上产生作用。 |
多路由表和IP地址 |
为了完全理解基于策略路由的使用,就需要学会使用Linux多路由表和IP地址,这包括多个方面的知识,下面通过示例来加以说明。 |
当获得ip工具,你可能会注意到在发布中有一个名为etc的子目录,其中有一个名为iproute2的子目录。应该拷贝该子目录到/etc目录下或在/etc目录下创建iproute2子目录。该目录包含用来命名路由表及策略路由结构的其他方面的文件。在该目录中创建rt_tables文件,其中示例文件一般已经包含了某些内容,并为路由表1提供了示例名。 |
下面首先编辑该文件来创建若干在下面的示例中使用的表: |
# reserved values |
# |
255 local |
254 main |
253 default |
0 unspec |
# |
# local |
# |
1 goodnet1 |
2 goodnet2 |
3 badnet1 |
4 badnet2 |
5 internet |
可以看到通过为路由表命名,就可以使用表数字ID或表名来引用路由表。例如下面两个命令将对同一个路由表进行操作: |
ip route list table 1 |
ip route list table goodnet1 |
通过表名可以更好的理解在对哪个路由表进行操作。 |
例 2:创建多个路由表 |
如果已经创建了如上所示的rt_table信息,可以通过下面的命令来察看各个路由表的内容: |
ip route list table |
当然即使没有定义rt_table文件同样可以使用数字来引用所有的0-255个路由表,因为它们都是存在的,只是其中大部分没有路由信息数据罢了。在上面的例子中通过rt_table文件来将表1定义为goodnet1。 |
下面的例子是向定义的每个路由表都添加一条路由: |
ip route add 10.10.10.0/24 via 192.168.1.2 table goodnet1 |
ip route add 10.10.11.0/24 via 192.168.1.2 table goodnet2 |
ip route add 10.10.12.0/24 via 192.168.1.2 table badnet1 |
ip route add 10.10.13.0/24 via 192.168.1.2 table badnet1 |
ip route add default via 192.168.1.254 table internet |
然后再通过ip rouite list talbe |
例3:建立多个IP地址 |
这里的多个IP地址并不同于IP别名,在Linux2.1及更高版本中已经反对使用":#"的IP别名方式。而应该用新的方式来使用多IP地址。 |
假设eth0输出接口应该具有三个不同的IP地址,其中的两个应该属于同一个子网,但是应该被独立地设置,示例同样说明了在Linux2.2及以上版本的关闭自动路由添加的方法。在Linux2.2及以上版本内核的系统中,当为一个接口赋予一个IP地址时,内核将自动为该IP地址属于的网络在路由表中添加一条对应的路由。而由于这里将为同一个接口赋予属于同一个子网的两个不同的IP,所以在添加IP地址时不希望添加路由,否则会造成路由冲突,因此就需要添加该地址为一个主机地址。只需要设置该地址时指定完全主机地址掩码,然后手工添加必要的路由。 |
为接口设置如下地址: |
192.168.1.1 |
192.168.1.128 |
192.168.3.1 |
在添加192.168.1.0/24的两个地址时需要关闭自动路由添加,而允许对192.168.3.0/24时允许自动路由添加功能。 |
ip addr add 192.168.1.1/32 dev eth0 |
ip addr add 192.168.1.128/32 dev eth0 |
ip addr add 192.168.3.1/24 dev eth0 |
这时候如果察看主路由表则会发现内核只为网络192.168.3.0/24添加了路由表,而没有为网络192.168.1.0/24添加路由。 |
通过ip addr命令可以察看系统的所有IP地址信息: |
root@netmonster# ip addr |
1: lo: |
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 |
inet 127.0.0.1/8 brd 127.255.255.255 scope host lo |
2: eth0: |
link/ether 00:00:49:61:32:bc brd ff:ff:ff:ff:ff:ff |
inet 192.168.1.1/32 scope global eth0 |
inet 192.168.1.128/32 scope global eth0 |
inet 192.168.3.1/24 scope global eth0 |
下面我们将讨论几个更加复杂的例子。 |
例 4:多路由表和IP地址 |
Linux内核路由代码最强大的特色就是基于策略的路由和使用多地址、多路由表的结合使用。下面的示例讨论的是一个充当路由器的连接三个不同的网络的系统。 |
参考文章开头的图片,可以看到核心系统的外部接口连接了三个外部网络。每个网络都有自己的路由器和自己的IP地址空间。但是其中的两个地址空间是重叠的,因此增加了情况的复杂性。这里我们设置如下规则的路由表来实现互联: |
? 从任何内部网络到Inetent的数据流都是允许的。 |
? 从内部网B到网络A的数据流是允许的。 |
? 从内部网A到网络C的数据流是允许的。 |
? 内部网A的地址为33-62的主机允许访问网络A。 |
? 内部网B的地址为65-78的主机允许访问网络C。 |
首先,配置两个外部IP地址-在DMZ以太网接口eth0的两个地址: |
ip addr add 10.254.254.2/30 dev eth0 |
ip addr add 172.17.1.128/24 dev eth0 |
下一步将讨论创建哪些路由表,解决这个问题的最好办法是想到基于策略的路由能实现根据源地址来决定使用哪个路由表。策略规则具有划分内部网络的能力,因此首先可以在路由表中添加基于目的的路由,在示例中我们将使用前面创建的新的路由表。 |
当在路由表中添加路由时下面的方法有助于澄清应该采取的步骤。假设你配置的是只有两个接口的路由器,外接口直接连接Interet出口路由器,而内接口直接连接内部网络。配置这样的路由器是非常简单的,为了说明我们这里在表1-goodnet1这个路由表进行操作: |
ip route add 10.10.0.0/16 via 10.254.254.2 table goodnet1 proto static |
ip route add default via 172.17.1.254 table goodnet1 proto static |
对于goodnet2进行配置则是: |
ip route add 172.18.0.0/16 via 172.17.1.1 table goodnet2 proto static |
ip route add default via 172.17.1.254 table goodnet2 proto static |
可以看到对三个目标网络只需要两个路由表,这里对于连接Internet的默认路由在两个表中都进行了设置。为什么不将默认路由存放在第三个路由表中呢?首先应该考虑到规则和路由表之间的交互,而且规则是实现对基于策略路由的定义。多条规则可以指向同一个路由表。然而,一旦进入某个路由表以后,则只能是匹配一条路由或返回一条路由链。如果匹配到一条规则则就认为你已经拥有一条正确的策略匹配,则该规则指向的路由表包含了该数据报所有的路由可能. |
如果有三个路由表,则需要添加一条规则来察看数据报目的。而检查数据报目的地址是标准路由的功能。为什么要对每种源、目的的组合都需要一个规则呢?通过使用路由表,可以实现定义尽量少的规则来达到目的。当然 系统的灵活性允许通过多条方法来实现这样的路由。可以根据在自己的喜好来决定那种方案最适合: |
ip rule add from 192.168.1.32/27 to 172.18.0.0/16 pref 15000 table goodnet1 |
ip rule add from 192.168.2.64/28 to 10.10.0.0/16 pref 15001 table goodnet2 |
ip rule add from 192.168.1.0/24 pref 15002 table goodnet1 |
ip rule add from 192.168.2.0/24 pref 15003 table goodnet2 |
上面的例子中使用了优先级参数设定来定义数据报匹配规则的顺序。现在来看看当一个数据报从内部网络经过路由系统时会发生什么情况。首先,它会通过优先级为0的规则检查;随后会遇到优先级为15000的规则,若匹配则会被goodnet1这个路由表进行操作,否则将会分别经过15001、15002、15003的规则。它肯定会被15000-15003几个规则中的一个所匹配。 |
下面为了说明定义路由结构的灵活性,我们将从另外一个角度来解决这个问题。Linux路由器的详细情况如下: |
eth0 - DMZ ethernet - addresses: 10.254.254.2/30, 172.17.1.128/24 |
eth1 - Internal A - addresses: 192.168.1.254/24 |
eth2 - Internal B - addresses: 192.168.2.254/24 |
首先假设重新开始,将重新定义路由和规则,首先编辑/etc/iproute2/rt_tables: |
# reserved values |
# |
255 local |
254 main |
253 default |
0 unspec |
# |
# Local Tables |
# |
1 int1 |
2 int2 |
创建路由和规则: |
ip route add 10.10.0.0/16 via 10.254.254.1 table int1 proto static |
ip route add throw 0/0 table int1 proto static |
ip route add 172.18.0.0/16 via 172.17.1.1 table int2 proto static |
ip route add throw 0/0 table int2 proto static |
ip route add 0/0 via 172.17.1.254 table main proto static |
ip rule add pref 15000 table int1 iif eth1 |
ip rule add pref 15001 table int2 iif eth2 |
ip rule add pref 15002 to 10.10.0.0/16 table int1 |
ip rule add pref 15003 to 172.18.0.0/16 table int2 |
这些路由和规实施和前面示例一样的操作(仔细研究这些规则和路由并理解它们) |
使用ipchains实现高级策略路由 |
在指定策略规则时可以使用的一个选项就是允许通过fwmark值来匹配某个规则。fwmark是一个数字标签,数据报过滤工具ipchains能将fwmark值附加给某个数据报。如果你对ipchains并不是很熟悉,你需要首先阅读ipchains-howto. |
例 5:简单基于fwmard的策略路由 |
首先从一个简单的例子开始-利用上面示例中的多路由表,希望实现来自内部网B的、目的端口为80的数据发送到Internet,但是来自内部网A的、目的端口为80的数据则被禁止。首先清空这些路由表: |
ip route flush table goodnet1 |
ip route flush table goodnet2 |
ip route flush table badnet1 |
ip route flush table badnet2 |
ip route flush table internet |
ip route flush cache |
而目前删除策略规则的方法就是将其一一列出来然后将其手工删除,也就是首先通过ip rule list命令将策略规则列出来然后使用ip rule del priority <#>将其删除。但这里假设当前没有任何规则并且路由表也是空的。 |
为了使用fwmark标记,首先应该指定希望使用ipchains标记的数据报,然后使用标记值来指定一条策略规则来处理该数据报。应该设定ipchians自动将十进制的标记转化为十六进制。ip rule希望输入为一个十六值。 |
首先配置ipchains规则使用合适的值标记输入数据报。假设当前没有其他防火墙规则: |
ipchains -I input -p tcp -s 192.168.2.0/24 -d 0/0 80 -m 2 |
ipchains -I input -p tcp -s 192.168.1.0/24 -d 0/0 80 -m 16 |
现在设立策略规则,在上面为内部网A的标记值为十机制的16,下面定义相关的策略(应该注意到策略定义中使用的是十六进制,因此为10): |
ip rule add fwmark 2 table goodnet1 |
ip rule add fwmark 10 prohibit |
最后为路由表goodnet1定义如下的路由: |
ip route add default via 172.17.1.254 table goodnet1 |
关于策略路由的一个常见问题是策略路由和IP伪装之间如何交互,这里我们不对该问题进行深入研究但是通过一个快速的示例来加以说明。需要注意的是在转发链之前对路由表进行查询。这意味着如果使用IP伪装,则路由选择器返回的任何源地址都将被作为进行IP伪装的地址。 |
例6:朵IP地址的IP伪装 |
使用上面的网络配置,我这里将对到三个网络的连接进行伪装处理,希望从系统中得到如下的输出: |
1. 从内部网A到网络C的数据报被伪装为10.254.254.2 |
2. 从内部网络B到网络A的数据报被伪装为172.17.1.2 |
3. 内部网到互联网的数据报都被伪装为172.17.1.128 |
eth0配置有如下地址: |
10.254.254.2/30 |
172.17.1.128/24 |
因此为了满足条件2,给eth0添加地址: |
ip addr add 172.17.1.2/32 dev eth0 |
假设系统被设置为对所有的输出数据报都进行IP伪装。首先清空旧的策略规则,然后创建新的规则如下: |
ip route add 10.10.0.0/16 via 10.254.254.2 src 10.254.254.2 |
table goodnet1 proto static |
ip route add default via 172.17.1.254 src 172.17.1.128 |
table goodnet1 proto static |
ip route add 172.18.0.0/16 via 172.17.1.1 src 172.17.1.2 |
table goodnet2 proto static |
ip route add default via 172.17.1.254 src 172.17.1.128 |
table goodnet2 proto static |
ip rule add from 192.168.1.0/24 pref 15000 table goodnet2 |
ip rule add from 192.168.2.0/24 pref 15001 table goodnet1 |
例7:综合实例 |
假设例6中的路由、规则和地址仍然在起作用,我希望实现下面的需求: |
? Internal A Hosts 33-62 to Network A Masq as 172.17.1.3 |
? Internal A Hosts 65-78 to tcp port 80 on Network A Masq as 172.17.1.4 |
? Internal B Hosts 33-62 to tcp port 80 on Network A Deny Access |
? Internal B Hosts 65-78 to tcp port 80 on Network C Masq as 10.254.254.2 |
应该记得我们仍然允许例6中的连接性,下面就是解决方案: |
ip addr add 172.17.1.3/32 dev eth0 |
ip addr add 172.17.1.4/32 dev eth0 |
ip route del default table goodnet1 |
ip route del default table goodnet2 |
ip route add throw 0/0 table goodnet1 proto static |
ip route add throw 0/0 table goodnet2 proto static |
ip route add default via 172.17.1.254 src 172.17.1.128 |
table internet proto static |
ip route add 172.18.0.0/16 via 172.17.1.1 src 172.17.1.3 |
table badnet1 proto static |
ip route add 172.18.0.0/16 via 172.17.1.1 src 172.17.1.4 |
table badnet2 proto static |
ip rule add from 192.168.1.32/27 to 172.18.0.0/16 pref 14999 table badnet1 |
ip rule add fwmark 1 pref 14998 table badnet2 |
ip rule add fwmark 2 pref 14997 table goodnet1 |
ip rule add fwmark 3 pref 14996 blackhole |
ip rule add pref 15003 table internet |
ipchains -I input -p tcp -s 192.168.1.64/28 -d 172.18.0.0/16 80 -m 1 |
ipchains -I input -p tcp -s 192.168.2.64/28 -d 10.10.0.0/16 80 -m 2 |
ipchains -I input -p tcp -s 192.168.2.32/27 -d 172.18.0.0/16 80 -m 3 |
其实有很多的有效方法,但是虽然这里使用名为badnet1和badnet2的表,但是名字是没有实际意义的,只是用来引用表3和表4的符号。 |
总结 |
希望你通过该文章能享受Linux2.2的强大路由功能,它提供的路由功能是很多路由器产品都是难以匹敌的, 如果考虑到它的免费性,它的性能价格比更是没有任何产品可以相比。例如例7中的例子可以很好的运行在只有16M内存的486/33的机器上。 |