什么是iptables

iptables是运行在用户空间的应用软件,通过控制Linux内核netfilter模块,来管理网络数据包的处理和转发。在大部分Linux发行版中,可以通过手册页或 man iptables 获取用户手册。通常iptables需要内核模块支持才能运行,此处相应的内核模块通常是Xtables。因此,iptables操作需要超级用户权限 。同时,需要说明的是,以上命令通常只用于处理 IPv4 数据包;而对于 IPv6 数据包,则使用类似的 ip6tables 命令。

目前,iptables 支持内核2.4以上版本,旧版内核环境下则使用ipchains(于2.2版内核)或 ipwadm(于2.0版内核)完成类似的功能。2014年1月19日起发行的Linux内核3.13版则使用nftables取而代之,但仍然提供 iptables 命令做为兼容接口。

规则

iptables、ip6tables等都使用Xtables框架。存在“表(tables)”、“链(chain)”和“规则(rules)”三个层面。

每个“表”指的是不同类型的数据包处理流程,如filter表表示进行数据包过滤。每个表中又可以存在多个“链”,系统按照预订的规则将数据包通过某个内建链,例如将从本机发出的数据通过OUTPUT链。在“链”中可以存在若干“规则”,这些规则会被逐一进行匹配,如果匹配,可以执行相应的动作,如修改数据包,或者跳转。跳转可以直接接受该数据包或拒绝该数据包,也可以跳转到其他链继续进行匹配,或者从当前链返回调用者链。当链中所有规则都执行完仍然没有跳转时,将根据该链的默认策略(“policy”)执行对应动作;如果也没有默认动作,则是返回调用者链。

filter表

filter表是默认的表,如果不指明表则使用此表。其通常用于过滤数据包。其中的内建链包括:

  • INPUT,输入链。发往本机的数据包通过此链。
  • OUTPUT,输出链。从本机发出的数据包通过此链。
  • FORWARD,转发链。本机转发的数据包通过此链。

nat表

nat表如其名,用于地址转换操作。其中的内建链包括:

  • PREROUTING,路由前链,在处理路由规则前通过此链,通常用于目的地址转换(DNAT)。
  • POSTROUTING,路由后链,完成路由规则后通过此链,通常用于源地址转换(SNAT)。
  • OUTPUT,输出链,类似PREROUTING,但是处理本机发出的数据包。

mangle表

mangle表用于处理数据包。其和nat表的主要区别在于,nat表侧重连接而mangle表侧重每一个数据包。其中内建链列表如下。

  • PREROUTING
  • OUTPUT
  • FORWARD
  • INPUT
  • POSTROUTING

raw表

raw表用于处理异常,有如下两个内建链:

  • PREROUTING
  • OUTPUT

模块

state

对于state模块的连接而言,”连接”其中的报文可以分为5种状态,报文状态可以为NEW、ESTABLISHED、RELATED、INVALID、UNTRACKED
含义大致与conntrack相同

conntrack

包的状态依据IP所包含的协议不同而不同,但在内核外部,也就是用户空间里,只有4种状态: NEWESTABLISHEDRELATEDINVALID 。它们主要是和状态匹配一起使用。下面就简要地介绍以下这几种状态:

表1: 数据包在用户空间的状态

State Comment
NEW NEW说明这个包是我们看到的第一个包。意思就是,这是conntrack模块看到的某个连接第一个包,它即将被匹配了。比如,我们看到一个SYN 包,是我们所留意的连接的第一个包,就要匹配它。第一个包也可能不是SYN包,但它仍会被认为是NEW状态。这样做有时会导致一些问题,但对某些情况是有非常大的帮助的。例如,在我们想恢复某条从其他的防火墙丢失的连接时,或者某个连接已经超时,但实际上并未关闭时.
ESTABLISHED ESTABLISHED已经注意到两个方向上的数据传输,而且会继续匹配这个连接的包。处于ESTABLISHED状态的连接是非常容易理解的。只要发送并接到应答,连接就是ESTABLISHED的了。一个连接要从NEW变为ESTABLISHED, 只需要接到应答包即可,不管这个包是发往防火墙的,还是要由防火墙转发的 。ICMP的错误和重定向等信息包也被看作是ESTABLISHED,只要它们是我们所发出的信息的应答.
RELATED RELATED是个比较麻烦的状态。当一个连接和某个已处于ESTABLISHED状态的连接有关系时,就被认为是RELATED的了。换句话说,一个连接要想是RELATED的, 首先要有一个ESTABLISHED的连接。这个ESTABLISHED连接再产生一个主连接之外的连接 ,这个新的连接就是RELATED的了,当然前提是conntrack模块要能理解RELATED。ftp是个很好的例子,FTP-data 连接就是和FTP-control有RELATED的。还有其他的例子,比如,通过IRC的DCC连接。有了这个状态,ICMP应答、FTP传输、DCC等才能穿过防火墙正常工作。注意,大部分还有一些UDP协议都依赖这个机制。这些协议是很复杂的,它们把连接信息放在数据包里,并且要求这些信息能被正确理解
INVALID INVALID说明 数据包不能被识别属于哪个连接或没有任何状态 。有几个原因可以产生这种情况,比如, 内存溢出 , 收到不知属于哪个连接的ICMP错误信息 。一般地,我们DROP这个状态的任何东西

这些状态可以一起使用,以便匹配数据包。这可以使防火墙非常强壮和有效。以前,我们经常打开1024以上的所有端口来放行应答的数据。现在,有了状态机制,就不需再这样了。可以只开放那些有应答数据的端口,其他的都可以关闭。这样就安全多了

命令使用

参数表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
[email protected]:~# iptables --help
iptables v1.8.4

