linux 高级路由 策略路由
linux 高级路由 策略路由
lartc(linux advanced routing and traffic control)
http://www.lartc.org
# rpm -qa |grep iproute --iproute2工具包软件
iproute-2.6.32-31.el6.x86_64
ip命令就属于iproute2软件包
ip addr
ip neigh
ip rule
ip route
ip tunnel
===========================================================
# ip rule list
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
# cat /etc/iproute2/rt_tables
--上面的local对应数字255,在rhel5.7里ip rule list看到的不是local,而是255;这只是对应的两种名称而已
#
# reserved values
#
255 local
254 main
253 default
0 unspec
#
# local
#
#1 inr.ruhep
# ip route list/show table local/255
# ip route list/show table main/254
# ip route list/show table default/253
================================================================================
50 内网用户 --------->路由器1------> 猫1 (快网络)
50 内网用户 --------->路由器2------> 猫2 (慢网络)
应用实例1:
----------------------->路由器1------> 猫1 (快网络)
|
|
100 内网用户 -----linux路由
|
|
------------------------->路由器2------> 猫2 (慢网络)
linux路由器有两条上网线路,一个快,一个慢
有这样的需求:内网用户需要给钱共享上网,有人给钱多,需要快线路,有人给钱少,需要快线路,这样的话,我们就可以使用策略路由了
模拟的话使用下面的图:
10.1.1.8--brige
------------------------>vm2 (vmnet0) 线路一
|
|
1.1.1.128 ---内网 | 10.1.1.9 vmnet0
vm1(vmnet1)---------linux路由1.1.1.1 vmnet1 公网
| 2.2.2.1 vmnet2
|
|
------------------------->vm3(hostonly2) 线路二
2.2.2.128
上图架构中:
1.把VM1网关指向1.1.1.1
2,把linux路由器的网关指向10.1.1.8
3.linux路由打开ip_forward
4,这四台的iptables都关闭
先测试:在VM1上ping一个外网IP(如 ping 8.8.8.8),这个时候在VM2和VM3上抓包,但只能在VM2上抓到相关的包,表示数据包从VM2出去
# tcpdump icmp and src 1.1.1.128
然后通过下面的策略让VM1ping的包从VM3出去
下面就是在linux路由上进行操作来实现:
操作命令:
echo 200 t1 >> /etc/iproute2/rt_tables
ip rule add from 1.1.1.128 table t1
ip route add default via 2.2.2.128 dev vmnet2 table t1
ip route flush cache
--如果加错了规则,想删掉,就使用ip rule del table t1删除规则,再ip route del table t1删除t1路由表
操作完后,测试
1,在内网ping 8.8.8.8
2,在两个模拟外网路由器的机器上抓包
# tcpdump icmp and src 1.1.1.128
3,结果这次只能在VM3上抓到包,OK
应用实例2:
10.1.1.8--brige
------------------------>vm2 (vmnet0) 线路一
|
|
1.1.1.128 ---内网 | 10.1.1.9 vmnet0
vm1(vmnet1)---------linux路由1.1.1.1 vmnet1 公网
| 2.2.2.1 vmnet2
|
|
------------------------->vm3(hostonly2) 线路二
2.2.2.128
要实现不同类型的包走不同的线路:如80的访问走一条线,其它的走另外一条线路
实现不同类型的包的策略路由,就要借助于iptables的mangle表的set mark功能
1,在linux路由器上使用策略路由实现
# iptables -t mangle -A PREROUTING -i vmnet1 -p tcp --dport 80 -j MARK --set-mark 1 ----把从内网进来要出去的80的包打标记为1
# echo 100 http.out >> /etc/iproute2/rt_tables ----建一张叫http.out的表,表编号100
# ip rule add fwmark 1 table http.out pref 20000 ----指定打了标记为1的所有包都走http.out这张路由表,并指定优先级为20000(这里优先级可以不指,因为只有这一条策略)
# ip route add default via 2.2.2.128 dev vmnet2 table http.out ----指定http.out表从vmnet8出去找2.2.2.128
# ip route flush cache -----刷新路由缓存
2,测试
测试一:在内网1.1.1.128客户端上
elinks 8.8.8.8
在模拟两个线路的机器上都执行下面的命令
tcpdump -i eth0 tcp port 80
----只有线路二上能抓到包,OK
测试二:在内网1.1.1.128客户端上
ping 8.8.8.8
在模拟两个线路的机器上都执行下面的命令
tcpdump -i eth0 icmp
----只有线路一上能抓到包,OK
--从上面就可以看到出去的80端口的包和其它的包走的路线不一致
iptables的mangle表打标记的应用举例:
1,刚讲的例二
2,iptables的mangle打标记+tc 做流量控制(这个课程不讨论,有兴趣上网去搜)
3,iptables的mangle打标记+LVS 做负载均衡
============================================================================
应用实例3:
实际情况下的图示,如果做实现得需要七台虚拟机
192.168.1.100 192.168.2.100
电信用户 网通用户
| |
192.168.1.1 | | 192.168.2.1
电信用户家里路由器 网通用户家里路由器
51.1.2.3 | | 61.1.2.3
| www.abc.com |
| |
71.1.2.3 | | 81.1.2.3
| |
公司电信路由器 公司网通路由器
10.1.1.1 | | 172.16.2.1
| |
| |
10.1.1.100 eth0 双线web服务器 eth1 172.16.2.100
精简一点可以使用下面的四台虚拟来做,并且要注意宿主机(真实机)不能在这里扮演角色,因为宿主机和任何虚拟机都是可以直接通的
下图中,电信客户端和网通客户端就没有使用去模拟路由器NAT,直接用一台虚拟机用两个网卡来模拟两个角色
172.16.2.51 vmnet0 客户端 vmnet2 2.2.2.129
| |
| |
| |
172.16.2.41 vmnet0 vmnet2 2.2.2.128
机房电信路由器1 机房网通路由器2
1.1.1.128 vmnet1 vmnet8 3.3.3.128
| |
| |
1.1.1.129 vmnet1 双线web服务 vmnet8 3.3.3.129
--假设上图里的客户端为内网用户,服务器为公网服务器;
--因为是模拟环境,所以这里两个路由器打开ip_forward,但上面四台都不用指网关
--我们实现的是当客户端用电信线路访问,也只能从电信线路返回;网通线路访问,也只能从网通线路返回
先在电信路由器和网通路由器上做好SNAT和DNAT,这样就不用把电信客户端的外网IP的网关指向电信路由器的外网IP了
(因为实际的公网IP,不会把网关指向你的,这个在讲iptables的SNAT就讨论过)
电信路由器上写两条(还要打开ip_forward) --也可以只写DNAT,SNAT那条不写它包会自动回来SNAT的
iptables -t nat -A PREROUTING -i eth0 -j DNAT --to-destination 1.1.1.129
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 172.16.2.41
网通路由器上写两条(还要打开ip_forward) --也可以只写DNAT,SNAT那条不写它包会自动回来SNAT的
iptables -t nat -A PREROUTING -i eth0 -j DNAT --to-destination 3.3.3.129
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 2.2.2.128
--上面四条当中的eth0自己换成对应的网卡名;电信路由器上的网卡名应该都为172.16.2.41的网卡名;网通路由器上的网卡名应该都为2.2.2.128的网卡名
做好上面四条和打开路由器的ip_forward后,并且默认上图所有的机器里现在都没有网关
在双线web服务器这台启动apache,随便做一个主页测试
验证:
1,在客户端elinks 172.16.2.41,得不到结果
在客户端elinks 2.2.2.128,得不到结果
2,上面两个线路都得不到结果,是因为能到web服务器,但回不来
所以把web服务器网关指向1.1.1.128的话,则再测试,只有elinks 172.16.2.41能得到结果
把web服务器网关指向3.3.3.128的话,则再测试,只有elinks 2.2.2.128能得到结果
3,也就是说,现在无法实现电信线路和网通线路都能访问成功;所以我们要借助于策略路由
1,在双线web服务器上使用策略路由实现
# ip rule
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
# echo 100 dianxin >> /etc/iproute2/rt_tables
# echo 200 wangtong >> /etc/iproute2/rt_tables
# ip rule add from 1.1.1.129 table dianxin
# ip rule add from 3.3.3.129 table wangtong
# ip route add default via 1.1.1.128 table dianxin
# ip route add default via 3.3.3.128 table wangtong
# ip rule
0: from all lookup local
32764: from 3.3.3.129 lookup wangtong
32765: from 1.1.1.129 lookup dianxin
32766: from all lookup main
32767: from all lookup default
测试:
再在客户端
elinks 172.16.2.41,能访问到web
elinks 2.2.2.128,也能访问到web
说明电信线路的包只走电信线路,网通线路的包只走网通线路
如果要深入测试的话,可以在客户端elinks电信线路的172.16.2.41时,去双线web服务器上双线路网卡都去tcpdump,会发现只有电信的网卡有包;网通的没有
反之,亦然
===================================================================================
应用实例4:
有些情况一个服务器多张网卡配置成同一个网段(这种做法是不正确的),
因为同一个网段,那么这多张网卡使用的路由是同一条,无法将他们区分开来
(从不同网卡进来的包,一般都会从eth0出去)
如果你想要实现从哪里进,从哪里去,使用iproute2对多张网卡设定不同的网关就可以(优先级要高于main表,也就是route -n看到的)
做法参考实例3
=====================================================================
dns 视图(dns view)
Berkeley Internet Name Domain (BIND) --伯克利网络名字域
CDN 内容分发网络 (content distributed network)
将网站源服务器中的内容存储到分布于各地的CDN网络节点上,通过智能网络流量分配控制系统,
将终端用户的访问请求自动指向健康可用且距离本地最近的CDN专用服务器上,以提高用户访问的响应速度和服务的可用性,改善互联网上的服务质量。
bind+squid 实现基本CDN
分布式缓存服务器(只缓存常用的网站静态元素) + 智能DNS(DNS view)
www.abc.com --> 不同的IP
有判断功能的DNS
内蒙电信用户
新疆用户 北京
成都 武汉 上海
广州
(网站源在深圳)
IP库如何获得?
IANA(互联网数字分配机构,internet assigned numbers authority)
ARIN (American registry for internet numbers)
北美,南美
RIPE
欧洲,中东,北非
APNIC
亚洲,大洋洲
www.apnic.net
这个网站上有一个叫whois数据库,可以查询所有的公网IP现在被分配到哪
参考网址:
http://bbs.chinaunix.net/thread-577601-1-1.html
--使用下面的脚本,就会在当前运行的目录下产生chinanet(电信),unicom(网通),others(其它)这三个IP库文件
# vim ripe.sh
#!/bin/sh
mkdir /root/apnic -p
FILE=/root/apnic/ip_apnic
wget http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest -O $FILE
grep 'apnic|CN|ipv4|' $FILE | cut -f 4,5 -d'|'|sed -e 's/|/ /g' | while read ip cnt
do
echo $ip:$cnt
mask=`cat << EOF | bc | tail -1
pow=32;
define log2(x) {
if (x<=1) return (pow);
pow--;
return(log2(x/2));
}
log2($cnt)
EOF`
echo $ip/$mask>> cn.net
if whois $ip@whois.apnic.net | grep -i ".*chinanet.*\|.*telecom.*">/dev/null;then
echo $ip/$mask >> chinanet
elif whois $ip@whois.apnic.net | grep -i ".*unicom.*">/dev/null;then
echo $ip/$mask >> unicom
else
echo $ip/$mask >> others
fi
done
--注意:如果上面的脚本要在rhel6里执行的话,则yum install jwhois -y(这个软件包包括了whois命令)
===============================================================
实践:上面我做的IP库是电信与网通的IP库
如果我现在是按地域来划分的,假设我划分成(北京,成都,上海,深圳,武汉)这五个CDN节点,请尝试把他们的IP库给做出来
(地域的划分情况随你自己,比如湖南离武汉和深圳都比较近,你要划分到哪一个区域自己定)
北京
成都 武汉 上海
广州
(网站源在深圳)
#!/bin/sh
mkdir /root/apnic -p
touch /root/apnic/ip_apnic
FILE=/root/apnic/ip_apnic
rm -f $FILE
wget http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest -O $FILE
grep 'apnic|CN|ipv4|' $FILE | cut -f 4,5 -d'|'|sed -e 's/|/ /g' | while read ip cnt
do
echo $ip:$cnt
mask=`cat << EOF | bc | tail -1
pow=32;
define log2(x) {
if (x<=1) return (pow);
pow--;
return(log2(x/2));
}
log2($cnt)
EOF`
echo $ip/$mask>> cn.net
if whois $ip@whois.apnic.net |grep descr:|head -1| grep -i ".*xinjiang.*\|.*tibet.*\|.*qinghai.*\|.*gansu.*\|.*yunnan.*\|.*sichuan.*">/dev/null;then
echo $ip/$mask >> chengdu
elif whois $ip@whois.apnic.net |grep descr:|head -1| grep -i ".*neimeng.*\|.*ningxia.*\|.*shanxi.*\|.*hebei.*\|.*beijing.*\|.*tianjin.*\|.*shandong.*\|.*liaoning.*\|.*jilin.*\|.*heilongjiang.*">/dev/null;then
echo $ip/$mask >> beijing
elif whois $ip@whois.apnic.net |grep descr:|head -1| grep -i ".*shannxi.*\|.*shaanxi.*\|.*henan.*\|.*chongqing.*\|.*hubei.*\|.*hunan.*\|.*jiangxi.*">/dev/null;then
echo $ip/$mask >> wuhan
elif whois $ip@whois.apnic.net |grep descr:|head -1|grep -i ".*guangxi.*\|.*guangdong.*\|.*hainan.*\|.*fujian.*\|.*hk.*\|.*macau.*">/dev/null;then
echo $ip/$mask >> shenzhen
elif whois $ip@whois.apnic.net |grep descr:|head -1| grep -i ".*anhui.*\|.*zhejiang.*\|.*jiangsu.*\|.*shanghai.*">/dev/null;then
echo $ip/$mask >> shanghai
else
echo $ip/$mask >> others
fi
done
----注意:上面的脚本产生的结果大部分应该是没问题的,但也有一些会存在分配的问题,改脚本或者是单独处理肯定是可以解决的;这里只是提供一个思路,不要把这个脚本直接用到真实环境
=====================================================================
DNS view
根据你访问过来的IP对应ACL列表来判断,从而解析到不同的服务器主机
在CDN中应用很多,也是解决目前区域间带宽小和延迟大的问题的一种方法。
第一步:定义ACL文件 (用来放网段的文件,IP库)
# yum install bind* -y
# vim /var/named/dianxin ----电信IP库
acl dx {
10.1.1.153;
10.1.1.101; --IP写法
200.11.22.0/24; --网段写法
};
# vim /var/named/wangtong --网通IP库
acl wt {
10.1.1.73;
10.1.1.174;
100.10.20.0/24;
};
第二步:配置named.conf
# vim /etc/named.conf
options {
listen-on port 53 { any; }; --改为any
listen-on-v6 port 53 { ::1; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
allow-query { any; }; --改为any
recursion yes;
dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;
bindkeys-file "/etc/named.iscdlv.key";
managed-keys-directory "/var/named/dynamic";
};
logging {
channel default_debug {
file "data/named.run";
severity dynamic;
};
};
#zone "." IN {
# type hint;
# file "named.ca";
#};
#include "/etc/named.rfc1912.zones"; --这里把上面的根域和子配置文件里所有域都注释掉;因为配置了视图,那么所有的域都得要配置才行,所以这里就直接注释不用
include "/etc/named.root.key";
----下面的就是在主配置文件上新加的
include "dianxin";
include "wangtong";
view "v1" { --视图名,随便取
match-clients {dx;}; --dx为acl名,而不是IP库文件名
zone "cluster.com" IN {
type master;
file "data/dx.cluster.com.zone";
};
};
view "v2" {
match-clients {wt;};
zone "cluster.com" IN {
type master;
file "data/wt.cluster.com.zone";
};
};
view "v3" {
match-clients {any;}; --any代表所有,这里一定要放在最后,匹配完了dx,wt,最后的所有都为others
zone "cluster.com" IN {
type master;
file "data/others.cluster.com.zone";
};
};
第三步:配置named.conf里定义的三个zone文件
# vim /var/named/data/dx.cluster.com.zone
$TTL 86400
@ IN SOA dx. root. (
2016012101
120
60
30
86400 )
IN NS 172.16.X.X.
www IN A 1.1.1.1 --此为www.cluster.com域名的电信线路的IP,或者是在电信机房的服务器的IP
# vim /var/named/data/wt.cluster.com.zone
$TTL 86400
@ IN SOA wt. root. (
2016012101
120
60
30
86400 )
IN NS 172.16.X.X.
www IN A 2.2.2.2 --网通线路的
# vim /var/named/others.cluster.com.zone
$TTL 86400
@ IN SOA others. root. (
2016012101
120
60
30
86400 )
IN NS 172.16.X.X.
www IN A 3.3.3.3 --除了电信和网通外的用户指向的服务器IP,如果你只有电信和网通两个线路,可以随意指向其中一个。但这里是实验,我假设有三个线路,所以这里指向第三个IP 3.3.3.3
第四步: 重启服务
# /etc/init.d/named restart
第五步: 测试
问题:上面做的是单机单域,多地域多运营商都要区分如何做?
也就是IP库文件要分得更细,
比如广东附近几个省的电信的IP段要单独一个IP库
广东附近几个省的网通的IP段要单独一个IP库
其它的类似
课外扩展:
上网查查类似腾讯dnspod,阿里dns,百度dns这种智能DNS服务运营商