iptables基本概念
工作流程
1.一个数据包进入网卡时,它首先进入PREROUTING链,内核根据数据包目的IP判断是否需要转发出去。
2.如果数据包就是进入本机的,它就会沿着图向下移动,到达INPUT链。数据包到了INPUT链后,任何进程都会收到它。本机上运行的程序可以发送数据包,这些数据包会经 过OUTPUT链,然后到达POSTROUTING链输出。
3.如果数据包是要转发出去的,且内核允许转发,数据包就会如图所示向右移动,经过 FORWARD链,然后到达POSTROUTING链输出。
iptables的原理主要是对数据包的控制,看下图:
规则(rules)
规则(rules)其实就是网络管理员预定义的条件,规则一般的定义为“如果数据包头符合这样的条件,就这样处理这个数据包”。规则存储在内核空间的信息包过滤表中,这些规则分别指定了源地址、目的地址、传输协议(如TCP、UDP、ICMP)和服务类型(如HTTP、FTP和SMTP)等。当数据包与规则匹配时,iptables就根据规则所定义的方法来处理这些数据包,如放行(accept)、拒绝(reject)和丢弃(drop)等。配置防火墙的主要工作就是添加、修改和删除这些规则。
- ACCEPT:允许数据包通过
- DROP:直接丢弃数据包,不给任何回应信息
- REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息。
- SNAT:源地址转换。在进入路由层面的route之后,出本地的网络栈之前,改写源地址,目标地址不变,并在本机建立NAT表项,当数据返回时,根据NAT表将目的地址数据改写为数据发送出去时候的源地址,并发送给主机。解决内网用户用同一个公网地址上网的问题。
- MASQUERADE,是SNAT的一种特殊形式,适用于像adsl这种临时会变的ip上
- DNAT:目标地址转换。和SNAT相反,IP包经过route之前,重新修改目标地址,源地址不变,在本机建立NAT表项,当数据返回时,根据NAT表将源地址修改为数据发送过来时的目标地址,并发给远程主机。可以隐藏后端服务器的真实地址。(感谢网友提出之前这个地方与SNAT写反了)
- REDIRECT:是DNAT的一种特殊形式,将网络包转发到本地host上(不管IP头部指定的目标地址是啥),方便在本机做端口转发。
- LOG:在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则
链(chains)
链(chains)是数据包传播的路径,每一条链其实就是众多规则中的一个检查清单,每一条链中可以有一条或数条规则。当一个数据包到达一个链时,iptables就会从链中第一条规则开始检查,看该数据包是否满足规则所定义的条件。如果满足,系统就会根据该条规则所定义的方法处理该数据包;否则iptables将继续检查下一条规则,如果该数据包不符合链中任一条规则,iptables就会根据该链预先定义的默认策略来处理数据包。
- INPUT链:当接收到防火墙本机地址的数据包(入站)时,应用此链中的规则。
- OUTPUT链:当防火墙本机向外发送数据包(出站)时,应用此链中的规则。
- FORWARD链:当接收到需要通过防火墙发送给其他地址的数据包(转发)时,应用此链中的规则。
- PREROUTING链:在对数据包作路由选择之前,应用此链中的规则,如DNAT。
- POSTROUTING链:在对数据包作路由选择之后,应用此链中的规则,如SNAT。
表(tables)
表(tables)提供特定的功能,iptables内置了4个表,即raw表、filter表、nat表和mangle表,分别用于实现包过滤,网络地址转换和包重构的功能。
RAW表
只使用在PREROUTING链和OUTPUT链上,因为优先级最高,从而可以对收到的数据包在连接跟踪前进行处理。一但用户使用了RAW表,在 某个链上,RAW表处理完后,将跳过NAT表和 ip_conntrack处理,即不再做地址转换和数据包的链接跟踪处理了.
filter表
主要用于过滤数据包,该表根据系统管理员预定义的一组规则过滤符合条件的数据包。对于防火墙而言,主要利用在filter表中指定的规则来实现对数据包的过滤。Filter表是默认的表,如果没有指定哪个表,iptables 就默认使用filter表来执行所有命令,filter表包含了INPUT链(处理进入的数据包),RORWARD链(处理转发的数据包),OUTPUT链(处理本地生成的数据包)在filter表中只能允许对数据包进行接受,丢弃的操作,而无法对数据包进行更改。
nat表
主要用于网络地址转换NAT,该表可以实现一对一,一对多,多对多等NAT 工作,iptables就是使用该表实现共享上网的,NAT表包含了PREROUTING链(修改即将到来的数据包),POSTROUTING链(修改即将出去的数据包),OUTPUT链(修改路由之前本地生成的数据包)
mangle表
主要用于对指定数据包进行更改,在内核版本2.4.18 后的linux版本中该表包含的链为:INPUT链(处理进入的数据包),RORWARD链(处理转发的数据包),OUTPUT链(处理本地生成的数据包)POSTROUTING链(修改即将出去的数据包),PREROUTING链(修改即将到来的数据包)
常用连接追踪状态
- NEW:该包想要开始一个连接(重新连接或将连接重定向)
- RELATED:该包是属于某个已经建立的连接所建立的新连接。例如:FTP的数据传输连接就是控制连接所 RELATED出来的连接。--icmp-type 0 ( ping 应答) 就是--icmp-type 8 (ping 请求)所RELATED出来的。
- ESTABLISHED :只要发送并接到应答,一个数据连接从NEW变为ESTABLISHED,而且该状态会继续匹配这个连接的后续数据包。
- INVALID:数据包不能被识别属于哪个连接或没有任何状态比如内存溢出,收到不知属于哪个连接的ICMP错误信息,一般应该DROP这个状态的任何数据。
iptables 规则
规则格式
iptables [-t table] COMMAND chain [-m matchname [per-match-options]] -j targetname [per-target-options]
COMMAND
链管理
- -N:new, 自定义一条新的规则链;
- -X:delete,删除自定义的规则链;
- -P:Policy,设置默认策略;对filter表中的链而言,其默认策略有:ACCEPT:接受、DROP:丢弃、REJECT:拒绝。
- -E:重命名自定义链;引用计数不为0的自定义链不能够被重命名,也不能被删除;
规则管理
- -A:append,追加,在规则列表的最后增加一条规则;
- -I:insert, 指定位置插入一条规则,省略时表示第一条;
- -D:delete,从规则列表中删除一条规则;删除可以通过规则本身删除也可以通过规则序号删除。
- -R:replace,替换指定链上的指定规则;
- -F:flush,清空指定的规则链;
- -Z:zero,将表中数据包计数器和流量计数器归零;
查看
- -L:list, 列出指定鏈上的所有规则;
- -n:numberic,以数字格式显示地址和端口号;
- -v:verbose,详细信息;
- -x:exactly,显示计数器结果的精确值;
- --line-numbers:显示规则的序号;
- -S:selected,以iptables-save命令的格式显示链上的规则。
举例
新增一条链:
# iptables -N newchain
# iptables -L newchain
Chain newchain (0 references)
target prot opt source destination
将链重命名:
# iptables -E newchain NewChain
删除:
# iptables -X NewChain
更改默认规则:
# iptables -t filter -P FORWARD DROP
# iptables -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
chain
- PREROUTING
- INPUT
- FORWARD
- OUTPUT
- POSTROUTING
匹配条件
基本匹配条件
无需加载任何模块,由iptables/netfilter自行提供
[!] -s, --source address[/mask][,...]
:用来比对数据包的来源IP,可以比对单机或网络,比对网络时请用数字来表示屏蔽,例如:-s 192.168.0.0/24,比对 IP 时可以使用!运算子进行反向比对,例如:-s ! 192.168.0.0/24。[!] -d, --destination address[/mask][,...]
:用来比对封包的目的地 IP,设定方式同上。- [!] -p, --protocol 比对通讯协议类型是否相符,可以使用 ! 运算子进行反向比对,例如:-p ! tcp ,意思是指除 tcp 以外的其它类型,包含udp、icmp ...等。如果要比对所有类型,则可以使用 all 关键词,例如:-p all。
- [!] -i, --in-interface name:数据报文流入的接口;只能应用于数据报文流入的环节,只能应用于PREROUTING,INPUT和FORWARD链;
- [!] -o, --out-interface name:数据报文流出的接口;只能应用于数据报文流出的环节,只能应用于FORWARD、OUTPUT和POSTROUTING链;
隐式扩展
不需要手动加载扩展模块;因为它们是对协议的扩展,所以,但凡使用-p指明了协议,就表示已经指明了要扩展的模块;
- [!] --source-port, --sport port[:port]:用来比对数据的包的来源端口号,可以比对单一端口,或是一个范围,例如:--sport 22:80,表示从 22 到 80 端口之间都算是符合件,如果要比对不连续的多个端口,则必须使用 --multiport 参数,详见后文。比对端口号时,可以使用 ! 运算子进行反向比对。
- [!] --destination-port,--dport port[:port]: 用来比对封包的目的地端口号,设定方式同上。
- [!] --tcp-flags:比对 TCP 封包的状态标志号,参数分为两个部分,第一个部分列举出想比对的标志号,第二部分则列举前述标志号中哪些有被设,未被列举的标志号必须是空的。TCP 状态标志号包括:SYN(同步)、ACK(应答)、FIN(结束)、RST(重设)、URG(紧急)PSH(强迫推送) 等均可使用于参数中,除此之外还可以使用关键词 ALL 和 NONE 进行比对。比对标志号时,可以使用 ! 运算子行反向比对。
- --syn:用来比对是否为要求联机之TCP 封包,与 iptables -p tcp --tcp-flags SYN,FIN,ACK SYN 的作用完全相同,如果使用 !运算子,可用来比对非要求联机封包。
- [!] --icmp-type {type[/code]|typename}:用来比对 ICMP 的类型编号,可以使用代码或数字编号来进行比对。请打 iptables -p icmp --help 来查看有哪些代码可用。这里是指禁止ping如,但是可以从该主机ping出。
设置22端口白名单:
# cat 22
*filter
:INPUT DROP
:FORWARD DROP
:OUTPUT DROP
-A INPUT -s 192.168.100.0/24 -p tcp --dport 22 -j ACCEPT
-A OUTPUT -d 192.168.100.0/24 -p tcp --sport 22 -j ACCEPT
COMMIT
# iptables-restore < 22
# iptables -nvL
Chain INPUT (policy DROP 4 packets, 312 bytes)
pkts bytes target prot opt in out source destination
22 1556 ACCEPT tcp -- * * 192.168.100.0/24 0.0.0.0/0 tcp dpt:22
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
14 1320 ACCEPT tcp -- * * 0.0.0.0/0 192.168.100.0/24 tcp spt:22
开放主机的ping请求:
# iptables -A INPUT -d 192.168.100.51 -p icmp -j ACCEPT
# iptables -A OUTPUT -s 192.168.100.51 -p icmp -j ACCEPT
或者通过下面的方式实现:
# iptables -A INPUT -d 192.168.100.51 -p icmp --icmp-type 8 -j ACCEPT
# iptables -A INPUT -d 192.168.100.51 -p icmp --icmp-type 0 -j ACCEPT
# iptables -A OUTPUT -s 192.168.100.51 -p icmp --icmp-type 0 -j ACCEPT
# iptables -A OUTPUT -s 192.168.100.51 -p icmp --icmp-type 8 -j ACCEPT
显式扩展-->multiport扩展
以离散方式定义多端口匹配;最多指定15个端口;
- [!] --source-ports,--sports port[,port|,port:port]...:指定多个源端口;
- [!] --destination-ports,--dports port[,port|,port:port]...:指定多个目标端口;
- [!] --ports port[,port|,port:port]...:指明多个端口;
开发主机的22,80端口:
# iptables -A INPUT -d 192.168.100.51 -p tcp -m multiport --dports 22,80 -j ACCEPT
# iptables -A OUTPUT -s 192.168.100.51 -p tcp -m multiport --sports 22,80 -j ACCEPT
# iptables -nvL
Chain INPUT (policy DROP 6 packets, 468 bytes)
pkts bytes target prot opt in out source destination
62 4911 ACCEPT tcp -- * * 0.0.0.0/0 192.168.100.51 multiport dports 22,80
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
25 6878 ACCEPT tcp -- * * 192.168.100.51 0.0.0.0/0 multiport sports 22,80
显式扩展-->iprange扩展
指明连续的(但一般不脑整个网络)ip地址范围;
- [!] --src-range from[-to]:源IP地址;
- [!] --dst-range from[-to]:目标IP地址;
将telnet端口开放到指定的IP地址访问:
# iptables -A INPUT -d 192.168.100.51 -p tcp --dport 23 -m iprange --src-range 192.168.100.1-192.168.100.100 -j ACCEPT
# iptables -A OUTPUT -s 192.168.100.51 -p tcp --sport 23 -m iprange --dst-range 192.168.100.1-192.168.100.100 -j ACCEPT
显式扩展-->string扩展
对报文中的应用层数据做字符串模式匹配检测;
- --algo {bm|kmp}:字符串匹配检测算法;
- [!] --string pattern:要检测的字符串模式;
- [!] --hex-string pattern:要检测的字符串模式,16进制格式;
# iptables -A OUTPUT -s 172.16.100.67 -d 172.16.0.0/16 -p tcp --sport 80 -m string --algo bm --string "gay" -j REJECT
显式扩展-->time扩展
根据将报文到达的时间与指定的时间范围进行匹配;
- --datestart YYYY[-MM[-DD[Thh[:mm[:ss]]]]]
- --datestop YYYY[-MM[-DD[Thh[:mm[:ss]]]]]
- --timestart hh:mm[:ss]
- --timestop hh:mm[:ss]
- [!] --monthdays day[,day...]
- [!] --weekdays day[,day...]
# iptables -A INPUT -d 192.168.100.51 -p tcp --dport 80 -m time --timestart 09:30 --timestop 18:30 --weekdays 1,2,3,4,5 -j ACCEPT
# iptables -A OUTPUT -s 192.168.100.51 -p tcp --sport 80 -m time --timestart 09:30 --timestop 18:30 --weekdays 1,2,3,4,5 -j ACCEPT
显式扩展-->connlimit扩展
根据每客户端IP做并发连接数数量匹配;
- --connlimit-upto n:连接的数量小于等于n时匹配;
- --connlimit-above n:连接的数量大于n时匹配;
限制本机的ssh端口连接的个数:
# iptables -A INPUT -d 192.168.100.51 -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
显式扩展-->limit扩展
基于收发报文的速率做匹配;
- --limit rate[/second|/minute|/hour|/day]:用来比对某段时间内数据包的平均流量,上面的例子是用来比对:每小时平均流量是否超过一次3个数据包。 除了每小时平均次外,也可以每秒钟、每分钟或每天平均一次,默认值为每小时平均一次,参数如后: /second、 /minute、/day。 除了进行数据包数量的比对外,设定这个参数也会在条件达成时,暂停数据包的比对动作,以避免因洪水攻击法,导致服务被阻断。
- --limit-burst number:用来比对瞬间大量封包的数量,上面的例子是用来比对一次同时涌入的封包是否超过 5 个(这是默认值),超过此上限的封将被直接丢弃。使用效果同上。
# iptables -A INPUT -d 192.168.100.51 -p icmp -m limit --limit 3/minute --limit-burst 5 -j ACCEPT
# iptables -A -OUTPUT -s 192.168.100.51 -p icmp -j ACCEPT
[root@study-2 ~]# ping 192.168.100.51
PING 192.168.100.51 (192.168.100.51) 56(84) bytes of data.
64 bytes from 192.168.100.51: icmp_seq=1 ttl=64 time=0.450 ms
64 bytes from 192.168.100.51: icmp_seq=2 ttl=64 time=0.160 ms
64 bytes from 192.168.100.51: icmp_seq=3 ttl=64 time=0.225 ms
64 bytes from 192.168.100.51: icmp_seq=4 ttl=64 time=0.280 ms
64 bytes from 192.168.100.51: icmp_seq=5 ttl=64 time=0.152 ms
64 bytes from 192.168.100.51: icmp_seq=21 ttl=64 time=0.211 ms
64 bytes from 192.168.100.51: icmp_seq=41 ttl=64 time=0.443 ms
64 bytes from 192.168.100.51: icmp_seq=61 ttl=64 time=0.211 ms
显式扩展-->state扩展
根据”连接追踪机制“去检查连接的状态;
conntrack机制:追踪本机上的请求和响应之间的关系;状态有如下几种:
- NEW:新发出请求;连接追踪模板中不存在此连接的相关信息条目,因此,将其识别为第一次发出的请求;
- ESTABLISHED:NEW状态之后,连接追踪模板中为其建立的条目失效之前期间内所进行的通信状态;
- RELATED:相关联的连接;如ftp协议中的数据连接与命令连接之间的关系;
- INVALID:无效的连接;
- UNTRACKED:未进行追踪的连接;
调整连接追踪功能所能够容纳的最大连接数量:
/proc/sys/net/nf_contrack_max
已经追踪到到的并记录下来的连接:
/proc/net/nf_conntrack
不同的协议的连接追踪时长:
/proc/sys/net/netfilter/
iptables的链接跟踪表最大容量为/proc/sys/net/ipv4/ip_conntrack_max,链接碰到各种状态的超时后就会从表中删除;当模板满载时,后续的连接可能会超时解決方法一般有两个:
(1) 加大nf_conntrack_max 值
vi /etc/sysctl.conf
net.ipv4.nf_conntrack_max = 393216
net.ipv4.netfilter.nf_conntrack_max = 393216
(2) 降低 nf_conntrack timeout时间
vi /etc/sysctl.conf
net.ipv4.netfilter.nf_conntrack_tcp_timeout_established = 300
net.ipv4.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
net.ipv4.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
net.ipv4.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
# iptables -A INPUT -d 192.168.100.51 -p tcp -m multiport --dports 22,80 -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A OUTPUT -s 192.168.100.51 -p tcp -m multiport --sports 22,80 -m state --state ESTABLISHED -j ACCEPT
开放被动模式的ftp服务:
(1) 装载ftp连接追踪的专用模块:
~]# modproble nf_conntrack_ftp
(2) 放行命令连接(假设Server地址为172.16.100.67):
~]# iptables -A INPUT -d 172.16.100.67 -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT
~]# iptables -A OUTPUT -s 172.16.100.67 -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT
(3) 放行数据连接(假设Server地址为172.16.100.67):
~]# iptables -A INPUT -d 172.16.100.67 -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
~]# iptables -I OUTPUT -s 172.16.100.67 -m state --state ESTABLISHED -j ACCEPT
开放本机的网络连接:
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A OUTPUT -m state --state NEW,ESTABLISHED -j ACCEPT
在上面的规则配置好后如果在放行端口可以使用下面的命令:
# iptables -A INPUT -p tcp -m multiport --dports 22,80 -m state --state NEW -j ACCEPT
如果开放ftp传输可以使用下面的命令:
# modprobe nf_conntrack_ftp
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A OUTPUT -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A INPUT -p tcp --dport 21 -m state --state NEW -j ACCEPT
forward转发配置
环境说明
主机 | IP |
---|---|
study-1 | 192.168.100.51 10.0.0.1 |
study-2 | 192.168.100.52 |
study-3 | 10.0.0.53 |
实验能够通过转发的功能将10.0.0.53主机能够访问到192.168.100.52上的资源。
study-1主机配置
iptables规则:
# Generated by iptables-save v1.4.21 on Wed May 10 22:20:44 2017
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [4:541]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
-A OUTPUT -m state --state NEW,ESTABLISHED -j ACCEPT
-A FORWARD -p icmp -j ACCEPT
-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -p tcp --dport 80 -m state --state NEW -j ACCEPT
-A FORWARD -p tcp --dport 21 -m state --state NEW -j ACCEPT
-A FORWARD -p tcp --dport 22 -m state --state NEW -j ACCEPT
COMMIT
# Completed on Wed May 10 22:20:44 2017
开启内核的ip转发功能:
# echo 1 > /proc/sys/net/ipv4/ip_forward
加载nf_conntrack_ftp模块:
# modprobe nf_conntrack_ftp
study-2主机配置
# route add -net 10.0.0.0/24 gw 192.168.100.51
# modprobe nf_conntrack_ftp
# systemctl start vsftpd.service
# ngninx
study-3主机测试
测试ping:
# ping 192.168.100.52
PING 192.168.100.52 (192.168.100.52) 56(84) bytes of data.
64 bytes from 192.168.100.52: icmp_seq=1 ttl=63 time=0.560 ms
64 bytes from 192.168.100.52: icmp_seq=2 ttl=63 time=0.703 ms
64 bytes from 192.168.100.52: icmp_seq=3 ttl=63 time=0.778 ms
测试http访问:
# curl -I 192.168.100.52
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Thu, 11 May 2017 11:32:58 GMT
Content-Type: text/html
Content-Length: 14
Last-Modified: Wed, 03 May 2017 09:04:07 GMT
Connection: keep-alive
ETag: "59099d07-e"
Accept-Ranges: bytes
测试ftp访问:
# lftp 192.168.100.52
lftp 192.168.100.52:~> ls
drwxr-xr-x 2 0 0 6 Nov 05 2016 pub
端口转发
# iptables -t nat -A PREROUTING -d 192.168.100.51 -p tcp --dport 80 -j REDIRECT --to-ports 8080
# ss -tnlp |grep 80
LISTEN 0 128 *:8080 *:* users:(("nginx",pid=2385,fd=6),("nginx",pid=2384,fd=6))
LISTEN 0 128 :::8080 :::* users:(("nginx",pid=2385,fd=7),("nginx",pid=2384,fd=7))
# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
41 2160 REDIRECT tcp -- * * 0.0.0.0/0 192.168.100.51 tcp dpt:80 redir ports 8080
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
测试
[root@study-2 ~]# curl http://192.168.100.51/
study-1
snat
# echo 1 > /proc/sys/net/ipv4/ip_forward
# iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -j SNAT --to-source 192.168.100.51
MASQUERADE
源地址转换:当源地址为动态获取的地址时,MASQUERADE可自行判断要转换为的地址;
# echo 1 > /proc/sys/net/ipv4/ip_forward
# iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -j MASQUERADE
dnat
# iptables -t nat -A PREROUTING -d 172.16.100.67 -p tcp --dport 80 -j DNAT --to-destination 192.168.12.77
# iptables -t nat -A PREROUTING -d 172.16.100.67 -p tcp --dport 80 -j DNAT --to-destination 192.168.12.77:8080
# iptables -t nat -A PREROUTING -d 172.16.100.67 -p tcp --dport 22012 -j DNAT --to-destination 192.168.12.78:22