Usage: iptables -[ACD] chain rule-specification [options]
iptables -I chain [rulenum] rule-specification [options]
iptables -R chain rulenum rule-specification [options]
iptables -D chain rulenum [options]
iptables -[LS] [chain [rulenum]] [options]
iptables -[FZ] [chain] [options]
iptables -[NX] chain
iptables -E old-chain-name new-chain-name
iptables -P chain target [options]
iptables -h (print this help information)

Commands:
Either long or short options are allowed.
--append -A chain Append to chain
--check -C chain Check for the existence of a rule
--delete -D chain Delete matching rule from chain
--delete -D chain rulenum
Delete rule rulenum (1 = first) from chain
--insert -I chain [rulenum]
Insert in chain as rulenum (default 1=first)
--replace -R chain rulenum
Replace rule rulenum (1 = first) in chain
--list -L [chain [rulenum]]
List the rules in a chain or all chains
--list-rules -S [chain [rulenum]]
Print the rules in a chain or all chains
--flush -F [chain] Delete all rules in chain or all chains
--zero -Z [chain [rulenum]]
Zero counters in chain or all chains
--new -N chain Create a new user-defined chain
--delete-chain
-X [chain] Delete a user-defined chain
--policy -P chain target
Change policy on chain to target
--rename-chain
-E old-chain new-chain
Change chain name, (moving any references)
Options:
--ipv4 -4 Nothing (line is ignored by ip6tables-restore)
--ipv6 -6 Error (line is ignored by iptables-restore)
[!] --protocol -p proto protocol: by number or name, eg. `tcp'
[!] --source -s address[/mask][...]
source specification
[!] --destination -d address[/mask][...]
destination specification
[!] --in-interface -i input name[+]
network interface name ([+] for wildcard)
--jump -j target
target for rule (may load target extension)
--goto -g chain
jump to chain with no return
--match -m match
extended match (may load extension)
--numeric -n numeric output of addresses and ports
[!] --out-interface -o output name[+]
network interface name ([+] for wildcard)
--table -t table table to manipulate (default: `filter')
--verbose -v verbose mode
--wait -w [seconds] maximum wait to acquire xtables lock before give up
--wait-interval -W [usecs] wait time to try to acquire xtables lock
default is 1 second
--line-numbers print line numbers when listing
--exact -x expand numbers (display exact values)
[!] --fragment -f match second or further fragments only
--modprobe=<command> try to insert modules using this command
--set-counters PKTS BYTES set the counter during insert/append
[!] --version -V print package version.


命令图解

基本语法
不使用-t指定表. 默认使用filter
参数命令
! 为取反

target参数详解

ACCEPT

放行, 不再对比其它规则, 进入下一个链

REDIRECT

将封包重新导向到另一个端口(PNAT). 这个功能可以用来端口映射或用来保护 web 服务器, 不会中断当前链比对.

SNAT

改写封包来源 IP 为指定IP地址, 使用--to-source指定IP或IP范围或端口范围, 只能用在POSTROUTING链上, 中断当前链.

MASQUERADE

相当于固定SNAT源IP为当前网卡的IP, 只能用在POSTROUTING链上, 中断当前链.

DNAT

改写封包地址地址 IP 为指定IP地址, 使用--to-destination指定IP或IP范围或端口范围, 只能用在PREROUTING链上, 中断当前链.

MIRROR

镜射封包,将来源 IP 与目的地 IP 对调后送回,该动作会中断过滤程序。

QUEUE

结束结束过滤, 将包放入队列以供其它程序处理.

RETURN

中断当前自定义链的规则对比, 返回主链.

MARK

将封包标上某个代号, 为后续规则过滤条件提供依据, 使用--set-mark, 不中断当前链比对.

使用例程

通常需要将服务器的闲置端口全部禁止外部访问, 不响应外部ping, 内部其它应用可以正常访问. 有两种选择, 一种在PREROUTING链处理, 另一种在INPUT链处理

  1. 先放行向外部提供服务的端口(以22,80,443为例)

    1
    2
    3
    4
    5
    6
    7
    8
    # PREROUTING 链
    iptables -t mangle -A PREROUTING -p tcp --dport 22 -j ACCEPT
    iptables -t mangle -A PREROUTING -p tcp --dport 80 -j ACCEPT
    iptables -t mangle -A PREROUTING -p tcp --dport 443 -j ACCEPT
    # INPUT 链
    iptables -A INPUT -p tcp --dport 22 -j ACCEPT
    iptables -A INPUT -p tcp --dport 80 -j ACCEPT
    iptables -A INPUT -p tcp --dport 443 -j ACCEPT
  2. 封锁闲置端口, 禁止外部访问, 禁ping

    1
    2
    3
    4
    5
    6
    # PREROUTING 链
    iptables -t mangle -A PREROUTING -p tcp -j DROP
    iptables -t mangle -A PREROUTING -p icmp -j DROP
    # INPUT 链
    iptables -A INPUT -p tcp -j DROP
    iptables -A INPUT -p icmp -j DROP

    到这一步就实现了禁ping和封锁闲置端口的功能, 但是除了放行的应用, 其它内部应用无法正常访问

  3. 让内部其它应用可以正常访问

    1
    2
    3
    4
    # PREROUTING 链
    iptables -t mangle -I PREROUTING -m state --state RELATED,ESTABLISHED -j ACCEPT
    # INPUT 链
    iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
  4. 允许本地回环

    1
    2
    3
    4
    # PREROUTING 链
    iptables -t mangle -I PREROUTING -i lo -j ACCEPT
    # INPUT 链
    iptables -I INPUT -i lo -j ACCEPT