iptables的mangle表
mangle表的主要功能是根据规则修改数据包的一些标志位,以便其他规则或程序可以利用这种标志对数据包进行过滤或策略路由。
使用策略路由
对应的场景, 都是有多个网口, 常见的使用步骤
1. 创建路由表 Create new routing table
编辑 /etc/iproute2/rt_tables
, 添加
[ID of your Table] [Name of your table]
使用ip rule 对指定的路由表table [Table Name or Table ID]
添加路由规则.
使用下面的命令检查
ip route show table [Table Name or Table ID]
为路由表指定默认的路由设备
ip route add default dev "${TUNDEV}" src "${INTERNAL_IP4_ADDRESS}" table "${TABLENAME}"
# 在路由表100上添加一个默认路由(对所有地址), 使用本地网关192.168.1.1, 这是一个可以从eth0到达的地址
ip route add default via 192.168.1.1 dev eth0 table 100
# 对10.1.1.0/30这个目的地址范围添加路由规则, 并添加MPLS标签
ip route add 10.1.1.0/30 encap mpls 200/300 via 10.1.1.1 dev eth0
确定数据包走哪个路由表
默认每个数据报文走的路由表都是main, 你可以给满足一定规则的数据报文指定不同的路由表, 而未满足的还继续使用默认的路由表.
路由规则(ip rule)
这里有所有可能用到的参数列表, 如果还不够, 你可以使用fwmark. 给数据报文打fwmark标签可以通过iptables来处理, 然后通过ip rule来处理. 例如
# 来源于167.99.208.1的用指定table
ip rule add from 167.99.208.1 table [table-name]
# 所有来源都用table ztable1
ip rule add from all table ztable1
# 所有来源中带标签2的都用table 20
ip rule add from all fwmark 2 table 20
2. 使用iptables打标签
使用的格式为 -j MARK --set-mark <Your marknumber in decimal form>
. MARK这个target只在mangle中有效.
对于流入的数据报文可以使用-t mangle -A PREROUTING
, 对于流出的数据报文可以使用-t mangle -A OUTPUT
. 注意: 当数据报文被进程(例如apache)处理过之后, 标签就丢失了. 所以如果打过标签的报文在返回时不正确, 只给流入的报文打标签是不够的, 你必须给产生的流出报文也打上标签.
3. 遇到的问题
报文丢失
很可能是因为被认为"martian"而被丢弃了. 在kernel中被丢弃可能不会留下日志, 可以通过下面的方式开启日志
# 编辑 /etc/sysctl.conf
net.ipv4.conf.default.log_martians = 1
net.ipv4.conf.all.log_martians = 1
如果确认是被作为martian丢弃, 可以进行下面的修改
# 编辑 /etc/sysctl.conf
# Enables source route verification
net.ipv4.conf.default.rp_filter=0
# Enable reverse path
net.ipv4.conf.all.rp_filter=0
关于 fwmark
https://docs.huihoo.com/hpc-cluster/linux-virtual-server/HOWTO/LVS-HOWTO.fwmark.html
Karl Kopper (Apr 2004) said that he thinks the correct term for this is "netfilter mark". A google search finds references to "netfilter mark" back to 2001, and with "fwmark" current at least to 2003. Both terms seem to be in use. The various netfilter HOWTOs don't say anything about new terminology. Horms (who wrote the fwmark code) doesn't know anything about a change in terminology, but thinks it's possible that fwmark is the implementation of netfilter marks.
I asked Harald Welte about this at OLS_2004 and the explanation was as clear as day, except that I didn't write it down and now I've forgotten it (geez, sorry about this). It was a matter of nomenclature rather than logic: it was something like - the entity in the command line is called a mark while the method of marking packets is called fwmark. Whatever it is, you can use either term and people will know what you're talking about.
fwmark实际上就是netfilter mark, 一种打标签的方式或者实现, 没有特殊的含义.
例一
内网的客户机通过Linux主机连入Internet,而Linux主机有两个网口与Internet连接, 分别有两条线路,它们的网关分别为10.10.1.1和10.10.2.1. 现要求对内网进行策略路由,所有通过TCP协议访问80端口的数据包都从10.10.1.1 线路出去,而所有访问UDP协议53号端口的数据包都从10.10.2.1线路出去。
这是一个策略路由的问题,为了达到目的,在对数据包进行路由前,要先根据数据包的协议和目的端口给数据包做上一种标志,然后再指定相应规则,根据数据包的标志进行策略路由。为了给特定的数据包做上标志,需要使用mangle表,mangle表共有5条链,由于需要在路由选择前做标志,因此应该使用PREROUTING链,下面是具体的命令。
iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 80 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -i eth0 -p udp --dprot 53 -j MARK --set-mark 2
以上命令在mangle表的PREROUTING链中添加规则,为来自eth0接口的数据包做标志,其匹配规则分别是TCP协议、目的端口号是80和UDP协议、目的端口号是53,标志的值分别是1和2。数据包经过PREROUTING链后,将要进入路由选择模块,为了对其进行策略路由,执行以下两条命令,添加相应的规则
编辑 /etc/iproute2/rt_tables
, 添加对应的路由表
`echo -e "${TABLEID}\t${TABLENAME}" >> /etc/iproute2/rt_tables`
添加路由
ip rule add from all fwmark 1 table 10
ip rule add from all fwmark 2 table 20
以上两条命令表示所有标志是1的数据包使用路由表10进行路由,而所有标志是2的数据包使用路由表20进行路由。路由表10和20分别使用了10.10.1.1和10.10.2.1作为默认网关
ip route add default via 10.10.1.1 dev eth1 table 10
ip route add default via 10.10.2.1 dev eth2 table 20
以上两条命令在路由表10和20上分别指定了10.10.1.1和10.10.2.1作为默认网关, 于是使用路由表10的数据包将通过10.10.1.1线路出去,而使用路由表20的数据包将通过10.10.2.1线路出去
例二
网关服务器三块网卡
- eth0 网通ip:10.0.0.1
- eth1 电信ip:20.0.0.1
- eth2 网关ip:192.168.10.1
内网要求192.168.10.1---100以内的ip使用10.0.0.1 网关上网, 其他IP使用 20.0.0.1上网
ip route add default gw 20.0.0.1
# eth0 是 10.0.0.1 所在的网卡, 10是路由表的编号
ip route add table 10 via 10.0.0.1 dev eth0
#fwmark 10 是标记, table 10 是路由表10, 标记了10的数据使用table 10路由表
ip rule add fwmark 10 table 10
#使用iptables给相应的数据打上标记, 对于这种IP范围需要用到iprange模块
iptables -A PREROUTING -t mangle -i eth2 -m iprange --src-range 192.168.10.1-192.168.10.100 -j MARK --set-mark 10
例三
网关服务器三块网卡
- eth0 网通ip:10.0.0.1
- eth1 电信ip:20.0.0.1
- eth2 网关ip:192.168.10.1
内网要求员工访问外面的网站使用 10.0.0.1 网关上网, 其他IP使用 20.0.0.1 上网
iptables -t mangle -A PREROUTING -i eth2 -p tcp --dport 80 -j MARK --set-mark 20
ip route add default gw 20.0.0.1
ip route add table 20 via 10.0.0.1 dev eth0
ip rule add fwmark 20 table 20
例四
使用dnsmasq, 将一个域名列表中匹配的域名解析得到的IP都放到一个名称为outside的ipset中, 让这个ipset的数据包都走指定的虚拟网卡
添加路由表
echo "200 outside" >> /etc/iproute2/rt_tables
添加ipset
# vi /etc/rc.local
ipset create outside hash:ip
添加iptables规则, 打标签
将匹配 ipset outside的包全部标上 mark 8, 在 /etc/firewall.user 中添加:
# vi /etc/firewall.user
iptables -t mangle -A fwmark -m set --match-set outside dst -j MARK --set-mark 8
指定使用的路由表
# 让 8.8.8.8 走 VPN,防止 DNS 污染
ip route add 8.8.8.8 dev $TUNDEV
ip route add default dev $TUNDEV table outside
ip rule add fwmark 8 table outside
将$TUNDEV替换为 VPN 设备名,比如ppp0, tun0等
配置dnsmasq, 使其解析时动态添加ipset
修改 /etc/dnsmasq.conf,在其中加入需要翻越的域名。 格式如下:
server=/域名/8.8.8.8
ipset=/域名/outside
其他
iptables: No chain/target/match by that name
# iptables -t mangle -A PREROUTING -s 192.168.2.0/24 -j
MARK --set-mark 1
iptables: No chain/target/match by that name
如果出现这个错误, 用下面的方式解决
[root@mpc8315erdb /root]# modprobe xt_MARK