Iptables

一、iptables的规则链 #

参考 Linux-iptables 防火墙、四表五链及SNAT与DNAT的原理与应用

1. 规则链图 #

2. 每个表对应的链 #

  • 表匹配顺序: raw -> mangle -> nat -> filter
说明 PREROUTING INPUT FORWARD OUTPUT POSTROUTING
raw 确定是否跟踪数据包状态 1 1
mangle 修改数据包内容,如设置标记 1 1 1 1 1
nat 网络地址转换 1 1 1 1
filter 数据包是否放行 1 1 1

3. 规则匹配顺序 #

  • 路由选择确实是在OUTPUT链前面,但是如果OUTPUT链里面做了nat或设置了mark,在netfilter里面会重新走一遍路由

4. 常用控制类型 #

  • ACCEPT: 允许数据包通过
  • DROP: 直接丢弃数据包,不给出任何回应信息
  • REJECT: 拒绝数据包通过,会给数据发送端一个响应信息
  • SNAT: 修改数据包的源地址
  • DNAT: 修改数据包的目的地址
  • MASQUERADE: 伪装成一个非固定公网IP地址
  • LOG: 在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则。LOG只是一种辅助动作,并没有真正处理数据包
    • 当前测试只能在filter表上才能加LOG,其他表加LOG没生效

5. 常用的管理选项 #

  • -t: 指定表,也就是raw、mangle、nat、filter,不指定默认是filter
  • -A: 在指定链的末尾追加(–append) 一条新的规则
  • -I: 在指定链的开头插入(–insert)一条新的规则,未指定序号时默认作为第一条规则
  • -R: 修改、替换(–replace) 指定链中的某一条规则,可指定规则序号或具体内容
  • -P: 设置指定链的默认策略(–policy)
  • -D: 删除(–delete)指定链中的某一条规则,可指定规则序号或具体内容
  • -F: 清空(–flush)指定链中的所有规则,若未指定链名,则清空表中的所有链
  • -L:列出(–list) 指定链中所有的规则,若未指定链名,则列出表中的所有链
  • -n: 使用数字形式(–numeric)显示输出结果,如显示IP地址而不是主机名
  • -v: 显示详细信息,包括每条规则的匹配包数量和匹配字节数
  • --line-numbers: 查看规则时,显示规则的序号

二、mark #

  • linux内核中网络相关的mark有三个,socket中的mark、netfilter的mark、sk_buff的mark
  • 分别在下面三个位置
 1// include/net/sock.h
 2/**
 3  *	struct sock - network layer representation of sockets
 4  ...
 5  *	@sk_mark: generic packet mark
 6  ...
 7  */
 8struct sock {
 9  ...
10	__u32			sk_mark;
11	...
12};
13
14// include/net/netfilter/nf_conntrack.h
15struct nf_conn {
16  ...
17#if defined(CONFIG_NF_CONNTRACK_MARK)
18	u_int32_t mark;
19#endif
20  ...
21};
22
23// include/linux/skbuff.h
24/**
25 *	struct sk_buff - socket buffer
26  ...
27 *	@mark: Generic packet mark
28  ...
29 */
30struct sk_buff {
31	...
32	union {
33		__u32		mark;
34		__u32		reserved_tailroom;
35	};
36  ...
37};

1. socket的mark #

  • socket的mark使用setsockopt来进行设置
1int mark = 100
2setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
  • 在使用此socket发包时,会自动添加mark到sk_buff的mark中,代码在下面
 1// net/ipv4/ip_output.c
 2/*
 3 *		Add an ip header to a skbuff and send it out.
 4 *
 5 */
 6int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk,
 7			  __be32 saddr, __be32 daddr, struct ip_options_rcu *opt,
 8			  u8 tos)
 9{
10  ...
11	if (!skb->mark)
12		skb->mark = sk->sk_mark;
13
14	/* Send it out. */
15	return ip_local_out(net, skb->sk, skb);
16}
17EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);

2. sk_buff的mark #

  • 使用iptables规则可以将数据包的mark保存到连接跟踪中,然后在回包时将连接跟踪的mark恢复到数据包上
  • 策略路由只能匹配sk_buff的mark
  • 下面使用iptables实现一个转发的需求,虚拟网卡来的发给物理网卡,物理网卡来的转回虚拟网卡
 1# 从虚拟网卡来的包,要转发给物理网卡,在走路由前给连接跟踪添加mark
 2# --set-mark 设置mark到连接跟踪上
 3iptables -t mangle -A PREROUTING -j CONNMARK -i tun0 --set-mark 1000 -m comment --comment "from tun"
 4# 物理网卡回包时,连接跟踪有mark,写到sk_buff中
 5# -m connmark --mark 1000   connmark上的mark为1000的包
 6# --restore-mark            连接跟踪的mark写到sk_buff上
 7iptables -t mangle -A PREROUTING -j CONNMARK -m connmark --mark 1000 ! -i tun+ --restore-mark -m comment --comment "need to tun"
 8# 策略路由添加mark为1000的给到1000路由表,fwmark匹配的是sk_buff的mark
 9ip rule add fwmark 1000 table 1000
10# 1000的路由表直接把所有流量路由到tun0上去
11ip route add default dev tun0 table 1000